@vsrepo/drizzle-adapter 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1 -0
- package/dist/index.cjs +1531 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +184 -0
- package/dist/index.d.ts +184 -0
- package/dist/index.js +1525 -0
- package/dist/index.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/drizzle.adapter.ts","../src/resolvers/fields-config.resolver.ts","../src/resolvers/isolation-level.resolver.ts","../src/resolvers/raw-sql.resolver.ts","../src/resolvers/raw-result.resolver.ts","../src/resolvers/map-drizzle-error.resolver.ts","../src/validators/validate-adapter-config.validator.ts","../src/validators/validate-relations.validator.ts","../src/validators/is-plain-object.validator.ts","../src/parsers/columns.parser.ts","../src/parsers/with.parser.ts","../src/parsers/where.parser.ts","../src/parsers/sql-where.parser.ts","../src/parsers/order-by.parser.ts","../src/parsers/sql-order-by.parser.ts","../src/resolvers/merge-entities.resolver.ts","../src/resolvers/relation-writes.resolver.ts"],"sourcesContent":["export { DrizzleAdapter } from \"./drizzle.adapter.js\";\n\nexport type { SupportedDialects } from \"./types/supported-dialects.type.js\";\nexport type { DrizzleAdapterConfig } from \"./types/drizzle-adapter-config.type.js\";\nexport type { DrizzleDbLike } from \"./types/drizzle-db-like.type.js\";\nexport type { DrizzleTransactionLike } from \"./types/drizzle-transaction-like.type.js\";\n","import { avg, count as countFn, eq, max as maxFn, min as minFn, sql, sum as sumFn, Table } from \"drizzle-orm\";\r\nimport {\r\n AdapterErrorCode,\r\n AdapterMethodOptions,\r\n AdapterQueryOptions,\r\n CountResult,\r\n DeepPartial,\r\n NumericKeys,\r\n VSRepoAdapter,\r\n VSRepoAdapterError,\r\n VSRepoTransactionOptions,\r\n VSRepoWhere,\r\n} from \"vsrepo\";\r\nimport { DrizzleAdapterConfig } from \"./types/drizzle-adapter-config.type.js\";\r\nimport { DrizzleDbLike } from \"./types/drizzle-db-like.type.js\";\r\nimport { SupportedDialects } from \"./types/supported-dialects.type.js\";\r\nimport { resolveFieldsConfig } from \"./resolvers/fields-config.resolver.js\";\r\nimport { DrizzleTransactionLike } from \"./types/drizzle-transaction-like.type.js\";\r\nimport { resolveIsolationLevel } from \"./resolvers/isolation-level.resolver.js\";\r\nimport { resolveRawSql } from \"./resolvers/raw-sql.resolver.js\";\r\nimport { resolveRawResult } from \"./resolvers/raw-result.resolver.js\";\r\nimport { mapDrizzleError } from \"./resolvers/map-drizzle-error.resolver.js\";\r\nimport { validateDrizzleAdapterConfig } from \"./validators/validate-adapter-config.validator.js\";\r\nimport { validateRelations } from \"./validators/validate-relations.validator.js\";\r\nimport { parseColumns } from \"./parsers/columns.parser.js\";\r\nimport { parseWith } from \"./parsers/with.parser.js\";\r\nimport { parseDrizzleWhere, hasQuantifierFilter } from \"./parsers/where.parser.js\";\r\nimport { parseSqlWhere, SqlWhereContext } from \"./parsers/sql-where.parser.js\";\r\nimport { parseOrderBy } from \"./parsers/order-by.parser.js\";\r\nimport { parseSqlOrderBy } from \"./parsers/sql-order-by.parser.js\";\r\nimport { PlainObject } from \"./types/plain-object.type.js\";\r\nimport { ResolvedRelation } from \"./types/resolved-relation.type.js\";\r\nimport { mergeEntities } from \"./resolvers/merge-entities.resolver.js\";\r\nimport { resolveFkHereFields, resolveFkThereFields, splitWritePayload } from \"./resolvers/relation-writes.resolver.js\";\r\n\r\n/**\r\n * @publicApi\r\n */\r\nexport class DrizzleAdapter<T, K extends DrizzleDbLike = DrizzleDbLike> extends VSRepoAdapter<T> {\r\n private readonly table: Table;\r\n private readonly db: DrizzleDbLike;\r\n private readonly dialect: SupportedDialects;\r\n private readonly pk: string;\r\n private readonly queryKey: keyof K[\"query\"];\r\n private readonly relations?: Map<string, ResolvedRelation>;\r\n\r\n constructor(db: K, config: DrizzleAdapterConfig<T, K>) {\r\n super();\r\n\r\n const validated = validateDrizzleAdapterConfig<T, K>(db, config);\r\n\r\n this.db = validated.db;\r\n this.table = validated.config.table;\r\n this.dialect = validated.config.dialect ?? \"postgresql\";\r\n this.queryKey = validated.config.queryKey;\r\n\r\n const fieldsConfig = resolveFieldsConfig(this.table);\r\n this.pk = fieldsConfig.pk;\r\n\r\n this.relations = validateRelations<T>(this.table, this.dialect, validated.config.relations);\r\n }\r\n\r\n /**\r\n * Returns `db.query[queryKey]` (the relational query builder entry for\r\n * this adapter's table), reading from `db` when a transaction/executor\r\n * override is passed via `options.db`, otherwise from the root client.\r\n */\r\n private getQueryBuilder(db?: unknown): {\r\n findFirst: (arg: PlainObject) => Promise<any>;\r\n findMany: (arg: PlainObject) => Promise<any>;\r\n } {\r\n const executor = (db as DrizzleDbLike | undefined) ?? this.db;\r\n return executor.query[this.queryKey as string] as any;\r\n }\r\n\r\n /**\r\n * Resolves the \"read\" part of a query arg: `columns`/`with`/`where`/\r\n * `orderBy`/pagination.\r\n *\r\n * Per the adapter contract: when both `select` and `relations` are\r\n * given, `select` wins and `relations` is ignored entirely.\r\n */\r\n private async resolveReadArgs(\r\n where: VSRepoWhere<T>,\r\n options?: AdapterMethodOptions<T>,\r\n single = false,\r\n ): Promise<PlainObject> {\r\n options ??= {};\r\n\r\n let columns: PlainObject | undefined;\r\n let withArg: PlainObject | undefined;\r\n\r\n if (options.select) {\r\n const parsedSelect = parseColumns(options.select);\r\n columns = parsedSelect.columns;\r\n withArg = parsedSelect.with;\r\n } else if (options.relations) {\r\n withArg = parseWith(options.relations);\r\n }\r\n\r\n const found = await this.resolveFindWhere(where, {\r\n db: options.db,\r\n order: options.order,\r\n limit: single ? 1 : options.pagination?.limit,\r\n offset: single ? undefined : options.pagination?.offset,\r\n });\r\n\r\n return {\r\n where: found.where,\r\n columns,\r\n with: withArg,\r\n // When the prefetch already applied limit/offset, `IN (pks)` no longer preserves that\r\n // order on its own, so the same ordering has to be re-applied at this level too — but\r\n // limit/offset themselves must NOT be re-applied, since the pk set is already the exact page.\r\n orderBy: found.paginationApplied ? found.orderBy : parseOrderBy<T>(options.order),\r\n limit: found.paginationApplied ? undefined : options.pagination?.limit,\r\n offset: found.paginationApplied ? undefined : options.pagination?.offset,\r\n };\r\n }\r\n\r\n /** Builds the context `parseSqlWhere` needs to resolve `_with`/`_without`/`_some`/`_every`/`_none` relation filters. */\r\n private getSqlWhereContext(db?: unknown): SqlWhereContext {\r\n return {\r\n table: this.table,\r\n pk: this.pk,\r\n relations: this.relations,\r\n db: (db as DrizzleDbLike | undefined) ?? this.db,\r\n };\r\n }\r\n\r\n /**\r\n * Resolves a user-supplied `VSRepoWhere<T>` into the `where` shape the\r\n * relational query API (`db.query[queryKey].findFirst/findMany`) accepts.\r\n *\r\n * The relational API's own object-shaped `where` (`where.parser.ts`) has\r\n * no native `_every`/`_none` semantics for to-many relations — so when\r\n * `where` contains one (`hasQuantifierFilter`), this instead:\r\n * 1. Resolves `where` into a `SQL` condition via `sql-where.parser.ts`\r\n * (which DOES support `_every`/`_none`, via `NOT EXISTS`);\r\n * 2. Runs `db.select({pk}).from(table).where(condition)`, applying the\r\n * SAME `order`/`limit`/`offset` the final query would've used\r\n * (`sql-order-by.parser.ts`), so the prefetch only ever pulls the\r\n * rows the caller actually needs, instead of every matching row;\r\n * 3. Returns `parseDrizzleWhere({ [pk]: { in: pks } })` instead — the\r\n * relational API then only has to filter by pk (trivial for it),\r\n * while still handling `columns`/`with` on the correct result set.\r\n *\r\n * Since SQL `IN (...)` doesn't preserve the given list's order, `resolveReadArgs`\r\n * re-applies `orderBy` (but NOT `limit`/`offset`, already baked into the pk set)\r\n * on the final relational query when `paginationApplied` comes back `true`.\r\n *\r\n * This keeps `_every`/`_none` support consistent between this adapter's\r\n * two `where` parsers — from the outside, `findOne`/`findMany`/etc. never\r\n * throw `NOT_SUPPORTED` for them, at the cost of an extra round-trip only\r\n * when they're actually used.\r\n */\r\n private async resolveFindWhere(\r\n where: VSRepoWhere<T>,\r\n opts?: { db?: unknown; order?: AdapterMethodOptions<T>[\"order\"]; limit?: number; offset?: number },\r\n ): Promise<{ where: PlainObject | undefined; orderBy?: PlainObject; paginationApplied: boolean }> {\r\n if (!hasQuantifierFilter(where)) {\r\n return { where: parseDrizzleWhere<T>(where, this.dialect), paginationApplied: false };\r\n }\r\n\r\n const executor = (opts?.db as DrizzleDbLike | undefined) ?? this.db;\r\n const pkColumn = (this.table as unknown as PlainObject)[this.pk];\r\n const condition = parseSqlWhere(where, this.getSqlWhereContext(executor));\r\n const sqlOrderBy = parseSqlOrderBy<T>(this.table, opts?.order);\r\n\r\n let qb = (executor as any).select({ pk: pkColumn }).from(this.table).where(condition);\r\n if (sqlOrderBy) qb = qb.orderBy(...sqlOrderBy);\r\n if (opts?.limit !== undefined) qb = qb.limit(opts.limit);\r\n if (opts?.offset !== undefined) qb = qb.offset(opts.offset);\r\n\r\n const rows = await qb;\r\n const pks = rows.map((row: PlainObject) => row.pk);\r\n\r\n return {\r\n where: parseDrizzleWhere<T>({ [this.pk]: { in: pks } } as unknown as VSRepoWhere<T>, this.dialect),\r\n orderBy: parseOrderBy<T>(opts?.order),\r\n paginationApplied: opts?.limit !== undefined || opts?.offset !== undefined,\r\n };\r\n }\r\n\r\n /**\r\n * Strips relation fields from a payload — used by `createMany`/`updateMany`/\r\n * `updateManyReturning`, since batch statements only accept flat column\r\n * data (no nested writes). Throws `VSRepoAdapterError` (code\r\n * `NOT_SUPPORTED`) instead of silently dropping the field, when a\r\n * configured relation field is present in the payload.\r\n */\r\n private stripRelationFields(obj: PlainObject): PlainObject {\r\n if (!this.relations) return obj;\r\n\r\n const data: PlainObject = {};\r\n\r\n for (const [key, value] of Object.entries(obj)) {\r\n if (value === undefined) continue;\r\n\r\n if (this.relations.has(key)) {\r\n throw new VSRepoAdapterError(\r\n `Field '${key}' is a configured relation, but this adapter's *Many operations don't support nested relation writes.`,\r\n AdapterErrorCode.NOT_SUPPORTED,\r\n null,\r\n );\r\n }\r\n\r\n data[key] = value;\r\n }\r\n\r\n return data;\r\n }\r\n\r\n private isRootClient(db: any): boolean {\r\n return typeof db?.rollback !== \"function\";\r\n }\r\n\r\n private async runTransactional<R>(db: any, fn: (tx: DrizzleTransactionLike) => Promise<R>): Promise<R> {\r\n if (db && !this.isRootClient(db)) {\r\n return fn(db);\r\n }\r\n\r\n return ((db as DrizzleDbLike) ?? this.db).transaction(fn);\r\n }\r\n\r\n async runInTransaction<R>(\r\n fn: (tx: DrizzleTransactionLike) => Promise<R>,\r\n options?: VSRepoTransactionOptions,\r\n ): Promise<R> {\r\n if (options?.timeoutMs !== undefined) {\r\n throw new VSRepoAdapterError(\r\n \"This adapter doesn't support 'timeoutMs' in transactions.\",\r\n AdapterErrorCode.NOT_SUPPORTED,\r\n null,\r\n );\r\n }\r\n\r\n try {\r\n return await this.db.transaction(fn, {\r\n isolationLevel: options?.isolationLevel && resolveIsolationLevel(options.isolationLevel),\r\n });\r\n } catch (error) {\r\n throw mapDrizzleError(error, \"runInTransaction\", this.dialect);\r\n }\r\n }\r\n\r\n getDbClient(): DrizzleDbLike {\r\n return this.db;\r\n }\r\n\r\n async query<R = any>(rawQuery: string, options?: AdapterQueryOptions): Promise<R> {\r\n const executor = (options?.db as DrizzleTransactionLike | undefined) ?? this.db;\r\n\r\n try {\r\n const sqlQuery = resolveRawSql(this.dialect, rawQuery, options?.args);\r\n const result = await executor.execute(sqlQuery);\r\n\r\n return resolveRawResult(this.dialect, result, options?.modifying ?? false) as R;\r\n } catch (error) {\r\n throw mapDrizzleError(error, \"query\", this.dialect);\r\n }\r\n }\r\n\r\n async findOne(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<T | null> {\r\n try {\r\n const arg = await this.resolveReadArgs(where, options, true);\r\n const result = await this.getQueryBuilder(options?.db).findFirst(arg);\r\n\r\n return (result ?? null) as T | null;\r\n } catch (error) {\r\n throw mapDrizzleError(error, \"findOne\", this.dialect);\r\n }\r\n }\r\n\r\n async findOneOrThrow(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<T> {\r\n try {\r\n const arg = await this.resolveReadArgs(where, options, true);\r\n const result = await this.getQueryBuilder(options?.db).findFirst(arg);\r\n\r\n if (!result) {\r\n throw new VSRepoAdapterError(\r\n \"'findOneOrThrow' found no record matching the given 'where'.\",\r\n AdapterErrorCode.NOT_FOUND,\r\n null,\r\n );\r\n }\r\n\r\n return result as T;\r\n } catch (error) {\r\n throw mapDrizzleError(error, \"findOneOrThrow\", this.dialect);\r\n }\r\n }\r\n\r\n async findMany(\r\n where: VSRepoWhere<T>,\r\n options?: AdapterMethodOptions<T> & { distinct?: (keyof T)[] },\r\n ): Promise<T[]> {\r\n if (options?.distinct !== undefined) {\r\n throw new VSRepoAdapterError(\r\n \"This adapter doesn't support 'distinct' in 'findMany': Drizzle's relational query API \" +\r\n \"(db.query[queryKey].findMany) has no 'distinct' option.\",\r\n AdapterErrorCode.NOT_SUPPORTED,\r\n null,\r\n );\r\n }\r\n\r\n try {\r\n const arg = await this.resolveReadArgs(where, options);\r\n return (await this.getQueryBuilder(options?.db).findMany(arg)) as T[];\r\n } catch (error) {\r\n throw mapDrizzleError(error, \"findMany\", this.dialect);\r\n }\r\n }\r\n\r\n async save(obj: DeepPartial<T>, options?: AdapterMethodOptions<T>): Promise<T> {\r\n try {\r\n const objAny = obj as unknown as PlainObject;\r\n const pkValue = objAny[this.pk];\r\n\r\n if (pkValue === undefined) {\r\n return await this.create(obj, options);\r\n }\r\n\r\n return await this.runTransactional(options?.db, async tx => {\r\n const pkColumn = (this.table as unknown as PlainObject)[this.pk];\r\n const existing = await (tx as any)\r\n .select({ pk: pkColumn })\r\n .from(this.table)\r\n .where(eq(pkColumn, pkValue))\r\n .limit(1);\r\n\r\n if (existing.length === 0) {\r\n return this.create(obj, { ...options, db: tx });\r\n }\r\n\r\n return this.update({ [this.pk]: pkValue } as unknown as VSRepoWhere<T>, obj, { ...options, db: tx });\r\n });\r\n } catch (error) {\r\n throw mapDrizzleError(error, \"save\", this.dialect);\r\n }\r\n }\r\n\r\n async saveMany(objs: DeepPartial<T>[], options?: AdapterMethodOptions<T>): Promise<T[]> {\r\n try {\r\n return await this.runTransactional(options?.db, tx =>\r\n Promise.all(objs.map(obj => this.save(obj, { ...options, db: tx }))),\r\n );\r\n } catch (error) {\r\n throw mapDrizzleError(error, \"saveMany\", this.dialect);\r\n }\r\n }\r\n\r\n async create(obj: DeepPartial<T>, options?: AdapterMethodOptions<T>): Promise<T> {\r\n try {\r\n return await this.runTransactional(options?.db, async tx => {\r\n const objAny = obj as unknown as PlainObject;\r\n\r\n const { scalarFields, fkHereEntries, fkThereEntries } = splitWritePayload(\r\n objAny,\r\n this.relations,\r\n this.pk,\r\n false,\r\n );\r\n\r\n await resolveFkHereFields(tx, fkHereEntries, scalarFields, undefined);\r\n\r\n const [created] = await (tx as any).insert(this.table).values(scalarFields).returning();\r\n const ownPkValue = created[this.pk];\r\n\r\n await resolveFkThereFields(tx, fkThereEntries, ownPkValue);\r\n\r\n const readArg = await this.resolveReadArgs(\r\n { [this.pk]: ownPkValue } as unknown as VSRepoWhere<T>,\r\n options,\r\n );\r\n const result = await this.getQueryBuilder(tx).findFirst(readArg);\r\n\r\n return (result ?? created) as T;\r\n });\r\n } catch (error) {\r\n throw mapDrizzleError(error, \"create\", this.dialect);\r\n }\r\n }\r\n\r\n async createMany(\r\n objs: DeepPartial<T>[],\r\n options?: AdapterMethodOptions<T> & { ignoreConflicts?: boolean },\r\n ): Promise<CountResult> {\r\n try {\r\n const data = objs.map(obj => this.stripRelationFields(obj as unknown as PlainObject));\r\n const executor = (options?.db as DrizzleDbLike | undefined) ?? this.db;\r\n\r\n let qb = (executor as any).insert(this.table).values(data);\r\n if (options?.ignoreConflicts) qb = qb.onConflictDoNothing();\r\n\r\n const result = await qb;\r\n const affected = resolveRawResult(this.dialect, result, true) as number;\r\n\r\n return { count: affected ?? data.length };\r\n } catch (error) {\r\n throw mapDrizzleError(error, \"createMany\", this.dialect);\r\n }\r\n }\r\n\r\n async createManyReturning(\r\n objs: DeepPartial<T>[],\r\n options?: AdapterMethodOptions<T> & { ignoreConflicts?: boolean },\r\n ): Promise<T[]> {\r\n try {\r\n const data = objs.map(obj => this.stripRelationFields(obj as unknown as PlainObject));\r\n const executor = (options?.db as DrizzleDbLike | undefined) ?? this.db;\r\n\r\n let qb = (executor as any).insert(this.table).values(data);\r\n if (options?.ignoreConflicts) qb = qb.onConflictDoNothing();\r\n\r\n return (await qb.returning()) as T[];\r\n } catch (error) {\r\n throw mapDrizzleError(error, \"createManyReturning\", this.dialect);\r\n }\r\n }\r\n\r\n async delete(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<T> {\r\n try {\r\n return await this.runTransactional(options?.db, async tx => {\r\n const readArg = await this.resolveReadArgs(where, options, true);\r\n const current = await this.getQueryBuilder(tx).findFirst(readArg);\r\n\r\n if (!current) {\r\n throw new VSRepoAdapterError(\r\n \"'delete' found no record matching the given 'where'.\",\r\n AdapterErrorCode.NOT_FOUND,\r\n null,\r\n );\r\n }\r\n\r\n const pkColumn = (this.table as unknown as PlainObject)[this.pk];\r\n await (tx as any).delete(this.table).where(eq(pkColumn, (current as PlainObject)[this.pk]));\r\n\r\n return current as T;\r\n });\r\n } catch (error) {\r\n throw mapDrizzleError(error, \"delete\", this.dialect);\r\n }\r\n }\r\n\r\n async deleteMany(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<CountResult> {\r\n try {\r\n const executor = (options?.db as DrizzleDbLike | undefined) ?? this.db;\r\n const condition = parseSqlWhere(where, this.getSqlWhereContext(executor));\r\n\r\n const result = await (executor as any).delete(this.table).where(condition);\r\n const affected = resolveRawResult(this.dialect, result, true) as number;\r\n\r\n return { count: affected ?? 0 };\r\n } catch (error) {\r\n throw mapDrizzleError(error, \"deleteMany\", this.dialect);\r\n }\r\n }\r\n\r\n async deleteManyReturning(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<T[]> {\r\n try {\r\n const executor = (options?.db as DrizzleDbLike | undefined) ?? this.db;\r\n const condition = parseSqlWhere(where, this.getSqlWhereContext(executor));\r\n\r\n return (await (executor as any).delete(this.table).where(condition).returning()) as T[];\r\n } catch (error) {\r\n throw mapDrizzleError(error, \"deleteManyReturning\", this.dialect);\r\n }\r\n }\r\n\r\n async update(where: VSRepoWhere<T>, obj: DeepPartial<T>, options?: AdapterMethodOptions<T>): Promise<T> {\r\n try {\r\n return await this.runTransactional(options?.db, async tx => {\r\n const current = await this.getQueryBuilder(tx).findFirst({\r\n where: (await this.resolveFindWhere(where, { db: tx, limit: 1 })).where,\r\n });\r\n\r\n if (!current) {\r\n throw new VSRepoAdapterError(\r\n \"'update' found no record matching the given 'where'.\",\r\n AdapterErrorCode.NOT_FOUND,\r\n null,\r\n );\r\n }\r\n\r\n const ownPkValue = (current as PlainObject)[this.pk];\r\n const objAny = obj as unknown as PlainObject;\r\n const { scalarFields, fkHereEntries, fkThereEntries } = splitWritePayload(\r\n objAny,\r\n this.relations,\r\n this.pk,\r\n true,\r\n );\r\n\r\n await resolveFkHereFields(tx, fkHereEntries, scalarFields, current as PlainObject);\r\n\r\n if (Object.keys(scalarFields).length > 0) {\r\n const pkColumn = (this.table as unknown as PlainObject)[this.pk];\r\n await (tx as any).update(this.table).set(scalarFields).where(eq(pkColumn, ownPkValue));\r\n }\r\n\r\n await resolveFkThereFields(tx, fkThereEntries, ownPkValue);\r\n\r\n const readArg = await this.resolveReadArgs(\r\n { [this.pk]: ownPkValue } as unknown as VSRepoWhere<T>,\r\n options,\r\n );\r\n const result = await this.getQueryBuilder(tx).findFirst(readArg);\r\n\r\n return (result ?? current) as T;\r\n });\r\n } catch (error) {\r\n throw mapDrizzleError(error, \"update\", this.dialect);\r\n }\r\n }\r\n\r\n async updateMany(\r\n where: VSRepoWhere<T>,\r\n obj: DeepPartial<T>,\r\n options?: AdapterMethodOptions<T>,\r\n ): Promise<CountResult> {\r\n try {\r\n const executor = (options?.db as DrizzleDbLike | undefined) ?? this.db;\r\n const data = this.stripRelationFields(obj as unknown as PlainObject);\r\n const condition = parseSqlWhere(where, this.getSqlWhereContext(executor));\r\n\r\n const result = await (executor as any).update(this.table).set(data).where(condition);\r\n const affected = resolveRawResult(this.dialect, result, true) as number;\r\n\r\n return { count: affected ?? 0 };\r\n } catch (error) {\r\n throw mapDrizzleError(error, \"updateMany\", this.dialect);\r\n }\r\n }\r\n\r\n async updateManyReturning(\r\n where: VSRepoWhere<T>,\r\n obj: DeepPartial<T>,\r\n options?: AdapterMethodOptions<T>,\r\n ): Promise<T[]> {\r\n try {\r\n const executor = (options?.db as DrizzleDbLike | undefined) ?? this.db;\r\n const data = this.stripRelationFields(obj as unknown as PlainObject);\r\n const condition = parseSqlWhere(where, this.getSqlWhereContext(executor));\r\n\r\n return (await (executor as any).update(this.table).set(data).where(condition).returning()) as T[];\r\n } catch (error) {\r\n throw mapDrizzleError(error, \"updateManyReturning\", this.dialect);\r\n }\r\n }\r\n\r\n async count(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<number> {\r\n try {\r\n const executor = (options?.db as DrizzleDbLike | undefined) ?? this.db;\r\n const condition = parseSqlWhere(where, this.getSqlWhereContext(executor));\r\n\r\n const [row] = await (executor as any).select({ value: countFn() }).from(this.table).where(condition);\r\n return Number(row?.value ?? 0);\r\n } catch (error) {\r\n throw mapDrizzleError(error, \"count\", this.dialect);\r\n }\r\n }\r\n\r\n async exists(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<boolean> {\r\n try {\r\n const executor = (options?.db as DrizzleDbLike | undefined) ?? this.db;\r\n const condition = parseSqlWhere(where, this.getSqlWhereContext(executor));\r\n\r\n const rows = await (executor as any)\r\n .select({ one: sql`1` })\r\n .from(this.table)\r\n .where(condition)\r\n .limit(1);\r\n return rows.length > 0;\r\n } catch (error) {\r\n throw mapDrizzleError(error, \"exists\", this.dialect);\r\n }\r\n }\r\n\r\n async merge<K>(where: VSRepoWhere<T>, obj: DeepPartial<T>, options?: AdapterMethodOptions<T>): Promise<K & T> {\r\n try {\r\n const readArg = await this.resolveReadArgs(where, options);\r\n const result = await this.getQueryBuilder(options?.db).findFirst(readArg);\r\n\r\n if (!result) {\r\n throw new VSRepoAdapterError(\r\n \"'merge' found no record matching the given 'where'.\",\r\n AdapterErrorCode.NOT_FOUND,\r\n null,\r\n );\r\n }\r\n\r\n return mergeEntities(result as PlainObject, obj as unknown as PlainObject, this.relations) as unknown as K &\r\n T;\r\n } catch (error) {\r\n throw mapDrizzleError(error, \"merge\", this.dialect);\r\n }\r\n }\r\n\r\n async upsert(\r\n where: VSRepoWhere<T>,\r\n create: DeepPartial<T>,\r\n update: DeepPartial<T>,\r\n options?: AdapterMethodOptions<T>,\r\n ): Promise<T> {\r\n try {\r\n return await this.runTransactional(options?.db, async tx => {\r\n const current = await this.getQueryBuilder(tx).findFirst({\r\n where: (await this.resolveFindWhere(where, { db: tx, limit: 1 })).where,\r\n });\r\n\r\n if (current) {\r\n const ownPkValue = (current as PlainObject)[this.pk];\r\n return this.update({ [this.pk]: ownPkValue } as unknown as VSRepoWhere<T>, update, {\r\n ...options,\r\n db: tx,\r\n });\r\n }\r\n\r\n return this.create(create, { ...options, db: tx });\r\n });\r\n } catch (error) {\r\n throw mapDrizzleError(error, \"upsert\", this.dialect);\r\n }\r\n }\r\n\r\n /** Shared implementation behind `incrementOne`/`decrementOne`/`multiplyOne`/`divideOne`. */\r\n private async atomicUpdate(\r\n operation: string,\r\n field: NumericKeys<T>,\r\n toExpression: (column: any, value: unknown) => unknown,\r\n value: unknown,\r\n where: VSRepoWhere<T>,\r\n options?: AdapterMethodOptions<T>,\r\n ): Promise<T> {\r\n try {\r\n return await this.runTransactional(options?.db, async tx => {\r\n const current = await this.getQueryBuilder(tx).findFirst({\r\n where: (await this.resolveFindWhere(where, { db: tx, limit: 1 })).where,\r\n });\r\n\r\n if (!current) {\r\n throw new VSRepoAdapterError(\r\n `'${operation}' found no record matching the given 'where'.`,\r\n AdapterErrorCode.NOT_FOUND,\r\n null,\r\n );\r\n }\r\n\r\n const ownPkValue = (current as PlainObject)[this.pk];\r\n const pkColumn = (this.table as unknown as PlainObject)[this.pk];\r\n const column = (this.table as unknown as PlainObject)[field as string];\r\n\r\n await (tx as any)\r\n .update(this.table)\r\n .set({ [field as string]: toExpression(column, value) })\r\n .where(eq(pkColumn, ownPkValue));\r\n\r\n const readArg = await this.resolveReadArgs(\r\n { [this.pk]: ownPkValue } as unknown as VSRepoWhere<T>,\r\n options,\r\n );\r\n return (await this.getQueryBuilder(tx).findFirst(readArg)) as T;\r\n });\r\n } catch (error) {\r\n throw mapDrizzleError(error, operation, this.dialect);\r\n }\r\n }\r\n\r\n incrementOne<K extends NumericKeys<T>>(\r\n field: K,\r\n value: NonNullable<T[K]>,\r\n where: VSRepoWhere<T>,\r\n options?: AdapterMethodOptions<T>,\r\n ): Promise<T> {\r\n return this.atomicUpdate(\"incrementOne\", field, (column, v) => sql`${column} + ${v}`, value, where, options);\r\n }\r\n\r\n decrementOne<K extends NumericKeys<T>>(\r\n field: K,\r\n value: NonNullable<T[K]>,\r\n where: VSRepoWhere<T>,\r\n options?: AdapterMethodOptions<T>,\r\n ): Promise<T> {\r\n return this.atomicUpdate(\"decrementOne\", field, (column, v) => sql`${column} - ${v}`, value, where, options);\r\n }\r\n\r\n multiplyOne<K extends NumericKeys<T>>(\r\n field: K,\r\n value: NonNullable<T[K]>,\r\n where: VSRepoWhere<T>,\r\n options?: AdapterMethodOptions<T>,\r\n ): Promise<T> {\r\n return this.atomicUpdate(\"multiplyOne\", field, (column, v) => sql`${column} * ${v}`, value, where, options);\r\n }\r\n\r\n divideOne<K extends NumericKeys<T>>(\r\n field: K,\r\n value: NonNullable<T[K]>,\r\n where: VSRepoWhere<T>,\r\n options?: AdapterMethodOptions<T>,\r\n ): Promise<T> {\r\n return this.atomicUpdate(\"divideOne\", field, (column, v) => sql`${column} / ${v}`, value, where, options);\r\n }\r\n\r\n /** Shared implementation behind `sum`/`average`/`min`/`max`. */\r\n private async aggregate(\r\n operation: string,\r\n fn: (column: any) => any,\r\n field: NumericKeys<T>,\r\n where: VSRepoWhere<T> | undefined,\r\n options: AdapterMethodOptions<T> | undefined,\r\n ): Promise<number | null> {\r\n try {\r\n const executor = (options?.db as DrizzleDbLike | undefined) ?? this.db;\r\n const condition = parseSqlWhere(where, this.getSqlWhereContext(executor));\r\n const column = (this.table as unknown as PlainObject)[field as string];\r\n\r\n const [row] = await (executor as any)\r\n .select({ value: fn(column) })\r\n .from(this.table)\r\n .where(condition);\r\n const raw = row?.value;\r\n\r\n if (raw === null || raw === undefined) return null;\r\n return typeof raw === \"number\" ? raw : Number(raw);\r\n } catch (error) {\r\n throw mapDrizzleError(error, operation, this.dialect);\r\n }\r\n }\r\n\r\n sum(field: NumericKeys<T>, where?: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<number | null> {\r\n return this.aggregate(\"sum\", sumFn, field, where, options);\r\n }\r\n\r\n average(field: NumericKeys<T>, where?: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<number | null> {\r\n return this.aggregate(\"average\", avg, field, where, options);\r\n }\r\n\r\n min(field: NumericKeys<T>, where?: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<number | null> {\r\n return this.aggregate(\"min\", minFn, field, where, options);\r\n }\r\n\r\n max(field: NumericKeys<T>, where?: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<number | null> {\r\n return this.aggregate(\"max\", maxFn, field, where, options);\r\n }\r\n}\r\n","import { AdapterErrorCode, VSRepoAdapterError } from \"vsrepo\";\r\nimport { getColumns, getTableName, Table } from \"drizzle-orm\";\r\n\r\nexport function resolveFieldsConfig(table: Table): { pk: string } {\r\n let pk: string | undefined;\r\n\r\n for (const column of Object.values(getColumns(table))) {\r\n if (column.primary) {\r\n pk = column.name;\r\n break;\r\n }\r\n }\r\n\r\n if (!pk) {\r\n throw new VSRepoAdapterError(\r\n `Table '${getTableName(table)}' has no primary key defined. VSRepoDrizzleAdapter requires every table to declare a primary key.`,\r\n AdapterErrorCode.INVALID_ADAPTER_CONFIG,\r\n null,\r\n );\r\n }\r\n\r\n return { pk };\r\n}\r\n","import { TransactionIsolationLevel } from \"vsrepo\";\n\nexport type DrizzleIsolationLevel = \"read uncommitted\" | \"read committed\" | \"repeatable read\" | \"serializable\";\n\nconst isolationRecord: Record<TransactionIsolationLevel, DrizzleIsolationLevel> = {\n ReadCommitted: \"read committed\",\n ReadUncommitted: \"read uncommitted\",\n RepeatableRead: \"repeatable read\",\n Serializable: \"serializable\",\n};\n\nexport function resolveIsolationLevel(vsrepoIsolation: TransactionIsolationLevel): DrizzleIsolationLevel {\n return isolationRecord[vsrepoIsolation];\n}\n","import { SQL, StringChunk, Param, type SQLChunk } from \"drizzle-orm\";\r\nimport { SupportedDialects } from \"../types/supported-dialects.type.js\";\r\n\r\nconst PLACEHOLDER_PATTERNS: Record<SupportedDialects, RegExp> = {\r\n postgresql: /\\$(\\d+)/g,\r\n cockroach: /\\$(\\d+)/g,\r\n sqlite: /\\?/g,\r\n};\r\n\r\n/**\r\n * Dialects whose placeholders carry an explicit index (e.g. `$1`, `@P1`).\r\n * For these, the same index can appear more than once in the query\r\n * (e.g. `$1 ... $1`) and must resolve to the same argument every time.\r\n * `?`-style placeholders have no index, so they stay strictly positional.\r\n */\r\nconst NUMBERED_DIALECTS = new Set<SupportedDialects>([\"postgresql\", \"cockroach\"]);\r\n\r\nexport function resolveRawSql(dialect: SupportedDialects, query: string, args: unknown[] = []): SQL {\r\n const pattern = PLACEHOLDER_PATTERNS[dialect];\r\n const isNumbered = NUMBERED_DIALECTS.has(dialect);\r\n\r\n const chunks: SQLChunk[] = [];\r\n let lastIndex = 0;\r\n let positionalIndex = 0;\r\n\r\n for (const match of query.matchAll(pattern)) {\r\n chunks.push(new StringChunk(query.slice(lastIndex, match.index)));\r\n\r\n const argIndex = isNumbered ? Number(match[1]) - 1 : positionalIndex++;\r\n chunks.push(new Param(args[argIndex]));\r\n\r\n lastIndex = match.index + match[0].length;\r\n }\r\n\r\n chunks.push(new StringChunk(query.slice(lastIndex)));\r\n\r\n return new SQL(chunks);\r\n}\r\n","import { SupportedDialects } from \"../types/supported-dialects.type.js\";\r\n\r\nexport function resolveRawResult(dialect: SupportedDialects, result: any, modifying: boolean): unknown {\r\n switch (dialect) {\r\n case \"postgresql\":\r\n case \"cockroach\":\r\n return modifying ? (result.rowCount ?? 0) : result.rows; // assume node-postgres\r\n\r\n case \"sqlite\":\r\n return modifying ? (result.changes ?? 0) : result; // assume better-sqlite3\r\n }\r\n}\r\n","import { AdapterErrorCode, VSRepoAdapterError } from \"vsrepo\";\r\nimport { DrizzleQueryError, TransactionRollbackError } from \"drizzle-orm\";\r\nimport { SupportedDialects } from \"../types/supported-dialects.type.js\";\r\n\r\n/** Duck-typed shape of the handful of native driver error properties this mapper reads. */\r\ntype DriverLikeError = {\r\n code?: string | number;\r\n message?: string;\r\n};\r\n\r\n/**\r\n * Postgres/CockroachDB SQLSTATE -> AdapterErrorCode (both are wire-compatible,\r\n * so the same table applies to node-postgres and postgres.js).\r\n * @see https://www.postgresql.org/docs/current/errcodes-appendix.html\r\n */\r\nconst POSTGRES_SQLSTATE_MAP: Record<string, AdapterErrorCode> = {\r\n \"23505\": AdapterErrorCode.UNIQUE_CONSTRAINT_VIOLATION,\r\n \"23503\": AdapterErrorCode.FOREIGN_KEY_VIOLATION,\r\n \"23502\": AdapterErrorCode.NOT_NULL_VIOLATION,\r\n \"23514\": AdapterErrorCode.CHECK_VIOLATION,\r\n \"23000\": AdapterErrorCode.CONSTRAINT_VIOLATION,\r\n \"22001\": AdapterErrorCode.VALUE_TOO_LONG,\r\n \"22P02\": AdapterErrorCode.CONVERSION_ERROR,\r\n \"42601\": AdapterErrorCode.INVALID_QUERY,\r\n \"42703\": AdapterErrorCode.TABLE_OR_COLUMN_NOT_FOUND,\r\n \"42P01\": AdapterErrorCode.TABLE_OR_COLUMN_NOT_FOUND,\r\n \"40P01\": AdapterErrorCode.DEADLOCK,\r\n \"40001\": AdapterErrorCode.TRANSACTION_CONFLICT,\r\n \"55P03\": AdapterErrorCode.LOCK_TIMEOUT,\r\n \"57014\": AdapterErrorCode.TIMEOUT,\r\n \"28000\": AdapterErrorCode.INVALID_CREDENTIALS,\r\n \"28P01\": AdapterErrorCode.INVALID_CREDENTIALS,\r\n \"3D000\": AdapterErrorCode.CONNECTION_FAILED,\r\n};\r\n\r\n/**\r\n * SQLite result code -> AdapterErrorCode (assumes `better-sqlite3`, the\r\n * officially supported driver for this dialect).\r\n * @see https://www.sqlite.org/rescode.html\r\n */\r\nconst SQLITE_CODE_MAP: Record<string, AdapterErrorCode> = {\r\n SQLITE_CONSTRAINT_UNIQUE: AdapterErrorCode.UNIQUE_CONSTRAINT_VIOLATION,\r\n SQLITE_CONSTRAINT_PRIMARYKEY: AdapterErrorCode.UNIQUE_CONSTRAINT_VIOLATION,\r\n SQLITE_CONSTRAINT_FOREIGNKEY: AdapterErrorCode.FOREIGN_KEY_VIOLATION,\r\n SQLITE_CONSTRAINT_NOTNULL: AdapterErrorCode.NOT_NULL_VIOLATION,\r\n SQLITE_CONSTRAINT_CHECK: AdapterErrorCode.CHECK_VIOLATION,\r\n SQLITE_CONSTRAINT: AdapterErrorCode.CONSTRAINT_VIOLATION,\r\n SQLITE_BUSY: AdapterErrorCode.LOCK_TIMEOUT,\r\n SQLITE_LOCKED: AdapterErrorCode.LOCKED,\r\n SQLITE_MISUSE: AdapterErrorCode.INVALID_QUERY,\r\n SQLITE_CANTOPEN: AdapterErrorCode.CONNECTION_FAILED,\r\n};\r\n\r\nfunction resolveCodeFromDriverError(dialect: SupportedDialects, error: DriverLikeError): AdapterErrorCode | undefined {\r\n switch (dialect) {\r\n case \"postgresql\":\r\n case \"cockroach\":\r\n return typeof error.code === \"string\" ? POSTGRES_SQLSTATE_MAP[error.code] : undefined;\r\n\r\n case \"sqlite\":\r\n return typeof error.code === \"string\" ? SQLITE_CODE_MAP[error.code] : undefined;\r\n }\r\n}\r\n\r\n/**\r\n * Converts any error caught around a Drizzle call into a `VSRepoAdapterError`,\r\n * so `DrizzleAdapter` never lets a raw Drizzle/driver error escape. Already\r\n * wrapped errors — e.g. bubbling up from a nested adapter call, or a\r\n * config/usage error thrown by the adapter itself (see `resolveFieldsConfig`)\r\n * — are returned as-is instead of being wrapped a second time.\r\n *\r\n * @param error - The raw error caught around a Drizzle call.\r\n * @param operation - Name of the adapter method that failed, used in the message.\r\n * @param dialect - Dialect configured for this adapter instance, used to pick the right native error code table.\r\n */\r\nexport function mapDrizzleError(error: unknown, operation: string, dialect: SupportedDialects): VSRepoAdapterError {\r\n if (error instanceof VSRepoAdapterError) return error;\r\n\r\n if (error instanceof TransactionRollbackError) {\r\n return new VSRepoAdapterError(\r\n `'${operation}' was rolled back intentionally via 'tx.rollback()'`,\r\n AdapterErrorCode.UNKNOWN,\r\n error,\r\n );\r\n }\r\n\r\n // DrizzleQueryError wraps the native driver error in `cause` — unwrap it so\r\n // the dialect-specific code tables above can read the real driver fields.\r\n const driverError: DriverLikeError =\r\n error instanceof DrizzleQueryError && error.cause\r\n ? (error.cause as DriverLikeError)\r\n : (error as DriverLikeError);\r\n\r\n const code = resolveCodeFromDriverError(dialect, driverError);\r\n\r\n return new VSRepoAdapterError(\r\n `'${operation}' failed: ${driverError?.message ?? \"unknown error\"}`,\r\n code ?? AdapterErrorCode.UNKNOWN,\r\n error,\r\n );\r\n}\r\n","import { is, Table } from \"drizzle-orm\";\r\nimport { AdapterErrorCode, VSRepoAdapterError } from \"vsrepo\";\r\nimport { DrizzleAdapterConfig } from \"../types/drizzle-adapter-config.type.js\";\r\nimport { DrizzleDbLike } from \"../types/drizzle-db-like.type.js\";\r\nimport { PlainObject } from \"../types/plain-object.type.js\";\r\nimport { SupportedDialects } from \"../types/supported-dialects.type.js\";\r\n\r\nconst SUPPORTED_DIALECTS: ReadonlySet<SupportedDialects> = new Set([\"postgresql\", \"sqlite\", \"cockroach\"]);\r\n\r\n/**\r\n * Validates the two arguments received by `DrizzleAdapter`'s constructor\r\n * (`db` and `config`), failing fast — with a clear `VSRepoAdapterError` —\r\n * instead of letting the adapter break later, on the first query, with a\r\n * generic runtime error (`Cannot read properties of undefined`, etc.).\r\n *\r\n * Checks, in order:\r\n * - `db` isn't null/undefined (code `MISSING_DB_CLIENT`);\r\n * - `db.query` is an object — only present when the client was created with\r\n * Drizzle's `relations` config, e.g. `drizzle(connection, { relations })`\r\n * (code `MISSING_DB_CLIENT`);\r\n * - `config` isn't null/undefined (code `INVALID_ADAPTER_CONFIG`);\r\n * - `config.table` is a Drizzle `Table` instance (code `INVALID_ADAPTER_CONFIG`);\r\n * - `config.dialect`, when provided, is one of `SupportedDialects` (code `INVALID_ADAPTER_CONFIG`);\r\n * - `config.queryKey` is a non-empty string (code `INVALID_ADAPTER_CONFIG`);\r\n * - `db.query[config.queryKey]` exists and exposes `findFirst`/`findMany` —\r\n * catches a typo'd/mismatched `queryKey` in the constructor, not three\r\n * calls later inside `findOne` (code `MODEL_NOT_FOUND`).\r\n */\r\nexport function validateDrizzleAdapterConfig<T, K extends DrizzleDbLike>(\r\n db: unknown,\r\n config: unknown,\r\n): { db: K; config: DrizzleAdapterConfig<T, K> } {\r\n if (db === null || db === undefined) {\r\n throw new VSRepoAdapterError(\r\n \"Missing Drizzle client: the first constructor argument (db) is null/undefined.\",\r\n AdapterErrorCode.MISSING_DB_CLIENT,\r\n null,\r\n );\r\n }\r\n\r\n const dbLike = db as DrizzleDbLike;\r\n\r\n if (typeof dbLike.query !== \"object\" || dbLike.query === null) {\r\n throw new VSRepoAdapterError(\r\n \"Invalid Drizzle client: 'db.query' is undefined — the client must be created with the 'relations' \" +\r\n \"config (e.g. 'drizzle(connection, { relations })') for DrizzleAdapter to run relational queries.\",\r\n AdapterErrorCode.MISSING_DB_CLIENT,\r\n null,\r\n );\r\n }\r\n\r\n if (config === null || config === undefined) {\r\n throw new VSRepoAdapterError(\r\n \"Invalid constructor config: the second constructor argument (config) is null/undefined.\",\r\n AdapterErrorCode.INVALID_ADAPTER_CONFIG,\r\n null,\r\n );\r\n }\r\n\r\n const { table, dialect, queryKey } = config as DrizzleAdapterConfig<T, K>;\r\n\r\n if (!is(table, Table)) {\r\n throw new VSRepoAdapterError(\r\n \"Invalid constructor config (table): expected a Drizzle 'Table' instance (the object exported by \" +\r\n \"your schema, e.g. 'userTable').\",\r\n AdapterErrorCode.INVALID_ADAPTER_CONFIG,\r\n null,\r\n );\r\n }\r\n\r\n if (dialect !== undefined && !SUPPORTED_DIALECTS.has(dialect)) {\r\n throw new VSRepoAdapterError(\r\n `Invalid constructor config (dialect): '${String(dialect)}' is not supported. Expected one of: ` +\r\n `${[...SUPPORTED_DIALECTS].join(\", \")}.`,\r\n AdapterErrorCode.INVALID_ADAPTER_CONFIG,\r\n null,\r\n );\r\n }\r\n\r\n if (typeof queryKey !== \"string\" || queryKey.length === 0) {\r\n throw new VSRepoAdapterError(\r\n \"Invalid constructor config (queryKey): expected a non-empty string matching a key of 'db.query' \" +\r\n \"(the name your schema exports the table under, e.g. 'userTable').\",\r\n AdapterErrorCode.INVALID_ADAPTER_CONFIG,\r\n null,\r\n );\r\n }\r\n\r\n const queryEntry = (dbLike.query as PlainObject)[queryKey];\r\n\r\n if (\r\n typeof queryEntry !== \"object\" ||\r\n queryEntry === null ||\r\n typeof (queryEntry as PlainObject).findFirst !== \"function\" ||\r\n typeof (queryEntry as PlainObject).findMany !== \"function\"\r\n ) {\r\n throw new VSRepoAdapterError(\r\n `Invalid constructor config (queryKey): no relational query builder found for '${queryKey}' on ` +\r\n `'db.query' (expected 'db.query.${queryKey}' to exist — check that '${queryKey}' matches the name ` +\r\n `your schema exports the table under, and that the table is included in the 'relations' config).`,\r\n AdapterErrorCode.MODEL_NOT_FOUND,\r\n null,\r\n );\r\n }\r\n\r\n return { db: db as K, config: config as DrizzleAdapterConfig<T, K> };\r\n}\r\n","/**\r\n * Validates the `relations` entry of the `DrizzleAdapter` constructor config\r\n * (see `AdapterRelations`/`AdapterRelation`), failing fast — with a clear\r\n * `VSRepoAdapterError` — instead of letting a typo'd/mismatched `fkHere`/\r\n * `fkThere` blow up later, deep inside a `create`/`update`/`upsert` call.\r\n *\r\n * For every configured relation, checks, in order:\r\n * - `table` is a Drizzle `Table` instance;\r\n * - `mode` is one of `\"otm\" | \"mto\" | \"oto\"`;\r\n * - `restriction` is one of `\"set\" | \"add\"`;\r\n * - the combination of `fkHere`/`fkThere` present matches what `mode` requires\r\n * (`otm` -> only `fkThere`; `mto` -> only `fkHere`; `oto` -> exactly one of the two);\r\n * - the given `fkHere` is an actual column of *this* adapter's table, and the\r\n * given `fkThere` is an actual column of the related `table`;\r\n * - the related `table` has a primary key (via `resolveFieldsConfig`, reused\r\n * to resolve `relatedPk`, needed to tell \"connect/upsert existing\" apart\r\n * from \"create new\" on nested writes).\r\n *\r\n * Returns a `Map` (rather than the original plain object) so nested-write\r\n * resolution can do `this.relations.get(key)` without repeated `in`/`hasOwnProperty`\r\n * checks, and because `Map` insertion order is guaranteed (relevant for\r\n * `mto`/`oto`-with-`fkHere` relations, which must be resolved *before* the\r\n * owning record is inserted).\r\n */\r\n\r\nimport { getColumns, getTableName, is, Table } from \"drizzle-orm\";\r\nimport { AdapterErrorCode, VSRepoAdapterError } from \"vsrepo\";\r\nimport { AdapterRelations } from \"../types/adapter-relations.type.js\";\r\nimport { PlainObject } from \"../types/plain-object.type.js\";\r\nimport { ResolvedRelation } from \"../types/resolved-relation.type.js\";\r\nimport { SupportedDialects } from \"../types/supported-dialects.type.js\";\r\nimport { resolveFieldsConfig } from \"../resolvers/fields-config.resolver.js\";\r\nimport { isPlainObject } from \"./is-plain-object.validator.js\";\r\n\r\nconst MODES = new Set([\"otm\", \"mto\", \"oto\"]);\r\nconst RESTRICTIONS = new Set([\"set\", \"add\"]);\r\n\r\nfunction fail(message: string): never {\r\n throw new VSRepoAdapterError(message, AdapterErrorCode.INVALID_ADAPTER_CONFIG, null);\r\n}\r\n\r\nexport function validateRelations<T>(\r\n table: Table,\r\n dialect: SupportedDialects,\r\n relations: AdapterRelations<T> | undefined,\r\n): Map<string, ResolvedRelation> | undefined {\r\n if (relations === undefined) return undefined;\r\n\r\n if (!isPlainObject(relations)) {\r\n fail(\r\n \"Invalid constructor config (relations): expected an object mapping relation field names to their config.\",\r\n );\r\n }\r\n\r\n const hereColumns = new Set(Object.keys(getColumns(table)));\r\n const resolved = new Map<string, ResolvedRelation>();\r\n\r\n for (const [key, rawRelation] of Object.entries(relations as PlainObject)) {\r\n if (rawRelation === undefined) continue;\r\n\r\n if (!isPlainObject(rawRelation)) {\r\n fail(`Invalid constructor config (relations.${key}): expected an object (an 'AdapterRelation').`);\r\n }\r\n\r\n const { mode, restriction, table: relatedTable, fkHere, fkThere, nullable } = rawRelation as PlainObject;\r\n\r\n if (!is(relatedTable, Table)) {\r\n fail(\r\n `Invalid constructor config (relations.${key}.table): expected a Drizzle 'Table' instance (the ` +\r\n \"object exported by your schema).\",\r\n );\r\n }\r\n\r\n if (!MODES.has(mode)) {\r\n fail(\r\n `Invalid constructor config (relations.${key}.mode): expected one of 'otm' | 'mto' | 'oto', got ` +\r\n `'${String(mode)}'.`,\r\n );\r\n }\r\n\r\n if (!RESTRICTIONS.has(restriction)) {\r\n fail(\r\n `Invalid constructor config (relations.${key}.restriction): expected one of 'set' | 'add', got ` +\r\n `'${String(restriction)}'.`,\r\n );\r\n }\r\n\r\n const thereColumns = new Set(Object.keys(getColumns(relatedTable)));\r\n\r\n if (mode === \"otm\") {\r\n if (fkHere !== undefined) {\r\n fail(`Invalid constructor config (relations.${key}): mode 'otm' doesn't accept 'fkHere'.`);\r\n }\r\n if (typeof fkThere !== \"string\" || fkThere.length === 0) {\r\n fail(\r\n `Invalid constructor config (relations.${key}): mode 'otm' requires 'fkThere' (a column of ` +\r\n \"the related table).\",\r\n );\r\n }\r\n if (!thereColumns.has(fkThere)) {\r\n fail(\r\n `Invalid constructor config (relations.${key}.fkThere): '${fkThere}' is not a column of table ` +\r\n `'${getTableName(relatedTable)}'.`,\r\n );\r\n }\r\n } else if (mode === \"mto\") {\r\n if (fkThere !== undefined) {\r\n fail(`Invalid constructor config (relations.${key}): mode 'mto' doesn't accept 'fkThere'.`);\r\n }\r\n if (typeof fkHere !== \"string\" || fkHere.length === 0) {\r\n fail(\r\n `Invalid constructor config (relations.${key}): mode 'mto' requires 'fkHere' (a column of ` +\r\n \"this adapter's table).\",\r\n );\r\n }\r\n if (!hereColumns.has(fkHere)) {\r\n fail(\r\n `Invalid constructor config (relations.${key}.fkHere): '${fkHere}' is not a column of table ` +\r\n `'${getTableName(table)}'.`,\r\n );\r\n }\r\n if (nullable !== undefined && typeof nullable !== \"boolean\") {\r\n fail(`Invalid constructor config (relations.${key}.nullable): expected a boolean.`);\r\n }\r\n } else {\r\n const hasHere = fkHere !== undefined;\r\n const hasThere = fkThere !== undefined;\r\n\r\n if (hasHere === hasThere) {\r\n fail(\r\n `Invalid constructor config (relations.${key}): mode 'oto' requires exactly one of 'fkHere' / ` +\r\n \"'fkThere'.\",\r\n );\r\n }\r\n\r\n if (hasHere) {\r\n if (typeof fkHere !== \"string\" || !hereColumns.has(fkHere)) {\r\n fail(\r\n `Invalid constructor config (relations.${key}.fkHere): '${String(fkHere)}' is not a ` +\r\n `column of table '${getTableName(table)}'.`,\r\n );\r\n }\r\n } else {\r\n if (typeof fkThere !== \"string\" || !thereColumns.has(fkThere)) {\r\n fail(\r\n `Invalid constructor config (relations.${key}.fkThere): '${String(fkThere)}' is not a ` +\r\n `column of table '${getTableName(relatedTable)}'.`,\r\n );\r\n }\r\n }\r\n }\r\n\r\n // Throws INVALID_ADAPTER_CONFIG (reused error code) if the related table has no pk.\r\n const relatedFieldsConfig = resolveFieldsConfig(relatedTable);\r\n\r\n resolved.set(key, {\r\n mode,\r\n restriction,\r\n table: relatedTable,\r\n fkHere,\r\n fkThere,\r\n nullable,\r\n relatedPk: relatedFieldsConfig.pk,\r\n });\r\n }\r\n\r\n return resolved;\r\n}\r\n","import { PlainObject } from \"../types/plain-object.type.js\";\n\nexport function isPlainObject(value: unknown): value is PlainObject {\n return typeof value === \"object\" && value !== null && !Array.isArray(value) && !(value instanceof Date);\n}\n","import { VSRepoSelect } from \"vsrepo\";\nimport { PlainObject } from \"../types/plain-object.type.js\";\nimport { isPlainObject } from \"../validators/is-plain-object.validator.js\";\n\n/**\n * Result of parsing a `VSRepoSelect<T>` into Drizzle's relational query\n * config shape: scalar fields go into `columns`, relation fields selected\n * with a nested `VSRepoSelect` go into `with` (recursively parsed the same way).\n */\nexport type ParsedColumns = { columns: PlainObject; with?: PlainObject };\n\n/**\n * Converts a `VSRepoSelect<T>` into Drizzle's `columns` (+ `with`, when the\n * select is nested) relational query config.\n *\n * - Plain select (every value is a `boolean`, e.g. `{ name: true, email: true }`)\n * -> only `columns` is filled, `with` stays `undefined`.\n * - Nested select (a relation field selected with its own `VSRepoSelect`,\n * e.g. `{ name: true, posts: { title: true } }`) -> the relation field is\n * moved into `with` (as `{ columns, with }`, recursively parsed the same\n * way) instead of `columns`.\n */\nexport function parseColumns<T>(select: VSRepoSelect<T>): ParsedColumns {\n const columns: PlainObject = {};\n let withResult: PlainObject | undefined;\n\n for (const [key, value] of Object.entries(select)) {\n if (value === undefined) continue;\n\n if (isPlainObject(value)) {\n withResult ??= {};\n const nested = parseColumns(value);\n withResult[key] = nested.with\n ? { columns: nested.columns, with: nested.with }\n : { columns: nested.columns };\n } else {\n columns[key] = value;\n }\n }\n\n return { columns, with: withResult };\n}\n","import { VSRepoRelations } from \"vsrepo\";\nimport { PlainObject } from \"../types/plain-object.type.js\";\nimport { isPlainObject } from \"../validators/is-plain-object.validator.js\";\n\n/**\n * Converts a `VSRepoRelations<T>` into Drizzle's `with` relational query config.\n *\n * A relation loaded as `true` stays `true`. A relation loaded together with\n * its own nested relations (`VSRepoRelations` again) is turned into\n * `{ with: parseWith(...) }`, matching Drizzle's own nested `with` shape —\n * each level is a full query config (`{ columns?, where?, with?, ... }`),\n * not a plain recursive include map.\n */\nexport function parseWith<T>(relations: VSRepoRelations<T>): PlainObject {\n const result: PlainObject = {};\n\n for (const [key, value] of Object.entries(relations)) {\n if (value === undefined) continue;\n\n result[key] = isPlainObject(value) ? { with: parseWith(value) } : value;\n }\n\n return result;\n}\n","/**\r\n * Parser that converts a `VSRepoWhere<T>` (the application's \"friendly\"\r\n * filter format) into the `where` shape accepted by\r\n * `db.query[queryKey].findFirst/findMany` — Drizzle's rqbv2 relational query\r\n * API, built via `defineRelations`.\r\n *\r\n * Supports:\r\n * - Direct value: { name: \"Ana\" } -> { name: \"Ana\" } (Drizzle's own shorthand for `eq`)\r\n * - Field operators: { age: { gte: 18, lte: 65 } } -> passed through as-is (Drizzle uses the same keys)\r\n * - `between`: { age: { between: [18, 65] } } -> { gte: 18, lte: 65 }\r\n * - `not` (value or operator): { name: { not: \"Ana\" } } -> { name: { NOT: \"Ana\" } }\r\n * { name: { not: { contains: \"an\" } } }\r\n * - Strings: { name: { contains: \"ana\" } } -> { like: \"%ana%\" }\r\n * { name: { contains: \"ana\", ignoreCase: true } } -> { ilike: \"%ana%\" } on\r\n * postgresql/cockroach (the only dialects with a real `ILIKE` operator); on\r\n * sqlite, `ignoreCase` is a no-op — plain `LIKE` is already case-insensitive\r\n * for ASCII there by default (`PRAGMA case_sensitive_like` is OFF unless the\r\n * app explicitly turns it on), so using the (nonexistent, dialect-specific)\r\n * `ilike` operator there would just be a SQL syntax error for no behavioral gain.\r\n * - To-many relation (array): { posts: { _some: { title: \"x\" } } } -> { posts: { title: \"x\" } }\r\n * Drizzle's relational filter has no native `every`/`none` semantics for\r\n * to-many relations (only an implicit `some`/exists filter) — `_every`/`_none`\r\n * throw `VSRepoAdapterError` (code `NOT_SUPPORTED`) instead of silently\r\n * producing a wrong query. `DrizzleAdapter` never actually hits this throw for\r\n * `_every`/`_none` on its own: it detects them upfront via `hasQuantifierFilter`\r\n * (exported below) and falls back to a pk-prefetch through `sql-where.parser.ts`\r\n * (which does support them) before ever calling this parser with such a `where`.\r\n * - To-one relation (object): { author: { _with: { id: 1 } } } -> { author: { id: 1 } }\r\n * { author: { _without: { id: 1 } } } -> { author: { NOT: { id: 1 } } }\r\n * - Root-level logical ops: { AND: [...], OR: [...], NOT: {...} }\r\n * `NOT` receiving a list (allowed by `VSRepoWhere`, but Drizzle's own `NOT`\r\n * only accepts a single nested filter) is translated into an `AND` of\r\n * individually-negated entries — \"none of these match\" — merging into any\r\n * `AND` already present at that level.\r\n */\r\n\r\nimport { AdapterErrorCode, VSRepoAdapterError, VSRepoWhere } from \"vsrepo\";\r\nimport { PlainObject } from \"../types/plain-object.type.js\";\r\nimport { SupportedDialects } from \"../types/supported-dialects.type.js\";\r\nimport { isPlainObject } from \"../validators/is-plain-object.validator.js\";\r\n\r\n/** Keys recognized as a `VSRepoFieldOperators` object. */\r\nconst FIELD_OPERATOR_KEYS = new Set([\r\n \"equals\",\r\n \"not\",\r\n \"in\",\r\n \"notIn\",\r\n \"gt\",\r\n \"gte\",\r\n \"lt\",\r\n \"lte\",\r\n \"between\",\r\n \"contains\",\r\n \"startsWith\",\r\n \"endsWith\",\r\n \"ignoreCase\",\r\n]);\r\n\r\nfunction isFieldOperatorObject(value: PlainObject): boolean {\r\n return Object.keys(value).some(key => FIELD_OPERATOR_KEYS.has(key));\r\n}\r\n\r\nfunction isArrayRelationFilter(value: PlainObject): boolean {\r\n return \"_some\" in value || \"_every\" in value || \"_none\" in value;\r\n}\r\n\r\nfunction isObjectRelationFilter(value: PlainObject): boolean {\r\n return \"_with\" in value || \"_without\" in value;\r\n}\r\n\r\n/** Converts a `VSRepoFieldOperators<V>` into a Drizzle relational field filter. */\r\nfunction parseFieldOperators(value: PlainObject, dialect: SupportedDialects): PlainObject {\r\n const result: PlainObject = {};\r\n // Only postgresql/cockroach have a real `ILIKE` operator — on sqlite, plain `LIKE` is\r\n // already case-insensitive for ASCII by default, so `ignoreCase` is a no-op there\r\n // rather than emitting the (dialect-specific, would-be-invalid-SQL) `ilike` key.\r\n const likeKey = value.ignoreCase === true && dialect !== \"sqlite\" ? \"ilike\" : \"like\";\r\n\r\n for (const [key, val] of Object.entries(value)) {\r\n if (val === undefined) continue;\r\n\r\n switch (key) {\r\n case \"ignoreCase\":\r\n // handled above, via `likeKey` — not a Drizzle filter key on its own\r\n break;\r\n\r\n case \"equals\":\r\n result.eq = val;\r\n break;\r\n\r\n case \"between\": {\r\n const [min, max] = val as [any, any];\r\n if (min !== undefined) result.gte = min;\r\n if (max !== undefined) result.lte = max;\r\n break;\r\n }\r\n\r\n case \"contains\":\r\n result[likeKey] = `%${val}%`;\r\n break;\r\n\r\n case \"startsWith\":\r\n result[likeKey] = `${val}%`;\r\n break;\r\n\r\n case \"endsWith\":\r\n result[likeKey] = `%${val}`;\r\n break;\r\n\r\n case \"not\":\r\n result.NOT = isPlainObject(val) && isFieldOperatorObject(val) ? parseFieldOperators(val, dialect) : val;\r\n break;\r\n\r\n default:\r\n // gt/gte/lt/lte/in/notIn already match Drizzle's field filter keys 1:1\r\n result[key] = val;\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/** Converts `{ _some, _every, _none }` into the filter applied to a to-many relation field. */\r\nfunction parseArrayRelationFilter(value: PlainObject, dialect: SupportedDialects): PlainObject {\r\n if (value._every !== undefined || value._none !== undefined) {\r\n throw new VSRepoAdapterError(\r\n \"Drizzle's relational query API has no native 'every'/'none' filter for to-many relations (only an \" +\r\n \"implicit 'some'/exists filter, via '_some') — rewrite the filter using '_some', or fall back to \" +\r\n \"'query()' with raw SQL.\",\r\n AdapterErrorCode.NOT_SUPPORTED,\r\n null,\r\n );\r\n }\r\n\r\n return parsePlainWhere(value._some, dialect) ?? {};\r\n}\r\n\r\n/** Converts `{ _with, _without }` into the filter applied to a to-one relation field. */\r\nfunction parseObjectRelationFilter(value: PlainObject, dialect: SupportedDialects): PlainObject {\r\n if (value._with !== undefined) {\r\n return parsePlainWhere(value._with, dialect) ?? {};\r\n }\r\n if (value._without !== undefined) {\r\n return { NOT: parsePlainWhere(value._without, dialect) };\r\n }\r\n return {};\r\n}\r\n\r\n/** Decides how to interpret the value of a single where field. */\r\nfunction parseFieldValue(value: unknown, dialect: SupportedDialects): unknown {\r\n // Primitive values (string, number, boolean, Date, null, bigint) pass through\r\n // as-is — Drizzle's own shorthand for `eq`.\r\n if (value === null || typeof value !== \"object\" || value instanceof Date) {\r\n return value;\r\n }\r\n\r\n // Plain arrays used as a shorthand for `in`, e.g. { status: [\"A\", \"B\"] }.\r\n if (Array.isArray(value)) {\r\n return { in: value };\r\n }\r\n\r\n const obj = value as PlainObject;\r\n\r\n if (isArrayRelationFilter(obj)) return parseArrayRelationFilter(obj, dialect);\r\n if (isObjectRelationFilter(obj)) return parseObjectRelationFilter(obj, dialect);\r\n if (isFieldOperatorObject(obj)) return parseFieldOperators(obj, dialect);\r\n\r\n // fallback: nested to-one filter passed directly, without a `_with`/`_without` wrapper\r\n return parsePlainWhere(obj, dialect);\r\n}\r\n\r\n/**\r\n * Converts a `VSRepoWherePlain<T>` (no root `AND`/`OR`/`NOT`) — used for the\r\n * body of relation filters (`_some`/`_every`/`_none`/`_with`/`_without`).\r\n */\r\nfunction parsePlainWhere(where: PlainObject | undefined | null, dialect: SupportedDialects): PlainObject | undefined {\r\n if (where === undefined || where === null) return undefined;\r\n\r\n const result: PlainObject = {};\r\n\r\n for (const [key, value] of Object.entries(where)) {\r\n if (value === undefined) continue;\r\n result[key] = parseFieldValue(value, dialect);\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/** Converts a full `VSRepoWhere<T>` (root level, with `AND`/`OR`/`NOT`) into a Drizzle relational filter. */\r\nfunction parseWhere(where: PlainObject | undefined | null, dialect: SupportedDialects): PlainObject | undefined {\r\n if (where === undefined || where === null) return undefined;\r\n\r\n const result: PlainObject = {};\r\n // Collected separately (instead of writing straight into `result.AND`) so\r\n // that an explicit `AND` and a list-form `NOT` at the same level merge\r\n // correctly no matter which key is iterated first.\r\n let andList: PlainObject[] | undefined;\r\n\r\n for (const [key, value] of Object.entries(where)) {\r\n if (value === undefined) continue;\r\n\r\n if (key === \"AND\") {\r\n const list = Array.isArray(value) ? value : [value];\r\n andList = [...(andList ?? []), ...list.map(v => parseWhere(v, dialect)!)];\r\n continue;\r\n }\r\n\r\n if (key === \"OR\") {\r\n const list = Array.isArray(value) ? value : [value];\r\n result.OR = list.map(v => parseWhere(v, dialect));\r\n continue;\r\n }\r\n\r\n if (key === \"NOT\") {\r\n if (Array.isArray(value)) {\r\n andList = [...(andList ?? []), ...value.map(v => ({ NOT: parseWhere(v, dialect) }))];\r\n } else {\r\n result.NOT = parseWhere(value, dialect);\r\n }\r\n continue;\r\n }\r\n\r\n result[key] = parseFieldValue(value, dialect);\r\n }\r\n\r\n if (andList) result.AND = andList;\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Use the second generic to type the return with the specific\r\n * `RelationsFilter<...>` for your table, if desired.\r\n */\r\nexport function parseDrizzleWhere<T, W = any>(\r\n where: VSRepoWhere<T> | undefined | null,\r\n dialect: SupportedDialects,\r\n): W | undefined {\r\n return parseWhere(where as PlainObject | undefined | null, dialect) as W | undefined;\r\n}\r\n\r\n/**\r\n * Recursively checks whether `where` contains an `_every`/`_none` key\r\n * anywhere (at any nesting level, inside `AND`/`OR`/`NOT`, or inside a\r\n * relation body) — used by `DrizzleAdapter` to decide whether a given\r\n * `where` needs the pk-prefetch fallback (see `DrizzleAdapter`'s\r\n * `resolveFindWhere`) instead of going straight to the relational query API,\r\n * which has no native `every`/`none` semantics (see this file's docstring).\r\n */\r\nexport function hasQuantifierFilter(where: unknown): boolean {\r\n if (where === null || where === undefined) return false;\r\n\r\n if (Array.isArray(where)) {\r\n return where.some(hasQuantifierFilter);\r\n }\r\n\r\n if (typeof where !== \"object\" || where instanceof Date) {\r\n return false;\r\n }\r\n\r\n for (const [key, value] of Object.entries(where as PlainObject)) {\r\n if (value === undefined) continue;\r\n if (key === \"_every\" || key === \"_none\") return true;\r\n if (hasQuantifierFilter(value)) return true;\r\n }\r\n\r\n return false;\r\n}\r\n","/**\r\n * Parser that converts a `VSRepoWhere<T>` into a drizzle-orm `SQL` condition,\r\n * for the methods that go through Drizzle's *core* query builder\r\n * (`db.update(table).where(...)`, `db.delete(table).where(...)`,\r\n * `db.select(...).from(table).where(...)`) instead of the relational query\r\n * API (`db.query[queryKey].findFirst/findMany`) — the relational API has its\r\n * own object-shaped `where` (see `where.parser.ts`), but `update`/`delete`/\r\n * `select` don't accept that shape; they need an actual `SQL` expression\r\n * built from `eq`/`and`/`or`/... .\r\n *\r\n * Supports the same filters as `where.parser.ts`:\r\n * - Direct value / field operators / `between` / `not` / string filters —\r\n * same semantics, built with the matching drizzle-orm operator function\r\n * instead of being passed through as a plain object.\r\n * - `_some` / `_every` / `_none` (to-many relation, `otm` only): all three\r\n * translated into `EXISTS`/`NOT EXISTS` correlated subqueries against the\r\n * related table (`_every` via the classic \"no row fails the filter\" SQL\r\n * trick — `NOT EXISTS (... WHERE join AND NOT filter)`, vacuously true\r\n * for a parent with no related rows, matching Prisma's `every` semantics).\r\n * Unlike `where.parser.ts` (the relational-API parser), which can't\r\n * express `_every`/`_none` at all, this parser supports all three\r\n * uniformly — `DrizzleAdapter` uses that to give `findOne`/`findMany`/etc.\r\n * `_every`/`_none` support too, via a pk-prefetch through this parser\r\n * (see `where.parser.ts`'s `hasQuantifierFilter`).\r\n * - `_with` / `_without` (to-one relation, `mto`/`oto`): also an `EXISTS`\r\n * subquery, joined on whichever side (`fkHere`/`fkThere`) the relation\r\n * puts the FK on; `_without` negates the nested filter (not the\r\n * existence check — mirrors `where.parser.ts`'s `NOT`-wrapping).\r\n * - Root-level `AND`/`OR`/`NOT`.\r\n *\r\n * Nested filters inside a relation body (`_some`/`_with`/`_without`) only\r\n * see the related table's own scalar columns — a relation field can't be\r\n * filtered another level deep, since resolving that would need the related\r\n * table's *own* relation config, which this adapter doesn't have (only `T`'s\r\n * relations are configured).\r\n */\r\n\r\nimport {\r\n and,\r\n eq,\r\n exists,\r\n getTableName,\r\n gt,\r\n gte,\r\n inArray,\r\n isNotNull,\r\n isNull,\r\n like,\r\n lt,\r\n lte,\r\n not,\r\n notInArray,\r\n or,\r\n sql,\r\n Table,\r\n type SQL,\r\n} from \"drizzle-orm\";\r\nimport { AdapterErrorCode, VSRepoAdapterError, VSRepoWhere } from \"vsrepo\";\r\nimport { DrizzleDbLike } from \"../types/drizzle-db-like.type.js\";\r\nimport { PlainObject } from \"../types/plain-object.type.js\";\r\nimport { ResolvedRelation } from \"../types/resolved-relation.type.js\";\r\nimport { isPlainObject } from \"../validators/is-plain-object.validator.js\";\r\n\r\nexport type SqlWhereContext = {\r\n table: Table;\r\n pk: string;\r\n relations?: Map<string, ResolvedRelation>;\r\n db: DrizzleDbLike;\r\n};\r\n\r\nconst FIELD_OPERATOR_KEYS = new Set([\r\n \"equals\",\r\n \"not\",\r\n \"in\",\r\n \"notIn\",\r\n \"gt\",\r\n \"gte\",\r\n \"lt\",\r\n \"lte\",\r\n \"between\",\r\n \"contains\",\r\n \"startsWith\",\r\n \"endsWith\",\r\n \"ignoreCase\",\r\n]);\r\n\r\nfunction isFieldOperatorObject(value: PlainObject): boolean {\r\n return Object.keys(value).some(key => FIELD_OPERATOR_KEYS.has(key));\r\n}\r\n\r\nfunction isArrayRelationFilter(value: PlainObject): boolean {\r\n return \"_some\" in value || \"_every\" in value || \"_none\" in value;\r\n}\r\n\r\nfunction isObjectRelationFilter(value: PlainObject): boolean {\r\n return \"_with\" in value || \"_without\" in value;\r\n}\r\n\r\n/** Converts a `VSRepoFieldOperators<V>` object into a single (possibly `AND`-combined) `SQL` condition. */\r\nfunction buildFieldOperators(column: any, ops: PlainObject): SQL | undefined {\r\n const parts: SQL[] = [];\r\n const likeFn =\r\n ops.ignoreCase === true\r\n ? (column: any, pattern: string) => sql`lower(${column}) like lower(${pattern})`\r\n : like;\r\n\r\n for (const [key, val] of Object.entries(ops)) {\r\n if (val === undefined) continue;\r\n\r\n switch (key) {\r\n case \"ignoreCase\":\r\n break;\r\n\r\n case \"equals\":\r\n parts.push(val === null ? isNull(column) : eq(column, val));\r\n break;\r\n\r\n case \"not\": {\r\n if (val === null) {\r\n parts.push(isNotNull(column));\r\n break;\r\n }\r\n const inner =\r\n isPlainObject(val) && isFieldOperatorObject(val)\r\n ? buildFieldOperators(column, val)\r\n : eq(column, val);\r\n if (inner) parts.push(not(inner));\r\n break;\r\n }\r\n\r\n case \"in\":\r\n parts.push(inArray(column, val as unknown[]));\r\n break;\r\n\r\n case \"notIn\":\r\n parts.push(notInArray(column, val as unknown[]));\r\n break;\r\n\r\n case \"gt\":\r\n parts.push(gt(column, val));\r\n break;\r\n case \"gte\":\r\n parts.push(gte(column, val));\r\n break;\r\n case \"lt\":\r\n parts.push(lt(column, val));\r\n break;\r\n case \"lte\":\r\n parts.push(lte(column, val));\r\n break;\r\n\r\n case \"between\": {\r\n const [min, max] = val as [any, any];\r\n if (min !== undefined) parts.push(gte(column, min));\r\n if (max !== undefined) parts.push(lte(column, max));\r\n break;\r\n }\r\n\r\n case \"contains\":\r\n parts.push(likeFn(column, `%${val}%`));\r\n break;\r\n case \"startsWith\":\r\n parts.push(likeFn(column, `${val}%`));\r\n break;\r\n case \"endsWith\":\r\n parts.push(likeFn(column, `%${val}`));\r\n break;\r\n }\r\n }\r\n\r\n if (parts.length === 0) return undefined;\r\n return parts.length === 1 ? parts[0] : and(...parts);\r\n}\r\n\r\n/** Builds the join condition between `ctx.table` and a relation's related table. */\r\nfunction buildJoinCondition(relation: ResolvedRelation, ctx: SqlWhereContext): SQL {\r\n const relatedColumns = relation.table as unknown as PlainObject;\r\n const hereColumns = ctx.table as unknown as PlainObject;\r\n\r\n if (relation.fkHere) {\r\n // FK lives on ctx.table, pointing at the related table's pk.\r\n return eq(relatedColumns[relation.relatedPk], hereColumns[relation.fkHere]);\r\n }\r\n\r\n // FK lives on the related table, pointing at ctx.table's pk.\r\n return eq(relatedColumns[relation.fkThere as string], hereColumns[ctx.pk]);\r\n}\r\n\r\nfunction buildExists(relation: ResolvedRelation, condition: SQL, ctx: SqlWhereContext): SQL {\r\n const subquery = (ctx.db.select({ one: sql`1` }) as any).from(relation.table).where(condition);\r\n return exists(subquery);\r\n}\r\n\r\nfunction buildRelationCondition(key: string, value: PlainObject, relation: ResolvedRelation, ctx: SqlWhereContext): SQL {\r\n const nestedCtx: SqlWhereContext = { ...ctx, table: relation.table, relations: undefined };\r\n\r\n if (isArrayRelationFilter(value)) {\r\n if (relation.mode !== \"otm\") {\r\n throw new VSRepoAdapterError(\r\n `Field '${key}': '_some'/'_every'/'_none' can only be used on a to-many ('otm') relation.`,\r\n AdapterErrorCode.INVALID_DATA,\r\n null,\r\n );\r\n }\r\n\r\n const join = buildJoinCondition(relation, ctx);\r\n\r\n if (value._some !== undefined) {\r\n const nested = parsePlainWhere(value._some as PlainObject | undefined, nestedCtx);\r\n return buildExists(relation, nested ? and(join, nested)! : join, ctx);\r\n }\r\n\r\n if (value._none !== undefined) {\r\n const nested = parsePlainWhere(value._none as PlainObject | undefined, nestedCtx);\r\n return not(buildExists(relation, nested ? and(join, nested)! : join, ctx));\r\n }\r\n\r\n // `_every`: no related row may FAIL the filter — i.e. no row exists matching\r\n // (joined AND NOT filter). Vacuously true when there are no related rows at\r\n // all, same as Prisma's `every` semantics. An empty filter (`{}`/`undefined`)\r\n // means \"every row trivially satisfies nothing\", so the condition is just `true`.\r\n const nested = parsePlainWhere(value._every as PlainObject | undefined, nestedCtx);\r\n if (!nested) return sql`(1 = 1)`;\r\n return not(buildExists(relation, and(join, not(nested))!, ctx));\r\n }\r\n\r\n if (isObjectRelationFilter(value)) {\r\n const isWithout = \"_without\" in value;\r\n const filter = (isWithout ? value._without : value._with) as PlainObject | undefined;\r\n const join = buildJoinCondition(relation, ctx);\r\n const nested = parsePlainWhere(filter, nestedCtx);\r\n\r\n const condition = nested ? and(join, isWithout ? not(nested) : nested)! : join;\r\n return buildExists(relation, condition, ctx);\r\n }\r\n\r\n // Fallback: nested to-one filter passed directly, without a `_with`/`_without` wrapper.\r\n if (relation.mode === \"otm\") {\r\n throw new VSRepoAdapterError(\r\n `Field '${key}': to-many relation filters require '_some' (or the unsupported '_every'/'_none').`,\r\n AdapterErrorCode.INVALID_DATA,\r\n null,\r\n );\r\n }\r\n\r\n const join = buildJoinCondition(relation, ctx);\r\n const nested = parsePlainWhere(value, nestedCtx);\r\n return buildExists(relation, nested ? and(join, nested)! : join, ctx);\r\n}\r\n\r\nfunction buildFieldCondition(column: any, value: unknown): SQL | undefined {\r\n if (value === null) return isNull(column);\r\n\r\n if (value instanceof Date || typeof value !== \"object\") {\r\n return eq(column, value);\r\n }\r\n\r\n if (Array.isArray(value)) {\r\n return inArray(column, value);\r\n }\r\n\r\n return buildFieldOperators(column, value as PlainObject);\r\n}\r\n\r\nfunction parsePlainWhere(where: PlainObject | undefined | null, ctx: SqlWhereContext): SQL | undefined {\r\n if (where === undefined || where === null) return undefined;\r\n\r\n const tableColumns = ctx.table as unknown as PlainObject;\r\n const parts: SQL[] = [];\r\n\r\n for (const [key, value] of Object.entries(where)) {\r\n if (value === undefined) continue;\r\n\r\n const relation = ctx.relations?.get(key);\r\n if (relation) {\r\n parts.push(buildRelationCondition(key, value as PlainObject, relation, ctx));\r\n continue;\r\n }\r\n\r\n const column = tableColumns[key];\r\n if (column === undefined) {\r\n throw new VSRepoAdapterError(\r\n `Unknown field '${key}' in 'where': no column or configured relation with that name on table ` +\r\n `'${getTableName(ctx.table)}'.`,\r\n AdapterErrorCode.FIELD_NOT_FOUND,\r\n null,\r\n );\r\n }\r\n\r\n const condition = buildFieldCondition(column, value);\r\n if (condition) parts.push(condition);\r\n }\r\n\r\n if (parts.length === 0) return undefined;\r\n return parts.length === 1 ? parts[0] : and(...parts);\r\n}\r\n\r\nfunction parseWhere(where: PlainObject | undefined | null, ctx: SqlWhereContext): SQL | undefined {\r\n if (where === undefined || where === null) return undefined;\r\n\r\n const parts: SQL[] = [];\r\n let orPart: SQL | undefined;\r\n const plainEntries: PlainObject = {};\r\n\r\n for (const [key, value] of Object.entries(where)) {\r\n if (value === undefined) continue;\r\n\r\n if (key === \"AND\") {\r\n const list = Array.isArray(value) ? value : [value];\r\n for (const v of list) {\r\n const c = parseWhere(v, ctx);\r\n if (c) parts.push(c);\r\n }\r\n continue;\r\n }\r\n\r\n if (key === \"OR\") {\r\n const list = Array.isArray(value) ? value : [value];\r\n const ors = list.map(v => parseWhere(v, ctx)).filter((c): c is SQL => c !== undefined);\r\n if (ors.length > 0) orPart = ors.length === 1 ? ors[0] : or(...ors);\r\n continue;\r\n }\r\n\r\n if (key === \"NOT\") {\r\n const list = Array.isArray(value) ? value : [value];\r\n for (const v of list) {\r\n const c = parseWhere(v, ctx);\r\n if (c) parts.push(not(c));\r\n }\r\n continue;\r\n }\r\n\r\n plainEntries[key] = value;\r\n }\r\n\r\n const plainCondition = parsePlainWhere(plainEntries, ctx);\r\n if (plainCondition) parts.push(plainCondition);\r\n if (orPart) parts.push(orPart);\r\n\r\n if (parts.length === 0) return undefined;\r\n return parts.length === 1 ? parts[0] : and(...parts);\r\n}\r\n\r\n/**\r\n * Use the second generic to type the return with a specific `SQL<...>`, if desired.\r\n */\r\nexport function parseSqlWhere<T>(where: VSRepoWhere<T> | undefined | null, ctx: SqlWhereContext): SQL | undefined {\r\n return parseWhere(where as PlainObject | undefined | null, ctx);\r\n}\r\n","import { AdapterErrorCode, Ordering, SortDirection, VSRepoAdapterError } from \"vsrepo\";\nimport { PlainObject } from \"../types/plain-object.type.js\";\nimport { isPlainObject } from \"../validators/is-plain-object.validator.js\";\n\nfunction isSortDirection(value: unknown): value is SortDirection {\n return value === \"asc\" || value === \"desc\" || value === \"ASC\" || value === \"DESC\";\n}\n\nfunction parseOrderByField(order: PlainObject): PlainObject {\n const result: PlainObject = {};\n\n for (const [key, value] of Object.entries(order)) {\n if (value === undefined) continue;\n\n if (isSortDirection(value)) {\n result[key] = value.toLowerCase();\n continue;\n }\n\n if (isPlainObject(value)) {\n // Drizzle's relational query `orderBy` only accepts a flat map of the\n // current table's own columns — ordering by a relation's field has to\n // be declared inside that relation's own `with` entry instead, so it\n // can't be resolved generically at this level.\n throw new VSRepoAdapterError(\n `Ordering by a nested relation field ('${key}') isn't supported at the top level of a Drizzle ` +\n \"relational query — nest the ordering inside that relation's own 'with' config instead.\",\n AdapterErrorCode.NOT_SUPPORTED,\n null,\n );\n }\n\n result[key] = value;\n }\n\n return result;\n}\n\n/**\n * Converts an `Ordering<T>` into Drizzle's relational query `orderBy` shape\n * (a flat `{ column: \"asc\" | \"desc\" }` map). Chained orderings\n * (`Ordering<T>[]`) are merged into a single map, in declaration order —\n * later entries win on key collisions, same as re-declaring a key in a\n * plain object literal.\n */\nexport function parseOrderBy<T>(order: Ordering<T> | undefined | null): PlainObject | undefined {\n if (order === undefined || order === null) return undefined;\n\n if (!Array.isArray(order)) return parseOrderByField(order as PlainObject);\n\n return order.reduce<PlainObject>((acc, field) => ({ ...acc, ...parseOrderByField(field as PlainObject) }), {});\n}\n","/**\r\n * Converts an `Ordering<T>` into drizzle-orm `asc(column)`/`desc(column)`\r\n * entries for a *core* query builder `.orderBy(...)` call — used only by\r\n * `DrizzleAdapter`'s pk-prefetch fallback (see `resolveFindWhere`), which\r\n * runs a raw `db.select({pk}).from(table).where(...)` and therefore needs\r\n * real SQL ordering (to `LIMIT`/`OFFSET` correctly), unlike the relational\r\n * query API's own `orderBy.parser.ts`, which just builds the flat map that\r\n * API expects.\r\n *\r\n * Same restriction as `order-by.parser.ts`: ordering by a nested relation\r\n * field isn't supported (a raw select over the base table has no join to\r\n * order by) — throws `VSRepoAdapterError` (code `NOT_SUPPORTED`) instead of\r\n * silently ignoring it.\r\n */\r\n\r\nimport { asc, desc, Table, type SQL } from \"drizzle-orm\";\r\nimport { AdapterErrorCode, Ordering, SortDirection, VSRepoAdapterError } from \"vsrepo\";\r\nimport { PlainObject } from \"../types/plain-object.type.js\";\r\nimport { isPlainObject } from \"../validators/is-plain-object.validator.js\";\r\n\r\nfunction isSortDirection(value: unknown): value is SortDirection {\r\n return value === \"asc\" || value === \"desc\" || value === \"ASC\" || value === \"DESC\";\r\n}\r\n\r\nfunction pushOrderByField(table: Table, order: PlainObject, acc: SQL[]): void {\r\n const tableColumns = table as unknown as PlainObject;\r\n\r\n for (const [key, value] of Object.entries(order)) {\r\n if (value === undefined) continue;\r\n\r\n if (!isSortDirection(value)) {\r\n if (isPlainObject(value)) {\r\n throw new VSRepoAdapterError(\r\n `Ordering by a nested relation field ('${key}') isn't supported by this adapter.`,\r\n AdapterErrorCode.NOT_SUPPORTED,\r\n null,\r\n );\r\n }\r\n continue;\r\n }\r\n\r\n const column = tableColumns[key];\r\n if (!column) continue;\r\n\r\n acc.push(value.toString().toLowerCase() === \"desc\" ? desc(column) : asc(column));\r\n }\r\n}\r\n\r\nexport function parseSqlOrderBy<T>(table: Table, order: Ordering<T> | undefined | null): SQL[] | undefined {\r\n if (order === undefined || order === null) return undefined;\r\n\r\n const acc: SQL[] = [];\r\n const list = Array.isArray(order) ? order : [order];\r\n for (const field of list) pushOrderByField(table, field as PlainObject, acc);\r\n\r\n return acc.length > 0 ? acc : undefined;\r\n}\r\n","/**\r\n * Deep-merges, IN MEMORY (nothing is persisted), a fetched `result` with the\r\n * `obj` payload passed to `merge()` — same behavior as\r\n * `VSRepoPrisma7Adapter`'s `mergeEntities`, minus the `mtm` case (this\r\n * adapter has no `mtm` relation mode). It's on the caller to decide what to\r\n * do with the returned value (e.g. pass it to `save` next).\r\n *\r\n * Without `relations`, this is a plain recursive object merge (arrays are\r\n * concatenated). With `relations`:\r\n * - to-one (`mto`/`oto`) fields are merged directly with the existing\r\n * related object, or replaced by `null` when `obj` explicitly sends `null`;\r\n * - to-many (`otm`) fields match `result[key]`'s items against `obj[key]`'s\r\n * by the relation's `relatedPk`: an item whose pk matches an existing one\r\n * is merged into it; one that doesn't is appended. Existing items that\r\n * aren't mentioned in `obj[key]` are kept — `merge` never removes anything.\r\n */\r\n\r\nimport { PlainObject } from \"../types/plain-object.type.js\";\r\nimport { ResolvedRelation } from \"../types/resolved-relation.type.js\";\r\nimport { isPlainObject } from \"../validators/is-plain-object.validator.js\";\r\n\r\nfunction deepMergeValue(target: unknown, source: unknown): unknown {\r\n if (Array.isArray(target) && Array.isArray(source)) {\r\n return [...target, ...source];\r\n }\r\n\r\n if (isPlainObject(target) && isPlainObject(source)) {\r\n return deepMergePlain(target as PlainObject, source as PlainObject);\r\n }\r\n\r\n return source;\r\n}\r\n\r\nfunction deepMergePlain(target: PlainObject, source: PlainObject): PlainObject {\r\n const merged: PlainObject = { ...target };\r\n\r\n for (const [key, value] of Object.entries(source)) {\r\n if (value === undefined) continue;\r\n merged[key] = key in target ? deepMergeValue(target[key], value) : value;\r\n }\r\n\r\n return merged;\r\n}\r\n\r\nfunction mergeToManyRelation(target: PlainObject[], source: PlainObject[], relatedPk: string): PlainObject[] {\r\n const targetByPk = new Map<unknown, PlainObject>();\r\n const targetWithoutPk: PlainObject[] = [];\r\n\r\n for (const item of target) {\r\n if (item[relatedPk] !== undefined) {\r\n targetByPk.set(item[relatedPk], item);\r\n } else {\r\n targetWithoutPk.push(item);\r\n }\r\n }\r\n\r\n const sourceWithoutPk: PlainObject[] = [];\r\n\r\n for (const item of source) {\r\n if (item[relatedPk] === undefined) {\r\n sourceWithoutPk.push(item);\r\n continue;\r\n }\r\n\r\n const existing = targetByPk.get(item[relatedPk]);\r\n targetByPk.set(item[relatedPk], existing ? deepMergePlain(existing, item) : item);\r\n }\r\n\r\n return [...targetByPk.values(), ...targetWithoutPk, ...sourceWithoutPk];\r\n}\r\n\r\nexport function mergeEntities<T extends PlainObject, U extends PlainObject>(\r\n result: T,\r\n obj: U,\r\n relations?: Map<string, ResolvedRelation>,\r\n): U & T {\r\n if (!relations) {\r\n return deepMergePlain(result, obj) as unknown as U & T;\r\n }\r\n\r\n const merged: PlainObject = { ...result };\r\n\r\n for (const [key, field] of Object.entries(obj)) {\r\n if (field === undefined) continue;\r\n\r\n const relation = relations.get(key);\r\n\r\n if (!relation) {\r\n merged[key] = field;\r\n continue;\r\n }\r\n\r\n if (relation.mode !== \"otm\" && isPlainObject(merged[key])) {\r\n merged[key] = field === null ? null : deepMergePlain(merged[key], field as PlainObject);\r\n continue;\r\n }\r\n\r\n if (relation.mode === \"otm\" && Array.isArray(merged[key])) {\r\n merged[key] = mergeToManyRelation(merged[key], field as PlainObject[], relation.relatedPk);\r\n continue;\r\n }\r\n\r\n merged[key] = field;\r\n }\r\n\r\n return merged as unknown as U & T;\r\n}\r\n","/**\r\n * Resolves the nested-relation part of a `create`/`update` payload into\r\n * actual Drizzle statements, run against `tx` (always a transaction, so a\r\n * failure partway through leaves nothing half-written) — the imperative\r\n * equivalent of what `VSRepoPrisma7Adapter`'s `data.parser.ts` builds\r\n * declaratively via Prisma's nested-write API (`create`/`connectOrCreate`/\r\n * `upsert`/`disconnect`/`delete`/`deleteMany`), which Drizzle has no\r\n * equivalent of. Behavior mirrors that adapter's rules 1:1 (see its\r\n * `data.parser.ts` docstring) — minus `mtm`, which this adapter's\r\n * `AdapterRelation` doesn't model.\r\n *\r\n * A payload field is split, by the configured relation's FK side, into:\r\n * - `fkHere` relations (`mto`, and `oto` when the FK lives on *this*\r\n * table) — the FK column is part of *this* table's own row, so these\r\n * MUST be resolved and merged into the row's data BEFORE it's inserted/\r\n * updated (`resolveFkHereFields`).\r\n * - `fkThere` relations (`otm`, and `oto` when the FK lives on the\r\n * *related* table) — the FK column lives on the related row and points\r\n * back via this table's pk, so these can only be resolved AFTER this\r\n * table's own row exists / its pk is known (`resolveFkThereFields`).\r\n *\r\n * Nested creates only go one level deep: a related record's own payload is\r\n * inserted as-is (its scalar fields), it is NOT recursively checked for\r\n * further relation fields of its own — this adapter's `relations` config\r\n * only describes the *owning* table's relations, not the whole schema graph\r\n * (unlike Prisma, which resolves nested writes against its full schema).\r\n */\r\n\r\nimport { and, eq, ne, notInArray } from \"drizzle-orm\";\r\nimport { AdapterErrorCode, VSRepoAdapterError } from \"vsrepo\";\r\nimport { DrizzleTransactionLike } from \"../types/drizzle-transaction-like.type.js\";\r\nimport { PlainObject } from \"../types/plain-object.type.js\";\r\nimport { ResolvedRelation } from \"../types/resolved-relation.type.js\";\r\n\r\n/** Sentinel returned by `resolveFkHereField` for \"leave this field out of the write entirely\". */\r\nconst SKIP = Symbol(\"skip\");\r\n\r\nfunction omitKey(item: PlainObject, key: string): PlainObject {\r\n const clone = { ...item };\r\n delete clone[key];\r\n return clone;\r\n}\r\n\r\nexport type SplitPayload = {\r\n /** This table's own scalar fields (relation fields and, on updates, the pk, are excluded). */\r\n scalarFields: PlainObject;\r\n /** Configured relations whose FK column lives on *this* table (`mto`, `oto` + `fkHere`). */\r\n fkHereEntries: [string, ResolvedRelation, unknown][];\r\n /** Configured relations whose FK column lives on the *related* table (`otm`, `oto` + `fkThere`). */\r\n fkThereEntries: [string, ResolvedRelation, unknown][];\r\n};\r\n\r\n/** Splits a raw `DeepPartial<T>` payload into own scalar fields vs. relation writes to resolve separately. */\r\nexport function splitWritePayload(\r\n obj: PlainObject,\r\n relations: Map<string, ResolvedRelation> | undefined,\r\n pkName: string,\r\n excludePk: boolean,\r\n): SplitPayload {\r\n const scalarFields: PlainObject = {};\r\n const fkHereEntries: [string, ResolvedRelation, unknown][] = [];\r\n const fkThereEntries: [string, ResolvedRelation, unknown][] = [];\r\n\r\n for (const [key, value] of Object.entries(obj)) {\r\n if (value === undefined) continue;\r\n\r\n const relation = relations?.get(key);\r\n\r\n if (!relation) {\r\n if (excludePk && key === pkName) continue;\r\n scalarFields[key] = value;\r\n continue;\r\n }\r\n\r\n if (relation.fkHere) {\r\n fkHereEntries.push([key, relation, value]);\r\n } else {\r\n fkThereEntries.push([key, relation, value]);\r\n }\r\n }\r\n\r\n return { scalarFields, fkHereEntries, fkThereEntries };\r\n}\r\n\r\n/**\r\n * Resolves one `fkHere` relation field (`mto`, or `oto` with the FK here)\r\n * into the value to put in this table's own `fkHere` column — creating,\r\n * connecting, or (on `restriction: \"set\"`) upserting the related record as\r\n * needed. Returns the `SKIP` sentinel when the field shouldn't be touched at\r\n * all (mirrors `data.parser.ts` returning `{}` for those same cases).\r\n *\r\n * `currentFkValue` is this table's own *current* value of the `fkHere`\r\n * column — only needed (and only passed on `update`) to find the\r\n * previously-linked related row when `restriction: \"set\"` + `field === null`\r\n * means \"delete the related row that was here\".\r\n */\r\nasync function resolveFkHereField(\r\n tx: DrizzleTransactionLike,\r\n relation: ResolvedRelation,\r\n field: PlainObject | null,\r\n currentFkValue: unknown,\r\n): Promise<unknown | typeof SKIP> {\r\n const relatedTable = relation.table as unknown as PlainObject;\r\n const pkColumn = relatedTable[relation.relatedPk];\r\n\r\n if (field === null) {\r\n if (relation.mode === \"mto\" && relation.nullable) return null;\r\n\r\n if (relation.mode === \"oto\" && relation.restriction === \"set\") {\r\n if (currentFkValue !== undefined && currentFkValue !== null) {\r\n await (tx as any).delete(relation.table).where(eq(pkColumn, currentFkValue));\r\n }\r\n return null;\r\n }\r\n\r\n return SKIP;\r\n }\r\n\r\n const pkValue = field[relation.relatedPk];\r\n\r\n if (pkValue === undefined) {\r\n const [created] = await (tx as any).insert(relation.table).values(field).returning();\r\n return created[relation.relatedPk];\r\n }\r\n\r\n const existing = await (tx as any).select({ pk: pkColumn }).from(relation.table).where(eq(pkColumn, pkValue)).limit(1);\r\n\r\n if (existing.length === 0) {\r\n await (tx as any).insert(relation.table).values(field);\r\n } else if (relation.restriction === \"set\") {\r\n const dataWithoutPk = omitKey(field, relation.relatedPk);\r\n if (Object.keys(dataWithoutPk).length > 0) {\r\n await (tx as any).update(relation.table).set(dataWithoutPk).where(eq(pkColumn, pkValue));\r\n }\r\n }\r\n\r\n return pkValue;\r\n}\r\n\r\n/** Resolves every `fkHere` relation field, merging the results straight into `scalarFields`. */\r\nexport async function resolveFkHereFields(\r\n tx: DrizzleTransactionLike,\r\n entries: [string, ResolvedRelation, unknown][],\r\n scalarFields: PlainObject,\r\n currentRow: PlainObject | undefined,\r\n): Promise<void> {\r\n for (const [key, relation, value] of entries) {\r\n if (value !== null && typeof value !== \"object\") {\r\n throw new VSRepoAdapterError(\r\n `Field '${key}': expected an object or 'null' for a to-one relation, got '${typeof value}'.`,\r\n AdapterErrorCode.INVALID_DATA,\r\n null,\r\n );\r\n }\r\n\r\n const currentFkValue = currentRow?.[relation.fkHere as string];\r\n const resolved = await resolveFkHereField(tx, relation, value as PlainObject | null, currentFkValue);\r\n\r\n if (resolved !== SKIP) {\r\n scalarFields[relation.fkHere as string] = resolved;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Resolves one `fkThere` relation field (`otm`, or `oto` with the FK there)\r\n * against `ownPkValue` (this table's own, already-known, pk value) — see\r\n * module docstring for why this can only run once that pk is known.\r\n */\r\nasync function resolveOtmField(\r\n tx: DrizzleTransactionLike,\r\n relation: ResolvedRelation,\r\n items: PlainObject[],\r\n ownPkValue: unknown,\r\n): Promise<void> {\r\n const relatedTable = relation.table as unknown as PlainObject;\r\n const fkColumn = relatedTable[relation.fkThere as string];\r\n const pkColumn = relatedTable[relation.relatedPk];\r\n\r\n const withoutPk = items.filter(item => item[relation.relatedPk] === undefined);\r\n const withPk = items.filter(item => item[relation.relatedPk] !== undefined);\r\n\r\n // Every pk that ends up part of this write — whether freshly generated (`withoutPk`) or\r\n // given up front (`withPk`) — has to be tracked BEFORE the `restriction: \"set\"` cleanup\r\n // below runs, or it'll treat a row inserted a moment ago as something to delete right away.\r\n const connectedIds: unknown[] = [];\r\n\r\n for (const item of withoutPk) {\r\n const [insertedRow] = await (tx as any)\r\n .insert(relation.table)\r\n .values({ ...item, [relation.fkThere as string]: ownPkValue })\r\n .returning();\r\n\r\n if (insertedRow?.[relation.relatedPk] !== undefined) {\r\n connectedIds.push(insertedRow[relation.relatedPk]);\r\n }\r\n }\r\n\r\n for (const item of withPk) {\r\n const pkValue = item[relation.relatedPk];\r\n connectedIds.push(pkValue);\r\n\r\n const existing = await (tx as any).select({ pk: pkColumn }).from(relation.table).where(eq(pkColumn, pkValue)).limit(1);\r\n\r\n if (existing.length === 0) {\r\n await (tx as any).insert(relation.table).values({ ...item, [relation.fkThere as string]: ownPkValue });\r\n continue;\r\n }\r\n\r\n const setData =\r\n relation.restriction === \"set\"\r\n ? { ...omitKey(item, relation.relatedPk), [relation.fkThere as string]: ownPkValue }\r\n : { [relation.fkThere as string]: ownPkValue };\r\n\r\n await (tx as any).update(relation.table).set(setData).where(eq(pkColumn, pkValue));\r\n }\r\n\r\n if (relation.restriction === \"set\") {\r\n const condition =\r\n connectedIds.length > 0\r\n ? and(eq(fkColumn, ownPkValue), notInArray(pkColumn, connectedIds))!\r\n : eq(fkColumn, ownPkValue);\r\n\r\n await (tx as any).delete(relation.table).where(condition);\r\n }\r\n}\r\n\r\n/** Resolves one `oto` field whose FK lives on the related table. */\r\nasync function resolveOtoFkThereField(\r\n tx: DrizzleTransactionLike,\r\n relation: ResolvedRelation,\r\n field: PlainObject | null,\r\n ownPkValue: unknown,\r\n): Promise<void> {\r\n const relatedTable = relation.table as unknown as PlainObject;\r\n const fkColumn = relatedTable[relation.fkThere as string];\r\n const pkColumn = relatedTable[relation.relatedPk];\r\n\r\n if (field === null) {\r\n if (relation.restriction === \"set\") {\r\n await (tx as any).delete(relation.table).where(eq(fkColumn, ownPkValue));\r\n }\r\n return;\r\n }\r\n\r\n const pkValue = field[relation.relatedPk];\r\n let keepPk: unknown = pkValue;\r\n\r\n if (pkValue === undefined) {\r\n const [insertedRow] = await (tx as any)\r\n .insert(relation.table)\r\n .values({ ...field, [relation.fkThere as string]: ownPkValue })\r\n .returning();\r\n\r\n keepPk = insertedRow?.[relation.relatedPk];\r\n } else {\r\n const existing = await (tx as any).select({ pk: pkColumn }).from(relation.table).where(eq(pkColumn, pkValue)).limit(1);\r\n\r\n if (existing.length === 0) {\r\n await (tx as any).insert(relation.table).values({ ...field, [relation.fkThere as string]: ownPkValue });\r\n } else {\r\n const setData =\r\n relation.restriction === \"set\"\r\n ? { ...omitKey(field, relation.relatedPk), [relation.fkThere as string]: ownPkValue }\r\n : { [relation.fkThere as string]: ownPkValue };\r\n\r\n await (tx as any).update(relation.table).set(setData).where(eq(pkColumn, pkValue));\r\n }\r\n }\r\n\r\n if (relation.restriction === \"set\" && keepPk !== undefined) {\r\n // Removes any other stale row previously linked to this parent (1:1 cleanup) —\r\n // `keepPk` is either the given pk or the pk freshly generated by the insert above,\r\n // so a just-inserted row is never mistaken for a stale one to clean up.\r\n await (tx as any).delete(relation.table).where(and(eq(fkColumn, ownPkValue), ne(pkColumn, keepPk)));\r\n }\r\n}\r\n\r\n/** Resolves every `fkThere` relation field, once `ownPkValue` (this table's own pk) is known. */\r\nexport async function resolveFkThereFields(\r\n tx: DrizzleTransactionLike,\r\n entries: [string, ResolvedRelation, unknown][],\r\n ownPkValue: unknown,\r\n): Promise<void> {\r\n for (const [key, relation, value] of entries) {\r\n if (relation.mode === \"otm\") {\r\n if (!Array.isArray(value)) {\r\n throw new VSRepoAdapterError(\r\n `Field '${key}': expected an array for a to-many relation, got '${typeof value}'.`,\r\n AdapterErrorCode.INVALID_DATA,\r\n null,\r\n );\r\n }\r\n await resolveOtmField(tx, relation, value as PlainObject[], ownPkValue);\r\n continue;\r\n }\r\n\r\n if (value !== null && typeof value !== \"object\") {\r\n throw new VSRepoAdapterError(\r\n `Field '${key}': expected an object or 'null' for a to-one relation, got '${typeof value}'.`,\r\n AdapterErrorCode.INVALID_DATA,\r\n null,\r\n );\r\n }\r\n\r\n await resolveOtoFkThereField(tx, relation, value as PlainObject | null, ownPkValue);\r\n }\r\n}\r\n"],"mappings":"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","names":["import_drizzle_orm","import_vsrepo","import_drizzle_orm","import_vsrepo","import_drizzle_orm","import_drizzle_orm","import_vsrepo","import_drizzle_orm","import_vsrepo","import_vsrepo","import_drizzle_orm","import_vsrepo","FIELD_OPERATOR_KEYS","isFieldOperatorObject","isArrayRelationFilter","isObjectRelationFilter","column","join","nested","parsePlainWhere","parseWhere","import_vsrepo","import_drizzle_orm","import_vsrepo","isSortDirection","import_drizzle_orm","import_vsrepo","countFn","sumFn","minFn","maxFn"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { KeysOfType, Primitive, RelationKeys, VSRepoAdapter, VSRepoTransactionOptions, AdapterQueryOptions, VSRepoWhere, AdapterMethodOptions, DeepPartial, CountResult, NumericKeys } from 'vsrepo';
|
|
2
|
+
import { SQLWrapper, Table } from 'drizzle-orm';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @publicApi
|
|
6
|
+
*/
|
|
7
|
+
type DrizzleTransactionLike = DrizzleDbLike & {
|
|
8
|
+
rollback(): never;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type Fn = (...args: any[]) => any;
|
|
12
|
+
/**
|
|
13
|
+
* @publicApi
|
|
14
|
+
*/
|
|
15
|
+
type DrizzleDbLike = {
|
|
16
|
+
select: Fn;
|
|
17
|
+
insert: Fn;
|
|
18
|
+
update: Fn;
|
|
19
|
+
delete: Fn;
|
|
20
|
+
query: Record<string, {
|
|
21
|
+
findFirst: Fn;
|
|
22
|
+
findMany: Fn;
|
|
23
|
+
}>;
|
|
24
|
+
selectDistinct: (fields: object) => {
|
|
25
|
+
from: (table: any) => any;
|
|
26
|
+
};
|
|
27
|
+
execute: (query: SQLWrapper) => Promise<any>;
|
|
28
|
+
transaction: <R>(fn: (tx: DrizzleTransactionLike) => Promise<R>, config?: any) => Promise<R>;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @publicApi
|
|
33
|
+
*/
|
|
34
|
+
type SupportedDialects = "postgresql" | "sqlite" | "cockroach";
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @publicApi
|
|
38
|
+
*/
|
|
39
|
+
type AdapterRelation<T, K> = {
|
|
40
|
+
restriction: "set" | "add";
|
|
41
|
+
table: Table;
|
|
42
|
+
fkHere?: KeysOfType<T, Primitive>;
|
|
43
|
+
fkThere?: KeysOfType<K, Primitive>;
|
|
44
|
+
} & ({
|
|
45
|
+
mode: "otm";
|
|
46
|
+
fkThere: KeysOfType<K, Primitive>;
|
|
47
|
+
fkHere?: never;
|
|
48
|
+
} | {
|
|
49
|
+
mode: "mto";
|
|
50
|
+
nullable?: boolean;
|
|
51
|
+
fkHere: KeysOfType<T, Primitive>;
|
|
52
|
+
} | ({
|
|
53
|
+
mode: "oto";
|
|
54
|
+
} & ({
|
|
55
|
+
fkHere: KeysOfType<T, Primitive>;
|
|
56
|
+
fkThere?: never;
|
|
57
|
+
} | {
|
|
58
|
+
fkThere: KeysOfType<K, Primitive>;
|
|
59
|
+
fkHere?: never;
|
|
60
|
+
})));
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @publicApi
|
|
64
|
+
*/
|
|
65
|
+
type AdapterRelations<T> = Partial<{
|
|
66
|
+
[P in RelationKeys<T>]: AdapterRelation<T, NonNullable<T[P]> extends Array<infer U> ? U : NonNullable<T[P]>>;
|
|
67
|
+
}>;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @publicApi
|
|
71
|
+
*/
|
|
72
|
+
type DrizzleAdapterConfig<T, K extends DrizzleDbLike = DrizzleDbLike> = {
|
|
73
|
+
table: Table;
|
|
74
|
+
dialect?: SupportedDialects;
|
|
75
|
+
queryKey: keyof K["query"];
|
|
76
|
+
relations?: AdapterRelations<T>;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @publicApi
|
|
81
|
+
*/
|
|
82
|
+
declare class DrizzleAdapter<T, K extends DrizzleDbLike = DrizzleDbLike> extends VSRepoAdapter<T> {
|
|
83
|
+
private readonly table;
|
|
84
|
+
private readonly db;
|
|
85
|
+
private readonly dialect;
|
|
86
|
+
private readonly pk;
|
|
87
|
+
private readonly queryKey;
|
|
88
|
+
private readonly relations?;
|
|
89
|
+
constructor(db: K, config: DrizzleAdapterConfig<T, K>);
|
|
90
|
+
/**
|
|
91
|
+
* Returns `db.query[queryKey]` (the relational query builder entry for
|
|
92
|
+
* this adapter's table), reading from `db` when a transaction/executor
|
|
93
|
+
* override is passed via `options.db`, otherwise from the root client.
|
|
94
|
+
*/
|
|
95
|
+
private getQueryBuilder;
|
|
96
|
+
/**
|
|
97
|
+
* Resolves the "read" part of a query arg: `columns`/`with`/`where`/
|
|
98
|
+
* `orderBy`/pagination.
|
|
99
|
+
*
|
|
100
|
+
* Per the adapter contract: when both `select` and `relations` are
|
|
101
|
+
* given, `select` wins and `relations` is ignored entirely.
|
|
102
|
+
*/
|
|
103
|
+
private resolveReadArgs;
|
|
104
|
+
/** Builds the context `parseSqlWhere` needs to resolve `_with`/`_without`/`_some`/`_every`/`_none` relation filters. */
|
|
105
|
+
private getSqlWhereContext;
|
|
106
|
+
/**
|
|
107
|
+
* Resolves a user-supplied `VSRepoWhere<T>` into the `where` shape the
|
|
108
|
+
* relational query API (`db.query[queryKey].findFirst/findMany`) accepts.
|
|
109
|
+
*
|
|
110
|
+
* The relational API's own object-shaped `where` (`where.parser.ts`) has
|
|
111
|
+
* no native `_every`/`_none` semantics for to-many relations — so when
|
|
112
|
+
* `where` contains one (`hasQuantifierFilter`), this instead:
|
|
113
|
+
* 1. Resolves `where` into a `SQL` condition via `sql-where.parser.ts`
|
|
114
|
+
* (which DOES support `_every`/`_none`, via `NOT EXISTS`);
|
|
115
|
+
* 2. Runs `db.select({pk}).from(table).where(condition)`, applying the
|
|
116
|
+
* SAME `order`/`limit`/`offset` the final query would've used
|
|
117
|
+
* (`sql-order-by.parser.ts`), so the prefetch only ever pulls the
|
|
118
|
+
* rows the caller actually needs, instead of every matching row;
|
|
119
|
+
* 3. Returns `parseDrizzleWhere({ [pk]: { in: pks } })` instead — the
|
|
120
|
+
* relational API then only has to filter by pk (trivial for it),
|
|
121
|
+
* while still handling `columns`/`with` on the correct result set.
|
|
122
|
+
*
|
|
123
|
+
* Since SQL `IN (...)` doesn't preserve the given list's order, `resolveReadArgs`
|
|
124
|
+
* re-applies `orderBy` (but NOT `limit`/`offset`, already baked into the pk set)
|
|
125
|
+
* on the final relational query when `paginationApplied` comes back `true`.
|
|
126
|
+
*
|
|
127
|
+
* This keeps `_every`/`_none` support consistent between this adapter's
|
|
128
|
+
* two `where` parsers — from the outside, `findOne`/`findMany`/etc. never
|
|
129
|
+
* throw `NOT_SUPPORTED` for them, at the cost of an extra round-trip only
|
|
130
|
+
* when they're actually used.
|
|
131
|
+
*/
|
|
132
|
+
private resolveFindWhere;
|
|
133
|
+
/**
|
|
134
|
+
* Strips relation fields from a payload — used by `createMany`/`updateMany`/
|
|
135
|
+
* `updateManyReturning`, since batch statements only accept flat column
|
|
136
|
+
* data (no nested writes). Throws `VSRepoAdapterError` (code
|
|
137
|
+
* `NOT_SUPPORTED`) instead of silently dropping the field, when a
|
|
138
|
+
* configured relation field is present in the payload.
|
|
139
|
+
*/
|
|
140
|
+
private stripRelationFields;
|
|
141
|
+
private isRootClient;
|
|
142
|
+
private runTransactional;
|
|
143
|
+
runInTransaction<R>(fn: (tx: DrizzleTransactionLike) => Promise<R>, options?: VSRepoTransactionOptions): Promise<R>;
|
|
144
|
+
getDbClient(): DrizzleDbLike;
|
|
145
|
+
query<R = any>(rawQuery: string, options?: AdapterQueryOptions): Promise<R>;
|
|
146
|
+
findOne(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<T | null>;
|
|
147
|
+
findOneOrThrow(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<T>;
|
|
148
|
+
findMany(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T> & {
|
|
149
|
+
distinct?: (keyof T)[];
|
|
150
|
+
}): Promise<T[]>;
|
|
151
|
+
save(obj: DeepPartial<T>, options?: AdapterMethodOptions<T>): Promise<T>;
|
|
152
|
+
saveMany(objs: DeepPartial<T>[], options?: AdapterMethodOptions<T>): Promise<T[]>;
|
|
153
|
+
create(obj: DeepPartial<T>, options?: AdapterMethodOptions<T>): Promise<T>;
|
|
154
|
+
createMany(objs: DeepPartial<T>[], options?: AdapterMethodOptions<T> & {
|
|
155
|
+
ignoreConflicts?: boolean;
|
|
156
|
+
}): Promise<CountResult>;
|
|
157
|
+
createManyReturning(objs: DeepPartial<T>[], options?: AdapterMethodOptions<T> & {
|
|
158
|
+
ignoreConflicts?: boolean;
|
|
159
|
+
}): Promise<T[]>;
|
|
160
|
+
delete(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<T>;
|
|
161
|
+
deleteMany(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<CountResult>;
|
|
162
|
+
deleteManyReturning(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<T[]>;
|
|
163
|
+
update(where: VSRepoWhere<T>, obj: DeepPartial<T>, options?: AdapterMethodOptions<T>): Promise<T>;
|
|
164
|
+
updateMany(where: VSRepoWhere<T>, obj: DeepPartial<T>, options?: AdapterMethodOptions<T>): Promise<CountResult>;
|
|
165
|
+
updateManyReturning(where: VSRepoWhere<T>, obj: DeepPartial<T>, options?: AdapterMethodOptions<T>): Promise<T[]>;
|
|
166
|
+
count(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<number>;
|
|
167
|
+
exists(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<boolean>;
|
|
168
|
+
merge<K>(where: VSRepoWhere<T>, obj: DeepPartial<T>, options?: AdapterMethodOptions<T>): Promise<K & T>;
|
|
169
|
+
upsert(where: VSRepoWhere<T>, create: DeepPartial<T>, update: DeepPartial<T>, options?: AdapterMethodOptions<T>): Promise<T>;
|
|
170
|
+
/** Shared implementation behind `incrementOne`/`decrementOne`/`multiplyOne`/`divideOne`. */
|
|
171
|
+
private atomicUpdate;
|
|
172
|
+
incrementOne<K extends NumericKeys<T>>(field: K, value: NonNullable<T[K]>, where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<T>;
|
|
173
|
+
decrementOne<K extends NumericKeys<T>>(field: K, value: NonNullable<T[K]>, where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<T>;
|
|
174
|
+
multiplyOne<K extends NumericKeys<T>>(field: K, value: NonNullable<T[K]>, where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<T>;
|
|
175
|
+
divideOne<K extends NumericKeys<T>>(field: K, value: NonNullable<T[K]>, where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<T>;
|
|
176
|
+
/** Shared implementation behind `sum`/`average`/`min`/`max`. */
|
|
177
|
+
private aggregate;
|
|
178
|
+
sum(field: NumericKeys<T>, where?: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<number | null>;
|
|
179
|
+
average(field: NumericKeys<T>, where?: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<number | null>;
|
|
180
|
+
min(field: NumericKeys<T>, where?: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<number | null>;
|
|
181
|
+
max(field: NumericKeys<T>, where?: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<number | null>;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export { DrizzleAdapter, type DrizzleAdapterConfig, type DrizzleDbLike, type DrizzleTransactionLike, type SupportedDialects };
|