@fragno-dev/db 0.1.10 → 0.1.11
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 +15 -14
- package/CHANGELOG.md +6 -0
- package/dist/adapters/drizzle/drizzle-query.d.ts +1 -0
- package/dist/adapters/drizzle/drizzle-query.d.ts.map +1 -1
- package/dist/adapters/drizzle/drizzle-query.js +3 -4
- package/dist/adapters/drizzle/drizzle-query.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts +2 -0
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.js +13 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +1 -1
- package/dist/adapters/drizzle/shared.d.ts +1 -0
- package/dist/adapters/kysely/kysely-query-builder.js +23 -12
- package/dist/adapters/kysely/kysely-query-builder.js.map +1 -1
- package/package.json +2 -2
- package/src/adapters/drizzle/drizzle-query.test.ts +2 -2
- package/src/adapters/drizzle/drizzle-query.ts +4 -4
- package/src/adapters/drizzle/drizzle-uow-compiler.ts +27 -2
- package/src/adapters/kysely/kysely-query-builder.ts +35 -11
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
> @fragno-dev/db@0.1.
|
|
2
|
+
> @fragno-dev/db@0.1.11 build /home/runner/work/fragno/fragno/packages/fragno-db
|
|
3
3
|
> tsdown
|
|
4
4
|
|
|
5
|
-
[34mℹ[39m tsdown [2mv0.15.
|
|
5
|
+
[34mℹ[39m tsdown [2mv0.15.12[22m powered by rolldown [2mv1.0.0-beta.45[22m
|
|
6
6
|
[34mℹ[39m Using tsdown config: [4m/home/runner/work/fragno/fragno/packages/fragno-db/tsdown.config.ts[24m
|
|
7
7
|
[34mℹ[39m entry: [34msrc/fragment.ts, src/id.ts, src/mod.ts, src/adapters/adapters.ts, src/migration-engine/generation-engine.ts, src/query/cursor.ts, src/query/query.ts, src/query/unit-of-work.ts, src/schema/create.ts, src/adapters/drizzle/drizzle-adapter.ts, src/adapters/drizzle/generate.ts, src/adapters/kysely/kysely-adapter.ts[39m
|
|
8
8
|
[34mℹ[39m tsconfig: [34mtsconfig.json[39m
|
|
@@ -22,14 +22,14 @@
|
|
|
22
22
|
[34mℹ[39m [2mdist/[22mschema/create.js.map [2m48.81 kB[22m [2m│ gzip: 11.78 kB[22m
|
|
23
23
|
[34mℹ[39m [2mdist/[22mquery/unit-of-work.js.map [2m45.94 kB[22m [2m│ gzip: 10.16 kB[22m
|
|
24
24
|
[34mℹ[39m [2mdist/[22madapters/drizzle/generate.js.map [2m34.28 kB[22m [2m│ gzip: 8.39 kB[22m
|
|
25
|
-
[34mℹ[39m [2mdist/[22madapters/drizzle/drizzle-uow-compiler.js.map [
|
|
26
|
-
[34mℹ[39m [2mdist/[22madapters/kysely/kysely-query-builder.js.map [
|
|
25
|
+
[34mℹ[39m [2mdist/[22madapters/drizzle/drizzle-uow-compiler.js.map [2m31.70 kB[22m [2m│ gzip: 7.84 kB[22m
|
|
26
|
+
[34mℹ[39m [2mdist/[22madapters/kysely/kysely-query-builder.js.map [2m30.22 kB[22m [2m│ gzip: 7.85 kB[22m
|
|
27
27
|
[34mℹ[39m [2mdist/[22mmigration-engine/generation-engine.js.map [2m16.35 kB[22m [2m│ gzip: 4.35 kB[22m
|
|
28
|
-
[34mℹ[39m [2mdist/[22madapters/drizzle/drizzle-
|
|
28
|
+
[34mℹ[39m [2mdist/[22madapters/drizzle/drizzle-uow-compiler.js [2m14.29 kB[22m [2m│ gzip: 3.65 kB[22m
|
|
29
|
+
[34mℹ[39m [2mdist/[22madapters/drizzle/drizzle-query.js.map [2m14.26 kB[22m [2m│ gzip: 3.64 kB[22m
|
|
29
30
|
[34mℹ[39m [2mdist/[22madapters/kysely/kysely-uow-compiler.js.map [2m13.93 kB[22m [2m│ gzip: 4.01 kB[22m
|
|
31
|
+
[34mℹ[39m [2mdist/[22madapters/kysely/kysely-query-builder.js [2m13.63 kB[22m [2m│ gzip: 3.77 kB[22m
|
|
30
32
|
[34mℹ[39m [2mdist/[22madapters/kysely/kysely-query.js.map [2m13.57 kB[22m [2m│ gzip: 3.66 kB[22m
|
|
31
|
-
[34mℹ[39m [2mdist/[22madapters/drizzle/drizzle-uow-compiler.js [2m13.48 kB[22m [2m│ gzip: 3.52 kB[22m
|
|
32
|
-
[34mℹ[39m [2mdist/[22madapters/kysely/kysely-query-builder.js [2m12.83 kB[22m [2m│ gzip: 3.58 kB[22m
|
|
33
33
|
[34mℹ[39m [2mdist/[22madapters/drizzle/drizzle-uow-executor.js.map [2m12.65 kB[22m [2m│ gzip: 3.76 kB[22m
|
|
34
34
|
[34mℹ[39m [2mdist/[22mschema/serialize.js.map [2m12.12 kB[22m [2m│ gzip: 2.75 kB[22m
|
|
35
35
|
[34mℹ[39m [2mdist/[22mschema/create.d.ts.map [2m11.85 kB[22m [2m│ gzip: 4.65 kB[22m
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
[34mℹ[39m [2mdist/[22madapters/drizzle/drizzle-uow-decoder.js.map [2m 7.73 kB[22m [2m│ gzip: 2.82 kB[22m
|
|
48
48
|
[34mℹ[39m [2mdist/[22mmigration-engine/create.js.map [2m 7.32 kB[22m [2m│ gzip: 2.14 kB[22m
|
|
49
49
|
[34mℹ[39m [2mdist/[22madapters/kysely/kysely-uow-executor.js.map [2m 7.10 kB[22m [2m│ gzip: 2.53 kB[22m
|
|
50
|
-
[34mℹ[39m [2mdist/[22madapters/drizzle/drizzle-query.js [2m 6.
|
|
50
|
+
[34mℹ[39m [2mdist/[22madapters/drizzle/drizzle-query.js [2m 6.61 kB[22m [2m│ gzip: 1.74 kB[22m
|
|
51
51
|
[34mℹ[39m [2mdist/[22mquery/query.d.ts.map [2m 6.51 kB[22m [2m│ gzip: 2.43 kB[22m
|
|
52
52
|
[34mℹ[39m [2mdist/[22madapters/kysely/kysely-query-compiler.js.map [2m 6.50 kB[22m [2m│ gzip: 1.62 kB[22m
|
|
53
53
|
[34mℹ[39m [2mdist/[22madapters/kysely/kysely-query.js [2m 6.30 kB[22m [2m│ gzip: 1.75 kB[22m
|
|
@@ -108,8 +108,8 @@
|
|
|
108
108
|
[34mℹ[39m [2mdist/[22mschema-generator/schema-generator.d.ts.map [2m 0.23 kB[22m [2m│ gzip: 0.17 kB[22m
|
|
109
109
|
[34mℹ[39m [2mdist/[22mutil/types.d.ts.map [2m 0.22 kB[22m [2m│ gzip: 0.16 kB[22m
|
|
110
110
|
[34mℹ[39m [2mdist/[22mmigration-engine/shared.js [2m 0.21 kB[22m [2m│ gzip: 0.17 kB[22m
|
|
111
|
-
[34mℹ[39m [2mdist/[22madapters/drizzle/drizzle-query.d.ts.map [2m 0.
|
|
112
|
-
[34mℹ[39m [2mdist/[22madapters/drizzle/drizzle-uow-compiler.d.ts.map [2m 0.
|
|
111
|
+
[34mℹ[39m [2mdist/[22madapters/drizzle/drizzle-query.d.ts.map [2m 0.18 kB[22m [2m│ gzip: 0.14 kB[22m
|
|
112
|
+
[34mℹ[39m [2mdist/[22madapters/drizzle/drizzle-uow-compiler.d.ts.map [2m 0.18 kB[22m [2m│ gzip: 0.14 kB[22m
|
|
113
113
|
[34mℹ[39m [2mdist/[22mshared/providers.d.ts.map [2m 0.15 kB[22m [2m│ gzip: 0.13 kB[22m
|
|
114
114
|
[34mℹ[39m [2mdist/[22m[32m[1mschema/create.d.ts[22m[39m [2m19.46 kB[22m [2m│ gzip: 4.72 kB[22m
|
|
115
115
|
[34mℹ[39m [2mdist/[22m[32m[1mquery/unit-of-work.d.ts[22m[39m [2m17.56 kB[22m [2m│ gzip: 4.28 kB[22m
|
|
@@ -126,11 +126,12 @@
|
|
|
126
126
|
[34mℹ[39m [2mdist/[22m[32mmigration-engine/shared.d.ts[39m [2m 2.76 kB[22m [2m│ gzip: 0.99 kB[22m
|
|
127
127
|
[34mℹ[39m [2mdist/[22m[32mquery/condition-builder.d.ts[39m [2m 2.00 kB[22m [2m│ gzip: 0.68 kB[22m
|
|
128
128
|
[34mℹ[39m [2mdist/[22m[32mmigration-engine/create.d.ts[39m [2m 1.10 kB[22m [2m│ gzip: 0.51 kB[22m
|
|
129
|
-
[34mℹ[39m [2mdist/[22m[32madapters/drizzle/drizzle-query.d.ts[39m [2m 0.
|
|
129
|
+
[34mℹ[39m [2mdist/[22m[32madapters/drizzle/drizzle-query.d.ts[39m [2m 0.71 kB[22m [2m│ gzip: 0.41 kB[22m
|
|
130
130
|
[34mℹ[39m [2mdist/[22m[32mquery/orm/orm.d.ts[39m [2m 0.61 kB[22m [2m│ gzip: 0.34 kB[22m
|
|
131
131
|
[34mℹ[39m [2mdist/[22m[32mschema-generator/schema-generator.d.ts[39m [2m 0.37 kB[22m [2m│ gzip: 0.20 kB[22m
|
|
132
132
|
[34mℹ[39m [2mdist/[22m[32mshared/providers.d.ts[39m [2m 0.26 kB[22m [2m│ gzip: 0.19 kB[22m
|
|
133
133
|
[34mℹ[39m [2mdist/[22m[32mutil/types.d.ts[39m [2m 0.26 kB[22m [2m│ gzip: 0.21 kB[22m
|
|
134
|
-
[34mℹ[39m [2mdist/[22m[32madapters/drizzle/drizzle-uow-compiler.d.ts[39m [2m 0.
|
|
135
|
-
[34mℹ[39m
|
|
136
|
-
[
|
|
134
|
+
[34mℹ[39m [2mdist/[22m[32madapters/drizzle/drizzle-uow-compiler.d.ts[39m [2m 0.25 kB[22m [2m│ gzip: 0.18 kB[22m
|
|
135
|
+
[34mℹ[39m [2mdist/[22m[32madapters/drizzle/shared.d.ts[39m [2m 0.02 kB[22m [2m│ gzip: 0.04 kB[22m
|
|
136
|
+
[34mℹ[39m 126 files, total: 745.03 kB
|
|
137
|
+
[32m✔[39m Build complete in [32m20040ms[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drizzle-query.d.ts","names":[],"sources":["../../../src/adapters/drizzle/drizzle-query.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"drizzle-query.d.ts","names":[],"sources":["../../../src/adapters/drizzle/drizzle-query.ts"],"sourcesContent":[],"mappings":";;;;;;;;UAaiB,gBAAA;;;;;oBAKG"}
|
|
@@ -68,10 +68,9 @@ function fromDrizzle(schema, pool, provider, mapper, uowConfig) {
|
|
|
68
68
|
});
|
|
69
69
|
}
|
|
70
70
|
return {
|
|
71
|
-
find(tableName, builderFn) {
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
return uow.executeRetrieve();
|
|
71
|
+
async find(tableName, builderFn) {
|
|
72
|
+
const [result] = await createUOW({ config: uowConfig }).find(tableName, builderFn).executeRetrieve();
|
|
73
|
+
return result;
|
|
75
74
|
},
|
|
76
75
|
async findFirst(tableName, builderFn) {
|
|
77
76
|
const uow = createUOW({ config: uowConfig });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drizzle-query.js","names":["executor: UOWExecutor<DrizzleCompiledQuery, DrizzleResult>","whereConfig: { indexName?: string; condition?: unknown }","setValues: unknown"],"sources":["../../../src/adapters/drizzle/drizzle-query.ts"],"sourcesContent":["import type { AbstractQuery } from \"../../query/query\";\nimport type { AnySchema } from \"../../schema/create\";\nimport type { CompiledMutation, UOWExecutor } 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\";\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 * 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 find(tableName, builderFn) {\n const uow = createUOW({ config: uowConfig });\n uow.find(tableName, builderFn);\n return uow.executeRetrieve();\n },\n\n async findFirst(tableName, builderFn) {\n const uow = createUOW({ config: uowConfig });\n if (builderFn) {\n uow.find(tableName, (b) => builderFn(b as never).pageSize(1));\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 as string, values as never);\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 as string, values as never);\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 as string, id, builderFn as never);\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 // FIXME: This is not correct\n\n let whereConfig: { indexName?: string; condition?: unknown } = {};\n let setValues: unknown;\n\n const specialBuilder = {\n whereIndex(indexName: string, condition?: unknown) {\n whereConfig = { indexName, condition };\n return this;\n },\n set(values: unknown) {\n setValues = values;\n return this;\n },\n };\n\n builderFn(specialBuilder);\n\n if (!whereConfig.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 (whereConfig.condition) {\n return b.whereIndex(whereConfig.indexName as never, whereConfig.condition as never);\n }\n return b.whereIndex(whereConfig.indexName as never);\n });\n const findResults = await findUow.executeRetrieve();\n const records = (findResults as unknown as [unknown])[0];\n\n // @ts-expect-error - Type narrowing doesn't work through unknown cast\n if (!records || records.length === 0) {\n return;\n }\n\n const updateUow = createUOW({ config: uowConfig });\n for (const record of records as never as Array<{ id: unknown }>) {\n updateUow.update(tableName as string, record.id as string, (b) =>\n b.set(setValues as never),\n );\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 as string, id, builderFn as never);\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 let whereConfig: { indexName?: string; condition?: unknown } = {};\n\n const specialBuilder = {\n whereIndex(indexName: string, condition?: unknown) {\n whereConfig = { indexName, condition };\n return this;\n },\n };\n\n builderFn(specialBuilder as never);\n\n if (!whereConfig.indexName) {\n throw new Error(\"whereIndex() must be called in deleteMany\");\n }\n\n const findUow = createUOW({ config: uowConfig });\n findUow.find(tableName as string, (b) => {\n if (whereConfig.condition) {\n return b.whereIndex(whereConfig.indexName as never, whereConfig.condition as never);\n }\n return b.whereIndex(whereConfig.indexName as never);\n });\n const findResults2 = await findUow.executeRetrieve();\n const records = (findResults2 as unknown as [unknown])[0];\n\n // @ts-expect-error - Type narrowing doesn't work through unknown cast\n if (!records || records.length === 0) {\n return;\n }\n\n const deleteUow = createUOW({ config: uowConfig });\n for (const record of records as never as Array<{ id: unknown }>) {\n deleteUow.delete(tableName as string, 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":["executor: UOWExecutor<DrizzleCompiledQuery, DrizzleResult>","whereConfig: { indexName?: string; condition?: unknown }","setValues: unknown"],"sources":["../../../src/adapters/drizzle/drizzle-query.ts"],"sourcesContent":["import type { AbstractQuery } from \"../../query/query\";\nimport type { AnySchema } from \"../../schema/create\";\nimport type { CompiledMutation, UOWExecutor } 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\";\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 * 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 const uow = createUOW({ config: uowConfig }).find(tableName, builderFn);\n const [result] = await uow.executeRetrieve();\n return result;\n },\n\n async findFirst(tableName, builderFn) {\n const uow = createUOW({ config: uowConfig });\n if (builderFn) {\n uow.find(tableName, (b) => builderFn(b as never).pageSize(1));\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 as string, values as never);\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 as string, values as never);\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 as string, id, builderFn as never);\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 // FIXME: This is not correct\n\n let whereConfig: { indexName?: string; condition?: unknown } = {};\n let setValues: unknown;\n\n const specialBuilder = {\n whereIndex(indexName: string, condition?: unknown) {\n whereConfig = { indexName, condition };\n return this;\n },\n set(values: unknown) {\n setValues = values;\n return this;\n },\n };\n\n builderFn(specialBuilder);\n\n if (!whereConfig.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 (whereConfig.condition) {\n return b.whereIndex(whereConfig.indexName as never, whereConfig.condition as never);\n }\n return b.whereIndex(whereConfig.indexName as never);\n });\n const findResults = await findUow.executeRetrieve();\n const records = (findResults as unknown as [unknown])[0];\n\n // @ts-expect-error - Type narrowing doesn't work through unknown cast\n if (!records || records.length === 0) {\n return;\n }\n\n const updateUow = createUOW({ config: uowConfig });\n for (const record of records as never as Array<{ id: unknown }>) {\n updateUow.update(tableName as string, record.id as string, (b) =>\n b.set(setValues as never),\n );\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 as string, id, builderFn as never);\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 let whereConfig: { indexName?: string; condition?: unknown } = {};\n\n const specialBuilder = {\n whereIndex(indexName: string, condition?: unknown) {\n whereConfig = { indexName, condition };\n return this;\n },\n };\n\n builderFn(specialBuilder as never);\n\n if (!whereConfig.indexName) {\n throw new Error(\"whereIndex() must be called in deleteMany\");\n }\n\n const findUow = createUOW({ config: uowConfig });\n findUow.find(tableName as string, (b) => {\n if (whereConfig.condition) {\n return b.whereIndex(whereConfig.indexName as never, whereConfig.condition as never);\n }\n return b.whereIndex(whereConfig.indexName as never);\n });\n const findResults2 = await findUow.executeRetrieve();\n const records = (findResults2 as unknown as [unknown])[0];\n\n // @ts-expect-error - Type narrowing doesn't work through unknown cast\n if (!records || records.length === 0) {\n return;\n }\n\n const deleteUow = createUOW({ config: uowConfig });\n for (const record of records as never as Array<{ id: unknown }>) {\n deleteUow.delete(tableName as string, 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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+CA,SAAgB,YACd,QACA,MACA,UACA,QACA,WACoC;CACpC,SAAS,UAAU,MAAoD;EACrE,MAAM,cAAc,yBAAyB,QAAQ,MAAM,UAAU,OAAO;EAE5E,MAAMA,WAA6D;GACjE,MAAM,sBAAsB,gBAAwC;AAElE,QAAI,KAAK,QAAQ,OACf,QAAO,eAAe,WAAW;KAC/B,MAAM,EAAE;KACR,cAAc;KACf,EAAE;IAGL,MAAM,OAAO,MAAM,KAAK,SAAS;AACjC,QAAI;KACF,MAAM,KAAK,aAAa,KAAK,GAAG,CAAC;AACjC,YAAO,MAAM,6BAA6B,IAAI,gBAAgB,SAAS;cAC/D;AACR,WAAM,KAAK,SAAS;;;GAGxB,MAAM,qBAAqB,eAAyD;AAElF,QAAI,KAAK,QAAQ,OACf,QAAO;KACL,SAAS;KACT,oBAAoB,cAAc,UAAU,KAAK;KAClD;IAGH,MAAM,OAAO,MAAM,KAAK,SAAS;AACjC,QAAI;KACF,MAAM,KAAK,aAAa,KAAK,GAAG,CAAC;AACjC,YAAO,MAAM,4BAA4B,IAAI,eAAe,SAAS;cAC7D;AACR,WAAM,KAAK,SAAS;;;GAGzB;EAED,MAAM,UAAU,wBAAwB,QAAQ,SAAS;EAEzD,MAAM,EAAE,QAAS,GAAG,kBAAkB,KAAK,UAAU,EAAE;AAEvD,SAAO,IAAI,WAAW,QAAQ,aAAa,UAAU,SAAS,KAAK,MAAM;GACvE,GAAG;GACH,UAAU,UAAU;IAIlB,MAAM,cACJ,SAAS,OAAO,UAAU,YAAY,WAAW,QAC5C,MAAiD,QACjD;AAEP,SAAK,QAAQ,UAAU,YAAY;;GAEtC,CAAC;;AAGJ,QAAO;EACL,MAAM,KAAK,WAAW,WAAW;GAE/B,MAAM,CAAC,UAAU,MADL,UAAU,EAAE,QAAQ,WAAW,CAAC,CAAC,KAAK,WAAW,UAAU,CAC5C,iBAAiB;AAC5C,UAAO;;EAGT,MAAM,UAAU,WAAW,WAAW;GACpC,MAAM,MAAM,UAAU,EAAE,QAAQ,WAAW,CAAC;AAC5C,OAAI,UACF,KAAI,KAAK,YAAY,MAAM,UAAU,EAAW,CAAC,SAAS,EAAE,CAAC;OAE7D,KAAI,KAAK,YAAY,MAAM,EAAE,WAAW,UAAU,CAAC,SAAS,EAAE,CAAC;GAGjE,MAAM,CAAC,UAAuB,MAAM,IAAI,iBAAiB;AACzD,UAAO,SAAS,MAAM;;EAGxB,MAAM,OAAO,WAAW,QAAQ;GAC9B,MAAM,MAAM,UAAU,EAAE,QAAQ,WAAW,CAAC;AAC5C,OAAI,OAAO,WAAqB,OAAgB;GAChD,MAAM,EAAE,YAAY,MAAM,IAAI,kBAAkB;AAChD,OAAI,CAAC,QACH,OAAM,IAAI,MAAM,0BAA0B;GAI5C,MAAM,YADa,IAAI,eAAe,CACT;AAC7B,OAAI,CAAC,UACH,OAAM,IAAI,MAAM,2BAA2B;AAE7C,UAAO;;EAGT,MAAM,WAAW,WAAW,aAAa;GACvC,MAAM,MAAM,UAAU,EAAE,QAAQ,WAAW,CAAC;AAC5C,QAAK,MAAM,UAAU,YACnB,KAAI,OAAO,WAAqB,OAAgB;GAElD,MAAM,EAAE,YAAY,MAAM,IAAI,kBAAkB;AAChD,OAAI,CAAC,QACH,OAAM,IAAI,MAAM,2BAA2B;AAG7C,UAAO,IAAI,eAAe;;EAG5B,MAAM,OAAO,WAAW,IAAI,WAAW;GACrC,MAAM,MAAM,UAAU,EAAE,QAAQ,WAAW,CAAC;AAC5C,OAAI,OAAO,WAAqB,IAAI,UAAmB;GACvD,MAAM,EAAE,YAAY,MAAM,IAAI,kBAAkB;AAChD,OAAI,CAAC,QACH,OAAM,IAAI,MAAM,iEAAiE;;EAIrF,MAAM,WAAW,WAAW,WAAW;GAGrC,IAAIC,cAA2D,EAAE;GACjE,IAAIC;AAaJ,aAXuB;IACrB,WAAW,WAAmB,WAAqB;AACjD,mBAAc;MAAE;MAAW;MAAW;AACtC,YAAO;;IAET,IAAI,QAAiB;AACnB,iBAAY;AACZ,YAAO;;IAEV,CAEwB;AAEzB,OAAI,CAAC,YAAY,UACf,OAAM,IAAI,MAAM,4CAA4C;AAE9D,OAAI,CAAC,UACH,OAAM,IAAI,MAAM,qCAAqC;GAGvD,MAAM,UAAU,UAAU,EAAE,QAAQ,WAAW,CAAC;AAChD,WAAQ,KAAK,YAAY,MAAM;AAC7B,QAAI,YAAY,UACd,QAAO,EAAE,WAAW,YAAY,WAAoB,YAAY,UAAmB;AAErF,WAAO,EAAE,WAAW,YAAY,UAAmB;KACnD;GAEF,MAAM,WADc,MAAM,QAAQ,iBAAiB,EACG;AAGtD,OAAI,CAAC,WAAW,QAAQ,WAAW,EACjC;GAGF,MAAM,YAAY,UAAU,EAAE,QAAQ,WAAW,CAAC;AAClD,QAAK,MAAM,UAAU,QACnB,WAAU,OAAO,WAAqB,OAAO,KAAe,MAC1D,EAAE,IAAI,UAAmB,CAC1B;GAEH,MAAM,EAAE,YAAY,MAAM,UAAU,kBAAkB;AACtD,OAAI,CAAC,QACH,OAAM,IAAI,MAAM,8CAA8C;;EAIlE,MAAM,OAAO,WAAW,IAAI,WAAW;GACrC,MAAM,MAAM,UAAU,EAAE,QAAQ,WAAW,CAAC;AAC5C,OAAI,OAAO,WAAqB,IAAI,UAAmB;GACvD,MAAM,EAAE,YAAY,MAAM,IAAI,kBAAkB;AAChD,OAAI,CAAC,QACH,OAAM,IAAI,MAAM,iEAAiE;;EAIrF,MAAM,WAAW,WAAW,WAAW;GACrC,IAAID,cAA2D,EAAE;AASjE,aAPuB,EACrB,WAAW,WAAmB,WAAqB;AACjD,kBAAc;KAAE;KAAW;KAAW;AACtC,WAAO;MAEV,CAEiC;AAElC,OAAI,CAAC,YAAY,UACf,OAAM,IAAI,MAAM,4CAA4C;GAG9D,MAAM,UAAU,UAAU,EAAE,QAAQ,WAAW,CAAC;AAChD,WAAQ,KAAK,YAAsB,MAAM;AACvC,QAAI,YAAY,UACd,QAAO,EAAE,WAAW,YAAY,WAAoB,YAAY,UAAmB;AAErF,WAAO,EAAE,WAAW,YAAY,UAAmB;KACnD;GAEF,MAAM,WADe,MAAM,QAAQ,iBAAiB,EACG;AAGvD,OAAI,CAAC,WAAW,QAAQ,WAAW,EACjC;GAGF,MAAM,YAAY,UAAU,EAAE,QAAQ,WAAW,CAAC;AAClD,QAAK,MAAM,UAAU,QACnB,WAAU,OAAO,WAAqB,OAAO,GAAa;GAE5D,MAAM,EAAE,YAAY,MAAM,UAAU,kBAAkB;AACtD,OAAI,CAAC,QACH,OAAM,IAAI,MAAM,8CAA8C;;EAIlE,iBAAiB,MAAM,iBAAiB;AACtC,UAAO,UAAU;IACf;IACA,QAAQ;KACN,GAAG;KACH,GAAG;KACJ;IACF,CAAC;;EAEL"}
|
|
@@ -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":";;;;KAwBY,oBAAA"}
|
|
@@ -52,7 +52,19 @@ function createDrizzleUOWCompiler(schema, pool, provider, mapper) {
|
|
|
52
52
|
const op = condition.operator;
|
|
53
53
|
let right = condition.b;
|
|
54
54
|
if (right instanceof Column) right = toDrizzleColumn(right);
|
|
55
|
-
else
|
|
55
|
+
else if (condition.a.role === "reference" && typeof right === "string") {
|
|
56
|
+
const table = Object.values(schema.tables).find((t) => Object.values(t.columns).includes(condition.a));
|
|
57
|
+
if (table) {
|
|
58
|
+
const relation = Object.values(table.relations).find((rel) => rel.on.some(([localCol]) => localCol === condition.a.ormName));
|
|
59
|
+
if (relation) {
|
|
60
|
+
const refTable = relation.table;
|
|
61
|
+
const internalIdCol = refTable.getInternalIdColumn();
|
|
62
|
+
const idCol = refTable.getIdColumn();
|
|
63
|
+
const physicalTableName = mapper ? mapper.toPhysical(refTable.ormName) : refTable.ormName;
|
|
64
|
+
right = Drizzle.sql`(select ${Drizzle.sql.identifier(internalIdCol.name)} from ${Drizzle.sql.identifier(physicalTableName)} where ${Drizzle.sql.identifier(idCol.name)} = ${right} limit 1)`;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
} else right = serialize(right, condition.a, provider);
|
|
56
68
|
switch (op) {
|
|
57
69
|
case "=": return Drizzle.eq(left, right);
|
|
58
70
|
case "!=": return Drizzle.ne(left, right);
|
|
@@ -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 // Serialize non-Column values (e.g., FragnoId -> string, Date -> number for SQLite)\n right = serialize(right, condition.a, provider);\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 const cursorData = decodeCursor(cursor!);\n const serializedValues = serializeCursorValues(cursorData, 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} 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 const cursorData = decodeCursor(cursor!);\n const serializedValues = serializeCursorValues(cursorData, 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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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "drizzle-orm";
|
|
@@ -31,6 +31,8 @@ function fullSQLName(column, mapper) {
|
|
|
31
31
|
* @param condition - The condition tree to build the WHERE clause from
|
|
32
32
|
* @param eb - Kysely expression builder for constructing SQL expressions
|
|
33
33
|
* @param provider - The SQL provider (affects SQL generation)
|
|
34
|
+
* @param mapper - Optional table name mapper for namespace prefixing
|
|
35
|
+
* @param table - The table being queried (used for resolving reference columns)
|
|
34
36
|
* @returns A Kysely expression wrapper representing the WHERE clause
|
|
35
37
|
* @internal
|
|
36
38
|
*
|
|
@@ -45,12 +47,21 @@ function fullSQLName(column, mapper) {
|
|
|
45
47
|
* const whereClause = buildWhere(condition, eb, 'postgresql');
|
|
46
48
|
* ```
|
|
47
49
|
*/
|
|
48
|
-
function buildWhere(condition, eb, provider, mapper) {
|
|
50
|
+
function buildWhere(condition, eb, provider, mapper, table) {
|
|
49
51
|
if (condition.type === "compare") {
|
|
50
52
|
const left = condition.a;
|
|
51
53
|
const op = condition.operator;
|
|
52
54
|
let val = condition.b;
|
|
53
|
-
if (!(val instanceof Column))
|
|
55
|
+
if (!(val instanceof Column)) if (left.role === "reference" && typeof val === "string" && table) {
|
|
56
|
+
const relation = Object.values(table.relations).find((rel) => rel.on.some(([localCol]) => localCol === left.ormName));
|
|
57
|
+
if (relation) {
|
|
58
|
+
const refTable = relation.table;
|
|
59
|
+
const internalIdCol = refTable.getInternalIdColumn();
|
|
60
|
+
const idCol = refTable.getIdColumn();
|
|
61
|
+
const physicalTableName = mapper ? mapper.toPhysical(refTable.ormName) : refTable.ormName;
|
|
62
|
+
val = eb.selectFrom(physicalTableName).select(internalIdCol.name).where(idCol.name, "=", val).limit(1);
|
|
63
|
+
}
|
|
64
|
+
} else val = serialize(val, left, provider);
|
|
54
65
|
let v;
|
|
55
66
|
let rhs;
|
|
56
67
|
switch (op) {
|
|
@@ -84,9 +95,9 @@ function buildWhere(condition, eb, provider, mapper) {
|
|
|
84
95
|
}
|
|
85
96
|
return eb(fullSQLName(left, mapper), v, rhs);
|
|
86
97
|
}
|
|
87
|
-
if (condition.type === "and") return eb.and(condition.items.map((v) => buildWhere(v, eb, provider, mapper)));
|
|
88
|
-
if (condition.type === "not") return eb.not(buildWhere(condition.item, eb, provider, mapper));
|
|
89
|
-
return eb.or(condition.items.map((v) => buildWhere(v, eb, provider, mapper)));
|
|
98
|
+
if (condition.type === "and") return eb.and(condition.items.map((v) => buildWhere(v, eb, provider, mapper, table)));
|
|
99
|
+
if (condition.type === "not") return eb.not(buildWhere(condition.item, eb, provider, mapper, table));
|
|
100
|
+
return eb.or(condition.items.map((v) => buildWhere(v, eb, provider, mapper, table)));
|
|
90
101
|
}
|
|
91
102
|
/**
|
|
92
103
|
* Maps a select clause to SQL column names with optional aliases.
|
|
@@ -215,7 +226,7 @@ function createKyselyQueryBuilder(kysely, provider, mapper) {
|
|
|
215
226
|
return {
|
|
216
227
|
count(table, { where }) {
|
|
217
228
|
let query = kysely.selectFrom(getTableName(table)).select(kysely.fn.countAll().as("count"));
|
|
218
|
-
if (where) query = query.where((b) => buildWhere(where, b, provider, mapper));
|
|
229
|
+
if (where) query = query.where((b) => buildWhere(where, b, provider, mapper, table));
|
|
219
230
|
return query.compile();
|
|
220
231
|
},
|
|
221
232
|
create(table, values) {
|
|
@@ -228,7 +239,7 @@ function createKyselyQueryBuilder(kysely, provider, mapper) {
|
|
|
228
239
|
findMany(table, v) {
|
|
229
240
|
let query = kysely.selectFrom(getTableName(table));
|
|
230
241
|
const where = v.where;
|
|
231
|
-
if (where) query = query.where((eb) => buildWhere(where, eb, provider, mapper));
|
|
242
|
+
if (where) query = query.where((eb) => buildWhere(where, eb, provider, mapper, table));
|
|
232
243
|
if (v.offset !== void 0) query = query.offset(v.offset);
|
|
233
244
|
if (v.limit !== void 0) query = provider === "mssql" ? query.top(v.limit) : query.limit(v.limit);
|
|
234
245
|
if (v.orderBy) for (const [col, mode] of v.orderBy) query = query.orderBy(fullSQLName(col, mapper), mode);
|
|
@@ -251,7 +262,7 @@ function createKyselyQueryBuilder(kysely, provider, mapper) {
|
|
|
251
262
|
const actualRight = targetTable.columns[right]?.role === "external-id" ? "_internalId" : right;
|
|
252
263
|
conditions.push(eb(`${parentTableName}.${parentTable.columns[left].name}`, "=", eb.ref(`${joinName}.${targetTable.columns[actualRight].name}`)));
|
|
253
264
|
}
|
|
254
|
-
if (joinOptions.where) conditions.push(buildWhere(joinOptions.where, eb, provider, mapper));
|
|
265
|
+
if (joinOptions.where) conditions.push(buildWhere(joinOptions.where, eb, provider, mapper, targetTable));
|
|
255
266
|
return eb.and(conditions);
|
|
256
267
|
}));
|
|
257
268
|
processJoins(joinOptions.join, targetTable, joinName, fullPath);
|
|
@@ -268,20 +279,20 @@ function createKyselyQueryBuilder(kysely, provider, mapper) {
|
|
|
268
279
|
processed[versionCol.name] = sql.raw(`COALESCE(${versionCol.name}, 0) + 1`);
|
|
269
280
|
let query = kysely.updateTable(getTableName(table)).set(processed);
|
|
270
281
|
const { where } = v;
|
|
271
|
-
if (where) query = query.where((eb) => buildWhere(where, eb, provider, mapper));
|
|
282
|
+
if (where) query = query.where((eb) => buildWhere(where, eb, provider, mapper, table));
|
|
272
283
|
return query.compile();
|
|
273
284
|
},
|
|
274
285
|
upsertCheck(table, where) {
|
|
275
286
|
const idColumn = table.getIdColumn();
|
|
276
287
|
let query = kysely.selectFrom(getTableName(table)).select([`${idColumn.name} as id`]);
|
|
277
|
-
if (where) query = query.where((b) => buildWhere(where, b, provider, mapper));
|
|
288
|
+
if (where) query = query.where((b) => buildWhere(where, b, provider, mapper, table));
|
|
278
289
|
return query.limit(1).compile();
|
|
279
290
|
},
|
|
280
291
|
upsertUpdate(table, update, where, top) {
|
|
281
292
|
const processed = processReferenceSubqueries(encodeValues(update, table, false, provider), kysely, mapper);
|
|
282
293
|
let query = kysely.updateTable(getTableName(table)).set(processed);
|
|
283
294
|
if (top) query = query.top(1);
|
|
284
|
-
if (where) query = query.where((b) => buildWhere(where, b, provider, mapper));
|
|
295
|
+
if (where) query = query.where((b) => buildWhere(where, b, provider, mapper, table));
|
|
285
296
|
return query.compile();
|
|
286
297
|
},
|
|
287
298
|
upsertUpdateById(table, update, id) {
|
|
@@ -295,7 +306,7 @@ function createKyselyQueryBuilder(kysely, provider, mapper) {
|
|
|
295
306
|
},
|
|
296
307
|
deleteMany(table, { where }) {
|
|
297
308
|
let query = kysely.deleteFrom(getTableName(table));
|
|
298
|
-
if (where) query = query.where((eb) => buildWhere(where, eb, provider, mapper));
|
|
309
|
+
if (where) query = query.where((eb) => buildWhere(where, eb, provider, mapper, table));
|
|
299
310
|
return query.compile();
|
|
300
311
|
},
|
|
301
312
|
findById(table, idValue) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kysely-query-builder.js","names":["v: BinaryOperator","rhs: unknown","out: string[]","extendedKeys: string[]","processed: Record<string, unknown>","mappedSelect: string[]"],"sources":["../../../src/adapters/kysely/kysely-query-builder.ts"],"sourcesContent":["import {\n type BinaryOperator,\n type CompiledQuery,\n type ExpressionBuilder,\n type ExpressionWrapper,\n type Kysely,\n sql,\n} from \"kysely\";\nimport type { AnySelectClause, FindManyOptions } from \"../../query/query\";\nimport type { SqlBool } from \"kysely\";\nimport { type AnyColumn, type AnyTable, Column } from \"../../schema/create\";\nimport type { SQLProvider } from \"../../shared/providers\";\nimport type { Condition } from \"../../query/condition-builder\";\nimport { serialize } from \"../../schema/serialize\";\nimport type { CompiledJoin, SimplifyFindOptions } from \"../../query/orm/orm\";\nimport { decodeResult, encodeValues, ReferenceSubquery } from \"../../query/result-transform\";\nimport type { TableNameMapper } from \"./kysely-shared\";\n\n/**\n * Returns the fully qualified SQL name for a column (table.column).\n *\n * @param column - The column to get the full name for\n * @param mapper - Optional table name mapper for namespace prefixing\n * @returns The fully qualified SQL name in the format \"tableName.columnName\"\n * @internal\n *\n * @example\n * ```ts\n * fullSQLName(userTable.columns.email)\n * // Returns: \"users.email\"\n * ```\n */\nexport function fullSQLName(column: AnyColumn, mapper?: TableNameMapper) {\n const tableName = mapper ? mapper.toPhysical(column.tableName) : column.tableName;\n return `${tableName}.${column.name}`;\n}\n\n/**\n * Builds a WHERE clause expression from a Condition tree.\n *\n * Recursively processes condition objects to build Kysely WHERE expressions.\n * Handles comparison operators, logical AND/OR/NOT, and special string operators\n * like \"contains\", \"starts with\", and \"ends with\".\n *\n * @param condition - The condition tree to build the WHERE clause from\n * @param eb - Kysely expression builder for constructing SQL expressions\n * @param provider - The SQL provider (affects SQL generation)\n * @returns A Kysely expression wrapper representing the WHERE clause\n * @internal\n *\n * @example\n * ```ts\n * const condition = {\n * type: \"compare\",\n * a: userTable.columns.name,\n * operator: \"contains\",\n * b: \"john\"\n * };\n * const whereClause = buildWhere(condition, eb, 'postgresql');\n * ```\n */\nexport function buildWhere(\n condition: Condition,\n eb: ExpressionBuilder<any, any>, // eslint-disable-line @typescript-eslint/no-explicit-any\n provider: SQLProvider,\n mapper?: TableNameMapper,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): ExpressionWrapper<any, any, SqlBool> {\n if (condition.type === \"compare\") {\n const left = condition.a;\n const op = condition.operator;\n let val = condition.b;\n\n if (!(val instanceof Column)) {\n val = serialize(val, left, provider);\n }\n\n let v: BinaryOperator;\n let rhs: unknown;\n\n switch (op) {\n case \"contains\":\n v = \"like\";\n rhs =\n val instanceof Column\n ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))}, '%')`\n : `%${val}%`;\n break;\n case \"not contains\":\n v = \"not like\";\n rhs =\n val instanceof Column\n ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))}, '%')`\n : `%${val}%`;\n break;\n case \"starts with\":\n v = \"like\";\n rhs =\n val instanceof Column ? sql`concat(${eb.ref(fullSQLName(val, mapper))}, '%')` : `${val}%`;\n break;\n case \"not starts with\":\n v = \"not like\";\n rhs =\n val instanceof Column ? sql`concat(${eb.ref(fullSQLName(val, mapper))}, '%')` : `${val}%`;\n break;\n case \"ends with\":\n v = \"like\";\n rhs =\n val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))})` : `%${val}`;\n break;\n case \"not ends with\":\n v = \"not like\";\n rhs =\n val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))})` : `%${val}`;\n break;\n default:\n v = op;\n rhs = val instanceof Column ? eb.ref(fullSQLName(val, mapper)) : val;\n }\n\n return eb(fullSQLName(left, mapper), v, rhs);\n }\n\n // Nested conditions\n if (condition.type === \"and\") {\n return eb.and(condition.items.map((v) => buildWhere(v, eb, provider, mapper)));\n }\n\n if (condition.type === \"not\") {\n return eb.not(buildWhere(condition.item, eb, provider, mapper));\n }\n\n return eb.or(condition.items.map((v) => buildWhere(v, eb, provider, mapper)));\n}\n\n/**\n * Maps a select clause to SQL column names with optional aliases.\n *\n * Converts application-level select clauses (either array of keys or \"select all\")\n * into SQL-compatible column selections with proper aliasing for relations.\n *\n * @param select - The select clause (array of keys or true for all columns)\n * @param table - The table schema containing column definitions\n * @param options - Optional configuration\n * @param options.relation - Relation name to prefix in aliases (for joined data)\n * @param options.tableName - Override the table name in the SQL (defaults to table.name)\n * @returns Array of SQL select strings in the format \"tableName.columnName as alias\"\n * @internal\n *\n * @example\n * ```ts\n * mapSelect(['id', 'name'], userTable)\n * // Returns: ['users.id as id', 'users.name as name']\n *\n * mapSelect(['title'], postTable, { relation: 'posts' })\n * // Returns: ['posts.title as posts:title']\n * ```\n */\nexport function mapSelect(\n select: AnySelectClause,\n table: AnyTable,\n options: {\n relation?: string;\n tableName?: string;\n } = {},\n): string[] {\n const { relation, tableName = table.name } = options;\n const out: string[] = [];\n const keys = Array.isArray(select) ? select : Object.keys(table.columns);\n\n for (const key of keys) {\n const col = table.columns[key];\n\n // Skip hidden columns when explicitly selecting\n if (Array.isArray(select) && col.isHidden) {\n continue;\n }\n\n // Add the column to the select list\n const name = relation ? `${relation}:${key}` : key;\n out.push(`${tableName}.${col.name} as ${name}`);\n }\n\n // Always include hidden columns (for FragnoId construction with internal ID and version)\n for (const key in table.columns) {\n const col = table.columns[key];\n if (col.isHidden && !keys.includes(key)) {\n const name = relation ? `${relation}:${key}` : key;\n out.push(`${tableName}.${col.name} as ${name}`);\n }\n }\n\n return out;\n}\n\n/**\n * Result type from compiling a select clause with extensions.\n * @internal\n */\nexport interface CompiledSelect {\n /**\n * The final select clause to use in the query\n */\n result: AnySelectClause;\n\n /**\n * Keys that were added to the select clause (not originally requested)\n */\n extendedKeys: string[];\n\n /**\n * Removes the extended keys from a record (mutates the record).\n * Used to clean up keys that were only needed for join operations.\n *\n * @param record - The record to remove extended keys from\n * @returns The same record with extended keys removed\n */\n removeExtendedKeys: (record: Record<string, unknown>) => Record<string, unknown>;\n}\n\n/**\n * Builder for extending a select clause with additional keys.\n * @internal\n */\nexport interface SelectBuilder {\n /**\n * Adds a key to the select clause if not already present.\n * Tracks which keys were added for later removal.\n *\n * @param key - The key to add to the select clause\n */\n extend: (key: string) => void;\n\n /**\n * Compiles the select clause into its final form.\n *\n * @returns The compiled select information\n */\n compile: () => CompiledSelect;\n}\n\n/**\n * Creates a builder that can extend a select clause with additional keys.\n *\n * This is useful when you need to temporarily include columns for join operations\n * or other internal processing, but don't want them in the final result.\n *\n * @param original - The original select clause from the user\n * @returns A select builder with extend() and compile() methods\n * @internal\n *\n * @example\n * ```ts\n * const builder = extendSelect(['name', 'email']);\n * builder.extend('id'); // Add id for join operation\n * const { result, removeExtendedKeys } = builder.compile();\n * // result: ['name', 'email', 'id']\n *\n * const record = { name: 'John', email: 'j@ex.com', id: 123 };\n * removeExtendedKeys(record);\n * // record: { name: 'John', email: 'j@ex.com' }\n * ```\n */\nexport function extendSelect(original: AnySelectClause): SelectBuilder {\n const select = Array.isArray(original) ? new Set(original) : true;\n const extendedKeys: string[] = [];\n\n return {\n extend(key) {\n if (select === true || select.has(key)) {\n return;\n }\n\n select.add(key);\n extendedKeys.push(key);\n },\n compile() {\n return {\n result: select instanceof Set ? Array.from(select) : true,\n extendedKeys,\n removeExtendedKeys(record) {\n for (const key of extendedKeys) {\n delete record[key];\n }\n return record;\n },\n };\n },\n };\n}\n\n/**\n * Executes a SELECT query to find multiple records.\n *\n * Builds and executes a Kysely query with the provided options including\n * filtering (where), ordering (orderBy), pagination (limit/offset), and\n * column selection (select).\n *\n * @param kysely - The Kysely database instance\n * @param provider - The SQL provider (affects SQL generation)\n * @param table - The table to query from\n * @param v - Query options including where, select, orderBy, limit, and offset\n * @param runSubQueryJoin - Function to execute subquery joins on the results\n * @returns Array of decoded records matching the query criteria\n * @internal\n *\n * @example\n * ```ts\n * const records = await findMany(kysely, 'postgresql', userTable, {\n * where: someCondition,\n * orderBy: [['name', 'asc']],\n * limit: 10\n * });\n * ```\n */\nexport async function findMany(\n kysely: Kysely<any>, // eslint-disable-line @typescript-eslint/no-explicit-any\n provider: SQLProvider,\n table: AnyTable,\n v: SimplifyFindOptions<FindManyOptions>,\n runSubQueryJoin: (records: Record<string, unknown>[], join: CompiledJoin) => Promise<void>,\n) {\n let query = kysely.selectFrom(table.name);\n\n const where = v.where;\n if (where) {\n query = query.where((eb) => buildWhere(where, eb, provider));\n }\n\n if (v.offset !== undefined) {\n query = query.offset(v.offset);\n }\n\n if (v.limit !== undefined) {\n query = provider === \"mssql\" ? query.top(v.limit) : query.limit(v.limit);\n }\n\n if (v.orderBy) {\n for (const [col, mode] of v.orderBy) {\n query = query.orderBy(fullSQLName(col), mode);\n }\n }\n\n const selectBuilder = extendSelect(v.select);\n const mappedSelect: string[] = [];\n const subqueryJoins: CompiledJoin[] = [];\n\n const compiledSelect = selectBuilder.compile();\n mappedSelect.push(...mapSelect(compiledSelect.result, table));\n\n const records = (await query.select(mappedSelect).execute()).map((v) =>\n decodeResult(v, table, provider),\n );\n\n await Promise.all(subqueryJoins.map((join) => runSubQueryJoin(records, join)));\n for (const record of records) {\n compiledSelect.removeExtendedKeys(record);\n }\n\n return records;\n}\n\n/**\n * Processes encoded values and replaces ReferenceSubquery markers with actual SQL subqueries.\n *\n * @param values - The encoded values that may contain ReferenceSubquery objects\n * @param kysely - The Kysely database instance for building subqueries\n * @param mapper - Optional table name mapper for namespace prefixing\n * @returns Processed values with subqueries in place of ReferenceSubquery markers\n * @internal\n */\nfunction processReferenceSubqueries(\n values: Record<string, unknown>,\n kysely: Kysely<any>, // eslint-disable-line @typescript-eslint/no-explicit-any\n mapper?: TableNameMapper,\n): Record<string, unknown> {\n const processed: Record<string, unknown> = {};\n const getTableName = (table: AnyTable) => (mapper ? mapper.toPhysical(table.name) : table.name);\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\n // Build a subquery: SELECT _internal_id FROM referenced_table WHERE id = external_id LIMIT 1\n processed[key] = kysely\n .selectFrom(getTableName(refTable))\n .select(refTable.getInternalIdColumn().name)\n .where(refTable.getIdColumn().name, \"=\", externalId)\n .limit(1);\n } else {\n processed[key] = value;\n }\n }\n\n return processed;\n}\n\n/**\n * Creates a query compiler that builds and compiles Kysely queries without executing them.\n *\n * Each method takes table and query parameters and returns a CompiledQuery that can be\n * executed later using kysely.executeQuery().\n *\n * @param kysely - The Kysely database instance\n * @param provider - The SQL provider (affects SQL generation)\n * @returns An object with methods for compiling various database operations\n * @internal\n *\n * @example\n * ```ts\n * const builder = createKyselyQueryBuilder(kysely, 'postgresql');\n * const query = builder.count(userTable, { where: someCondition });\n * const result = await kysely.executeQuery(query);\n * ```\n */\nexport function createKyselyQueryBuilder(\n kysely: Kysely<any>, // eslint-disable-line @typescript-eslint/no-explicit-any\n provider: SQLProvider,\n mapper?: TableNameMapper,\n) {\n // Helper to get the physical table name (with namespace suffix if mapper is provided)\n const getTableName = (table: AnyTable) => (mapper ? mapper.toPhysical(table.name) : table.name);\n\n return {\n count(table: AnyTable, { where }: { where?: Condition }): CompiledQuery {\n let query = kysely.selectFrom(getTableName(table)).select(kysely.fn.countAll().as(\"count\"));\n if (where) {\n query = query.where((b) => buildWhere(where, b, provider, mapper));\n }\n return query.compile();\n },\n\n create(table: AnyTable, values: Record<string, unknown>): CompiledQuery {\n const encodedValues = encodeValues(values, table, true, provider);\n const processedValues = processReferenceSubqueries(encodedValues, kysely, mapper);\n const insert = kysely.insertInto(getTableName(table)).values(processedValues);\n\n if (provider === \"mssql\") {\n return (\n insert\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n .output(mapSelect(true, table, { tableName: \"inserted\" }) as any[])\n .compile()\n );\n }\n\n if (provider === \"postgresql\" || provider === \"sqlite\") {\n return insert\n .returning(mapSelect(true, table, { tableName: getTableName(table) }))\n .compile();\n }\n\n // For MySQL/other providers, return the insert query\n return insert.compile();\n },\n\n findMany<T extends AnyTable>(\n table: T,\n v: SimplifyFindOptions<FindManyOptions<T>>,\n ): CompiledQuery {\n let query = kysely.selectFrom(getTableName(table));\n\n const where = v.where;\n if (where) {\n query = query.where((eb) => buildWhere(where, eb, provider, mapper));\n }\n\n if (v.offset !== undefined) {\n query = query.offset(v.offset);\n }\n\n if (v.limit !== undefined) {\n query = provider === \"mssql\" ? query.top(v.limit) : query.limit(v.limit);\n }\n\n if (v.orderBy) {\n for (const [col, mode] of v.orderBy) {\n query = query.orderBy(fullSQLName(col, mapper), mode);\n }\n }\n\n const selectBuilder = extendSelect(v.select);\n const mappedSelect: string[] = [];\n\n // Process joins recursively to support nested joins\n const processJoins = (\n joins: CompiledJoin[] | undefined,\n parentTable: AnyTable,\n parentTableName: string,\n parentPath: string = \"\",\n ) => {\n for (const join of joins ?? []) {\n const { options: joinOptions, relation } = join;\n\n if (joinOptions === false) {\n continue;\n }\n\n const targetTable = relation.table;\n // Build the full path for this join (e.g., \"author:inviter\")\n const fullPath = parentPath ? `${parentPath}:${relation.name}` : relation.name;\n // SQL table alias uses underscores (e.g., \"author_inviter\")\n const joinName = fullPath.replace(/:/g, \"_\");\n\n // update select\n mappedSelect.push(\n ...mapSelect(joinOptions.select, targetTable, {\n relation: fullPath, // Use full path with colons for column aliases\n tableName: joinName, // Use underscore version for table name\n }),\n );\n\n query = query.leftJoin(`${getTableName(targetTable)} as ${joinName}`, (b) =>\n b.on((eb) => {\n const conditions = [];\n for (const [left, right] of relation.on) {\n // Foreign keys always use internal IDs\n // If the relation references an external ID column (any name), translate to \"_internalId\"\n const rightCol = targetTable.columns[right];\n const actualRight = rightCol?.role === \"external-id\" ? \"_internalId\" : right;\n\n conditions.push(\n eb(\n `${parentTableName}.${parentTable.columns[left].name}`,\n \"=\",\n eb.ref(`${joinName}.${targetTable.columns[actualRight].name}`),\n ),\n );\n }\n\n if (joinOptions.where) {\n conditions.push(buildWhere(joinOptions.where, eb, provider, mapper));\n }\n\n return eb.and(conditions);\n }),\n );\n\n // Recursively process nested joins with the full path\n processJoins(joinOptions.join, targetTable, joinName, fullPath);\n }\n };\n\n processJoins(v.join, table, getTableName(table));\n\n const compiledSelect = selectBuilder.compile();\n mappedSelect.push(\n ...mapSelect(compiledSelect.result, table, { tableName: getTableName(table) }),\n );\n\n return query.select(mappedSelect).compile();\n },\n\n updateMany(\n table: AnyTable,\n v: {\n where?: Condition;\n set: Record<string, unknown>;\n },\n ): CompiledQuery {\n const encoded = encodeValues(v.set, table, false, provider);\n const processed = processReferenceSubqueries(encoded, kysely, mapper);\n\n // Automatically increment _version for optimistic concurrency control\n const versionCol = table.getVersionColumn();\n // Safe cast: we're building a SQL expression for incrementing the version\n processed[versionCol.name] = sql.raw(`COALESCE(${versionCol.name}, 0) + 1`) as unknown;\n\n let query = kysely.updateTable(getTableName(table)).set(processed);\n const { where } = v;\n if (where) {\n query = query.where((eb) => buildWhere(where, eb, provider, mapper));\n }\n return query.compile();\n },\n\n upsertCheck(table: AnyTable, where: Condition | undefined): CompiledQuery {\n const idColumn = table.getIdColumn();\n let query = kysely.selectFrom(getTableName(table)).select([`${idColumn.name} as id`]);\n if (where) {\n query = query.where((b) => buildWhere(where, b, provider, mapper));\n }\n return query.limit(1).compile();\n },\n\n upsertUpdate(\n table: AnyTable,\n update: Record<string, unknown>,\n where: Condition | undefined,\n top?: boolean,\n ): CompiledQuery {\n const encoded = encodeValues(update, table, false, provider);\n const processed = processReferenceSubqueries(encoded, kysely, mapper);\n let query = kysely.updateTable(getTableName(table)).set(processed);\n if (top) {\n query = query.top(1);\n }\n if (where) {\n query = query.where((b) => buildWhere(where, b, provider, mapper));\n }\n return query.compile();\n },\n\n upsertUpdateById(table: AnyTable, update: Record<string, unknown>, id: unknown): CompiledQuery {\n const idColumn = table.getIdColumn();\n const encoded = encodeValues(update, table, false, provider);\n const processed = processReferenceSubqueries(encoded, kysely, mapper);\n return kysely\n .updateTable(getTableName(table))\n .set(processed)\n .where(idColumn.name, \"=\", id)\n .compile();\n },\n\n createMany(table: AnyTable, values: Record<string, unknown>[]): CompiledQuery {\n const encodedValues = values.map((v) => encodeValues(v, table, true, provider));\n const processedValues = encodedValues.map((v) =>\n processReferenceSubqueries(v, kysely, mapper),\n );\n return kysely.insertInto(getTableName(table)).values(processedValues).compile();\n },\n\n deleteMany(table: AnyTable, { where }: { where?: Condition }): CompiledQuery {\n let query = kysely.deleteFrom(getTableName(table));\n if (where) {\n query = query.where((eb) => buildWhere(where, eb, provider, mapper));\n }\n return query.compile();\n },\n\n findById(table: AnyTable, idValue: unknown): CompiledQuery {\n const idColumn = table.getIdColumn();\n return kysely\n .selectFrom(getTableName(table))\n .select(mapSelect(true, table, { tableName: getTableName(table) }))\n .where(idColumn.name, \"=\", idValue)\n .limit(1)\n .compile();\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"kysely-query-builder.js","names":["v: BinaryOperator","rhs: unknown","out: string[]","extendedKeys: string[]","processed: Record<string, unknown>","mappedSelect: string[]"],"sources":["../../../src/adapters/kysely/kysely-query-builder.ts"],"sourcesContent":["import {\n type BinaryOperator,\n type CompiledQuery,\n type ExpressionBuilder,\n type ExpressionWrapper,\n type Kysely,\n sql,\n} from \"kysely\";\nimport type { AnySelectClause, FindManyOptions } from \"../../query/query\";\nimport type { SqlBool } from \"kysely\";\nimport { type AnyColumn, type AnyTable, Column } from \"../../schema/create\";\nimport type { SQLProvider } from \"../../shared/providers\";\nimport type { Condition } from \"../../query/condition-builder\";\nimport { serialize } from \"../../schema/serialize\";\nimport type { CompiledJoin, SimplifyFindOptions } from \"../../query/orm/orm\";\nimport { decodeResult, encodeValues, ReferenceSubquery } from \"../../query/result-transform\";\nimport type { TableNameMapper } from \"./kysely-shared\";\n\n/**\n * Returns the fully qualified SQL name for a column (table.column).\n *\n * @param column - The column to get the full name for\n * @param mapper - Optional table name mapper for namespace prefixing\n * @returns The fully qualified SQL name in the format \"tableName.columnName\"\n * @internal\n *\n * @example\n * ```ts\n * fullSQLName(userTable.columns.email)\n * // Returns: \"users.email\"\n * ```\n */\nexport function fullSQLName(column: AnyColumn, mapper?: TableNameMapper) {\n const tableName = mapper ? mapper.toPhysical(column.tableName) : column.tableName;\n return `${tableName}.${column.name}`;\n}\n\n/**\n * Builds a WHERE clause expression from a Condition tree.\n *\n * Recursively processes condition objects to build Kysely WHERE expressions.\n * Handles comparison operators, logical AND/OR/NOT, and special string operators\n * like \"contains\", \"starts with\", and \"ends with\".\n *\n * @param condition - The condition tree to build the WHERE clause from\n * @param eb - Kysely expression builder for constructing SQL expressions\n * @param provider - The SQL provider (affects SQL generation)\n * @param mapper - Optional table name mapper for namespace prefixing\n * @param table - The table being queried (used for resolving reference columns)\n * @returns A Kysely expression wrapper representing the WHERE clause\n * @internal\n *\n * @example\n * ```ts\n * const condition = {\n * type: \"compare\",\n * a: userTable.columns.name,\n * operator: \"contains\",\n * b: \"john\"\n * };\n * const whereClause = buildWhere(condition, eb, 'postgresql');\n * ```\n */\nexport function buildWhere(\n condition: Condition,\n eb: ExpressionBuilder<any, any>, // eslint-disable-line @typescript-eslint/no-explicit-any\n provider: SQLProvider,\n mapper?: TableNameMapper,\n table?: AnyTable,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): ExpressionWrapper<any, any, SqlBool> {\n if (condition.type === \"compare\") {\n const left = condition.a;\n const op = condition.operator;\n let val = condition.b;\n\n if (!(val instanceof Column)) {\n // Handle string references - convert external ID to internal ID via subquery\n if (left.role === \"reference\" && typeof val === \"string\" && table) {\n // Find relation that uses this column\n const relation = Object.values(table.relations).find((rel) =>\n rel.on.some(([localCol]) => localCol === left.ormName),\n );\n if (relation) {\n const refTable = relation.table;\n const internalIdCol = refTable.getInternalIdColumn();\n const idCol = refTable.getIdColumn();\n const physicalTableName = mapper ? mapper.toPhysical(refTable.ormName) : refTable.ormName;\n\n // Build a SQL subquery\n val = eb\n .selectFrom(physicalTableName)\n .select(internalIdCol.name)\n .where(idCol.name, \"=\", val)\n .limit(1);\n }\n } else {\n val = serialize(val, left, provider);\n }\n }\n\n let v: BinaryOperator;\n let rhs: unknown;\n\n switch (op) {\n case \"contains\":\n v = \"like\";\n rhs =\n val instanceof Column\n ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))}, '%')`\n : `%${val}%`;\n break;\n case \"not contains\":\n v = \"not like\";\n rhs =\n val instanceof Column\n ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))}, '%')`\n : `%${val}%`;\n break;\n case \"starts with\":\n v = \"like\";\n rhs =\n val instanceof Column ? sql`concat(${eb.ref(fullSQLName(val, mapper))}, '%')` : `${val}%`;\n break;\n case \"not starts with\":\n v = \"not like\";\n rhs =\n val instanceof Column ? sql`concat(${eb.ref(fullSQLName(val, mapper))}, '%')` : `${val}%`;\n break;\n case \"ends with\":\n v = \"like\";\n rhs =\n val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))})` : `%${val}`;\n break;\n case \"not ends with\":\n v = \"not like\";\n rhs =\n val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))})` : `%${val}`;\n break;\n default:\n v = op;\n rhs = val instanceof Column ? eb.ref(fullSQLName(val, mapper)) : val;\n }\n\n return eb(fullSQLName(left, mapper), v, rhs);\n }\n\n // Nested conditions\n if (condition.type === \"and\") {\n return eb.and(condition.items.map((v) => buildWhere(v, eb, provider, mapper, table)));\n }\n\n if (condition.type === \"not\") {\n return eb.not(buildWhere(condition.item, eb, provider, mapper, table));\n }\n\n return eb.or(condition.items.map((v) => buildWhere(v, eb, provider, mapper, table)));\n}\n\n/**\n * Maps a select clause to SQL column names with optional aliases.\n *\n * Converts application-level select clauses (either array of keys or \"select all\")\n * into SQL-compatible column selections with proper aliasing for relations.\n *\n * @param select - The select clause (array of keys or true for all columns)\n * @param table - The table schema containing column definitions\n * @param options - Optional configuration\n * @param options.relation - Relation name to prefix in aliases (for joined data)\n * @param options.tableName - Override the table name in the SQL (defaults to table.name)\n * @returns Array of SQL select strings in the format \"tableName.columnName as alias\"\n * @internal\n *\n * @example\n * ```ts\n * mapSelect(['id', 'name'], userTable)\n * // Returns: ['users.id as id', 'users.name as name']\n *\n * mapSelect(['title'], postTable, { relation: 'posts' })\n * // Returns: ['posts.title as posts:title']\n * ```\n */\nexport function mapSelect(\n select: AnySelectClause,\n table: AnyTable,\n options: {\n relation?: string;\n tableName?: string;\n } = {},\n): string[] {\n const { relation, tableName = table.name } = options;\n const out: string[] = [];\n const keys = Array.isArray(select) ? select : Object.keys(table.columns);\n\n for (const key of keys) {\n const col = table.columns[key];\n\n // Skip hidden columns when explicitly selecting\n if (Array.isArray(select) && col.isHidden) {\n continue;\n }\n\n // Add the column to the select list\n const name = relation ? `${relation}:${key}` : key;\n out.push(`${tableName}.${col.name} as ${name}`);\n }\n\n // Always include hidden columns (for FragnoId construction with internal ID and version)\n for (const key in table.columns) {\n const col = table.columns[key];\n if (col.isHidden && !keys.includes(key)) {\n const name = relation ? `${relation}:${key}` : key;\n out.push(`${tableName}.${col.name} as ${name}`);\n }\n }\n\n return out;\n}\n\n/**\n * Result type from compiling a select clause with extensions.\n * @internal\n */\nexport interface CompiledSelect {\n /**\n * The final select clause to use in the query\n */\n result: AnySelectClause;\n\n /**\n * Keys that were added to the select clause (not originally requested)\n */\n extendedKeys: string[];\n\n /**\n * Removes the extended keys from a record (mutates the record).\n * Used to clean up keys that were only needed for join operations.\n *\n * @param record - The record to remove extended keys from\n * @returns The same record with extended keys removed\n */\n removeExtendedKeys: (record: Record<string, unknown>) => Record<string, unknown>;\n}\n\n/**\n * Builder for extending a select clause with additional keys.\n * @internal\n */\nexport interface SelectBuilder {\n /**\n * Adds a key to the select clause if not already present.\n * Tracks which keys were added for later removal.\n *\n * @param key - The key to add to the select clause\n */\n extend: (key: string) => void;\n\n /**\n * Compiles the select clause into its final form.\n *\n * @returns The compiled select information\n */\n compile: () => CompiledSelect;\n}\n\n/**\n * Creates a builder that can extend a select clause with additional keys.\n *\n * This is useful when you need to temporarily include columns for join operations\n * or other internal processing, but don't want them in the final result.\n *\n * @param original - The original select clause from the user\n * @returns A select builder with extend() and compile() methods\n * @internal\n *\n * @example\n * ```ts\n * const builder = extendSelect(['name', 'email']);\n * builder.extend('id'); // Add id for join operation\n * const { result, removeExtendedKeys } = builder.compile();\n * // result: ['name', 'email', 'id']\n *\n * const record = { name: 'John', email: 'j@ex.com', id: 123 };\n * removeExtendedKeys(record);\n * // record: { name: 'John', email: 'j@ex.com' }\n * ```\n */\nexport function extendSelect(original: AnySelectClause): SelectBuilder {\n const select = Array.isArray(original) ? new Set(original) : true;\n const extendedKeys: string[] = [];\n\n return {\n extend(key) {\n if (select === true || select.has(key)) {\n return;\n }\n\n select.add(key);\n extendedKeys.push(key);\n },\n compile() {\n return {\n result: select instanceof Set ? Array.from(select) : true,\n extendedKeys,\n removeExtendedKeys(record) {\n for (const key of extendedKeys) {\n delete record[key];\n }\n return record;\n },\n };\n },\n };\n}\n\n/**\n * Executes a SELECT query to find multiple records.\n *\n * Builds and executes a Kysely query with the provided options including\n * filtering (where), ordering (orderBy), pagination (limit/offset), and\n * column selection (select).\n *\n * @param kysely - The Kysely database instance\n * @param provider - The SQL provider (affects SQL generation)\n * @param table - The table to query from\n * @param v - Query options including where, select, orderBy, limit, and offset\n * @param runSubQueryJoin - Function to execute subquery joins on the results\n * @returns Array of decoded records matching the query criteria\n * @internal\n *\n * @example\n * ```ts\n * const records = await findMany(kysely, 'postgresql', userTable, {\n * where: someCondition,\n * orderBy: [['name', 'asc']],\n * limit: 10\n * });\n * ```\n */\nexport async function findMany(\n kysely: Kysely<any>, // eslint-disable-line @typescript-eslint/no-explicit-any\n provider: SQLProvider,\n table: AnyTable,\n v: SimplifyFindOptions<FindManyOptions>,\n runSubQueryJoin: (records: Record<string, unknown>[], join: CompiledJoin) => Promise<void>,\n) {\n let query = kysely.selectFrom(table.name);\n\n const where = v.where;\n if (where) {\n query = query.where((eb) => buildWhere(where, eb, provider));\n }\n\n if (v.offset !== undefined) {\n query = query.offset(v.offset);\n }\n\n if (v.limit !== undefined) {\n query = provider === \"mssql\" ? query.top(v.limit) : query.limit(v.limit);\n }\n\n if (v.orderBy) {\n for (const [col, mode] of v.orderBy) {\n query = query.orderBy(fullSQLName(col), mode);\n }\n }\n\n const selectBuilder = extendSelect(v.select);\n const mappedSelect: string[] = [];\n const subqueryJoins: CompiledJoin[] = [];\n\n const compiledSelect = selectBuilder.compile();\n mappedSelect.push(...mapSelect(compiledSelect.result, table));\n\n const records = (await query.select(mappedSelect).execute()).map((v) =>\n decodeResult(v, table, provider),\n );\n\n await Promise.all(subqueryJoins.map((join) => runSubQueryJoin(records, join)));\n for (const record of records) {\n compiledSelect.removeExtendedKeys(record);\n }\n\n return records;\n}\n\n/**\n * Processes encoded values and replaces ReferenceSubquery markers with actual SQL subqueries.\n *\n * @param values - The encoded values that may contain ReferenceSubquery objects\n * @param kysely - The Kysely database instance for building subqueries\n * @param mapper - Optional table name mapper for namespace prefixing\n * @returns Processed values with subqueries in place of ReferenceSubquery markers\n * @internal\n */\nfunction processReferenceSubqueries(\n values: Record<string, unknown>,\n kysely: Kysely<any>, // eslint-disable-line @typescript-eslint/no-explicit-any\n mapper?: TableNameMapper,\n): Record<string, unknown> {\n const processed: Record<string, unknown> = {};\n const getTableName = (table: AnyTable) => (mapper ? mapper.toPhysical(table.name) : table.name);\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\n // Build a subquery: SELECT _internal_id FROM referenced_table WHERE id = external_id LIMIT 1\n processed[key] = kysely\n .selectFrom(getTableName(refTable))\n .select(refTable.getInternalIdColumn().name)\n .where(refTable.getIdColumn().name, \"=\", externalId)\n .limit(1);\n } else {\n processed[key] = value;\n }\n }\n\n return processed;\n}\n\n/**\n * Creates a query compiler that builds and compiles Kysely queries without executing them.\n *\n * Each method takes table and query parameters and returns a CompiledQuery that can be\n * executed later using kysely.executeQuery().\n *\n * @param kysely - The Kysely database instance\n * @param provider - The SQL provider (affects SQL generation)\n * @returns An object with methods for compiling various database operations\n * @internal\n *\n * @example\n * ```ts\n * const builder = createKyselyQueryBuilder(kysely, 'postgresql');\n * const query = builder.count(userTable, { where: someCondition });\n * const result = await kysely.executeQuery(query);\n * ```\n */\nexport function createKyselyQueryBuilder(\n kysely: Kysely<any>, // eslint-disable-line @typescript-eslint/no-explicit-any\n provider: SQLProvider,\n mapper?: TableNameMapper,\n) {\n // Helper to get the physical table name (with namespace suffix if mapper is provided)\n const getTableName = (table: AnyTable) => (mapper ? mapper.toPhysical(table.name) : table.name);\n\n return {\n count(table: AnyTable, { where }: { where?: Condition }): CompiledQuery {\n let query = kysely.selectFrom(getTableName(table)).select(kysely.fn.countAll().as(\"count\"));\n if (where) {\n query = query.where((b) => buildWhere(where, b, provider, mapper, table));\n }\n return query.compile();\n },\n\n create(table: AnyTable, values: Record<string, unknown>): CompiledQuery {\n const encodedValues = encodeValues(values, table, true, provider);\n const processedValues = processReferenceSubqueries(encodedValues, kysely, mapper);\n const insert = kysely.insertInto(getTableName(table)).values(processedValues);\n\n if (provider === \"mssql\") {\n return (\n insert\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n .output(mapSelect(true, table, { tableName: \"inserted\" }) as any[])\n .compile()\n );\n }\n\n if (provider === \"postgresql\" || provider === \"sqlite\") {\n return insert\n .returning(mapSelect(true, table, { tableName: getTableName(table) }))\n .compile();\n }\n\n // For MySQL/other providers, return the insert query\n return insert.compile();\n },\n\n findMany<T extends AnyTable>(\n table: T,\n v: SimplifyFindOptions<FindManyOptions<T>>,\n ): CompiledQuery {\n let query = kysely.selectFrom(getTableName(table));\n\n const where = v.where;\n if (where) {\n query = query.where((eb) => buildWhere(where, eb, provider, mapper, table));\n }\n\n if (v.offset !== undefined) {\n query = query.offset(v.offset);\n }\n\n if (v.limit !== undefined) {\n query = provider === \"mssql\" ? query.top(v.limit) : query.limit(v.limit);\n }\n\n if (v.orderBy) {\n for (const [col, mode] of v.orderBy) {\n query = query.orderBy(fullSQLName(col, mapper), mode);\n }\n }\n\n const selectBuilder = extendSelect(v.select);\n const mappedSelect: string[] = [];\n\n // Process joins recursively to support nested joins\n const processJoins = (\n joins: CompiledJoin[] | undefined,\n parentTable: AnyTable,\n parentTableName: string,\n parentPath: string = \"\",\n ) => {\n for (const join of joins ?? []) {\n const { options: joinOptions, relation } = join;\n\n if (joinOptions === false) {\n continue;\n }\n\n const targetTable = relation.table;\n // Build the full path for this join (e.g., \"author:inviter\")\n const fullPath = parentPath ? `${parentPath}:${relation.name}` : relation.name;\n // SQL table alias uses underscores (e.g., \"author_inviter\")\n const joinName = fullPath.replace(/:/g, \"_\");\n\n // update select\n mappedSelect.push(\n ...mapSelect(joinOptions.select, targetTable, {\n relation: fullPath, // Use full path with colons for column aliases\n tableName: joinName, // Use underscore version for table name\n }),\n );\n\n query = query.leftJoin(`${getTableName(targetTable)} as ${joinName}`, (b) =>\n b.on((eb) => {\n const conditions = [];\n for (const [left, right] of relation.on) {\n // Foreign keys always use internal IDs\n // If the relation references an external ID column (any name), translate to \"_internalId\"\n const rightCol = targetTable.columns[right];\n const actualRight = rightCol?.role === \"external-id\" ? \"_internalId\" : right;\n\n conditions.push(\n eb(\n `${parentTableName}.${parentTable.columns[left].name}`,\n \"=\",\n eb.ref(`${joinName}.${targetTable.columns[actualRight].name}`),\n ),\n );\n }\n\n if (joinOptions.where) {\n conditions.push(buildWhere(joinOptions.where, eb, provider, mapper, targetTable));\n }\n\n return eb.and(conditions);\n }),\n );\n\n // Recursively process nested joins with the full path\n processJoins(joinOptions.join, targetTable, joinName, fullPath);\n }\n };\n\n processJoins(v.join, table, getTableName(table));\n\n const compiledSelect = selectBuilder.compile();\n mappedSelect.push(\n ...mapSelect(compiledSelect.result, table, { tableName: getTableName(table) }),\n );\n\n return query.select(mappedSelect).compile();\n },\n\n updateMany(\n table: AnyTable,\n v: {\n where?: Condition;\n set: Record<string, unknown>;\n },\n ): CompiledQuery {\n const encoded = encodeValues(v.set, table, false, provider);\n const processed = processReferenceSubqueries(encoded, kysely, mapper);\n\n // Automatically increment _version for optimistic concurrency control\n const versionCol = table.getVersionColumn();\n // Safe cast: we're building a SQL expression for incrementing the version\n processed[versionCol.name] = sql.raw(`COALESCE(${versionCol.name}, 0) + 1`) as unknown;\n\n let query = kysely.updateTable(getTableName(table)).set(processed);\n const { where } = v;\n if (where) {\n query = query.where((eb) => buildWhere(where, eb, provider, mapper, table));\n }\n return query.compile();\n },\n\n upsertCheck(table: AnyTable, where: Condition | undefined): CompiledQuery {\n const idColumn = table.getIdColumn();\n let query = kysely.selectFrom(getTableName(table)).select([`${idColumn.name} as id`]);\n if (where) {\n query = query.where((b) => buildWhere(where, b, provider, mapper, table));\n }\n return query.limit(1).compile();\n },\n\n upsertUpdate(\n table: AnyTable,\n update: Record<string, unknown>,\n where: Condition | undefined,\n top?: boolean,\n ): CompiledQuery {\n const encoded = encodeValues(update, table, false, provider);\n const processed = processReferenceSubqueries(encoded, kysely, mapper);\n let query = kysely.updateTable(getTableName(table)).set(processed);\n if (top) {\n query = query.top(1);\n }\n if (where) {\n query = query.where((b) => buildWhere(where, b, provider, mapper, table));\n }\n return query.compile();\n },\n\n upsertUpdateById(table: AnyTable, update: Record<string, unknown>, id: unknown): CompiledQuery {\n const idColumn = table.getIdColumn();\n const encoded = encodeValues(update, table, false, provider);\n const processed = processReferenceSubqueries(encoded, kysely, mapper);\n return kysely\n .updateTable(getTableName(table))\n .set(processed)\n .where(idColumn.name, \"=\", id)\n .compile();\n },\n\n createMany(table: AnyTable, values: Record<string, unknown>[]): CompiledQuery {\n const encodedValues = values.map((v) => encodeValues(v, table, true, provider));\n const processedValues = encodedValues.map((v) =>\n processReferenceSubqueries(v, kysely, mapper),\n );\n return kysely.insertInto(getTableName(table)).values(processedValues).compile();\n },\n\n deleteMany(table: AnyTable, { where }: { where?: Condition }): CompiledQuery {\n let query = kysely.deleteFrom(getTableName(table));\n if (where) {\n query = query.where((eb) => buildWhere(where, eb, provider, mapper, table));\n }\n return query.compile();\n },\n\n findById(table: AnyTable, idValue: unknown): CompiledQuery {\n const idColumn = table.getIdColumn();\n return kysely\n .selectFrom(getTableName(table))\n .select(mapSelect(true, table, { tableName: getTableName(table) }))\n .where(idColumn.name, \"=\", idValue)\n .limit(1)\n .compile();\n },\n };\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fragno-dev/db",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"kysely-pglite": "^0.6.1",
|
|
75
75
|
"vitest": "^3.2.4",
|
|
76
76
|
"zod": "^4.1.12",
|
|
77
|
-
"@fragno-dev/core": "0.1.
|
|
77
|
+
"@fragno-dev/core": "0.1.5",
|
|
78
78
|
"@fragno-private/typescript-config": "0.0.1",
|
|
79
79
|
"@fragno-private/vitest-config": "0.0.0"
|
|
80
80
|
},
|
|
@@ -178,7 +178,7 @@ describe("drizzle-query", () => {
|
|
|
178
178
|
|
|
179
179
|
const [query] = queries;
|
|
180
180
|
expect(query.sql).toMatchInlineSnapshot(
|
|
181
|
-
`"select "id", "userId", "expiresAt", "createdAt", "_internalId", "_version" from "session" "session" where "session"."userId" = $1"`,
|
|
181
|
+
`"select "id", "userId", "expiresAt", "createdAt", "_internalId", "_version" from "session" "session" where "session"."userId" = (select "_internalId" from "user" where "id" = $1 limit 1)"`,
|
|
182
182
|
);
|
|
183
183
|
expect(query.params).toEqual([userId]);
|
|
184
184
|
});
|
|
@@ -394,7 +394,7 @@ describe("drizzle-query", () => {
|
|
|
394
394
|
// Verify the find query that's executed first
|
|
395
395
|
const findQuery = queries[0];
|
|
396
396
|
expect(findQuery.sql).toMatchInlineSnapshot(
|
|
397
|
-
`"select "id", "userId", "expiresAt", "createdAt", "_internalId", "_version" from "session" "session" where "session"."userId" = $1"`,
|
|
397
|
+
`"select "id", "userId", "expiresAt", "createdAt", "_internalId", "_version" from "session" "session" where "session"."userId" = (select "_internalId" from "user" where "id" = $1 limit 1)"`,
|
|
398
398
|
);
|
|
399
399
|
expect(findQuery.params).toEqual([userId]);
|
|
400
400
|
|
|
@@ -113,10 +113,10 @@ export function fromDrizzle<T extends AnySchema>(
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
return {
|
|
116
|
-
find(tableName, builderFn) {
|
|
117
|
-
const uow = createUOW({ config: uowConfig });
|
|
118
|
-
uow.
|
|
119
|
-
return
|
|
116
|
+
async find(tableName, builderFn) {
|
|
117
|
+
const uow = createUOW({ config: uowConfig }).find(tableName, builderFn);
|
|
118
|
+
const [result] = await uow.executeRetrieve();
|
|
119
|
+
return result;
|
|
120
120
|
},
|
|
121
121
|
|
|
122
122
|
async findFirst(tableName, builderFn) {
|
|
@@ -97,8 +97,33 @@ export function createDrizzleUOWCompiler<TSchema extends AnySchema>(
|
|
|
97
97
|
if (right instanceof Column) {
|
|
98
98
|
right = toDrizzleColumn(right);
|
|
99
99
|
} else {
|
|
100
|
-
//
|
|
101
|
-
|
|
100
|
+
// Handle string references - convert external ID to internal ID via subquery
|
|
101
|
+
if (condition.a.role === "reference" && typeof right === "string") {
|
|
102
|
+
// Find the table that contains this column
|
|
103
|
+
const table = Object.values(schema.tables).find((t) =>
|
|
104
|
+
Object.values(t.columns).includes(condition.a),
|
|
105
|
+
);
|
|
106
|
+
if (table) {
|
|
107
|
+
// Find relation that uses this column
|
|
108
|
+
const relation = Object.values(table.relations).find((rel) =>
|
|
109
|
+
rel.on.some(([localCol]) => localCol === condition.a.ormName),
|
|
110
|
+
);
|
|
111
|
+
if (relation) {
|
|
112
|
+
const refTable = relation.table;
|
|
113
|
+
const internalIdCol = refTable.getInternalIdColumn();
|
|
114
|
+
const idCol = refTable.getIdColumn();
|
|
115
|
+
const physicalTableName = mapper
|
|
116
|
+
? mapper.toPhysical(refTable.ormName)
|
|
117
|
+
: refTable.ormName;
|
|
118
|
+
|
|
119
|
+
// Build a SQL subquery using Drizzle's sql template
|
|
120
|
+
right = Drizzle.sql`(select ${Drizzle.sql.identifier(internalIdCol.name)} from ${Drizzle.sql.identifier(physicalTableName)} where ${Drizzle.sql.identifier(idCol.name)} = ${right} limit 1)`;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
// Serialize non-Column values (e.g., FragnoId -> string, Date -> number for SQLite)
|
|
125
|
+
right = serialize(right, condition.a, provider);
|
|
126
|
+
}
|
|
102
127
|
}
|
|
103
128
|
|
|
104
129
|
switch (op) {
|
|
@@ -45,6 +45,8 @@ export function fullSQLName(column: AnyColumn, mapper?: TableNameMapper) {
|
|
|
45
45
|
* @param condition - The condition tree to build the WHERE clause from
|
|
46
46
|
* @param eb - Kysely expression builder for constructing SQL expressions
|
|
47
47
|
* @param provider - The SQL provider (affects SQL generation)
|
|
48
|
+
* @param mapper - Optional table name mapper for namespace prefixing
|
|
49
|
+
* @param table - The table being queried (used for resolving reference columns)
|
|
48
50
|
* @returns A Kysely expression wrapper representing the WHERE clause
|
|
49
51
|
* @internal
|
|
50
52
|
*
|
|
@@ -64,6 +66,7 @@ export function buildWhere(
|
|
|
64
66
|
eb: ExpressionBuilder<any, any>, // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
65
67
|
provider: SQLProvider,
|
|
66
68
|
mapper?: TableNameMapper,
|
|
69
|
+
table?: AnyTable,
|
|
67
70
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
68
71
|
): ExpressionWrapper<any, any, SqlBool> {
|
|
69
72
|
if (condition.type === "compare") {
|
|
@@ -72,7 +75,28 @@ export function buildWhere(
|
|
|
72
75
|
let val = condition.b;
|
|
73
76
|
|
|
74
77
|
if (!(val instanceof Column)) {
|
|
75
|
-
|
|
78
|
+
// Handle string references - convert external ID to internal ID via subquery
|
|
79
|
+
if (left.role === "reference" && typeof val === "string" && table) {
|
|
80
|
+
// Find relation that uses this column
|
|
81
|
+
const relation = Object.values(table.relations).find((rel) =>
|
|
82
|
+
rel.on.some(([localCol]) => localCol === left.ormName),
|
|
83
|
+
);
|
|
84
|
+
if (relation) {
|
|
85
|
+
const refTable = relation.table;
|
|
86
|
+
const internalIdCol = refTable.getInternalIdColumn();
|
|
87
|
+
const idCol = refTable.getIdColumn();
|
|
88
|
+
const physicalTableName = mapper ? mapper.toPhysical(refTable.ormName) : refTable.ormName;
|
|
89
|
+
|
|
90
|
+
// Build a SQL subquery
|
|
91
|
+
val = eb
|
|
92
|
+
.selectFrom(physicalTableName)
|
|
93
|
+
.select(internalIdCol.name)
|
|
94
|
+
.where(idCol.name, "=", val)
|
|
95
|
+
.limit(1);
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
val = serialize(val, left, provider);
|
|
99
|
+
}
|
|
76
100
|
}
|
|
77
101
|
|
|
78
102
|
let v: BinaryOperator;
|
|
@@ -123,14 +147,14 @@ export function buildWhere(
|
|
|
123
147
|
|
|
124
148
|
// Nested conditions
|
|
125
149
|
if (condition.type === "and") {
|
|
126
|
-
return eb.and(condition.items.map((v) => buildWhere(v, eb, provider, mapper)));
|
|
150
|
+
return eb.and(condition.items.map((v) => buildWhere(v, eb, provider, mapper, table)));
|
|
127
151
|
}
|
|
128
152
|
|
|
129
153
|
if (condition.type === "not") {
|
|
130
|
-
return eb.not(buildWhere(condition.item, eb, provider, mapper));
|
|
154
|
+
return eb.not(buildWhere(condition.item, eb, provider, mapper, table));
|
|
131
155
|
}
|
|
132
156
|
|
|
133
|
-
return eb.or(condition.items.map((v) => buildWhere(v, eb, provider, mapper)));
|
|
157
|
+
return eb.or(condition.items.map((v) => buildWhere(v, eb, provider, mapper, table)));
|
|
134
158
|
}
|
|
135
159
|
|
|
136
160
|
/**
|
|
@@ -426,7 +450,7 @@ export function createKyselyQueryBuilder(
|
|
|
426
450
|
count(table: AnyTable, { where }: { where?: Condition }): CompiledQuery {
|
|
427
451
|
let query = kysely.selectFrom(getTableName(table)).select(kysely.fn.countAll().as("count"));
|
|
428
452
|
if (where) {
|
|
429
|
-
query = query.where((b) => buildWhere(where, b, provider, mapper));
|
|
453
|
+
query = query.where((b) => buildWhere(where, b, provider, mapper, table));
|
|
430
454
|
}
|
|
431
455
|
return query.compile();
|
|
432
456
|
},
|
|
@@ -463,7 +487,7 @@ export function createKyselyQueryBuilder(
|
|
|
463
487
|
|
|
464
488
|
const where = v.where;
|
|
465
489
|
if (where) {
|
|
466
|
-
query = query.where((eb) => buildWhere(where, eb, provider, mapper));
|
|
490
|
+
query = query.where((eb) => buildWhere(where, eb, provider, mapper, table));
|
|
467
491
|
}
|
|
468
492
|
|
|
469
493
|
if (v.offset !== undefined) {
|
|
@@ -530,7 +554,7 @@ export function createKyselyQueryBuilder(
|
|
|
530
554
|
}
|
|
531
555
|
|
|
532
556
|
if (joinOptions.where) {
|
|
533
|
-
conditions.push(buildWhere(joinOptions.where, eb, provider, mapper));
|
|
557
|
+
conditions.push(buildWhere(joinOptions.where, eb, provider, mapper, targetTable));
|
|
534
558
|
}
|
|
535
559
|
|
|
536
560
|
return eb.and(conditions);
|
|
@@ -570,7 +594,7 @@ export function createKyselyQueryBuilder(
|
|
|
570
594
|
let query = kysely.updateTable(getTableName(table)).set(processed);
|
|
571
595
|
const { where } = v;
|
|
572
596
|
if (where) {
|
|
573
|
-
query = query.where((eb) => buildWhere(where, eb, provider, mapper));
|
|
597
|
+
query = query.where((eb) => buildWhere(where, eb, provider, mapper, table));
|
|
574
598
|
}
|
|
575
599
|
return query.compile();
|
|
576
600
|
},
|
|
@@ -579,7 +603,7 @@ export function createKyselyQueryBuilder(
|
|
|
579
603
|
const idColumn = table.getIdColumn();
|
|
580
604
|
let query = kysely.selectFrom(getTableName(table)).select([`${idColumn.name} as id`]);
|
|
581
605
|
if (where) {
|
|
582
|
-
query = query.where((b) => buildWhere(where, b, provider, mapper));
|
|
606
|
+
query = query.where((b) => buildWhere(where, b, provider, mapper, table));
|
|
583
607
|
}
|
|
584
608
|
return query.limit(1).compile();
|
|
585
609
|
},
|
|
@@ -597,7 +621,7 @@ export function createKyselyQueryBuilder(
|
|
|
597
621
|
query = query.top(1);
|
|
598
622
|
}
|
|
599
623
|
if (where) {
|
|
600
|
-
query = query.where((b) => buildWhere(where, b, provider, mapper));
|
|
624
|
+
query = query.where((b) => buildWhere(where, b, provider, mapper, table));
|
|
601
625
|
}
|
|
602
626
|
return query.compile();
|
|
603
627
|
},
|
|
@@ -624,7 +648,7 @@ export function createKyselyQueryBuilder(
|
|
|
624
648
|
deleteMany(table: AnyTable, { where }: { where?: Condition }): CompiledQuery {
|
|
625
649
|
let query = kysely.deleteFrom(getTableName(table));
|
|
626
650
|
if (where) {
|
|
627
|
-
query = query.where((eb) => buildWhere(where, eb, provider, mapper));
|
|
651
|
+
query = query.where((eb) => buildWhere(where, eb, provider, mapper, table));
|
|
628
652
|
}
|
|
629
653
|
return query.compile();
|
|
630
654
|
},
|