@fragno-dev/db 0.1.13 → 0.1.15
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/.turbo/turbo-build.log +179 -132
- package/CHANGELOG.md +30 -0
- package/dist/adapters/adapters.d.ts +27 -1
- package/dist/adapters/adapters.d.ts.map +1 -1
- package/dist/adapters/adapters.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-adapter.d.ts +5 -1
- package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -1
- package/dist/adapters/drizzle/drizzle-adapter.js +15 -3
- package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-query.js +7 -5
- package/dist/adapters/drizzle/drizzle-query.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts +0 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.js +76 -44
- package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-decoder.js +23 -16
- package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-executor.js +18 -7
- package/dist/adapters/drizzle/drizzle-uow-executor.js.map +1 -1
- package/dist/adapters/drizzle/generate.d.ts +4 -1
- package/dist/adapters/drizzle/generate.d.ts.map +1 -1
- package/dist/adapters/drizzle/generate.js +11 -18
- package/dist/adapters/drizzle/generate.js.map +1 -1
- package/dist/adapters/drizzle/shared.d.ts +14 -1
- package/dist/adapters/drizzle/shared.d.ts.map +1 -0
- package/dist/adapters/kysely/kysely-adapter.d.ts +5 -1
- package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -1
- package/dist/adapters/kysely/kysely-adapter.js +14 -3
- package/dist/adapters/kysely/kysely-adapter.js.map +1 -1
- package/dist/adapters/kysely/kysely-query-builder.js +1 -1
- package/dist/adapters/kysely/kysely-query-compiler.js +3 -2
- package/dist/adapters/kysely/kysely-query-compiler.js.map +1 -1
- package/dist/adapters/kysely/kysely-query.d.ts +1 -0
- package/dist/adapters/kysely/kysely-query.d.ts.map +1 -1
- package/dist/adapters/kysely/kysely-query.js +28 -19
- package/dist/adapters/kysely/kysely-query.js.map +1 -1
- package/dist/adapters/kysely/kysely-shared.d.ts +14 -0
- package/dist/adapters/kysely/kysely-shared.d.ts.map +1 -0
- package/dist/adapters/kysely/kysely-shared.js +16 -1
- package/dist/adapters/kysely/kysely-shared.js.map +1 -1
- package/dist/adapters/kysely/kysely-uow-compiler.js +68 -16
- package/dist/adapters/kysely/kysely-uow-compiler.js.map +1 -1
- package/dist/adapters/kysely/kysely-uow-executor.js +8 -4
- package/dist/adapters/kysely/kysely-uow-executor.js.map +1 -1
- package/dist/adapters/kysely/migration/execute-base.js +1 -1
- package/dist/adapters/kysely/migration/execute-base.js.map +1 -1
- package/dist/db-fragment-definition-builder.d.ts +152 -0
- package/dist/db-fragment-definition-builder.d.ts.map +1 -0
- package/dist/db-fragment-definition-builder.js +137 -0
- package/dist/db-fragment-definition-builder.js.map +1 -0
- package/dist/fragments/internal-fragment.d.ts +19 -0
- package/dist/fragments/internal-fragment.d.ts.map +1 -0
- package/dist/fragments/internal-fragment.js +39 -0
- package/dist/fragments/internal-fragment.js.map +1 -0
- package/dist/migration-engine/generation-engine.d.ts.map +1 -1
- package/dist/migration-engine/generation-engine.js +35 -15
- package/dist/migration-engine/generation-engine.js.map +1 -1
- package/dist/mod.d.ts +8 -18
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +7 -34
- package/dist/mod.js.map +1 -1
- package/dist/node_modules/.pnpm/rou3@0.7.8/node_modules/rou3/dist/index.js +165 -0
- package/dist/node_modules/.pnpm/rou3@0.7.8/node_modules/rou3/dist/index.js.map +1 -0
- package/dist/packages/fragno/dist/api/bind-services.js +20 -0
- package/dist/packages/fragno/dist/api/bind-services.js.map +1 -0
- package/dist/packages/fragno/dist/api/error.js +48 -0
- package/dist/packages/fragno/dist/api/error.js.map +1 -0
- package/dist/packages/fragno/dist/api/fragment-definition-builder.js +320 -0
- package/dist/packages/fragno/dist/api/fragment-definition-builder.js.map +1 -0
- package/dist/packages/fragno/dist/api/fragment-instantiator.js +487 -0
- package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +1 -0
- package/dist/packages/fragno/dist/api/fragno-response.js +73 -0
- package/dist/packages/fragno/dist/api/fragno-response.js.map +1 -0
- package/dist/packages/fragno/dist/api/internal/response-stream.js +81 -0
- package/dist/packages/fragno/dist/api/internal/response-stream.js.map +1 -0
- package/dist/packages/fragno/dist/api/internal/route.js +10 -0
- package/dist/packages/fragno/dist/api/internal/route.js.map +1 -0
- package/dist/packages/fragno/dist/api/mutable-request-state.js +97 -0
- package/dist/packages/fragno/dist/api/mutable-request-state.js.map +1 -0
- package/dist/packages/fragno/dist/api/request-context-storage.js +43 -0
- package/dist/packages/fragno/dist/api/request-context-storage.js.map +1 -0
- package/dist/packages/fragno/dist/api/request-input-context.js +118 -0
- package/dist/packages/fragno/dist/api/request-input-context.js.map +1 -0
- package/dist/packages/fragno/dist/api/request-middleware.js +83 -0
- package/dist/packages/fragno/dist/api/request-middleware.js.map +1 -0
- package/dist/packages/fragno/dist/api/request-output-context.js +119 -0
- package/dist/packages/fragno/dist/api/request-output-context.js.map +1 -0
- package/dist/packages/fragno/dist/api/route.js +17 -0
- package/dist/packages/fragno/dist/api/route.js.map +1 -0
- package/dist/packages/fragno/dist/internal/symbols.js +10 -0
- package/dist/packages/fragno/dist/internal/symbols.js.map +1 -0
- package/dist/query/cursor.d.ts +10 -2
- package/dist/query/cursor.d.ts.map +1 -1
- package/dist/query/cursor.js +11 -4
- package/dist/query/cursor.js.map +1 -1
- package/dist/query/execute-unit-of-work.d.ts +123 -0
- package/dist/query/execute-unit-of-work.d.ts.map +1 -0
- package/dist/query/execute-unit-of-work.js +184 -0
- package/dist/query/execute-unit-of-work.js.map +1 -0
- package/dist/query/query.d.ts +3 -3
- package/dist/query/query.d.ts.map +1 -1
- package/dist/query/result-transform.js +4 -2
- package/dist/query/result-transform.js.map +1 -1
- package/dist/query/retry-policy.d.ts +88 -0
- package/dist/query/retry-policy.d.ts.map +1 -0
- package/dist/query/retry-policy.js +61 -0
- package/dist/query/retry-policy.js.map +1 -0
- package/dist/query/unit-of-work.d.ts +171 -32
- package/dist/query/unit-of-work.d.ts.map +1 -1
- package/dist/query/unit-of-work.js +530 -133
- package/dist/query/unit-of-work.js.map +1 -1
- package/dist/schema/serialize.js +12 -7
- package/dist/schema/serialize.js.map +1 -1
- package/dist/with-database.d.ts +28 -0
- package/dist/with-database.d.ts.map +1 -0
- package/dist/with-database.js +34 -0
- package/dist/with-database.js.map +1 -0
- package/package.json +10 -3
- package/src/adapters/adapters.ts +30 -0
- package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +86 -17
- package/src/adapters/drizzle/drizzle-adapter-sqlite.test.ts +291 -7
- package/src/adapters/drizzle/drizzle-adapter.test.ts +3 -51
- package/src/adapters/drizzle/drizzle-adapter.ts +35 -7
- package/src/adapters/drizzle/drizzle-query.ts +25 -15
- package/src/adapters/drizzle/drizzle-uow-compiler-mysql.test.ts +1442 -0
- package/src/adapters/drizzle/drizzle-uow-compiler-sqlite.test.ts +1414 -0
- package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +78 -61
- package/src/adapters/drizzle/drizzle-uow-compiler.ts +123 -42
- package/src/adapters/drizzle/drizzle-uow-decoder.ts +34 -27
- package/src/adapters/drizzle/drizzle-uow-executor.ts +41 -8
- package/src/adapters/drizzle/generate.test.ts +102 -269
- package/src/adapters/drizzle/generate.ts +12 -30
- package/src/adapters/drizzle/test-utils.ts +36 -5
- package/src/adapters/kysely/kysely-adapter-pglite.test.ts +66 -22
- package/src/adapters/kysely/kysely-adapter-sqlite.test.ts +156 -0
- package/src/adapters/kysely/kysely-adapter.ts +25 -2
- package/src/adapters/kysely/kysely-query-compiler.ts +3 -8
- package/src/adapters/kysely/kysely-query.ts +57 -37
- package/src/adapters/kysely/kysely-shared.ts +34 -0
- package/src/adapters/kysely/kysely-uow-compiler.test.ts +62 -74
- package/src/adapters/kysely/kysely-uow-compiler.ts +92 -24
- package/src/adapters/kysely/kysely-uow-executor.ts +26 -7
- package/src/adapters/kysely/kysely-uow-joins.test.ts +33 -50
- package/src/adapters/kysely/migration/execute-base.ts +1 -1
- package/src/db-fragment-definition-builder.test.ts +887 -0
- package/src/db-fragment-definition-builder.ts +506 -0
- package/src/db-fragment-instantiator.test.ts +467 -0
- package/src/db-fragment-integration.test.ts +408 -0
- package/src/fragments/internal-fragment.test.ts +160 -0
- package/src/fragments/internal-fragment.ts +85 -0
- package/src/migration-engine/generation-engine.test.ts +58 -15
- package/src/migration-engine/generation-engine.ts +78 -25
- package/src/mod.ts +35 -43
- package/src/query/cursor.test.ts +119 -0
- package/src/query/cursor.ts +17 -4
- package/src/query/execute-unit-of-work.test.ts +1310 -0
- package/src/query/execute-unit-of-work.ts +463 -0
- package/src/query/query.ts +4 -4
- package/src/query/result-transform.test.ts +129 -0
- package/src/query/result-transform.ts +4 -1
- package/src/query/retry-policy.test.ts +217 -0
- package/src/query/retry-policy.ts +141 -0
- package/src/query/unit-of-work-coordinator.test.ts +833 -0
- package/src/query/unit-of-work-types.test.ts +15 -2
- package/src/query/unit-of-work.test.ts +878 -200
- package/src/query/unit-of-work.ts +963 -321
- package/src/schema/serialize.ts +22 -11
- package/src/with-database.ts +140 -0
- package/tsdown.config.ts +1 -0
- package/dist/fragment.d.ts +0 -54
- package/dist/fragment.d.ts.map +0 -1
- package/dist/fragment.js +0 -92
- package/dist/fragment.js.map +0 -1
- package/dist/shared/settings-schema.js +0 -36
- package/dist/shared/settings-schema.js.map +0 -1
- package/src/fragment.test.ts +0 -341
- package/src/fragment.ts +0 -198
- package/src/shared/settings-schema.ts +0 -61
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drizzle-adapter.js","names":["#connectionPool","#provider"],"sources":["../../../src/adapters/drizzle/drizzle-adapter.ts"],"sourcesContent":["import type { DatabaseAdapter } from \"../adapters\";\nimport { type AnySchema } from \"../../schema/create\";\nimport type { AbstractQuery } from \"../../query/query\";\nimport type { SchemaGenerator } from \"../../schema-generator/schema-generator\";\nimport { generateSchema } from \"./generate\";\nimport { fromDrizzle, type DrizzleUOWConfig } from \"./drizzle-query\";\nimport { createTableNameMapper, type DBType, type DrizzleResult } from \"./shared\";\nimport {
|
|
1
|
+
{"version":3,"file":"drizzle-adapter.js","names":["#connectionPool","#provider","#contextStorage","#schemaNamespaceMap"],"sources":["../../../src/adapters/drizzle/drizzle-adapter.ts"],"sourcesContent":["import type { DatabaseAdapter, DatabaseContextStorage } from \"../adapters\";\nimport { type AnySchema } from \"../../schema/create\";\nimport type { AbstractQuery } from \"../../query/query\";\nimport type { SchemaGenerator } from \"../../schema-generator/schema-generator\";\nimport { generateSchema } from \"./generate\";\nimport { fromDrizzle, type DrizzleUOWConfig } from \"./drizzle-query\";\nimport { createTableNameMapper, type DBType, type DrizzleResult } from \"./shared\";\nimport { sql } from \"drizzle-orm\";\nimport { settingsSchema, SETTINGS_TABLE_NAME } from \"../../fragments/internal-fragment\";\nimport {\n fragnoDatabaseAdapterNameFakeSymbol,\n fragnoDatabaseAdapterVersionFakeSymbol,\n} from \"../adapters\";\nimport type { ConnectionPool } from \"../../shared/connection-pool\";\nimport { createDrizzleConnectionPool } from \"./drizzle-connection-pool\";\nimport { RequestContextStorage } from \"@fragno-dev/core/internal/request-context-storage\";\n\nexport interface DrizzleConfig {\n db: unknown | (() => unknown | Promise<unknown>);\n provider: \"sqlite\" | \"mysql\" | \"postgresql\";\n}\n\nexport class DrizzleAdapter implements DatabaseAdapter<DrizzleUOWConfig> {\n #connectionPool: ConnectionPool<DBType>;\n #provider: \"sqlite\" | \"mysql\" | \"postgresql\";\n #schemaNamespaceMap = new WeakMap<AnySchema, string>();\n #contextStorage: RequestContextStorage<DatabaseContextStorage>;\n\n constructor(config: DrizzleConfig) {\n this.#connectionPool = createDrizzleConnectionPool(\n config.db as DBType | (() => DBType | Promise<DBType>),\n );\n this.#provider = config.provider;\n this.#contextStorage = new RequestContextStorage();\n }\n\n get [fragnoDatabaseAdapterNameFakeSymbol](): string {\n return \"drizzle\";\n }\n\n get [fragnoDatabaseAdapterVersionFakeSymbol](): number {\n return 0;\n }\n\n get contextStorage(): RequestContextStorage<DatabaseContextStorage> {\n return this.#contextStorage;\n }\n\n async close(): Promise<void> {\n await this.#connectionPool.close();\n }\n\n createTableNameMapper(namespace: string) {\n return createTableNameMapper(namespace);\n }\n\n get provider(): \"sqlite\" | \"mysql\" | \"postgresql\" {\n return this.#provider;\n }\n\n async isConnectionHealthy(): Promise<boolean> {\n const conn = await this.#connectionPool.connect();\n try {\n const result = await conn.db.execute(sql`SELECT 1 as healthy`);\n\n // Handle different result formats across providers\n // PostgreSQL/MySQL: { rows: [...] }\n // SQLite: array directly or { rows: [...] }\n if (Array.isArray(result)) {\n return result.length > 0 && result[0][\"healthy\"] === 1;\n } else {\n const drizzleResult = result as DrizzleResult;\n return drizzleResult.rows[0][\"healthy\"] === 1;\n }\n } catch {\n return false;\n } finally {\n await conn.release();\n }\n }\n\n async getSchemaVersion(namespace: string): Promise<string | undefined> {\n // Note: This looks up arbitrary fragment schema versions (e.g., \"my-fragment.schema_version\")\n // which are different from Fragno's internal settings (prefixed with SETTINGS_NAMESPACE)\n // So we can't use the internal fragment here, we need direct query engine access\n const queryEngine = this.createQueryEngine(settingsSchema, \"\");\n\n const uow = queryEngine\n .createUnitOfWork()\n .find(SETTINGS_TABLE_NAME, (b) =>\n b.whereIndex(\"unique_key\", (eb) => eb(\"key\", \"=\", `${namespace}.schema_version`)),\n );\n const [[result]] = await uow.executeRetrieve();\n return result?.value;\n }\n\n createQueryEngine<TSchema extends AnySchema>(\n schema: TSchema,\n namespace: string,\n ): AbstractQuery<TSchema, DrizzleUOWConfig> {\n // Register schema-namespace mapping\n this.#schemaNamespaceMap.set(schema, namespace);\n\n // Only create mapper if namespace is non-empty\n const mapper = namespace ? createTableNameMapper(namespace) : undefined;\n return fromDrizzle(\n schema,\n this.#connectionPool,\n this.#provider,\n mapper,\n undefined,\n this.#schemaNamespaceMap,\n );\n }\n\n createSchemaGenerator(\n fragments: { schema: AnySchema; namespace: string }[],\n options?: { path?: string },\n ): SchemaGenerator {\n return {\n generateSchema: (genOptions) => {\n const path = genOptions?.path ?? options?.path ?? \"fragno-schema.ts\";\n\n return {\n schema: generateSchema(fragments, this.#provider),\n path,\n };\n },\n };\n }\n}\n"],"mappings":";;;;;;;;;;;AAsBA,IAAa,iBAAb,MAAyE;CACvE;CACA;CACA,sCAAsB,IAAI,SAA4B;CACtD;CAEA,YAAY,QAAuB;AACjC,QAAKA,iBAAkB,4BACrB,OAAO,GACR;AACD,QAAKC,WAAY,OAAO;AACxB,QAAKC,iBAAkB,IAAI,uBAAuB;;CAGpD,KAAK,uCAA+C;AAClD,SAAO;;CAGT,KAAK,0CAAkD;AACrD,SAAO;;CAGT,IAAI,iBAAgE;AAClE,SAAO,MAAKA;;CAGd,MAAM,QAAuB;AAC3B,QAAM,MAAKF,eAAgB,OAAO;;CAGpC,sBAAsB,WAAmB;AACvC,SAAO,sBAAsB,UAAU;;CAGzC,IAAI,WAA8C;AAChD,SAAO,MAAKC;;CAGd,MAAM,sBAAwC;EAC5C,MAAM,OAAO,MAAM,MAAKD,eAAgB,SAAS;AACjD,MAAI;GACF,MAAM,SAAS,MAAM,KAAK,GAAG,QAAQ,GAAG,sBAAsB;AAK9D,OAAI,MAAM,QAAQ,OAAO,CACvB,QAAO,OAAO,SAAS,KAAK,OAAO,GAAG,eAAe;OAGrD,QADsB,OACD,KAAK,GAAG,eAAe;UAExC;AACN,UAAO;YACC;AACR,SAAM,KAAK,SAAS;;;CAIxB,MAAM,iBAAiB,WAAgD;EAWrE,MAAM,CAAC,CAAC,WAAW,MAPC,KAAK,kBAAkB,gBAAgB,GAAG,CAG3D,kBAAkB,CAClB,KAAK,sBAAsB,MAC1B,EAAE,WAAW,eAAe,OAAO,GAAG,OAAO,KAAK,GAAG,UAAU,iBAAiB,CAAC,CAClF,CAC0B,iBAAiB;AAC9C,SAAO,QAAQ;;CAGjB,kBACE,QACA,WAC0C;AAE1C,QAAKG,mBAAoB,IAAI,QAAQ,UAAU;EAG/C,MAAM,SAAS,YAAY,sBAAsB,UAAU,GAAG;AAC9D,SAAO,YACL,QACA,MAAKH,gBACL,MAAKC,UACL,QACA,QACA,MAAKE,mBACN;;CAGH,sBACE,WACA,SACiB;AACjB,SAAO,EACL,iBAAiB,eAAe;GAC9B,MAAM,OAAO,YAAY,QAAQ,SAAS,QAAQ;AAElD,UAAO;IACL,QAAQ,eAAe,WAAW,MAAKF,SAAU;IACjD;IACD;KAEJ"}
|
|
@@ -40,6 +40,8 @@ var UpdateManySpecialBuilder = class {
|
|
|
40
40
|
* @param pool - Connection pool for acquiring database connections
|
|
41
41
|
* @param provider - SQL provider (sqlite, mysql, postgresql)
|
|
42
42
|
* @param mapper - Optional table name mapper for namespace prefixing
|
|
43
|
+
* @param uowConfig - Optional UOW configuration
|
|
44
|
+
* @param schemaNamespaceMap - Optional WeakMap for schema-to-namespace lookups
|
|
43
45
|
* @returns An AbstractQuery instance for performing database operations
|
|
44
46
|
*
|
|
45
47
|
* @example
|
|
@@ -50,9 +52,9 @@ var UpdateManySpecialBuilder = class {
|
|
|
50
52
|
* const uow = queryEngine.createUnitOfWork('myOperation');
|
|
51
53
|
* ```
|
|
52
54
|
*/
|
|
53
|
-
function fromDrizzle(schema, pool, provider, mapper, uowConfig) {
|
|
55
|
+
function fromDrizzle(schema, pool, provider, mapper, uowConfig, schemaNamespaceMap) {
|
|
54
56
|
function createUOW(opts) {
|
|
55
|
-
const uowCompiler = createDrizzleUOWCompiler(
|
|
57
|
+
const uowCompiler = createDrizzleUOWCompiler(pool, provider, mapper);
|
|
56
58
|
const executor = {
|
|
57
59
|
async executeRetrievalPhase(retrievalBatch) {
|
|
58
60
|
if (opts.config?.dryRun) return retrievalBatch.map(() => ({
|
|
@@ -81,15 +83,15 @@ function fromDrizzle(schema, pool, provider, mapper, uowConfig) {
|
|
|
81
83
|
}
|
|
82
84
|
}
|
|
83
85
|
};
|
|
84
|
-
const decoder = createDrizzleUOWDecoder(
|
|
86
|
+
const decoder = createDrizzleUOWDecoder(provider);
|
|
85
87
|
const { onQuery,...restUowConfig } = opts.config ?? {};
|
|
86
|
-
return new UnitOfWork(
|
|
88
|
+
return new UnitOfWork(uowCompiler, executor, decoder, opts.name, {
|
|
87
89
|
...restUowConfig,
|
|
88
90
|
onQuery: (query) => {
|
|
89
91
|
const actualQuery = query && typeof query === "object" && "query" in query ? query.query : query;
|
|
90
92
|
opts.config?.onQuery?.(actualQuery);
|
|
91
93
|
}
|
|
92
|
-
});
|
|
94
|
+
}, schemaNamespaceMap).forSchema(schema);
|
|
93
95
|
}
|
|
94
96
|
return {
|
|
95
97
|
async find(tableName, builderFn) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drizzle-query.js","names":["#indexName","#condition","#setValues","executor: UOWExecutor<DrizzleCompiledQuery, DrizzleResult>"],"sources":["../../../src/adapters/drizzle/drizzle-query.ts"],"sourcesContent":["import type { AbstractQuery } from \"../../query/query\";\nimport type { AnySchema, AnyTable } from \"../../schema/create\";\nimport type { CompiledMutation, UOWExecutor, ValidIndexName } from \"../../query/unit-of-work\";\nimport { createDrizzleUOWCompiler, type DrizzleCompiledQuery } from \"./drizzle-uow-compiler\";\nimport { executeDrizzleRetrievalPhase, executeDrizzleMutationPhase } from \"./drizzle-uow-executor\";\nimport { UnitOfWork } from \"../../query/unit-of-work\";\nimport { parseDrizzle, type DrizzleResult, type TableNameMapper, type DBType } from \"./shared\";\nimport { createDrizzleUOWDecoder } from \"./drizzle-uow-decoder\";\nimport type { ConnectionPool } from \"../../shared/connection-pool\";\nimport type { TableToUpdateValues } from \"../../query/query\";\nimport type { CursorResult } from \"../../query/cursor\";\n\n/**\n * Configuration options for creating a Drizzle Unit of Work\n */\nexport interface DrizzleUOWConfig {\n /**\n * Optional callback to receive compiled SQL queries for logging/debugging\n * This callback is invoked for each query as it's compiled\n */\n onQuery?: (query: DrizzleCompiledQuery) => void;\n /**\n * If true, the query will not be executed and the query will be returned. Not respected for UOWs\n * since those have to be manually executed.\n */\n dryRun?: boolean;\n}\n\n/**\n * Special builder for updateMany operations that captures configuration\n */\nclass UpdateManySpecialBuilder<TTable extends AnyTable> {\n #indexName?: string;\n #condition?: unknown;\n #setValues?: TableToUpdateValues<TTable>;\n\n whereIndex<TIndexName extends ValidIndexName<TTable>>(\n indexName: TIndexName,\n condition?: unknown,\n ): this {\n this.#indexName = indexName as string;\n this.#condition = condition;\n return this;\n }\n\n set(values: TableToUpdateValues<TTable>): this {\n this.#setValues = values;\n return this;\n }\n\n getConfig() {\n return {\n indexName: this.#indexName,\n condition: this.#condition,\n setValues: this.#setValues,\n };\n }\n}\n\n/**\n * Creates a Drizzle-based query engine for the given schema.\n *\n * This is the main entry point for creating a database query interface using Drizzle.\n * It uses a compiler-based architecture where queries are compiled to SQL and then executed,\n * enabling features like SQL snapshot testing.\n *\n * @param schema - The database schema definition\n * @param pool - Connection pool for acquiring database connections\n * @param provider - SQL provider (sqlite, mysql, postgresql)\n * @param mapper - Optional table name mapper for namespace prefixing\n * @returns An AbstractQuery instance for performing database operations\n *\n * @example\n * ```ts\n * const pool = createSimpleConnectionPool(drizzle);\n * const queryEngine = fromDrizzle(mySchema, pool, 'postgresql');\n *\n * const uow = queryEngine.createUnitOfWork('myOperation');\n * ```\n */\nexport function fromDrizzle<T extends AnySchema>(\n schema: T,\n pool: ConnectionPool<DBType>,\n provider: \"sqlite\" | \"mysql\" | \"postgresql\",\n mapper?: TableNameMapper,\n uowConfig?: DrizzleUOWConfig,\n): AbstractQuery<T, DrizzleUOWConfig> {\n function createUOW(opts: { name?: string; config?: DrizzleUOWConfig }) {\n const uowCompiler = createDrizzleUOWCompiler(schema, pool, provider, mapper);\n\n const executor: UOWExecutor<DrizzleCompiledQuery, DrizzleResult> = {\n async executeRetrievalPhase(retrievalBatch: DrizzleCompiledQuery[]) {\n // In dryRun mode, skip execution and return empty results\n if (opts.config?.dryRun) {\n return retrievalBatch.map(() => ({\n rows: [],\n affectedRows: 0,\n }));\n }\n\n const conn = await pool.connect();\n try {\n const db = parseDrizzle(conn.db)[0];\n return await executeDrizzleRetrievalPhase(db, retrievalBatch, provider);\n } finally {\n await conn.release();\n }\n },\n async executeMutationPhase(mutationBatch: CompiledMutation<DrizzleCompiledQuery>[]) {\n // In dryRun mode, skip execution and return success with mock internal IDs\n if (opts.config?.dryRun) {\n return {\n success: true,\n createdInternalIds: mutationBatch.map(() => null),\n };\n }\n\n const conn = await pool.connect();\n try {\n const db = parseDrizzle(conn.db)[0];\n return await executeDrizzleMutationPhase(db, mutationBatch, provider);\n } finally {\n await conn.release();\n }\n },\n };\n\n const decoder = createDrizzleUOWDecoder(schema, provider);\n\n const { onQuery, ...restUowConfig } = opts.config ?? {};\n\n return new UnitOfWork(schema, uowCompiler, executor, decoder, opts.name, {\n ...restUowConfig,\n onQuery: (query) => {\n // Handle both CompiledQuery and CompiledMutation structures\n // Retrieval operations return DrizzleCompiledQuery directly: { sql, params }\n // Mutation operations return CompiledMutation: { query: DrizzleCompiledQuery, expectedAffectedRows }\n const actualQuery =\n query && typeof query === \"object\" && \"query\" in query\n ? (query as CompiledMutation<DrizzleCompiledQuery>).query\n : (query as DrizzleCompiledQuery);\n\n opts.config?.onQuery?.(actualQuery);\n },\n });\n }\n\n return {\n async find(tableName, builderFn) {\n // Safe: builderFn returns a FindBuilder (or void), which matches UnitOfWork signature\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const uow = createUOW({ config: uowConfig }).find(tableName, builderFn as any);\n const [result] = await uow.executeRetrieve();\n return result;\n },\n\n async findWithCursor(tableName, builderFn) {\n // Safe: builderFn returns a FindBuilder, which matches UnitOfWork signature\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const uow = createUOW({ config: uowConfig }).findWithCursor(tableName, builderFn as any);\n const [result] = await uow.executeRetrieve();\n return result as CursorResult<unknown>;\n },\n\n async findFirst(tableName, builderFn) {\n const uow = createUOW({ config: uowConfig });\n if (builderFn) {\n uow.find(tableName, (b) => {\n builderFn(b);\n return b.pageSize(1);\n });\n } else {\n uow.find(tableName, (b) => b.whereIndex(\"primary\").pageSize(1));\n }\n // executeRetrieve runs an array of `find` operation results, which each return an array of rows\n const [result]: unknown[][] = await uow.executeRetrieve();\n return result?.[0] ?? null;\n },\n\n async create(tableName, values) {\n const uow = createUOW({ config: uowConfig });\n uow.create(tableName, values);\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to create record\");\n }\n\n const createdIds = uow.getCreatedIds();\n const createdId = createdIds[0];\n if (!createdId) {\n throw new Error(\"Failed to get created ID\");\n }\n return createdId;\n },\n\n async createMany(tableName, valuesArray) {\n const uow = createUOW({ config: uowConfig });\n for (const values of valuesArray) {\n uow.create(tableName, values);\n }\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to create records\");\n }\n\n return uow.getCreatedIds();\n },\n\n async update(tableName, id, builderFn) {\n const uow = createUOW({ config: uowConfig });\n uow.update(tableName, id, builderFn);\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to update record (version conflict or record not found)\");\n }\n },\n\n async updateMany(tableName, builderFn) {\n const table = schema.tables[tableName];\n if (!table) {\n throw new Error(`Table ${tableName} not found in schema`);\n }\n\n const specialBuilder = new UpdateManySpecialBuilder<typeof table>();\n builderFn(specialBuilder);\n\n const { indexName, condition, setValues } = specialBuilder.getConfig();\n\n if (!indexName) {\n throw new Error(\"whereIndex() must be called in updateMany\");\n }\n if (!setValues) {\n throw new Error(\"set() must be called in updateMany\");\n }\n\n const findUow = createUOW({ config: uowConfig });\n findUow.find(tableName, (b) => {\n if (condition) {\n // Safe: condition is captured from whereIndex call with proper typing\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return b.whereIndex(indexName as ValidIndexName<typeof table>, condition as any);\n }\n return b.whereIndex(indexName as ValidIndexName<typeof table>);\n });\n const [records]: unknown[][] = await findUow.executeRetrieve();\n\n if (!records || records.length === 0) {\n return;\n }\n\n const updateUow = createUOW({ config: uowConfig });\n for (const record of records as Array<{ id: unknown }>) {\n updateUow.update(tableName, record.id as string, (b) => b.set(setValues));\n }\n const { success } = await updateUow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to update records (version conflict)\");\n }\n },\n\n async delete(tableName, id, builderFn) {\n const uow = createUOW({ config: uowConfig });\n uow.delete(tableName, id, builderFn);\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to delete record (version conflict or record not found)\");\n }\n },\n\n async deleteMany(tableName, builderFn) {\n const findUow = createUOW({ config: uowConfig });\n findUow.find(tableName, builderFn);\n const [records]: unknown[][] = await findUow.executeRetrieve();\n\n if (!records || records.length === 0) {\n return;\n }\n\n const deleteUow = createUOW({ config: uowConfig });\n for (const record of records as Array<{ id: unknown }>) {\n deleteUow.delete(tableName, record.id as string);\n }\n const { success } = await deleteUow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to delete records (version conflict)\");\n }\n },\n\n createUnitOfWork(name, nestedUowConfig) {\n return createUOW({\n name,\n config: {\n ...uowConfig,\n ...nestedUowConfig,\n },\n });\n },\n } as AbstractQuery<T, DrizzleUOWConfig>;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"drizzle-query.js","names":["#indexName","#condition","#setValues","executor: UOWExecutor<DrizzleCompiledQuery, DrizzleResult>"],"sources":["../../../src/adapters/drizzle/drizzle-query.ts"],"sourcesContent":["import type { AbstractQuery } from \"../../query/query\";\nimport type { AnySchema, AnyTable } from \"../../schema/create\";\nimport type { CompiledMutation, UOWExecutor, ValidIndexName } from \"../../query/unit-of-work\";\nimport { createDrizzleUOWCompiler, type DrizzleCompiledQuery } from \"./drizzle-uow-compiler\";\nimport { executeDrizzleRetrievalPhase, executeDrizzleMutationPhase } from \"./drizzle-uow-executor\";\nimport { UnitOfWork } from \"../../query/unit-of-work\";\nimport { parseDrizzle, type DrizzleResult, type TableNameMapper, type DBType } from \"./shared\";\nimport { createDrizzleUOWDecoder } from \"./drizzle-uow-decoder\";\nimport type { ConnectionPool } from \"../../shared/connection-pool\";\nimport type { TableToUpdateValues } from \"../../query/query\";\nimport type { CursorResult } from \"../../query/cursor\";\n\n/**\n * Configuration options for creating a Drizzle Unit of Work\n */\nexport interface DrizzleUOWConfig {\n /**\n * Optional callback to receive compiled SQL queries for logging/debugging\n * This callback is invoked for each query as it's compiled\n */\n onQuery?: (query: DrizzleCompiledQuery) => void;\n /**\n * If true, the query will not be executed and the query will be returned. Not respected for UOWs\n * since those have to be manually executed.\n */\n dryRun?: boolean;\n}\n\n/**\n * Special builder for updateMany operations that captures configuration\n */\nclass UpdateManySpecialBuilder<TTable extends AnyTable> {\n #indexName?: string;\n #condition?: unknown;\n #setValues?: TableToUpdateValues<TTable>;\n\n whereIndex<TIndexName extends ValidIndexName<TTable>>(\n indexName: TIndexName,\n condition?: unknown,\n ): this {\n this.#indexName = indexName as string;\n this.#condition = condition;\n return this;\n }\n\n set(values: TableToUpdateValues<TTable>): this {\n this.#setValues = values;\n return this;\n }\n\n getConfig() {\n return {\n indexName: this.#indexName,\n condition: this.#condition,\n setValues: this.#setValues,\n };\n }\n}\n\n/**\n * Creates a Drizzle-based query engine for the given schema.\n *\n * This is the main entry point for creating a database query interface using Drizzle.\n * It uses a compiler-based architecture where queries are compiled to SQL and then executed,\n * enabling features like SQL snapshot testing.\n *\n * @param schema - The database schema definition\n * @param pool - Connection pool for acquiring database connections\n * @param provider - SQL provider (sqlite, mysql, postgresql)\n * @param mapper - Optional table name mapper for namespace prefixing\n * @param uowConfig - Optional UOW configuration\n * @param schemaNamespaceMap - Optional WeakMap for schema-to-namespace lookups\n * @returns An AbstractQuery instance for performing database operations\n *\n * @example\n * ```ts\n * const pool = createSimpleConnectionPool(drizzle);\n * const queryEngine = fromDrizzle(mySchema, pool, 'postgresql');\n *\n * const uow = queryEngine.createUnitOfWork('myOperation');\n * ```\n */\nexport function fromDrizzle<T extends AnySchema>(\n schema: T,\n pool: ConnectionPool<DBType>,\n provider: \"sqlite\" | \"mysql\" | \"postgresql\",\n mapper?: TableNameMapper,\n uowConfig?: DrizzleUOWConfig,\n schemaNamespaceMap?: WeakMap<AnySchema, string>,\n): AbstractQuery<T, DrizzleUOWConfig> {\n function createUOW(opts: { name?: string; config?: DrizzleUOWConfig }) {\n const uowCompiler = createDrizzleUOWCompiler(pool, provider, mapper);\n\n const executor: UOWExecutor<DrizzleCompiledQuery, DrizzleResult> = {\n async executeRetrievalPhase(retrievalBatch: DrizzleCompiledQuery[]) {\n // In dryRun mode, skip execution and return empty results\n if (opts.config?.dryRun) {\n return retrievalBatch.map(() => ({\n rows: [],\n affectedRows: 0,\n }));\n }\n\n const conn = await pool.connect();\n try {\n const db = parseDrizzle(conn.db)[0];\n return await executeDrizzleRetrievalPhase(db, retrievalBatch, provider);\n } finally {\n await conn.release();\n }\n },\n async executeMutationPhase(mutationBatch: CompiledMutation<DrizzleCompiledQuery>[]) {\n // In dryRun mode, skip execution and return success with mock internal IDs\n if (opts.config?.dryRun) {\n return {\n success: true,\n createdInternalIds: mutationBatch.map(() => null),\n };\n }\n\n const conn = await pool.connect();\n try {\n const db = parseDrizzle(conn.db)[0];\n return await executeDrizzleMutationPhase(db, mutationBatch, provider);\n } finally {\n await conn.release();\n }\n },\n };\n\n const decoder = createDrizzleUOWDecoder(provider);\n\n const { onQuery, ...restUowConfig } = opts.config ?? {};\n\n return new UnitOfWork(\n uowCompiler,\n executor,\n decoder,\n opts.name,\n {\n ...restUowConfig,\n onQuery: (query) => {\n // Handle both CompiledQuery and CompiledMutation structures\n // Retrieval operations return DrizzleCompiledQuery directly: { sql, params }\n // Mutation operations return CompiledMutation: { query: DrizzleCompiledQuery, expectedAffectedRows }\n const actualQuery =\n query && typeof query === \"object\" && \"query\" in query\n ? (query as CompiledMutation<DrizzleCompiledQuery>).query\n : (query as DrizzleCompiledQuery);\n\n opts.config?.onQuery?.(actualQuery);\n },\n },\n schemaNamespaceMap,\n ).forSchema(schema);\n }\n\n return {\n async find(tableName, builderFn) {\n // Safe: builderFn returns a FindBuilder (or void), which matches UnitOfWork signature\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const uow = createUOW({ config: uowConfig }).find(tableName, builderFn as any);\n const [result] = await uow.executeRetrieve();\n return result;\n },\n\n async findWithCursor(tableName, builderFn) {\n // Safe: builderFn returns a FindBuilder, which matches UnitOfWork signature\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const uow = createUOW({ config: uowConfig }).findWithCursor(tableName, builderFn as any);\n const [result] = await uow.executeRetrieve();\n return result as CursorResult<unknown>;\n },\n\n async findFirst(tableName, builderFn) {\n const uow = createUOW({ config: uowConfig });\n if (builderFn) {\n uow.find(tableName, (b) => {\n builderFn(b);\n return b.pageSize(1);\n });\n } else {\n uow.find(tableName, (b) => b.whereIndex(\"primary\").pageSize(1));\n }\n // executeRetrieve runs an array of `find` operation results, which each return an array of rows\n const [result]: unknown[][] = await uow.executeRetrieve();\n return result?.[0] ?? null;\n },\n\n async create(tableName, values) {\n const uow = createUOW({ config: uowConfig });\n uow.create(tableName, values);\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to create record\");\n }\n\n const createdIds = uow.getCreatedIds();\n const createdId = createdIds[0];\n if (!createdId) {\n throw new Error(\"Failed to get created ID\");\n }\n return createdId;\n },\n\n async createMany(tableName, valuesArray) {\n const uow = createUOW({ config: uowConfig });\n for (const values of valuesArray) {\n uow.create(tableName, values);\n }\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to create records\");\n }\n\n return uow.getCreatedIds();\n },\n\n async update(tableName, id, builderFn) {\n const uow = createUOW({ config: uowConfig });\n uow.update(tableName, id, builderFn);\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to update record (version conflict or record not found)\");\n }\n },\n\n async updateMany(tableName, builderFn) {\n const table = schema.tables[tableName];\n if (!table) {\n throw new Error(`Table ${tableName} not found in schema`);\n }\n\n const specialBuilder = new UpdateManySpecialBuilder<typeof table>();\n builderFn(specialBuilder);\n\n const { indexName, condition, setValues } = specialBuilder.getConfig();\n\n if (!indexName) {\n throw new Error(\"whereIndex() must be called in updateMany\");\n }\n if (!setValues) {\n throw new Error(\"set() must be called in updateMany\");\n }\n\n const findUow = createUOW({ config: uowConfig });\n findUow.find(tableName, (b) => {\n if (condition) {\n // Safe: condition is captured from whereIndex call with proper typing\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return b.whereIndex(indexName as ValidIndexName<typeof table>, condition as any);\n }\n return b.whereIndex(indexName as ValidIndexName<typeof table>);\n });\n const [records]: unknown[][] = await findUow.executeRetrieve();\n\n if (!records || records.length === 0) {\n return;\n }\n\n const updateUow = createUOW({ config: uowConfig });\n for (const record of records as Array<{ id: unknown }>) {\n updateUow.update(tableName, record.id as string, (b) => b.set(setValues));\n }\n const { success } = await updateUow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to update records (version conflict)\");\n }\n },\n\n async delete(tableName, id, builderFn) {\n const uow = createUOW({ config: uowConfig });\n uow.delete(tableName, id, builderFn);\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to delete record (version conflict or record not found)\");\n }\n },\n\n async deleteMany(tableName, builderFn) {\n const findUow = createUOW({ config: uowConfig });\n findUow.find(tableName, builderFn);\n const [records]: unknown[][] = await findUow.executeRetrieve();\n\n if (!records || records.length === 0) {\n return;\n }\n\n const deleteUow = createUOW({ config: uowConfig });\n for (const record of records as Array<{ id: unknown }>) {\n deleteUow.delete(tableName, record.id as string);\n }\n const { success } = await deleteUow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to delete records (version conflict)\");\n }\n },\n\n createUnitOfWork(name, nestedUowConfig) {\n return createUOW({\n name,\n config: {\n ...uowConfig,\n ...nestedUowConfig,\n },\n });\n },\n } as AbstractQuery<T, DrizzleUOWConfig>;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drizzle-uow-compiler.d.ts","names":[],"sources":["../../../src/adapters/drizzle/drizzle-uow-compiler.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"drizzle-uow-compiler.d.ts","names":[],"sources":["../../../src/adapters/drizzle/drizzle-uow-compiler.ts"],"sourcesContent":[],"mappings":";;;AAyBY,KAAA,oBAAA,GAAoB"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Column } from "../../schema/create.js";
|
|
2
|
+
import { buildCondition } from "../../query/condition-builder.js";
|
|
2
3
|
import { serialize } from "../../schema/serialize.js";
|
|
3
4
|
import { decodeCursor, serializeCursorValues } from "../../query/cursor.js";
|
|
4
|
-
import {
|
|
5
|
-
import { parseDrizzle } from "./shared.js";
|
|
5
|
+
import { createTableNameMapper, parseDrizzle } from "./shared.js";
|
|
6
6
|
import { ReferenceSubquery, encodeValues } from "../../query/result-transform.js";
|
|
7
7
|
import { getOrderedJoinColumns } from "./join-column-utils.js";
|
|
8
8
|
import * as Drizzle from "drizzle-orm";
|
|
@@ -14,20 +14,28 @@ import * as Drizzle from "drizzle-orm";
|
|
|
14
14
|
* This compiler translates UOW operations into Drizzle query functions
|
|
15
15
|
* that can be executed as a batch/transaction.
|
|
16
16
|
*
|
|
17
|
-
* @param schema - The database schema
|
|
18
17
|
* @param pool - Connection pool for acquiring database connections
|
|
19
18
|
* @param provider - SQL provider (sqlite, mysql, postgresql)
|
|
20
|
-
* @param mapper - Optional table name mapper for namespace prefixing
|
|
19
|
+
* @param mapper - Optional table name mapper for namespace prefixing (fallback for operations without explicit namespace)
|
|
21
20
|
* @returns A UOWCompiler instance for Drizzle
|
|
22
21
|
*/
|
|
23
|
-
function createDrizzleUOWCompiler(
|
|
22
|
+
function createDrizzleUOWCompiler(pool, provider, mapper) {
|
|
24
23
|
const [db, drizzleTables] = parseDrizzle(pool.getDatabaseSync());
|
|
25
24
|
/**
|
|
25
|
+
* Get the mapper for a specific operation
|
|
26
|
+
* Uses operation's namespace if provided, otherwise falls back to the default mapper
|
|
27
|
+
*/
|
|
28
|
+
function getMapperForOperation(namespace) {
|
|
29
|
+
if (namespace) return createTableNameMapper(namespace);
|
|
30
|
+
return mapper;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
26
33
|
* Convert a Fragno table to a Drizzle table
|
|
27
34
|
* @throws Error if table is not found in Drizzle schema
|
|
28
35
|
*/
|
|
29
|
-
function toDrizzleTable(table) {
|
|
30
|
-
const
|
|
36
|
+
function toDrizzleTable(table, namespace) {
|
|
37
|
+
const opMapper = getMapperForOperation(namespace);
|
|
38
|
+
const physicalTableName = opMapper ? opMapper.toPhysical(table.ormName) : table.ormName;
|
|
31
39
|
const out = drizzleTables[physicalTableName];
|
|
32
40
|
if (out) return out;
|
|
33
41
|
throw new Error(`[Drizzle] Unknown table name ${physicalTableName} (logical: ${table.ormName}), is it included in your Drizzle schema?`);
|
|
@@ -36,22 +44,22 @@ function createDrizzleUOWCompiler(schema, pool, provider, mapper) {
|
|
|
36
44
|
* Convert a Fragno column to a Drizzle column
|
|
37
45
|
* @throws Error if column is not found in Drizzle table
|
|
38
46
|
*/
|
|
39
|
-
function toDrizzleColumn(col) {
|
|
47
|
+
function toDrizzleColumn(schema, namespace, col) {
|
|
40
48
|
const fragnoTable = schema.tables[col.tableName];
|
|
41
49
|
if (!fragnoTable) throw new Error(`[Drizzle] Unknown table ${col.tableName} for column ${col.ormName}.`);
|
|
42
|
-
const out = toDrizzleTable(fragnoTable)[col.ormName];
|
|
50
|
+
const out = toDrizzleTable(fragnoTable, namespace)[col.ormName];
|
|
43
51
|
if (out) return out;
|
|
44
52
|
throw new Error(`[Drizzle] Unknown column name ${col.ormName} in ${fragnoTable.ormName}.`);
|
|
45
53
|
}
|
|
46
54
|
/**
|
|
47
55
|
* Build a WHERE clause from a condition using Drizzle's query builder
|
|
48
56
|
*/
|
|
49
|
-
function buildWhere(condition) {
|
|
57
|
+
function buildWhere(schema, namespace, condition) {
|
|
50
58
|
if (condition.type === "compare") {
|
|
51
|
-
const left = toDrizzleColumn(condition.a);
|
|
59
|
+
const left = toDrizzleColumn(schema, namespace, condition.a);
|
|
52
60
|
const op = condition.operator;
|
|
53
61
|
let right = condition.b;
|
|
54
|
-
if (right instanceof Column) right = toDrizzleColumn(right);
|
|
62
|
+
if (right instanceof Column) right = toDrizzleColumn(schema, namespace, right);
|
|
55
63
|
else if (condition.a.role === "reference" && typeof right === "string") {
|
|
56
64
|
const table = Object.values(schema.tables).find((t) => Object.values(t.columns).includes(condition.a));
|
|
57
65
|
if (table) {
|
|
@@ -97,13 +105,13 @@ function createDrizzleUOWCompiler(schema, pool, provider, mapper) {
|
|
|
97
105
|
default: throw new Error(`Unsupported operator: ${op}`);
|
|
98
106
|
}
|
|
99
107
|
}
|
|
100
|
-
if (condition.type === "and") return Drizzle.and(...condition.items.map((item) => buildWhere(item)));
|
|
108
|
+
if (condition.type === "and") return Drizzle.and(...condition.items.map((item) => buildWhere(schema, namespace, item)));
|
|
101
109
|
if (condition.type === "not") {
|
|
102
|
-
const result = buildWhere(condition.item);
|
|
110
|
+
const result = buildWhere(schema, namespace, condition.item);
|
|
103
111
|
if (!result) return;
|
|
104
112
|
return Drizzle.not(result);
|
|
105
113
|
}
|
|
106
|
-
return Drizzle.or(...condition.items.map((item) => buildWhere(item)));
|
|
114
|
+
return Drizzle.or(...condition.items.map((item) => buildWhere(schema, namespace, item)));
|
|
107
115
|
}
|
|
108
116
|
/**
|
|
109
117
|
* Process reference subqueries in encoded values, converting them to Drizzle SQL subqueries
|
|
@@ -124,7 +132,7 @@ function createDrizzleUOWCompiler(schema, pool, provider, mapper) {
|
|
|
124
132
|
* Get table from schema by name
|
|
125
133
|
* @throws Error if table is not found in schema
|
|
126
134
|
*/
|
|
127
|
-
function getTable(name) {
|
|
135
|
+
function getTable(schema, name) {
|
|
128
136
|
const table = schema.tables[name];
|
|
129
137
|
if (!table) throw new Error(`Invalid table name ${name}.`);
|
|
130
138
|
return table;
|
|
@@ -142,7 +150,7 @@ function createDrizzleUOWCompiler(schema, pool, provider, mapper) {
|
|
|
142
150
|
/**
|
|
143
151
|
* Process joins recursively to support nested joins with orderBy and limit
|
|
144
152
|
*/
|
|
145
|
-
function processJoins(joins) {
|
|
153
|
+
function processJoins(schema, namespace, joins) {
|
|
146
154
|
const result = {};
|
|
147
155
|
for (const join of joins) {
|
|
148
156
|
const { options, relation } = join;
|
|
@@ -154,33 +162,34 @@ function createDrizzleUOWCompiler(schema, pool, provider, mapper) {
|
|
|
154
162
|
for (const colName of orderedColumns) joinColumns[colName] = true;
|
|
155
163
|
let joinOrderBy;
|
|
156
164
|
if (options.orderBy && options.orderBy.length > 0) joinOrderBy = options.orderBy.map(([col, direction]) => {
|
|
157
|
-
const drizzleCol = toDrizzleColumn(col);
|
|
165
|
+
const drizzleCol = toDrizzleColumn(schema, namespace, col);
|
|
158
166
|
return direction === "asc" ? Drizzle.asc(drizzleCol) : Drizzle.desc(drizzleCol);
|
|
159
167
|
});
|
|
160
168
|
let joinWhere;
|
|
161
|
-
if (options.where) joinWhere = buildWhere(options.where);
|
|
169
|
+
if (options.where) joinWhere = buildWhere(schema, namespace, options.where);
|
|
162
170
|
const joinConfig = {
|
|
163
171
|
columns: joinColumns,
|
|
164
172
|
orderBy: joinOrderBy,
|
|
165
173
|
limit: options.limit,
|
|
166
174
|
where: joinWhere
|
|
167
175
|
};
|
|
168
|
-
if (options.join && options.join.length > 0) joinConfig.with = processJoins(options.join);
|
|
176
|
+
if (options.join && options.join.length > 0) joinConfig.with = processJoins(schema, namespace, options.join);
|
|
169
177
|
result[joinName] = joinConfig;
|
|
170
178
|
}
|
|
171
179
|
return result;
|
|
172
180
|
}
|
|
173
181
|
return {
|
|
174
182
|
compileRetrievalOperation(op) {
|
|
183
|
+
const schema = op.schema;
|
|
175
184
|
switch (op.type) {
|
|
176
185
|
case "count": {
|
|
177
186
|
let whereClause;
|
|
178
187
|
if (op.options.where) {
|
|
179
188
|
const condition = buildCondition(op.table.columns, op.options.where);
|
|
180
189
|
if (condition === false) return null;
|
|
181
|
-
if (condition !== true) whereClause = buildWhere(condition);
|
|
190
|
+
if (condition !== true) whereClause = buildWhere(schema, op.namespace, condition);
|
|
182
191
|
}
|
|
183
|
-
const drizzleTable = toDrizzleTable(op.table);
|
|
192
|
+
const drizzleTable = toDrizzleTable(op.table, op.namespace);
|
|
184
193
|
const query = db.select({ count: Drizzle.count() }).from(drizzleTable);
|
|
185
194
|
return whereClause ? query.where(whereClause).toSQL() : query.toSQL();
|
|
186
195
|
}
|
|
@@ -197,7 +206,7 @@ function createDrizzleUOWCompiler(schema, pool, provider, mapper) {
|
|
|
197
206
|
}
|
|
198
207
|
let orderBy;
|
|
199
208
|
if (indexColumns.length > 0) orderBy = indexColumns.map((col) => {
|
|
200
|
-
const drizzleCol = toDrizzleColumn(col);
|
|
209
|
+
const drizzleCol = toDrizzleColumn(schema, op.namespace, col);
|
|
201
210
|
return orderDirection === "asc" ? Drizzle.asc(drizzleCol) : Drizzle.desc(drizzleCol);
|
|
202
211
|
});
|
|
203
212
|
const columns = {};
|
|
@@ -212,7 +221,7 @@ function createDrizzleUOWCompiler(schema, pool, provider, mapper) {
|
|
|
212
221
|
const condition = buildCondition(op.table.columns, findOptions.where);
|
|
213
222
|
if (condition === false) return null;
|
|
214
223
|
if (condition !== true) {
|
|
215
|
-
const clause = buildWhere(condition);
|
|
224
|
+
const clause = buildWhere(schema, op.namespace, condition);
|
|
216
225
|
if (clause) whereClauses.push(clause);
|
|
217
226
|
}
|
|
218
227
|
}
|
|
@@ -222,11 +231,11 @@ function createDrizzleUOWCompiler(schema, pool, provider, mapper) {
|
|
|
222
231
|
const isAfter = !!after;
|
|
223
232
|
const useGreaterThan = isAfter && orderDirection === "asc" || !isAfter && orderDirection === "desc";
|
|
224
233
|
if (indexColumns.length === 1) {
|
|
225
|
-
const col = toDrizzleColumn(indexColumns[0]);
|
|
234
|
+
const col = toDrizzleColumn(schema, op.namespace, indexColumns[0]);
|
|
226
235
|
const val = serializedValues[indexColumns[0].ormName];
|
|
227
236
|
whereClauses.push(useGreaterThan ? Drizzle.gt(col, val) : Drizzle.lt(col, val));
|
|
228
237
|
} else {
|
|
229
|
-
const drizzleCols = indexColumns.map((c) => toDrizzleColumn(c));
|
|
238
|
+
const drizzleCols = indexColumns.map((c) => toDrizzleColumn(schema, op.namespace, c));
|
|
230
239
|
const vals = indexColumns.map((c) => serializedValues[c.ormName]);
|
|
231
240
|
const operator = useGreaterThan ? ">" : "<";
|
|
232
241
|
const colsSQL = Drizzle.sql.join(drizzleCols, Drizzle.sql.raw(", "));
|
|
@@ -234,62 +243,85 @@ function createDrizzleUOWCompiler(schema, pool, provider, mapper) {
|
|
|
234
243
|
whereClauses.push(Drizzle.sql`(${colsSQL}) ${Drizzle.sql.raw(operator)} (${valsSQL})`);
|
|
235
244
|
}
|
|
236
245
|
}
|
|
246
|
+
const whereClause = whereClauses.length > 0 ? Drizzle.and(...whereClauses) : void 0;
|
|
237
247
|
const queryConfig = {
|
|
238
248
|
columns,
|
|
239
|
-
limit: pageSize,
|
|
240
|
-
where:
|
|
249
|
+
limit: pageSize && op.withCursor ? pageSize + 1 : pageSize,
|
|
250
|
+
where: whereClause,
|
|
241
251
|
orderBy,
|
|
242
252
|
with: {}
|
|
243
253
|
};
|
|
244
|
-
if (joins) queryConfig.with = processJoins(joins);
|
|
245
|
-
const
|
|
246
|
-
|
|
254
|
+
if (joins) queryConfig.with = processJoins(schema, op.namespace, joins);
|
|
255
|
+
const opMapper = getMapperForOperation(op.namespace);
|
|
256
|
+
const physicalTableName = opMapper ? opMapper.toPhysical(op.table.ormName) : op.table.ormName;
|
|
257
|
+
const tableQuery = db.query[physicalTableName];
|
|
258
|
+
if (!tableQuery) throw new Error(`[Drizzle] Table ${op.table.ormName} (physical: ${physicalTableName}) not found in db.query. Available tables: ${Object.keys(db.query).join(", ")}`);
|
|
259
|
+
return tableQuery.findMany(queryConfig).toSQL();
|
|
247
260
|
}
|
|
248
261
|
}
|
|
249
262
|
},
|
|
250
263
|
compileMutationOperation(op) {
|
|
264
|
+
const schema = op.schema;
|
|
251
265
|
switch (op.type) {
|
|
252
266
|
case "create": {
|
|
253
|
-
const table = getTable(op.table);
|
|
254
|
-
const drizzleTable = toDrizzleTable(table);
|
|
255
|
-
const values = processReferenceSubqueries(encodeValues(op.values, table, true, provider));
|
|
267
|
+
const table = getTable(schema, op.table);
|
|
268
|
+
const drizzleTable = toDrizzleTable(table, op.namespace);
|
|
269
|
+
const values = processReferenceSubqueries(encodeValues(op.values, table, true, provider, true));
|
|
256
270
|
return {
|
|
257
271
|
query: db.insert(drizzleTable).values(values).toSQL(),
|
|
258
|
-
expectedAffectedRows: null
|
|
272
|
+
expectedAffectedRows: null,
|
|
273
|
+
expectedReturnedRows: null
|
|
259
274
|
};
|
|
260
275
|
}
|
|
261
276
|
case "update": {
|
|
262
|
-
const table = getTable(op.table);
|
|
277
|
+
const table = getTable(schema, op.table);
|
|
263
278
|
const idColumn = table.getIdColumn();
|
|
264
279
|
const versionColumn = table.getVersionColumn();
|
|
265
|
-
const drizzleTable = toDrizzleTable(table);
|
|
280
|
+
const drizzleTable = toDrizzleTable(table, op.namespace);
|
|
266
281
|
const externalId = typeof op.id === "string" ? op.id : op.id.externalId;
|
|
267
282
|
const versionToCheck = getVersionToCheck(op.id, op.checkVersion);
|
|
268
283
|
const condition = versionToCheck !== void 0 ? buildCondition(table.columns, (eb) => eb.and(eb(idColumn.ormName, "=", externalId), eb(versionColumn.ormName, "=", versionToCheck))) : buildCondition(table.columns, (eb) => eb(idColumn.ormName, "=", externalId));
|
|
269
284
|
if (condition === false) return null;
|
|
270
|
-
const whereClause = condition === true ? void 0 : buildWhere(condition);
|
|
271
|
-
const setValues = processReferenceSubqueries(encodeValues(op.set, table, false, provider));
|
|
285
|
+
const whereClause = condition === true ? void 0 : buildWhere(schema, op.namespace, condition);
|
|
286
|
+
const setValues = processReferenceSubqueries(encodeValues(op.set, table, false, provider, true));
|
|
272
287
|
setValues[versionColumn.ormName] = Drizzle.sql.raw(`COALESCE(${versionColumn.ormName}, 0) + 1`);
|
|
273
288
|
return {
|
|
274
289
|
query: db.update(drizzleTable).set(setValues).where(whereClause).toSQL(),
|
|
275
|
-
expectedAffectedRows: op.checkVersion ? 1 : null
|
|
290
|
+
expectedAffectedRows: op.checkVersion ? 1 : null,
|
|
291
|
+
expectedReturnedRows: null
|
|
276
292
|
};
|
|
277
293
|
}
|
|
278
294
|
case "delete": {
|
|
279
|
-
const table = getTable(op.table);
|
|
295
|
+
const table = getTable(schema, op.table);
|
|
280
296
|
const idColumn = table.getIdColumn();
|
|
281
297
|
const versionColumn = table.getVersionColumn();
|
|
282
|
-
const drizzleTable = toDrizzleTable(table);
|
|
298
|
+
const drizzleTable = toDrizzleTable(table, op.namespace);
|
|
283
299
|
if (!op.id) throw new Error(`[Drizzle] Delete operation on table "${op.table}" has undefined id. Make sure you're passing a valid FragnoId or string ID.`);
|
|
284
300
|
const externalId = typeof op.id === "string" ? op.id : op.id.externalId;
|
|
285
301
|
if (!externalId) throw new Error(`[Drizzle] Delete operation on table "${op.table}" has invalid id. The FragnoId object exists but has no externalId. Received: ${JSON.stringify(op.id)}. Make sure the record was properly loaded from the database.`);
|
|
286
302
|
const versionToCheck = getVersionToCheck(op.id, op.checkVersion);
|
|
287
303
|
const condition = versionToCheck !== void 0 ? buildCondition(table.columns, (eb) => eb.and(eb(idColumn.ormName, "=", externalId), eb(versionColumn.ormName, "=", versionToCheck))) : buildCondition(table.columns, (eb) => eb(idColumn.ormName, "=", externalId));
|
|
288
304
|
if (condition === false) return null;
|
|
289
|
-
const whereClause = condition === true ? void 0 : buildWhere(condition);
|
|
305
|
+
const whereClause = condition === true ? void 0 : buildWhere(schema, op.namespace, condition);
|
|
290
306
|
return {
|
|
291
307
|
query: db.delete(drizzleTable).where(whereClause).toSQL(),
|
|
292
|
-
expectedAffectedRows: op.checkVersion ? 1 : null
|
|
308
|
+
expectedAffectedRows: op.checkVersion ? 1 : null,
|
|
309
|
+
expectedReturnedRows: null
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
case "check": {
|
|
313
|
+
const table = getTable(schema, op.table);
|
|
314
|
+
const idColumn = table.getIdColumn();
|
|
315
|
+
const versionColumn = table.getVersionColumn();
|
|
316
|
+
const drizzleTable = toDrizzleTable(table, op.namespace);
|
|
317
|
+
const externalId = op.id.externalId;
|
|
318
|
+
const version = op.id.version;
|
|
319
|
+
const condition = buildCondition(table.columns, (eb) => eb.and(eb(idColumn.ormName, "=", externalId), eb(versionColumn.ormName, "=", version)));
|
|
320
|
+
if (typeof condition === "boolean") throw new Error("Condition is a boolean, but should be a condition object.");
|
|
321
|
+
return {
|
|
322
|
+
query: db.select({ exists: Drizzle.sql`1`.as("exists") }).from(drizzleTable).where(buildWhere(schema, op.namespace, condition)).limit(1).toSQL(),
|
|
323
|
+
expectedAffectedRows: null,
|
|
324
|
+
expectedReturnedRows: 1
|
|
293
325
|
};
|
|
294
326
|
}
|
|
295
327
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drizzle-uow-compiler.js","names":["processed: Record<string, unknown>","result: Record<string, Drizzle.DBQueryConfig<\"many\", boolean>>","joinColumns: Record<string, boolean>","joinOrderBy: Drizzle.SQL[] | undefined","joinWhere: Drizzle.SQL | undefined","joinConfig: Drizzle.DBQueryConfig<\"many\", boolean>","whereClause: Drizzle.SQL | undefined","indexColumns: AnyColumn[]","orderDirection: \"asc\" | \"desc\"","orderBy: Drizzle.SQL[] | undefined","columns: Record<string, boolean>","whereClauses: Drizzle.SQL[]","queryConfig: Drizzle.DBQueryConfig<\"many\", boolean>"],"sources":["../../../src/adapters/drizzle/drizzle-uow-compiler.ts"],"sourcesContent":["import * as Drizzle from \"drizzle-orm\";\nimport type { AnyColumn, AnySchema, AnyTable, FragnoId } from \"../../schema/create\";\nimport { Column } from \"../../schema/create\";\nimport type {\n CompiledMutation,\n MutationOperation,\n RetrievalOperation,\n UOWCompiler,\n} from \"../../query/unit-of-work\";\nimport { buildCondition, type Condition } from \"../../query/condition-builder\";\nimport {\n type ColumnType,\n type TableType,\n type TableNameMapper,\n parseDrizzle,\n type DBType,\n} from \"./shared\";\nimport { encodeValues, ReferenceSubquery } from \"../../query/result-transform\";\nimport { serialize } from \"../../schema/serialize\";\nimport { decodeCursor, serializeCursorValues } from \"../../query/cursor\";\nimport type { CompiledJoin } from \"../../query/orm/orm\";\nimport { getOrderedJoinColumns } from \"./join-column-utils\";\nimport type { ConnectionPool } from \"../../shared/connection-pool\";\n\nexport type DrizzleCompiledQuery = {\n sql: string;\n params: unknown[];\n};\n\n/**\n * Create a Drizzle-specific Unit of Work compiler\n *\n * This compiler translates UOW operations into Drizzle query functions\n * that can be executed as a batch/transaction.\n *\n * @param schema - The database schema\n * @param pool - Connection pool for acquiring database connections\n * @param provider - SQL provider (sqlite, mysql, postgresql)\n * @param mapper - Optional table name mapper for namespace prefixing\n * @returns A UOWCompiler instance for Drizzle\n */\nexport function createDrizzleUOWCompiler<TSchema extends AnySchema>(\n schema: TSchema,\n pool: ConnectionPool<DBType>,\n provider: \"sqlite\" | \"mysql\" | \"postgresql\",\n mapper?: TableNameMapper,\n): UOWCompiler<TSchema, DrizzleCompiledQuery> {\n // Get db synchronously for compilation (doesn't execute, just builds SQL)\n // TODO: We don't even need a Drizzle instance with a db client attached here. `drizzle({ schema })` is enough.\n const dbRaw = pool.getDatabaseSync();\n const [db, drizzleTables] = parseDrizzle(dbRaw);\n\n /**\n * Convert a Fragno table to a Drizzle table\n * @throws Error if table is not found in Drizzle schema\n */\n function toDrizzleTable(table: AnyTable): TableType {\n // Map logical table name to physical table name using the mapper\n const physicalTableName = mapper ? mapper.toPhysical(table.ormName) : table.ormName;\n const out = drizzleTables[physicalTableName];\n if (out) {\n return out;\n }\n\n throw new Error(\n `[Drizzle] Unknown table name ${physicalTableName} (logical: ${table.ormName}), is it included in your Drizzle schema?`,\n );\n }\n\n /**\n * Convert a Fragno column to a Drizzle column\n * @throws Error if column is not found in Drizzle table\n */\n function toDrizzleColumn(col: AnyColumn): ColumnType {\n const fragnoTable = schema.tables[col.tableName];\n if (!fragnoTable) {\n throw new Error(`[Drizzle] Unknown table ${col.tableName} for column ${col.ormName}.`);\n }\n\n const table = toDrizzleTable(fragnoTable);\n const out = table[col.ormName];\n if (out) {\n return out;\n }\n\n throw new Error(`[Drizzle] Unknown column name ${col.ormName} in ${fragnoTable.ormName}.`);\n }\n\n /**\n * Build a WHERE clause from a condition using Drizzle's query builder\n */\n function buildWhere(condition: Condition): Drizzle.SQL | undefined {\n if (condition.type === \"compare\") {\n const left = toDrizzleColumn(condition.a);\n const op = condition.operator;\n let right = condition.b;\n if (right instanceof Column) {\n right = toDrizzleColumn(right);\n } else {\n // Handle string references - convert external ID to internal ID via subquery\n if (condition.a.role === \"reference\" && typeof right === \"string\") {\n // Find the table that contains this column\n const table = Object.values(schema.tables).find((t) =>\n Object.values(t.columns).includes(condition.a),\n );\n if (table) {\n // Find relation that uses this column\n const relation = Object.values(table.relations).find((rel) =>\n rel.on.some(([localCol]) => localCol === condition.a.ormName),\n );\n if (relation) {\n const refTable = relation.table;\n const internalIdCol = refTable.getInternalIdColumn();\n const idCol = refTable.getIdColumn();\n const physicalTableName = mapper\n ? mapper.toPhysical(refTable.ormName)\n : refTable.ormName;\n\n // Build a SQL subquery using Drizzle's sql template\n right = Drizzle.sql`(select ${Drizzle.sql.identifier(internalIdCol.name)} from ${Drizzle.sql.identifier(physicalTableName)} where ${Drizzle.sql.identifier(idCol.name)} = ${right} limit 1)`;\n }\n }\n } else {\n // Serialize non-Column values (e.g., FragnoId -> string, Date -> number for SQLite)\n right = serialize(right, condition.a, provider);\n }\n }\n\n switch (op) {\n case \"=\":\n return Drizzle.eq(left, right);\n case \"!=\":\n return Drizzle.ne(left, right);\n case \">\":\n return Drizzle.gt(left, right);\n case \">=\":\n return Drizzle.gte(left, right);\n case \"<\":\n return Drizzle.lt(left, right);\n case \"<=\":\n return Drizzle.lte(left, right);\n case \"in\": {\n return Drizzle.inArray(left, right as never[]);\n }\n case \"not in\":\n return Drizzle.notInArray(left, right as never[]);\n case \"is\":\n return right === null ? Drizzle.isNull(left) : Drizzle.eq(left, right);\n case \"is not\":\n return right === null ? Drizzle.isNotNull(left) : Drizzle.ne(left, right);\n case \"contains\": {\n right =\n typeof right === \"string\" ? `%${right}%` : Drizzle.sql`concat('%', ${right}, '%')`;\n return Drizzle.like(left, right as string);\n }\n case \"not contains\": {\n right =\n typeof right === \"string\" ? `%${right}%` : Drizzle.sql`concat('%', ${right}, '%')`;\n return Drizzle.notLike(left, right as string);\n }\n case \"ends with\": {\n right = typeof right === \"string\" ? `%${right}` : Drizzle.sql`concat('%', ${right})`;\n return Drizzle.like(left, right as string);\n }\n case \"not ends with\": {\n right = typeof right === \"string\" ? `%${right}` : Drizzle.sql`concat('%', ${right})`;\n return Drizzle.notLike(left, right as string);\n }\n case \"starts with\": {\n right = typeof right === \"string\" ? `${right}%` : Drizzle.sql`concat(${right}, '%')`;\n return Drizzle.like(left, right as string);\n }\n case \"not starts with\": {\n right = typeof right === \"string\" ? `${right}%` : Drizzle.sql`concat(${right}, '%')`;\n return Drizzle.notLike(left, right as string);\n }\n\n default:\n throw new Error(`Unsupported operator: ${op}`);\n }\n }\n\n if (condition.type === \"and\") {\n return Drizzle.and(...condition.items.map((item) => buildWhere(item)));\n }\n\n if (condition.type === \"not\") {\n const result = buildWhere(condition.item);\n if (!result) {\n return;\n }\n\n return Drizzle.not(result);\n }\n\n return Drizzle.or(...condition.items.map((item) => buildWhere(item)));\n }\n\n /**\n * Process reference subqueries in encoded values, converting them to Drizzle SQL subqueries\n */\n function processReferenceSubqueries(values: Record<string, unknown>): Record<string, unknown> {\n const processed: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(values)) {\n if (value instanceof ReferenceSubquery) {\n const refTable = value.referencedTable;\n const externalId = value.externalIdValue;\n const internalIdCol = refTable.getInternalIdColumn();\n const idCol = refTable.getIdColumn();\n\n // Map logical table name to physical table name using the mapper\n const physicalTableName = mapper ? mapper.toPhysical(refTable.ormName) : refTable.ormName;\n\n // Build a SQL subquery using Drizzle's sql template\n // This creates a subquery: (SELECT _internalId FROM table WHERE id = ? LIMIT 1)\n // Safe cast: we're building a SQL subquery that returns a single bigint value\n processed[key] =\n Drizzle.sql`(select ${Drizzle.sql.identifier(internalIdCol.name)} from ${Drizzle.sql.identifier(physicalTableName)} where ${Drizzle.sql.identifier(idCol.name)} = ${externalId} limit 1)`;\n } else {\n processed[key] = value;\n }\n }\n\n return processed;\n }\n\n /**\n * Get table from schema by name\n * @throws Error if table is not found in schema\n */\n function getTable(name: unknown): AnyTable {\n const table = schema.tables[name as string];\n if (!table) {\n throw new Error(`Invalid table name ${name}.`);\n }\n return table;\n }\n\n /**\n * Get the version to check for a given ID and checkVersion flag.\n * @returns The version to check or undefined if no check is required.\n * @throws Error if the ID is a string and checkVersion is true.\n */\n function getVersionToCheck(id: FragnoId | string, checkVersion: boolean): number | undefined {\n if (!checkVersion) {\n return undefined;\n }\n\n if (typeof id === \"string\") {\n throw new Error(\n `Cannot use checkVersion with a string ID. Version checking requires a FragnoId with version information.`,\n );\n }\n\n return id.version;\n }\n\n /**\n * Process joins recursively to support nested joins with orderBy and limit\n */\n function processJoins(\n joins: CompiledJoin[],\n ): Record<string, Drizzle.DBQueryConfig<\"many\", boolean>> {\n const result: Record<string, Drizzle.DBQueryConfig<\"many\", boolean>> = {};\n\n for (const join of joins) {\n const { options, relation } = join;\n\n if (!options) {\n continue;\n }\n\n const targetTable = relation.table;\n const joinName = relation.name;\n\n // Build columns for this join using shared utility\n const selectOption = options.select === undefined ? true : options.select;\n const orderedColumns = getOrderedJoinColumns(targetTable, selectOption);\n const joinColumns: Record<string, boolean> = {};\n for (const colName of orderedColumns) {\n joinColumns[colName] = true;\n }\n\n // Build orderBy for this join\n let joinOrderBy: Drizzle.SQL[] | undefined;\n if (options.orderBy && options.orderBy.length > 0) {\n joinOrderBy = options.orderBy.map(([col, direction]) => {\n const drizzleCol = toDrizzleColumn(col);\n return direction === \"asc\" ? Drizzle.asc(drizzleCol) : Drizzle.desc(drizzleCol);\n });\n }\n\n // Build WHERE clause for this join if provided\n let joinWhere: Drizzle.SQL | undefined;\n if (options.where) {\n joinWhere = buildWhere(options.where);\n }\n\n // Build the join config\n const joinConfig: Drizzle.DBQueryConfig<\"many\", boolean> = {\n columns: joinColumns,\n orderBy: joinOrderBy,\n limit: options.limit,\n where: joinWhere,\n };\n\n // Recursively process nested joins\n if (options.join && options.join.length > 0) {\n joinConfig.with = processJoins(options.join);\n }\n\n result[joinName] = joinConfig;\n }\n\n return result;\n }\n\n return {\n compileRetrievalOperation(op: RetrievalOperation<TSchema>): DrizzleCompiledQuery | null {\n switch (op.type) {\n case \"count\": {\n // Build WHERE clause\n let whereClause: Drizzle.SQL | undefined;\n if (op.options.where) {\n const condition = buildCondition(op.table.columns, op.options.where);\n if (condition === false) {\n // Never matches - return null\n return null;\n }\n if (condition !== true) {\n whereClause = buildWhere(condition);\n }\n }\n\n const drizzleTable = toDrizzleTable(op.table);\n const query = db.select({ count: Drizzle.count() }).from(drizzleTable);\n\n const compiledQuery = whereClause ? query.where(whereClause).toSQL() : query.toSQL();\n return compiledQuery;\n }\n\n case \"find\": {\n const {\n useIndex: _useIndex,\n orderByIndex,\n joins,\n after,\n before,\n pageSize,\n ...findOptions\n } = op.options;\n\n // Get index columns for ordering and cursor pagination\n let indexColumns: AnyColumn[] = [];\n let orderDirection: \"asc\" | \"desc\" = \"asc\";\n\n if (orderByIndex) {\n const index = op.table.indexes[orderByIndex.indexName];\n orderDirection = orderByIndex.direction;\n\n if (!index) {\n // If _primary index doesn't exist, fall back to ID column\n if (orderByIndex.indexName === \"_primary\") {\n indexColumns = [op.table.getIdColumn()];\n } else {\n throw new Error(\n `Index \"${orderByIndex.indexName}\" not found on table \"${op.table.name}\"`,\n );\n }\n } else {\n indexColumns = index.columns;\n }\n }\n\n // Convert orderByIndex to orderBy format\n let orderBy: Drizzle.SQL[] | undefined;\n if (indexColumns.length > 0) {\n orderBy = indexColumns.map((col) => {\n const drizzleCol = toDrizzleColumn(col);\n return orderDirection === \"asc\" ? Drizzle.asc(drizzleCol) : Drizzle.desc(drizzleCol);\n });\n }\n\n // Build query configuration\n const columns: Record<string, boolean> = {};\n const select = findOptions.select;\n\n if (select === true || select === undefined) {\n for (const col of Object.values(op.table.columns)) {\n columns[col.ormName] = true;\n }\n } else {\n for (const k of select) {\n columns[op.table.columns[k].ormName] = true;\n }\n // Always include hidden columns (for FragnoId construction with internal ID and version)\n for (const col of Object.values(op.table.columns)) {\n if (col.isHidden && !columns[col.ormName]) {\n columns[col.ormName] = true;\n }\n }\n }\n\n // Build WHERE clause with cursor conditions\n const whereClauses: Drizzle.SQL[] = [];\n\n // Add user-defined where clause\n if (findOptions.where) {\n const condition = buildCondition(op.table.columns, findOptions.where);\n if (condition === false) {\n // Never matches - return null to indicate this query should be skipped\n return null;\n }\n if (condition !== true) {\n const clause = buildWhere(condition);\n if (clause) {\n whereClauses.push(clause);\n }\n }\n }\n\n // Add cursor-based pagination conditions\n if ((after || before) && indexColumns.length > 0) {\n const cursor = after || before;\n // Decode cursor if it's a string, otherwise use it as-is\n const cursorObj = typeof cursor === \"string\" ? decodeCursor(cursor!) : cursor!;\n const serializedValues = serializeCursorValues(cursorObj, indexColumns, provider);\n\n // Build tuple comparison for cursor pagination\n // For \"after\" with \"asc\": (col1, col2, ...) > (val1, val2, ...)\n // For \"before\" with \"desc\": reverse the comparison\n const isAfter = !!after;\n const useGreaterThan =\n (isAfter && orderDirection === \"asc\") || (!isAfter && orderDirection === \"desc\");\n\n if (indexColumns.length === 1) {\n // Simple single-column case\n const col = toDrizzleColumn(indexColumns[0]!);\n const val = serializedValues[indexColumns[0]!.ormName];\n whereClauses.push(useGreaterThan ? Drizzle.gt(col, val) : Drizzle.lt(col, val));\n } else {\n // Multi-column tuple comparison using SQL\n const drizzleCols = indexColumns.map((c) => toDrizzleColumn(c));\n const vals = indexColumns.map((c) => serializedValues[c.ormName]);\n const operator = useGreaterThan ? \">\" : \"<\";\n // Safe cast: building a SQL comparison expression for cursor pagination\n // Build the tuple comparison: (col1, col2) > (val1, val2)\n const colsSQL = Drizzle.sql.join(drizzleCols, Drizzle.sql.raw(\", \"));\n const valsSQL = Drizzle.sql.join(\n vals.map((v) => Drizzle.sql`${v}`),\n Drizzle.sql.raw(\", \"),\n );\n whereClauses.push(\n Drizzle.sql`(${colsSQL}) ${Drizzle.sql.raw(operator)} (${valsSQL})`,\n );\n }\n }\n\n const whereClause = whereClauses.length > 0 ? Drizzle.and(...whereClauses) : undefined;\n\n const queryConfig: Drizzle.DBQueryConfig<\"many\", boolean> = {\n columns,\n limit: pageSize,\n where: whereClause,\n orderBy,\n with: {},\n };\n\n // Process joins recursively to support nested joins\n if (joins) {\n queryConfig.with = processJoins(joins);\n }\n\n const physicalTableName = mapper ? mapper.toPhysical(op.table.ormName) : op.table.ormName;\n const compiledQuery = db.query[physicalTableName].findMany(queryConfig).toSQL();\n return compiledQuery;\n }\n }\n },\n\n compileMutationOperation(\n op: MutationOperation<TSchema>,\n ): CompiledMutation<DrizzleCompiledQuery> | null {\n switch (op.type) {\n case \"create\": {\n const table = getTable(op.table);\n const drizzleTable = toDrizzleTable(table);\n // encodeValues now handles runtime defaults automatically\n const encodedValues = encodeValues(op.values, table, true, provider);\n const values = processReferenceSubqueries(encodedValues);\n\n const compiledQuery = db.insert(drizzleTable).values(values).toSQL();\n return {\n query: compiledQuery,\n expectedAffectedRows: null, // creates don't need affected row checks\n };\n }\n\n case \"update\": {\n const table = getTable(op.table);\n const idColumn = table.getIdColumn();\n const versionColumn = table.getVersionColumn();\n const drizzleTable = toDrizzleTable(table);\n\n const externalId = typeof op.id === \"string\" ? op.id : op.id.externalId;\n const versionToCheck = getVersionToCheck(op.id, op.checkVersion);\n\n // Build WHERE clause that filters by ID and optionally by version\n const condition =\n versionToCheck !== undefined\n ? buildCondition(table.columns, (eb) =>\n eb.and(\n eb(idColumn.ormName, \"=\", externalId),\n eb(versionColumn.ormName, \"=\", versionToCheck),\n ),\n )\n : buildCondition(table.columns, (eb) => eb(idColumn.ormName, \"=\", externalId));\n\n // Handle boolean cases\n if (condition === false) {\n // Never matches - skip this operation\n return null;\n }\n\n const whereClause = condition === true ? undefined : buildWhere(condition);\n const encodedSetValues = encodeValues(op.set, table, false, provider);\n const setValues = processReferenceSubqueries(encodedSetValues);\n\n // Automatically increment _version for optimistic concurrency control\n // Safe cast: we're building a SQL expression for incrementing the version\n setValues[versionColumn.ormName] = Drizzle.sql.raw(\n `COALESCE(${versionColumn.ormName}, 0) + 1`,\n ) as unknown;\n\n const compiledQuery = db.update(drizzleTable).set(setValues).where(whereClause).toSQL();\n return {\n query: compiledQuery,\n expectedAffectedRows: op.checkVersion ? 1 : null,\n };\n }\n\n case \"delete\": {\n const table = getTable(op.table);\n const idColumn = table.getIdColumn();\n const versionColumn = table.getVersionColumn();\n const drizzleTable = toDrizzleTable(table);\n\n if (!op.id) {\n throw new Error(\n `[Drizzle] Delete operation on table \"${op.table}\" has undefined id. ` +\n `Make sure you're passing a valid FragnoId or string ID.`,\n );\n }\n\n const externalId = typeof op.id === \"string\" ? op.id : op.id.externalId;\n\n if (!externalId) {\n throw new Error(\n `[Drizzle] Delete operation on table \"${op.table}\" has invalid id. ` +\n `The FragnoId object exists but has no externalId. ` +\n `Received: ${JSON.stringify(op.id)}. ` +\n `Make sure the record was properly loaded from the database.`,\n );\n }\n const versionToCheck = getVersionToCheck(op.id, op.checkVersion);\n\n // Build WHERE clause that filters by ID and optionally by version\n const condition =\n versionToCheck !== undefined\n ? buildCondition(table.columns, (eb) =>\n eb.and(\n eb(idColumn.ormName, \"=\", externalId),\n eb(versionColumn.ormName, \"=\", versionToCheck),\n ),\n )\n : buildCondition(table.columns, (eb) => eb(idColumn.ormName, \"=\", externalId));\n\n // Handle boolean cases\n if (condition === false) {\n // Never matches - skip this operation\n return null;\n }\n\n const whereClause = condition === true ? undefined : buildWhere(condition);\n\n const compiledQuery = db.delete(drizzleTable).where(whereClause).toSQL();\n return {\n query: compiledQuery,\n expectedAffectedRows: op.checkVersion ? 1 : null,\n };\n }\n }\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"drizzle-uow-compiler.js","names":["processed: Record<string, unknown>","result: Record<string, Drizzle.DBQueryConfig<\"many\", boolean>>","joinColumns: Record<string, boolean>","joinOrderBy: Drizzle.SQL[] | undefined","joinWhere: Drizzle.SQL | undefined","joinConfig: Drizzle.DBQueryConfig<\"many\", boolean>","whereClause: Drizzle.SQL | undefined","indexColumns: AnyColumn[]","orderDirection: \"asc\" | \"desc\"","orderBy: Drizzle.SQL[] | undefined","columns: Record<string, boolean>","whereClauses: Drizzle.SQL[]","queryConfig: Drizzle.DBQueryConfig<\"many\", boolean>"],"sources":["../../../src/adapters/drizzle/drizzle-uow-compiler.ts"],"sourcesContent":["import * as Drizzle from \"drizzle-orm\";\nimport type { AnyColumn, AnySchema, AnyTable, FragnoId } from \"../../schema/create\";\nimport { Column } from \"../../schema/create\";\nimport type {\n CompiledMutation,\n MutationOperation,\n RetrievalOperation,\n UOWCompiler,\n} from \"../../query/unit-of-work\";\nimport { buildCondition, type Condition } from \"../../query/condition-builder\";\nimport {\n type ColumnType,\n type TableType,\n type TableNameMapper,\n parseDrizzle,\n type DBType,\n createTableNameMapper,\n} from \"./shared\";\nimport { encodeValues, ReferenceSubquery } from \"../../query/result-transform\";\nimport { serialize } from \"../../schema/serialize\";\nimport { decodeCursor, serializeCursorValues } from \"../../query/cursor\";\nimport type { CompiledJoin } from \"../../query/orm/orm\";\nimport { getOrderedJoinColumns } from \"./join-column-utils\";\nimport type { ConnectionPool } from \"../../shared/connection-pool\";\n\nexport type DrizzleCompiledQuery = {\n sql: string;\n params: unknown[];\n};\n\n/**\n * Create a Drizzle-specific Unit of Work compiler\n *\n * This compiler translates UOW operations into Drizzle query functions\n * that can be executed as a batch/transaction.\n *\n * @param pool - Connection pool for acquiring database connections\n * @param provider - SQL provider (sqlite, mysql, postgresql)\n * @param mapper - Optional table name mapper for namespace prefixing (fallback for operations without explicit namespace)\n * @returns A UOWCompiler instance for Drizzle\n */\nexport function createDrizzleUOWCompiler(\n pool: ConnectionPool<DBType>,\n provider: \"sqlite\" | \"mysql\" | \"postgresql\",\n mapper?: TableNameMapper,\n): UOWCompiler<DrizzleCompiledQuery> {\n // Get db synchronously for compilation (doesn't execute, just builds SQL)\n // TODO: We don't even need a Drizzle instance with a db client attached here. `drizzle({ schema })` is enough.\n const dbRaw = pool.getDatabaseSync();\n const [db, drizzleTables] = parseDrizzle(dbRaw);\n\n /**\n * Get the mapper for a specific operation\n * Uses operation's namespace if provided, otherwise falls back to the default mapper\n */\n function getMapperForOperation(namespace: string | undefined): TableNameMapper | undefined {\n if (namespace) {\n return createTableNameMapper(namespace);\n }\n return mapper;\n }\n\n /**\n * Convert a Fragno table to a Drizzle table\n * @throws Error if table is not found in Drizzle schema\n */\n function toDrizzleTable(table: AnyTable, namespace: string | undefined): TableType {\n // Get the mapper for this operation's namespace\n const opMapper = getMapperForOperation(namespace);\n\n // Map logical table name to physical table name using the operation-specific mapper\n const physicalTableName = opMapper ? opMapper.toPhysical(table.ormName) : table.ormName;\n const out = drizzleTables[physicalTableName];\n if (out) {\n return out;\n }\n\n throw new Error(\n `[Drizzle] Unknown table name ${physicalTableName} (logical: ${table.ormName}), is it included in your Drizzle schema?`,\n );\n }\n\n /**\n * Convert a Fragno column to a Drizzle column\n * @throws Error if column is not found in Drizzle table\n */\n function toDrizzleColumn(\n schema: AnySchema,\n namespace: string | undefined,\n col: AnyColumn,\n ): ColumnType {\n const fragnoTable = schema.tables[col.tableName];\n if (!fragnoTable) {\n throw new Error(`[Drizzle] Unknown table ${col.tableName} for column ${col.ormName}.`);\n }\n\n const table = toDrizzleTable(fragnoTable, namespace);\n const out = table[col.ormName];\n if (out) {\n return out;\n }\n\n throw new Error(`[Drizzle] Unknown column name ${col.ormName} in ${fragnoTable.ormName}.`);\n }\n\n /**\n * Build a WHERE clause from a condition using Drizzle's query builder\n */\n function buildWhere(\n schema: AnySchema,\n namespace: string | undefined,\n condition: Condition,\n ): Drizzle.SQL | undefined {\n if (condition.type === \"compare\") {\n const left = toDrizzleColumn(schema, namespace, condition.a);\n const op = condition.operator;\n let right = condition.b;\n if (right instanceof Column) {\n right = toDrizzleColumn(schema, namespace, right);\n } else {\n // Handle string references - convert external ID to internal ID via subquery\n if (condition.a.role === \"reference\" && typeof right === \"string\") {\n // Find the table that contains this column\n const table = Object.values(schema.tables).find((t) =>\n Object.values(t.columns).includes(condition.a),\n );\n if (table) {\n // Find relation that uses this column\n const relation = Object.values(table.relations).find((rel) =>\n rel.on.some(([localCol]) => localCol === condition.a.ormName),\n );\n if (relation) {\n const refTable = relation.table;\n const internalIdCol = refTable.getInternalIdColumn();\n const idCol = refTable.getIdColumn();\n const physicalTableName = mapper\n ? mapper.toPhysical(refTable.ormName)\n : refTable.ormName;\n\n // Build a SQL subquery using Drizzle's sql template\n right = Drizzle.sql`(select ${Drizzle.sql.identifier(internalIdCol.name)} from ${Drizzle.sql.identifier(physicalTableName)} where ${Drizzle.sql.identifier(idCol.name)} = ${right} limit 1)`;\n }\n }\n } else {\n // Serialize non-Column values (e.g., FragnoId -> string, Date -> number for SQLite)\n right = serialize(right, condition.a, provider);\n }\n }\n\n switch (op) {\n case \"=\":\n return Drizzle.eq(left, right);\n case \"!=\":\n return Drizzle.ne(left, right);\n case \">\":\n return Drizzle.gt(left, right);\n case \">=\":\n return Drizzle.gte(left, right);\n case \"<\":\n return Drizzle.lt(left, right);\n case \"<=\":\n return Drizzle.lte(left, right);\n case \"in\": {\n return Drizzle.inArray(left, right as never[]);\n }\n case \"not in\":\n return Drizzle.notInArray(left, right as never[]);\n case \"is\":\n return right === null ? Drizzle.isNull(left) : Drizzle.eq(left, right);\n case \"is not\":\n return right === null ? Drizzle.isNotNull(left) : Drizzle.ne(left, right);\n case \"contains\": {\n right =\n typeof right === \"string\" ? `%${right}%` : Drizzle.sql`concat('%', ${right}, '%')`;\n return Drizzle.like(left, right as string);\n }\n case \"not contains\": {\n right =\n typeof right === \"string\" ? `%${right}%` : Drizzle.sql`concat('%', ${right}, '%')`;\n return Drizzle.notLike(left, right as string);\n }\n case \"ends with\": {\n right = typeof right === \"string\" ? `%${right}` : Drizzle.sql`concat('%', ${right})`;\n return Drizzle.like(left, right as string);\n }\n case \"not ends with\": {\n right = typeof right === \"string\" ? `%${right}` : Drizzle.sql`concat('%', ${right})`;\n return Drizzle.notLike(left, right as string);\n }\n case \"starts with\": {\n right = typeof right === \"string\" ? `${right}%` : Drizzle.sql`concat(${right}, '%')`;\n return Drizzle.like(left, right as string);\n }\n case \"not starts with\": {\n right = typeof right === \"string\" ? `${right}%` : Drizzle.sql`concat(${right}, '%')`;\n return Drizzle.notLike(left, right as string);\n }\n\n default:\n throw new Error(`Unsupported operator: ${op}`);\n }\n }\n\n if (condition.type === \"and\") {\n return Drizzle.and(...condition.items.map((item) => buildWhere(schema, namespace, item)));\n }\n\n if (condition.type === \"not\") {\n const result = buildWhere(schema, namespace, condition.item);\n if (!result) {\n return;\n }\n\n return Drizzle.not(result);\n }\n\n return Drizzle.or(...condition.items.map((item) => buildWhere(schema, namespace, item)));\n }\n\n /**\n * Process reference subqueries in encoded values, converting them to Drizzle SQL subqueries\n */\n function processReferenceSubqueries(values: Record<string, unknown>): Record<string, unknown> {\n const processed: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(values)) {\n if (value instanceof ReferenceSubquery) {\n const refTable = value.referencedTable;\n const externalId = value.externalIdValue;\n const internalIdCol = refTable.getInternalIdColumn();\n const idCol = refTable.getIdColumn();\n\n // Map logical table name to physical table name using the mapper\n const physicalTableName = mapper ? mapper.toPhysical(refTable.ormName) : refTable.ormName;\n\n // Build a SQL subquery using Drizzle's sql template\n // This creates a subquery: (SELECT _internalId FROM table WHERE id = ? LIMIT 1)\n // Safe cast: we're building a SQL subquery that returns a single bigint value\n processed[key] =\n Drizzle.sql`(select ${Drizzle.sql.identifier(internalIdCol.name)} from ${Drizzle.sql.identifier(physicalTableName)} where ${Drizzle.sql.identifier(idCol.name)} = ${externalId} limit 1)`;\n } else {\n processed[key] = value;\n }\n }\n\n return processed;\n }\n\n /**\n * Get table from schema by name\n * @throws Error if table is not found in schema\n */\n function getTable(schema: AnySchema, name: unknown): AnyTable {\n const table = schema.tables[name as string];\n if (!table) {\n throw new Error(`Invalid table name ${name}.`);\n }\n return table;\n }\n\n /**\n * Get the version to check for a given ID and checkVersion flag.\n * @returns The version to check or undefined if no check is required.\n * @throws Error if the ID is a string and checkVersion is true.\n */\n function getVersionToCheck(id: FragnoId | string, checkVersion: boolean): number | undefined {\n if (!checkVersion) {\n return undefined;\n }\n\n if (typeof id === \"string\") {\n throw new Error(\n `Cannot use checkVersion with a string ID. Version checking requires a FragnoId with version information.`,\n );\n }\n\n return id.version;\n }\n\n /**\n * Process joins recursively to support nested joins with orderBy and limit\n */\n function processJoins(\n schema: AnySchema,\n namespace: string | undefined,\n joins: CompiledJoin[],\n ): Record<string, Drizzle.DBQueryConfig<\"many\", boolean>> {\n const result: Record<string, Drizzle.DBQueryConfig<\"many\", boolean>> = {};\n\n for (const join of joins) {\n const { options, relation } = join;\n\n if (!options) {\n continue;\n }\n\n const targetTable = relation.table;\n const joinName = relation.name;\n\n // Build columns for this join using shared utility\n const selectOption = options.select === undefined ? true : options.select;\n const orderedColumns = getOrderedJoinColumns(targetTable, selectOption);\n const joinColumns: Record<string, boolean> = {};\n for (const colName of orderedColumns) {\n joinColumns[colName] = true;\n }\n\n // Build orderBy for this join\n let joinOrderBy: Drizzle.SQL[] | undefined;\n if (options.orderBy && options.orderBy.length > 0) {\n joinOrderBy = options.orderBy.map(([col, direction]) => {\n const drizzleCol = toDrizzleColumn(schema, namespace, col);\n return direction === \"asc\" ? Drizzle.asc(drizzleCol) : Drizzle.desc(drizzleCol);\n });\n }\n\n // Build WHERE clause for this join if provided\n let joinWhere: Drizzle.SQL | undefined;\n if (options.where) {\n joinWhere = buildWhere(schema, namespace, options.where);\n }\n\n // Build the join config\n const joinConfig: Drizzle.DBQueryConfig<\"many\", boolean> = {\n columns: joinColumns,\n orderBy: joinOrderBy,\n limit: options.limit,\n where: joinWhere,\n };\n\n // Recursively process nested joins\n if (options.join && options.join.length > 0) {\n joinConfig.with = processJoins(schema, namespace, options.join);\n }\n\n result[joinName] = joinConfig;\n }\n\n return result;\n }\n\n return {\n compileRetrievalOperation(op: RetrievalOperation<AnySchema>): DrizzleCompiledQuery | null {\n const schema = op.schema;\n switch (op.type) {\n case \"count\": {\n // Build WHERE clause\n let whereClause: Drizzle.SQL | undefined;\n if (op.options.where) {\n const condition = buildCondition(op.table.columns, op.options.where);\n if (condition === false) {\n // Never matches - return null\n return null;\n }\n if (condition !== true) {\n whereClause = buildWhere(schema, op.namespace, condition);\n }\n }\n\n const drizzleTable = toDrizzleTable(op.table, op.namespace);\n const query = db.select({ count: Drizzle.count() }).from(drizzleTable);\n\n const compiledQuery = whereClause ? query.where(whereClause).toSQL() : query.toSQL();\n return compiledQuery;\n }\n\n case \"find\": {\n const {\n useIndex: _useIndex,\n orderByIndex,\n joins,\n after,\n before,\n pageSize,\n ...findOptions\n } = op.options;\n\n // Get index columns for ordering and cursor pagination\n let indexColumns: AnyColumn[] = [];\n let orderDirection: \"asc\" | \"desc\" = \"asc\";\n\n if (orderByIndex) {\n const index = op.table.indexes[orderByIndex.indexName];\n orderDirection = orderByIndex.direction;\n\n if (!index) {\n // If _primary index doesn't exist, fall back to ID column\n if (orderByIndex.indexName === \"_primary\") {\n indexColumns = [op.table.getIdColumn()];\n } else {\n throw new Error(\n `Index \"${orderByIndex.indexName}\" not found on table \"${op.table.name}\"`,\n );\n }\n } else {\n indexColumns = index.columns;\n }\n }\n\n // Convert orderByIndex to orderBy format\n let orderBy: Drizzle.SQL[] | undefined;\n if (indexColumns.length > 0) {\n orderBy = indexColumns.map((col) => {\n const drizzleCol = toDrizzleColumn(schema, op.namespace, col);\n return orderDirection === \"asc\" ? Drizzle.asc(drizzleCol) : Drizzle.desc(drizzleCol);\n });\n }\n\n // Build query configuration\n const columns: Record<string, boolean> = {};\n const select = findOptions.select;\n\n if (select === true || select === undefined) {\n for (const col of Object.values(op.table.columns)) {\n columns[col.ormName] = true;\n }\n } else {\n for (const k of select) {\n columns[op.table.columns[k].ormName] = true;\n }\n // Always include hidden columns (for FragnoId construction with internal ID and version)\n for (const col of Object.values(op.table.columns)) {\n if (col.isHidden && !columns[col.ormName]) {\n columns[col.ormName] = true;\n }\n }\n }\n\n // Build WHERE clause with cursor conditions\n const whereClauses: Drizzle.SQL[] = [];\n\n // Add user-defined where clause\n if (findOptions.where) {\n const condition = buildCondition(op.table.columns, findOptions.where);\n if (condition === false) {\n // Never matches - return null to indicate this query should be skipped\n return null;\n }\n if (condition !== true) {\n const clause = buildWhere(schema, op.namespace, condition);\n if (clause) {\n whereClauses.push(clause);\n }\n }\n }\n\n // Add cursor-based pagination conditions\n if ((after || before) && indexColumns.length > 0) {\n const cursor = after || before;\n // Decode cursor if it's a string, otherwise use it as-is\n const cursorObj = typeof cursor === \"string\" ? decodeCursor(cursor!) : cursor!;\n const serializedValues = serializeCursorValues(cursorObj, indexColumns, provider);\n\n // Build tuple comparison for cursor pagination\n // For \"after\" with \"asc\": (col1, col2, ...) > (val1, val2, ...)\n // For \"before\" with \"desc\": reverse the comparison\n const isAfter = !!after;\n const useGreaterThan =\n (isAfter && orderDirection === \"asc\") || (!isAfter && orderDirection === \"desc\");\n\n if (indexColumns.length === 1) {\n // Simple single-column case\n const col = toDrizzleColumn(schema, op.namespace, indexColumns[0]!);\n const val = serializedValues[indexColumns[0]!.ormName];\n whereClauses.push(useGreaterThan ? Drizzle.gt(col, val) : Drizzle.lt(col, val));\n } else {\n // Multi-column tuple comparison using SQL\n const drizzleCols = indexColumns.map((c) => toDrizzleColumn(schema, op.namespace, c));\n const vals = indexColumns.map((c) => serializedValues[c.ormName]);\n const operator = useGreaterThan ? \">\" : \"<\";\n // Safe cast: building a SQL comparison expression for cursor pagination\n // Build the tuple comparison: (col1, col2) > (val1, val2)\n const colsSQL = Drizzle.sql.join(drizzleCols, Drizzle.sql.raw(\", \"));\n const valsSQL = Drizzle.sql.join(\n vals.map((v) => Drizzle.sql`${v}`),\n Drizzle.sql.raw(\", \"),\n );\n whereClauses.push(\n Drizzle.sql`(${colsSQL}) ${Drizzle.sql.raw(operator)} (${valsSQL})`,\n );\n }\n }\n\n const whereClause = whereClauses.length > 0 ? Drizzle.and(...whereClauses) : undefined;\n\n // For cursor pagination, fetch one extra item to determine if there's a next page\n // Only apply this when using the high-level findWithCursor() API (op.withCursor === true)\n const effectiveLimit = pageSize && op.withCursor ? pageSize + 1 : pageSize;\n\n const queryConfig: Drizzle.DBQueryConfig<\"many\", boolean> = {\n columns,\n limit: effectiveLimit,\n where: whereClause,\n orderBy,\n with: {},\n };\n\n // Process joins recursively to support nested joins\n if (joins) {\n queryConfig.with = processJoins(schema, op.namespace, joins);\n }\n\n // For multi-schema support: get the mapper for the operation's namespace\n const opMapper = getMapperForOperation(op.namespace);\n const physicalTableName = opMapper\n ? opMapper.toPhysical(op.table.ormName)\n : op.table.ormName;\n const tableQuery = db.query[physicalTableName];\n\n if (!tableQuery) {\n throw new Error(\n `[Drizzle] Table ${op.table.ormName} (physical: ${physicalTableName}) not found in db.query. ` +\n `Available tables: ${Object.keys(db.query).join(\", \")}`,\n );\n }\n\n const compiledQuery = tableQuery.findMany(queryConfig).toSQL();\n return compiledQuery;\n }\n }\n },\n\n compileMutationOperation(\n op: MutationOperation<AnySchema>,\n ): CompiledMutation<DrizzleCompiledQuery> | null {\n const schema = op.schema;\n switch (op.type) {\n case \"create\": {\n const table = getTable(schema, op.table);\n const drizzleTable = toDrizzleTable(table, op.namespace);\n // encodeValues now handles runtime defaults automatically\n const encodedValues = encodeValues(op.values, table, true, provider, true);\n const values = processReferenceSubqueries(encodedValues);\n\n const compiledQuery = db.insert(drizzleTable).values(values).toSQL();\n return {\n query: compiledQuery,\n expectedAffectedRows: null, // creates don't need affected row checks\n expectedReturnedRows: null,\n };\n }\n\n case \"update\": {\n const table = getTable(schema, op.table);\n const idColumn = table.getIdColumn();\n const versionColumn = table.getVersionColumn();\n const drizzleTable = toDrizzleTable(table, op.namespace);\n\n const externalId = typeof op.id === \"string\" ? op.id : op.id.externalId;\n const versionToCheck = getVersionToCheck(op.id, op.checkVersion);\n\n // Build WHERE clause that filters by ID and optionally by version\n const condition =\n versionToCheck !== undefined\n ? buildCondition(table.columns, (eb) =>\n eb.and(\n eb(idColumn.ormName, \"=\", externalId),\n eb(versionColumn.ormName, \"=\", versionToCheck),\n ),\n )\n : buildCondition(table.columns, (eb) => eb(idColumn.ormName, \"=\", externalId));\n\n // Handle boolean cases\n if (condition === false) {\n // Never matches - skip this operation\n return null;\n }\n\n const whereClause =\n condition === true ? undefined : buildWhere(schema, op.namespace, condition);\n const encodedSetValues = encodeValues(op.set, table, false, provider, true);\n const setValues = processReferenceSubqueries(encodedSetValues);\n\n // Automatically increment _version for optimistic concurrency control\n // Safe cast: we're building a SQL expression for incrementing the version\n setValues[versionColumn.ormName] = Drizzle.sql.raw(\n `COALESCE(${versionColumn.ormName}, 0) + 1`,\n ) as unknown;\n\n const compiledQuery = db.update(drizzleTable).set(setValues).where(whereClause).toSQL();\n return {\n query: compiledQuery,\n expectedAffectedRows: op.checkVersion ? 1 : null,\n expectedReturnedRows: null,\n };\n }\n\n case \"delete\": {\n const table = getTable(schema, op.table);\n const idColumn = table.getIdColumn();\n const versionColumn = table.getVersionColumn();\n const drizzleTable = toDrizzleTable(table, op.namespace);\n\n if (!op.id) {\n throw new Error(\n `[Drizzle] Delete operation on table \"${op.table}\" has undefined id. ` +\n `Make sure you're passing a valid FragnoId or string ID.`,\n );\n }\n\n const externalId = typeof op.id === \"string\" ? op.id : op.id.externalId;\n\n if (!externalId) {\n throw new Error(\n `[Drizzle] Delete operation on table \"${op.table}\" has invalid id. ` +\n `The FragnoId object exists but has no externalId. ` +\n `Received: ${JSON.stringify(op.id)}. ` +\n `Make sure the record was properly loaded from the database.`,\n );\n }\n const versionToCheck = getVersionToCheck(op.id, op.checkVersion);\n\n // Build WHERE clause that filters by ID and optionally by version\n const condition =\n versionToCheck !== undefined\n ? buildCondition(table.columns, (eb) =>\n eb.and(\n eb(idColumn.ormName, \"=\", externalId),\n eb(versionColumn.ormName, \"=\", versionToCheck),\n ),\n )\n : buildCondition(table.columns, (eb) => eb(idColumn.ormName, \"=\", externalId));\n\n // Handle boolean cases\n if (condition === false) {\n // Never matches - skip this operation\n return null;\n }\n\n const whereClause =\n condition === true ? undefined : buildWhere(schema, op.namespace, condition);\n\n const compiledQuery = db.delete(drizzleTable).where(whereClause).toSQL();\n return {\n query: compiledQuery,\n expectedAffectedRows: op.checkVersion ? 1 : null,\n expectedReturnedRows: null,\n };\n }\n\n case \"check\": {\n const table = getTable(schema, op.table);\n const idColumn = table.getIdColumn();\n const versionColumn = table.getVersionColumn();\n const drizzleTable = toDrizzleTable(table, op.namespace);\n\n const externalId = op.id.externalId;\n const version = op.id.version;\n\n // Build WHERE clause that filters by ID and version\n const condition = buildCondition(table.columns, (eb) =>\n eb.and(eb(idColumn.ormName, \"=\", externalId), eb(versionColumn.ormName, \"=\", version)),\n );\n\n if (typeof condition === \"boolean\") {\n throw new Error(\"Condition is a boolean, but should be a condition object.\");\n }\n\n // Build a SELECT query to check if the row exists with the correct version\n // Use sql`1` to select a constant with an alias\n const compiledQuery = db\n .select({ exists: Drizzle.sql<number>`1`.as(\"exists\") })\n .from(drizzleTable)\n .where(buildWhere(schema, op.namespace, condition))\n .limit(1)\n .toSQL();\n\n return {\n query: compiledQuery,\n expectedAffectedRows: null,\n expectedReturnedRows: 1, // Check that exactly 1 row was returned\n };\n }\n }\n },\n };\n}\n"],"mappings":"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"}
|