refactor(oauth): OAuth server tables through repositories

OauthClientsRepository/OauthTokensRepository/OauthConsentsRepository
replace OauthService's raw SQL (OA1-OA33). revokeChain's recursive CTE
and the oauth_clients join (its FK actually targets client_id, not the
row id the generated relation assumes) go through em.getKysely();
OA19's chain revoke is one nativeUpdate($in); OA12's consent grant is
em.upsert on the (client, user) unique key. revokeAllForUser built now
for Task 5. Every row-out read is disableIdentityMap: true; inserts go
through em.insert.
This commit is contained in:
jubnl
2026-09-22 21:18:08 +02:00
parent 44cf31c958
commit d82395d0ae
13 changed files with 1985 additions and 137 deletions
+24
View File
@@ -1,5 +1,6 @@
import { raw, type Platform, type RawQueryFragment } from '@mikro-orm/core';
import { SqlitePlatform } from '@mikro-orm/sql';
import { sql, type Expression } from 'kysely';
/**
* The only place a repository may spell a database function.
@@ -99,3 +100,26 @@ export function lower(platform: Platform, ref: string): RawQueryFragment & symbo
if (platform instanceof SqlitePlatform) return raw(`LOWER(${column(ref)})`);
return unsupported(platform);
}
/**
* `CURRENT_TIMESTAMP`, for a query built through `em.getKysely()` — the
* escape hatch for a recursive CTE (`OauthTokensRepository.collectChainIds`)
* or a join the QueryBuilder's relation metadata cannot express correctly
* (`OauthTokensRepository.listActiveByUser`/`listAllActiveWithClientAndUser`
* — `oauth_tokens.client_id` references `oauth_clients.client_id`, not its
* primary key, and the generated entity's `client` relation has no
* `referencedColumnNames` override, so a QueryBuilder `.innerJoin('ot.client',
* …)` silently joins on the wrong column; see those methods' docstrings).
* Kysely has its own expression system, entirely separate from MikroORM's
* `raw()` — `currentTimestamp` above returns a value this file's OTHER
* consumers (the QueryBuilder, `nativeUpdate`) accept, but a Kysely query
* cannot use a `RawQueryFragment` as an operand. This is the one place a
* repository may reach for the Kysely spelling of the same literal, kept
* here rather than in a repository file so `no-restricted-syntax`'s ban on
* spelling raw SQL directly in `src/db/repositories/**` still holds — this
* file is exempt from that rule by design (it IS the one approved place).
*/
export function currentTimestampKysely(platform: Platform): Expression<string> {
if (platform instanceof SqlitePlatform) return sql<string>`CURRENT_TIMESTAMP`;
return unsupported(platform);
}