@fragno-dev/db 0.1.14 → 0.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/.turbo/turbo-build.log +179 -139
  2. package/CHANGELOG.md +24 -0
  3. package/dist/adapters/adapters.d.ts +15 -1
  4. package/dist/adapters/adapters.d.ts.map +1 -1
  5. package/dist/adapters/adapters.js.map +1 -1
  6. package/dist/adapters/drizzle/drizzle-adapter.d.ts +3 -1
  7. package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -1
  8. package/dist/adapters/drizzle/drizzle-adapter.js +9 -2
  9. package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -1
  10. package/dist/adapters/drizzle/drizzle-query.js +2 -2
  11. package/dist/adapters/drizzle/drizzle-query.js.map +1 -1
  12. package/dist/adapters/drizzle/drizzle-uow-compiler.js +27 -8
  13. package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +1 -1
  14. package/dist/adapters/drizzle/drizzle-uow-decoder.js +22 -15
  15. package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +1 -1
  16. package/dist/adapters/drizzle/drizzle-uow-executor.js +18 -7
  17. package/dist/adapters/drizzle/drizzle-uow-executor.js.map +1 -1
  18. package/dist/adapters/drizzle/generate.d.ts +4 -1
  19. package/dist/adapters/drizzle/generate.d.ts.map +1 -1
  20. package/dist/adapters/drizzle/generate.js +11 -18
  21. package/dist/adapters/drizzle/generate.js.map +1 -1
  22. package/dist/adapters/kysely/kysely-adapter.d.ts +3 -1
  23. package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -1
  24. package/dist/adapters/kysely/kysely-adapter.js +7 -1
  25. package/dist/adapters/kysely/kysely-adapter.js.map +1 -1
  26. package/dist/adapters/kysely/kysely-query-builder.js +1 -1
  27. package/dist/adapters/kysely/kysely-query-compiler.js +3 -2
  28. package/dist/adapters/kysely/kysely-query-compiler.js.map +1 -1
  29. package/dist/adapters/kysely/kysely-query.d.ts +1 -0
  30. package/dist/adapters/kysely/kysely-query.d.ts.map +1 -1
  31. package/dist/adapters/kysely/kysely-query.js +25 -18
  32. package/dist/adapters/kysely/kysely-query.js.map +1 -1
  33. package/dist/adapters/kysely/kysely-shared.d.ts +3 -0
  34. package/dist/adapters/kysely/kysely-shared.d.ts.map +1 -1
  35. package/dist/adapters/kysely/kysely-shared.js +16 -1
  36. package/dist/adapters/kysely/kysely-shared.js.map +1 -1
  37. package/dist/adapters/kysely/kysely-uow-compiler.js +34 -11
  38. package/dist/adapters/kysely/kysely-uow-compiler.js.map +1 -1
  39. package/dist/adapters/kysely/kysely-uow-executor.js +8 -4
  40. package/dist/adapters/kysely/kysely-uow-executor.js.map +1 -1
  41. package/dist/adapters/kysely/migration/execute-base.js +1 -1
  42. package/dist/adapters/kysely/migration/execute-base.js.map +1 -1
  43. package/dist/db-fragment-definition-builder.d.ts +152 -0
  44. package/dist/db-fragment-definition-builder.d.ts.map +1 -0
  45. package/dist/db-fragment-definition-builder.js +137 -0
  46. package/dist/db-fragment-definition-builder.js.map +1 -0
  47. package/dist/fragments/internal-fragment.d.ts +19 -0
  48. package/dist/fragments/internal-fragment.d.ts.map +1 -0
  49. package/dist/fragments/internal-fragment.js +39 -0
  50. package/dist/fragments/internal-fragment.js.map +1 -0
  51. package/dist/migration-engine/generation-engine.d.ts.map +1 -1
  52. package/dist/migration-engine/generation-engine.js +35 -15
  53. package/dist/migration-engine/generation-engine.js.map +1 -1
  54. package/dist/mod.d.ts +8 -20
  55. package/dist/mod.d.ts.map +1 -1
  56. package/dist/mod.js +7 -35
  57. package/dist/mod.js.map +1 -1
  58. package/dist/node_modules/.pnpm/rou3@0.7.8/node_modules/rou3/dist/index.js +165 -0
  59. package/dist/node_modules/.pnpm/rou3@0.7.8/node_modules/rou3/dist/index.js.map +1 -0
  60. package/dist/packages/fragno/dist/api/bind-services.js +20 -0
  61. package/dist/packages/fragno/dist/api/bind-services.js.map +1 -0
  62. package/dist/packages/fragno/dist/api/error.js +48 -0
  63. package/dist/packages/fragno/dist/api/error.js.map +1 -0
  64. package/dist/packages/fragno/dist/api/fragment-definition-builder.js +320 -0
  65. package/dist/packages/fragno/dist/api/fragment-definition-builder.js.map +1 -0
  66. package/dist/packages/fragno/dist/api/fragment-instantiator.js +487 -0
  67. package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +1 -0
  68. package/dist/packages/fragno/dist/api/fragno-response.js +73 -0
  69. package/dist/packages/fragno/dist/api/fragno-response.js.map +1 -0
  70. package/dist/packages/fragno/dist/api/internal/response-stream.js +81 -0
  71. package/dist/packages/fragno/dist/api/internal/response-stream.js.map +1 -0
  72. package/dist/packages/fragno/dist/api/internal/route.js +10 -0
  73. package/dist/packages/fragno/dist/api/internal/route.js.map +1 -0
  74. package/dist/packages/fragno/dist/api/mutable-request-state.js +97 -0
  75. package/dist/packages/fragno/dist/api/mutable-request-state.js.map +1 -0
  76. package/dist/packages/fragno/dist/api/request-context-storage.js +43 -0
  77. package/dist/packages/fragno/dist/api/request-context-storage.js.map +1 -0
  78. package/dist/packages/fragno/dist/api/request-input-context.js +118 -0
  79. package/dist/packages/fragno/dist/api/request-input-context.js.map +1 -0
  80. package/dist/packages/fragno/dist/api/request-middleware.js +83 -0
  81. package/dist/packages/fragno/dist/api/request-middleware.js.map +1 -0
  82. package/dist/packages/fragno/dist/api/request-output-context.js +119 -0
  83. package/dist/packages/fragno/dist/api/request-output-context.js.map +1 -0
  84. package/dist/packages/fragno/dist/api/route.js +17 -0
  85. package/dist/packages/fragno/dist/api/route.js.map +1 -0
  86. package/dist/packages/fragno/dist/internal/symbols.js +10 -0
  87. package/dist/packages/fragno/dist/internal/symbols.js.map +1 -0
  88. package/dist/query/cursor.d.ts +10 -2
  89. package/dist/query/cursor.d.ts.map +1 -1
  90. package/dist/query/cursor.js +11 -4
  91. package/dist/query/cursor.js.map +1 -1
  92. package/dist/query/execute-unit-of-work.d.ts +123 -0
  93. package/dist/query/execute-unit-of-work.d.ts.map +1 -0
  94. package/dist/query/execute-unit-of-work.js +184 -0
  95. package/dist/query/execute-unit-of-work.js.map +1 -0
  96. package/dist/query/query.d.ts +2 -2
  97. package/dist/query/query.d.ts.map +1 -1
  98. package/dist/query/result-transform.js +4 -2
  99. package/dist/query/result-transform.js.map +1 -1
  100. package/dist/query/retry-policy.d.ts +88 -0
  101. package/dist/query/retry-policy.d.ts.map +1 -0
  102. package/dist/query/retry-policy.js +61 -0
  103. package/dist/query/retry-policy.js.map +1 -0
  104. package/dist/query/unit-of-work.d.ts +104 -50
  105. package/dist/query/unit-of-work.d.ts.map +1 -1
  106. package/dist/query/unit-of-work.js +384 -194
  107. package/dist/query/unit-of-work.js.map +1 -1
  108. package/dist/schema/serialize.js +12 -7
  109. package/dist/schema/serialize.js.map +1 -1
  110. package/dist/with-database.d.ts +28 -0
  111. package/dist/with-database.d.ts.map +1 -0
  112. package/dist/with-database.js +34 -0
  113. package/dist/with-database.js.map +1 -0
  114. package/package.json +9 -2
  115. package/src/adapters/adapters.ts +16 -0
  116. package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +80 -16
  117. package/src/adapters/drizzle/drizzle-adapter-sqlite.test.ts +158 -2
  118. package/src/adapters/drizzle/drizzle-adapter.test.ts +3 -51
  119. package/src/adapters/drizzle/drizzle-adapter.ts +20 -7
  120. package/src/adapters/drizzle/drizzle-query.ts +1 -2
  121. package/src/adapters/drizzle/drizzle-uow-compiler-mysql.test.ts +1442 -0
  122. package/src/adapters/drizzle/drizzle-uow-compiler-sqlite.test.ts +1414 -0
  123. package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +21 -4
  124. package/src/adapters/drizzle/drizzle-uow-compiler.ts +44 -3
  125. package/src/adapters/drizzle/drizzle-uow-decoder.ts +32 -22
  126. package/src/adapters/drizzle/drizzle-uow-executor.ts +41 -8
  127. package/src/adapters/drizzle/generate.test.ts +102 -269
  128. package/src/adapters/drizzle/generate.ts +12 -30
  129. package/src/adapters/drizzle/test-utils.ts +36 -5
  130. package/src/adapters/kysely/kysely-adapter-pglite.test.ts +64 -20
  131. package/src/adapters/kysely/kysely-adapter-sqlite.test.ts +156 -0
  132. package/src/adapters/kysely/kysely-adapter.ts +9 -1
  133. package/src/adapters/kysely/kysely-query-compiler.ts +3 -8
  134. package/src/adapters/kysely/kysely-query.ts +34 -25
  135. package/src/adapters/kysely/kysely-shared.ts +34 -0
  136. package/src/adapters/kysely/kysely-uow-compiler.test.ts +61 -73
  137. package/src/adapters/kysely/kysely-uow-compiler.ts +44 -12
  138. package/src/adapters/kysely/kysely-uow-executor.ts +26 -7
  139. package/src/adapters/kysely/kysely-uow-joins.test.ts +31 -48
  140. package/src/adapters/kysely/migration/execute-base.ts +1 -1
  141. package/src/db-fragment-definition-builder.test.ts +887 -0
  142. package/src/db-fragment-definition-builder.ts +506 -0
  143. package/src/db-fragment-instantiator.test.ts +467 -0
  144. package/src/db-fragment-integration.test.ts +408 -0
  145. package/src/fragments/internal-fragment.test.ts +160 -0
  146. package/src/fragments/internal-fragment.ts +85 -0
  147. package/src/migration-engine/generation-engine.test.ts +58 -15
  148. package/src/migration-engine/generation-engine.ts +78 -25
  149. package/src/mod.ts +25 -52
  150. package/src/query/cursor.test.ts +119 -0
  151. package/src/query/cursor.ts +17 -4
  152. package/src/query/execute-unit-of-work.test.ts +1310 -0
  153. package/src/query/execute-unit-of-work.ts +463 -0
  154. package/src/query/query.ts +2 -2
  155. package/src/query/result-transform.test.ts +129 -0
  156. package/src/query/result-transform.ts +4 -1
  157. package/src/query/retry-policy.test.ts +217 -0
  158. package/src/query/retry-policy.ts +141 -0
  159. package/src/query/unit-of-work-coordinator.test.ts +833 -0
  160. package/src/query/unit-of-work-types.test.ts +2 -2
  161. package/src/query/unit-of-work.test.ts +873 -191
  162. package/src/query/unit-of-work.ts +602 -409
  163. package/src/schema/serialize.ts +22 -11
  164. package/src/with-database.ts +140 -0
  165. package/tsdown.config.ts +1 -0
  166. package/dist/bind-services.d.ts +0 -7
  167. package/dist/bind-services.d.ts.map +0 -1
  168. package/dist/bind-services.js +0 -14
  169. package/dist/bind-services.js.map +0 -1
  170. package/dist/fragment.d.ts +0 -173
  171. package/dist/fragment.d.ts.map +0 -1
  172. package/dist/fragment.js +0 -191
  173. package/dist/fragment.js.map +0 -1
  174. package/dist/shared/settings-schema.js +0 -36
  175. package/dist/shared/settings-schema.js.map +0 -1
  176. package/src/bind-services.test.ts +0 -214
  177. package/src/bind-services.ts +0 -37
  178. package/src/db-fragment.test.ts +0 -800
  179. package/src/fragment.ts +0 -727
  180. package/src/query/unit-of-work-multi-schema.test.ts +0 -64
  181. package/src/shared/settings-schema.ts +0 -61
  182. package/src/uow-context-integration.test.ts +0 -102
  183. package/src/uow-context.test.ts +0 -182
@@ -1 +1 @@
1
- {"version":3,"file":"generate.d.ts","names":[],"sources":["../../../src/adapters/drizzle/generate.ts"],"sourcesContent":[],"mappings":";;;;KA8BY,iBAAA,GAAoB,QAAQ;UAqjBvB,qBAAA;EArjBL;EAqjBK,iBAAA,CAAA,EAAA;IA4BD;IAC0B,IAAA,EAAA,MAAA;IAC9B;IACA,IAAA,EAAA,MAAA;EAAqB,CAAA;;;;;iBAHjB,cAAA;;UAC0B;eAC9B,6BACA"}
1
+ {"version":3,"file":"generate.d.ts","names":[],"sources":["../../../src/adapters/drizzle/generate.ts"],"sourcesContent":[],"mappings":";;;;KA6BY,iBAAA,GAAoB,QAAQ;UAyjBvB,qBAAA;EAzjBL;EAyjBK,iBAAA,CAAA,EAAA;IAgBD;IAC0B,IAAA,EAAA,MAAA;IAC9B;IACA,IAAA,EAAA,MAAA;EAAqB,CAAA;;;;;;;;iBAHjB,cAAA;;UAC0B;eAC9B,6BACA"}
@@ -1,6 +1,5 @@
1
1
  import { InternalIdColumn } from "../../schema/create.js";
2
2
  import { schemaToDBType } from "../../schema/serialize.js";
3
- import { SETTINGS_TABLE_NAME, settingsSchema } from "../../shared/settings-schema.js";
4
3
  import { importGenerator } from "../../util/import-generator.js";
5
4
  import { ident, parseVarchar } from "../../util/parse.js";
6
5
  import { createTableNameMapper, sanitizeNamespace } from "./shared.js";
@@ -100,7 +99,11 @@ function mapDBTypeToDrizzleFunction(ctx, dbType, column, customTypes) {
100
99
  name: generateBinaryCustomType(ctx, customTypes),
101
100
  isCustomType: true
102
101
  };
103
- case "bigint": return { name: "bigint" };
102
+ case "bigint": return {
103
+ name: "bigint",
104
+ params: [`{ mode: "number" }`]
105
+ };
106
+ case "integer": return { name: "int" };
104
107
  default:
105
108
  if (dbType.startsWith("varchar(")) return {
106
109
  name: "varchar",
@@ -306,26 +309,14 @@ function generateFragmentSchemaExport(schema, namespace, tablesWithRelations) {
306
309
  /**
307
310
  * Generate a settings table for storing fragment versions
308
311
  */
309
- function generateSettingsTable(ctx) {
310
- const settingsTable = settingsSchema.tables[SETTINGS_TABLE_NAME];
311
- return generateTable(ctx, settingsTable, []);
312
- }
313
312
  /**
314
- * Generate a schema file from one or more fragments with a shared settings table
313
+ * Generate a schema file from one or more fragments with automatic de-duplication
315
314
  */
316
315
  function generateSchema(fragments, provider, options) {
317
316
  const ctx = createContext(provider, options?.idGeneratorImport);
318
317
  const customTypes = [];
319
318
  const sections = [];
320
- sections.push("");
321
- sections.push("// ============================================================================");
322
- sections.push("// Settings Table (shared across all fragments)");
323
- sections.push("// ============================================================================");
324
- sections.push("");
325
- sections.push(generateSettingsTable(ctx));
326
- sections.push("");
327
- sections.push(`export const fragnoDbSettingSchemaVersion = ${settingsSchema.version};`);
328
- for (const { namespace, schema } of fragments) {
319
+ for (const { schema, namespace } of fragments) {
329
320
  const fragmentTables = [];
330
321
  fragmentTables.push("");
331
322
  fragmentTables.push("// ============================================================================");
@@ -354,8 +345,10 @@ function generateSchema(fragments, provider, options) {
354
345
  tablesWithRelations.add(table.name);
355
346
  }
356
347
  }
357
- fragmentTables.push("");
358
- fragmentTables.push(generateFragmentSchemaExport(schema, namespace, tablesWithRelations));
348
+ if (namespace !== "") {
349
+ fragmentTables.push("");
350
+ fragmentTables.push(generateFragmentSchemaExport(schema, namespace, tablesWithRelations));
351
+ }
359
352
  sections.push(...fragmentTables);
360
353
  }
361
354
  return [
@@ -1 +1 @@
1
- {"version":3,"file":"generate.js","names":["parts: string[]","params: string[]","value: string","keys: string[]","columns: string[]","foreignColumns: string[]","indexes: string[]","args: string[]","relations: string[]","options: string[]","fields: string[]","references: string[]","tableRef","drizzleEntries: string[]","customTypes: string[]","sections: string[]","fragmentTables: string[]"],"sources":["../../../src/adapters/drizzle/generate.ts"],"sourcesContent":["import { importGenerator } from \"../../util/import-generator\";\nimport { ident, parseVarchar } from \"../../util/parse\";\nimport {\n type AnyColumn,\n type AnySchema,\n type AnyTable,\n type Relation,\n InternalIdColumn,\n} from \"../../schema/create\";\nimport type { SQLProvider } from \"../../shared/providers\";\nimport { schemaToDBType, type DBTypeLiteral } from \"../../schema/serialize\";\nimport { createTableNameMapper, sanitizeNamespace } from \"./shared\";\nimport { settingsSchema, SETTINGS_TABLE_NAME } from \"../../shared/settings-schema\";\n\n// ============================================================================\n// PROVIDER CONFIGURATION\n// ============================================================================\n\nconst PROVIDER_IMPORTS = {\n mysql: \"drizzle-orm/mysql-core\",\n postgresql: \"drizzle-orm/pg-core\",\n sqlite: \"drizzle-orm/sqlite-core\",\n} as const;\n\nconst PROVIDER_TABLE_FUNCTIONS = {\n mysql: \"mysqlTable\",\n postgresql: \"pgTable\",\n sqlite: \"sqliteTable\",\n} as const;\n\nexport type SupportedProvider = Exclude<SQLProvider, \"cockroachdb\" | \"mssql\">;\n\n// ============================================================================\n// CONTEXT\n// ============================================================================\n\ninterface GeneratorContext {\n provider: SupportedProvider;\n imports: ReturnType<typeof importGenerator>;\n importSource: string;\n generatedCustomTypes: Set<string>;\n idGeneratorImport?: { name: string; from: string };\n}\n\nfunction createContext(\n provider: SupportedProvider,\n idGeneratorImport?: { name: string; from: string },\n): GeneratorContext {\n return {\n provider,\n imports: importGenerator(),\n importSource: PROVIDER_IMPORTS[provider],\n generatedCustomTypes: new Set<string>(),\n idGeneratorImport,\n };\n}\n\n// ============================================================================\n// CUSTOM TYPE GENERATION\n// ============================================================================\n\ninterface CustomTypeOptions {\n dataType: string;\n driverDataType: string;\n databaseDataType: string;\n fromDriverCode: string;\n toDriverCode: string;\n}\n\nfunction generateCustomType(\n ctx: GeneratorContext,\n name: string,\n options: CustomTypeOptions,\n): string | undefined {\n if (ctx.generatedCustomTypes.has(name)) {\n return undefined;\n }\n\n ctx.imports.addImport(\"customType\", ctx.importSource);\n ctx.generatedCustomTypes.add(name);\n\n return `const ${name} = customType<\n {\n data: ${options.dataType};\n driverData: ${options.driverDataType};\n }\n>({\n dataType() {\n return \"${options.databaseDataType}\";\n },\n fromDriver(value) {\n ${options.fromDriverCode}\n },\n toDriver(value) {\n ${options.toDriverCode}\n }\n});`;\n}\n\nfunction generateBinaryCustomType(ctx: GeneratorContext, customTypes: string[]): string {\n const name = \"customBinary\";\n const code = generateCustomType(ctx, name, {\n dataType: \"Uint8Array\",\n driverDataType: \"Buffer\",\n databaseDataType: schemaToDBType({ type: \"binary\" }, ctx.provider),\n fromDriverCode: \"return new Uint8Array(value.buffer, value.byteOffset, value.byteLength)\",\n toDriverCode: `return value instanceof Buffer? value : Buffer.from(value)`,\n });\n\n if (code) {\n customTypes.push(code);\n }\n return name;\n}\n\n// ============================================================================\n// COLUMN TYPE MAPPING\n// ============================================================================\n\ninterface ColumnTypeFunction {\n name: string;\n isCustomType?: boolean;\n params?: string[];\n}\n\n/**\n * Maps SQL database types to Drizzle function names and parameters.\n * Uses schemaToDBType as the source of truth for type conversion.\n */\nfunction getColumnTypeFunction(\n ctx: GeneratorContext,\n column: AnyColumn,\n customTypes: string[],\n): ColumnTypeFunction {\n // Get the canonical database type from schemaToDBType\n const dbType = schemaToDBType(column, ctx.provider);\n\n // Map database types to Drizzle function names\n return mapDBTypeToDrizzleFunction(ctx, dbType, column, customTypes);\n}\n\n/**\n * Maps a database type string to a Drizzle function name and parameters.\n */\nfunction mapDBTypeToDrizzleFunction(\n ctx: GeneratorContext,\n dbType: DBTypeLiteral,\n column: AnyColumn,\n customTypes: string[],\n): ColumnTypeFunction {\n // Handle provider-specific types\n if (ctx.provider === \"postgresql\") {\n switch (dbType) {\n case \"bigserial\":\n // bigserial requires a mode parameter in Drizzle\n return { name: \"bigserial\", params: [`{ mode: \"number\" }`] };\n case \"serial\":\n return { name: \"serial\" };\n case \"boolean\":\n return { name: \"boolean\" };\n case \"bytea\":\n return { name: generateBinaryCustomType(ctx, customTypes), isCustomType: true };\n case \"json\":\n return { name: \"json\" };\n case \"text\":\n return { name: \"text\" };\n case \"bigint\":\n return { name: \"bigint\", params: [`{ mode: \"number\" }`] };\n default:\n if (dbType.startsWith(\"varchar(\")) {\n const length = parseVarchar(dbType);\n return { name: \"varchar\", params: [`{ length: ${length} }`] };\n }\n return { name: dbType };\n }\n }\n\n if (ctx.provider === \"mysql\") {\n switch (dbType) {\n case \"boolean\":\n return { name: \"boolean\" };\n case \"text\":\n return { name: \"text\" };\n case \"longblob\":\n return { name: generateBinaryCustomType(ctx, customTypes), isCustomType: true };\n case \"bigint\":\n return { name: \"bigint\" };\n default:\n if (dbType.startsWith(\"varchar(\")) {\n const length = parseVarchar(dbType);\n return { name: \"varchar\", params: [`{ length: ${length} }`] };\n }\n return { name: dbType };\n }\n }\n\n if (ctx.provider === \"sqlite\") {\n switch (dbType) {\n case \"integer\":\n // Need to determine the mode based on the original column type\n if (column.type === \"bool\") {\n return { name: \"integer\", params: [`{ mode: \"boolean\" }`] };\n }\n if (column.type === \"timestamp\" || column.type === \"date\") {\n return { name: \"integer\", params: [`{ mode: \"timestamp\" }`] };\n }\n return { name: \"integer\" };\n case \"blob\":\n // Need to determine the mode based on the original column type\n if (column.type === \"bigint\") {\n return { name: \"blob\", params: [`{ mode: \"bigint\" }`] };\n }\n return { name: generateBinaryCustomType(ctx, customTypes), isCustomType: true };\n case \"text\":\n // Check if it's JSON\n if (column.type === \"json\") {\n return { name: \"blob\", params: [`{ mode: \"json\" }`] };\n }\n return { name: \"text\" };\n case \"real\":\n return { name: \"real\" };\n default:\n return { name: dbType };\n }\n }\n\n // Fallback for other providers\n return { name: dbType };\n}\n\n// ============================================================================\n// COLUMN GENERATION\n// ============================================================================\n\nfunction generateColumnDefinition(\n ctx: GeneratorContext,\n column: AnyColumn,\n customTypes: string[],\n): string {\n const parts: string[] = [];\n const typeFn = getColumnTypeFunction(ctx, column, customTypes);\n\n // Column type with parameters\n const params: string[] = [`\"${column.name}\"`, ...(typeFn.params ?? [])];\n if (!typeFn.isCustomType) {\n ctx.imports.addImport(typeFn.name, ctx.importSource);\n }\n parts.push(`${typeFn.name}(${params.join(\", \")})`);\n\n // Primary key for internal ID\n if (column instanceof InternalIdColumn || column.role === \"internal-id\") {\n if (ctx.provider === \"sqlite\") {\n // SQLite uses primaryKey({ autoIncrement: true })\n parts.push(\"primaryKey({ autoIncrement: true })\");\n } else if (ctx.provider === \"mysql\") {\n // MySQL uses primaryKey().autoincrement()\n parts.push(\"primaryKey()\");\n parts.push(\"autoincrement()\");\n } else {\n // PostgreSQL just uses primaryKey()\n parts.push(\"primaryKey()\");\n }\n }\n\n // Nullability\n if (!column.isNullable) {\n parts.push(\"notNull()\");\n }\n\n // Default values\n if (column.default) {\n if (\"value\" in column.default) {\n // Static defaults: defaultTo(value)\n let value: string;\n if (typeof column.default.value === \"bigint\") {\n ctx.imports.addImport(\"sql\", \"drizzle-orm\");\n value = `sql\\`${column.default.value.toString()}\\``;\n } else {\n value = JSON.stringify(column.default.value);\n }\n parts.push(`default(${value})`);\n } else if (\"dbSpecial\" in column.default) {\n // Database-level special functions: defaultTo(b => b.now())\n if (column.default.dbSpecial === \"now\") {\n parts.push(\"defaultNow()\");\n }\n } else if (\"runtime\" in column.default) {\n // Runtime defaults: defaultTo$()\n if (column.default.runtime === \"cuid\") {\n const idGen = ctx.idGeneratorImport ?? { name: \"createId\", from: \"@fragno-dev/db/id\" };\n ctx.imports.addImport(idGen.name, idGen.from);\n parts.push(`$defaultFn(() => ${idGen.name}())`);\n } else if (column.default.runtime === \"now\") {\n // Runtime-generated timestamp (not database-level)\n parts.push(\"$defaultFn(() => new Date())\");\n }\n // Note: Custom functions in defaultTo$(() => ...) are not supported in schema generation\n }\n }\n\n return ` ${column.ormName}: ${parts.join(\".\")}`;\n}\n\nfunction generateAllColumns(\n ctx: GeneratorContext,\n table: AnyTable,\n customTypes: string[],\n): string[] {\n return Object.values(table.columns).map((column) =>\n generateColumnDefinition(ctx, column, customTypes),\n );\n}\n\n// ============================================================================\n// CONSTRAINT GENERATION\n// ============================================================================\n\nfunction generateForeignKeys(ctx: GeneratorContext, table: AnyTable, namespace?: string): string[] {\n const mapper = namespace ? createTableNameMapper(namespace) : undefined;\n const keys: string[] = [];\n\n for (const relation of Object.values(table.relations)) {\n // Only \"one\" relations generate foreign keys\n // \"many\" relations don't have foreign keys (they're on the other side)\n if (relation.type === \"many\") {\n continue;\n }\n\n const columns: string[] = [];\n const foreignColumns: string[] = [];\n const isSelfReference = relation.table.ormName === table.ormName;\n\n for (const [localCol, refCol] of relation.on) {\n columns.push(`table.${localCol}`);\n // Foreign keys always reference internal IDs\n const actualRefCol = refCol === \"id\" ? \"_internalId\" : refCol;\n // For self-referencing foreign keys, use table parameter instead of table constant\n if (isSelfReference) {\n foreignColumns.push(`table.${actualRefCol}`);\n } else {\n // Suffix the foreign table reference with namespace if provided\n const foreignTableRef = namespace\n ? `${relation.table.ormName}_${sanitizeNamespace(namespace)}`\n : relation.table.ormName;\n foreignColumns.push(`${foreignTableRef}.${actualRefCol}`);\n }\n }\n\n ctx.imports.addImport(\"foreignKey\", ctx.importSource);\n // Include namespace in FK name to avoid collisions\n const fkName =\n namespace && mapper\n ? \"fk_\" + mapper.toPhysical(`${table.ormName}_${relation.table.ormName}_${relation.name}`)\n : `${table.ormName}_${relation.table.ormName}_${relation.name}_fk`;\n\n keys.push(`foreignKey({\n columns: [${columns.join(\", \")}],\n foreignColumns: [${foreignColumns.join(\", \")}],\n name: \"${fkName}\"\n})`);\n }\n\n return keys;\n}\n\nfunction generateIndexes(ctx: GeneratorContext, table: AnyTable, namespace?: string): string[] {\n const indexes: string[] = [];\n\n for (const idx of Object.values(table.indexes)) {\n const columns = idx.columns.map((col) => `table.${col.ormName}`).join(\", \");\n\n // Include namespace in index name to avoid collisions\n const indexName = namespace ? `${idx.name}_${namespace}` : idx.name;\n\n if (idx.unique) {\n ctx.imports.addImport(\"uniqueIndex\", ctx.importSource);\n indexes.push(`uniqueIndex(\"${indexName}\").on(${columns})`);\n } else {\n ctx.imports.addImport(\"index\", ctx.importSource);\n indexes.push(`index(\"${indexName}\").on(${columns})`);\n }\n }\n\n return indexes;\n}\n\nfunction generateTableConstraints(\n ctx: GeneratorContext,\n table: AnyTable,\n namespace?: string,\n): string[] {\n return [...generateForeignKeys(ctx, table, namespace), ...generateIndexes(ctx, table, namespace)];\n}\n\n// ============================================================================\n// TABLE GENERATION\n// ============================================================================\n\nfunction generateTable(\n ctx: GeneratorContext,\n table: AnyTable,\n customTypes: string[],\n namespace?: string,\n): string {\n const tableFn = PROVIDER_TABLE_FUNCTIONS[ctx.provider];\n ctx.imports.addImport(tableFn, ctx.importSource);\n\n const columns = generateAllColumns(ctx, table, customTypes);\n const constraints = generateTableConstraints(ctx, table, namespace);\n\n // Suffix table name with namespace if provided, and sanitize for use as database table name\n // Database table names must also be valid identifiers to work with Drizzle's relational query system\n const physicalTableName = namespace\n ? `${table.ormName}_${sanitizeNamespace(namespace)}`\n : table.ormName;\n // Same sanitized name for TypeScript export\n const exportName = physicalTableName;\n\n const args: string[] = [`\"${physicalTableName}\"`, `{\\n${columns.join(\",\\n\")}\\n}`];\n\n if (constraints.length > 0) {\n args.push(`(table) => [\\n${ident(constraints.join(\",\\n\"))}\\n]`);\n }\n\n return `export const ${exportName} = ${tableFn}(${args.join(\", \")})`;\n}\n\n// ============================================================================\n// RELATION GENERATION\n// ============================================================================\n\nfunction generateRelation(\n ctx: GeneratorContext,\n table: AnyTable,\n namespace?: string,\n inverseRelations?: Array<{ fromTable: AnyTable; relation: Relation }>,\n): string | undefined {\n const relations: string[] = [];\n let hasOne = false;\n let hasMany = false;\n\n // Generate explicit relations defined on this table\n for (const relation of Object.values(table.relations)) {\n const options: string[] = [`relationName: \"${relation.id}\"`];\n\n // Track which relation types are used\n if (relation.type === \"one\") {\n hasOne = true;\n } else if (relation.type === \"many\") {\n hasMany = true;\n }\n\n // For \"one\" relations, specify fields and references\n if (relation.type === \"one\") {\n const fields: string[] = [];\n const references: string[] = [];\n\n // Use sanitized namespace for identifier references\n const tableRef = namespace\n ? `${table.ormName}_${sanitizeNamespace(namespace)}`\n : table.ormName;\n const relatedTableRef = namespace\n ? `${relation.table.ormName}_${sanitizeNamespace(namespace)}`\n : relation.table.ormName;\n\n for (const [left, right] of relation.on) {\n fields.push(`${tableRef}.${left}`);\n // Relations reference internal IDs\n const actualRight = right === \"id\" ? \"_internalId\" : right;\n references.push(`${relatedTableRef}.${actualRight}`);\n }\n\n options.push(`fields: [${fields.join(\", \")}]`, `references: [${references.join(\", \")}]`);\n }\n\n const relatedTableRef = namespace\n ? `${relation.table.ormName}_${sanitizeNamespace(namespace)}`\n : relation.table.ormName;\n\n const args: string[] = [relatedTableRef];\n if (options.length > 0) {\n args.push(`{\\n${ident(options.join(\",\\n\"))}\\n}`);\n }\n\n relations.push(ident(`${relation.name}: ${relation.type}(${args.join(\", \")})`));\n }\n\n // Generate inverse relations for tables that reference this table\n // Drizzle requires both sides of a relation to be defined\n if (inverseRelations && inverseRelations.length > 0) {\n for (const { fromTable, relation } of inverseRelations) {\n // Only generate inverse for \"one\" relations (they become \"many\" on this side)\n if (relation.type === \"one\") {\n hasMany = true;\n\n const fromTableRef = namespace\n ? `${fromTable.ormName}_${sanitizeNamespace(namespace)}`\n : fromTable.ormName;\n\n // Generate inverse relation name with consistent suffix\n // e.g., if session has \"sessionOwner\" relation to user, user gets \"sessionList\" inverse relation\n const inverseRelationName = `${fromTable.ormName}List`;\n\n const options: string[] = [`relationName: \"${relation.id}\"`];\n const args: string[] = [fromTableRef, `{\\n${ident(options.join(\",\\n\"))}\\n}`];\n\n relations.push(ident(`${inverseRelationName}: many(${args.join(\", \")})`));\n }\n }\n }\n\n if (relations.length === 0) {\n return undefined;\n }\n\n // Only include the relation types that are actually used\n const params: string[] = [];\n if (hasOne) {\n params.push(\"one\");\n }\n if (hasMany) {\n params.push(\"many\");\n }\n const relationParams = params.length > 0 ? `{ ${params.join(\", \")} }` : \"{}\";\n\n const tableRef = namespace ? `${table.ormName}_${sanitizeNamespace(namespace)}` : table.ormName;\n const relationsName = namespace\n ? `${table.ormName}_${sanitizeNamespace(namespace)}Relations`\n : `${table.ormName}Relations`;\n\n ctx.imports.addImport(\"relations\", \"drizzle-orm\");\n return `export const ${relationsName} = relations(${tableRef}, (${relationParams}) => ({\n${relations.join(\",\\n\")}\n}));`;\n}\n\n// ============================================================================\n// UTILITIES\n// ============================================================================\n\n/**\n * Generate a schema export object for a fragment\n * This groups all tables by their logical names for easier access\n */\nfunction generateFragmentSchemaExport(\n schema: AnySchema,\n namespace: string,\n tablesWithRelations?: Set<string>,\n): string {\n const drizzleEntries: string[] = [];\n\n for (const table of Object.values(schema.tables)) {\n const physicalExportName = namespace\n ? `${table.ormName}_${sanitizeNamespace(namespace)}`\n : table.ormName;\n\n // Add physical table name to drizzle schema\n drizzleEntries.push(` ${physicalExportName}: ${physicalExportName}`);\n\n // Include relations for this table if they exist (either explicit or inverse)\n if (tablesWithRelations?.has(table.name)) {\n const relationsName = namespace\n ? `${table.ormName}_${sanitizeNamespace(namespace)}Relations`\n : `${table.ormName}Relations`;\n\n drizzleEntries.push(` ${relationsName}: ${relationsName}`);\n }\n\n // Add convenience aliases WITH their relations to work around Drizzle bug\n // The key insight: Drizzle needs BOTH the table alias AND its relations alias\n // in the same schema object for relational queries to work\n if (namespace) {\n drizzleEntries.push(` ${table.ormName}: ${physicalExportName}`);\n\n // Also add the relations under the aliased name if they exist\n if (tablesWithRelations?.has(table.name)) {\n const physicalRelationsName = `${table.ormName}_${sanitizeNamespace(namespace)}Relations`;\n const aliasRelationsName = `${table.ormName}Relations`;\n drizzleEntries.push(` ${aliasRelationsName}: ${physicalRelationsName}`);\n }\n }\n }\n\n // Add schema version as a number\n drizzleEntries.push(` schemaVersion: ${schema.version}`);\n\n const exportName = namespace ? `${sanitizeNamespace(namespace)}_schema` : \"_schema\";\n\n return `export const ${exportName} = {\\n${drizzleEntries.join(\",\\n\")}\\n}`;\n}\n\n// ============================================================================\n// MAIN GENERATION\n// ============================================================================\n\nexport interface GenerateSchemaOptions {\n /** Custom ID generator import configuration */\n idGeneratorImport?: {\n /** Function name to import */\n name: string;\n /** Module to import from */\n from: string;\n };\n}\n\n/**\n * Generate a settings table for storing fragment versions\n */\nfunction generateSettingsTable(ctx: GeneratorContext): string {\n // Use centralized settings schema\n\n // Extract the table from the schema\n const settingsTable =\n settingsSchema.tables[SETTINGS_TABLE_NAME as keyof typeof settingsSchema.tables];\n\n // Generate the table using the existing generateTable function\n const customTypes: string[] = [];\n return generateTable(ctx, settingsTable, customTypes);\n}\n\n/**\n * Generate a schema file from one or more fragments with a shared settings table\n */\nexport function generateSchema(\n fragments: { namespace: string; schema: AnySchema }[],\n provider: SupportedProvider,\n options?: GenerateSchemaOptions,\n): string {\n const ctx = createContext(provider, options?.idGeneratorImport);\n const customTypes: string[] = [];\n const sections: string[] = [];\n\n // Generate settings table first\n sections.push(\"\");\n sections.push(\"// ============================================================================\");\n sections.push(\"// Settings Table (shared across all fragments)\");\n sections.push(\"// ============================================================================\");\n sections.push(\"\");\n sections.push(generateSettingsTable(ctx));\n sections.push(\"\");\n sections.push(`export const fragnoDbSettingSchemaVersion = ${settingsSchema.version};`);\n\n // Generate each fragment's tables\n for (const { namespace, schema } of fragments) {\n const fragmentTables: string[] = [];\n\n // Add section header\n fragmentTables.push(\"\");\n fragmentTables.push(\n \"// ============================================================================\",\n );\n fragmentTables.push(`// Fragment: ${namespace}`);\n fragmentTables.push(\n \"// ============================================================================\",\n );\n\n // Generate tables for this fragment\n for (const table of Object.values(schema.tables)) {\n const tableCode = generateTable(ctx, table, customTypes, namespace);\n fragmentTables.push(\"\");\n fragmentTables.push(tableCode);\n }\n\n // Build a map of inverse relations for tables that are referenced but don't have their own relations\n // This is needed for Drizzle's relational query API to work correctly\n const inverseRelations = new Map<string, Array<{ fromTable: AnyTable; relation: Relation }>>();\n for (const table of Object.values(schema.tables)) {\n for (const relation of Object.values(table.relations)) {\n // Track this relation as an inverse on the target table\n const targetTableName = relation.table.name;\n if (!inverseRelations.has(targetTableName)) {\n inverseRelations.set(targetTableName, []);\n }\n inverseRelations.get(targetTableName)!.push({ fromTable: table, relation });\n }\n }\n\n // Generate relations for all tables (both explicit and inverse)\n const tablesWithRelations = new Set<string>();\n for (const table of Object.values(schema.tables)) {\n const relationCode = generateRelation(\n ctx,\n table,\n namespace,\n inverseRelations.get(table.name),\n );\n if (relationCode) {\n fragmentTables.push(\"\");\n fragmentTables.push(relationCode);\n tablesWithRelations.add(table.name);\n }\n }\n\n // Generate schema export object\n fragmentTables.push(\"\");\n fragmentTables.push(generateFragmentSchemaExport(schema, namespace, tablesWithRelations));\n\n sections.push(...fragmentTables);\n }\n\n // Assemble final output\n const lines: string[] = [ctx.imports.format(), ...customTypes, ...sections];\n return lines.join(\"\\n\");\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"generate.js","names":["parts: string[]","params: string[]","value: string","keys: string[]","columns: string[]","foreignColumns: string[]","indexes: string[]","args: string[]","relations: string[]","options: string[]","fields: string[]","references: string[]","tableRef","drizzleEntries: string[]","customTypes: string[]","sections: string[]","fragmentTables: string[]"],"sources":["../../../src/adapters/drizzle/generate.ts"],"sourcesContent":["import { importGenerator } from \"../../util/import-generator\";\nimport { ident, parseVarchar } from \"../../util/parse\";\nimport {\n type AnyColumn,\n type AnySchema,\n type AnyTable,\n type Relation,\n InternalIdColumn,\n} from \"../../schema/create\";\nimport type { SQLProvider } from \"../../shared/providers\";\nimport { schemaToDBType, type DBTypeLiteral } from \"../../schema/serialize\";\nimport { createTableNameMapper, sanitizeNamespace } from \"./shared\";\n\n// ============================================================================\n// PROVIDER CONFIGURATION\n// ============================================================================\n\nconst PROVIDER_IMPORTS = {\n mysql: \"drizzle-orm/mysql-core\",\n postgresql: \"drizzle-orm/pg-core\",\n sqlite: \"drizzle-orm/sqlite-core\",\n} as const;\n\nconst PROVIDER_TABLE_FUNCTIONS = {\n mysql: \"mysqlTable\",\n postgresql: \"pgTable\",\n sqlite: \"sqliteTable\",\n} as const;\n\nexport type SupportedProvider = Exclude<SQLProvider, \"cockroachdb\" | \"mssql\">;\n\n// ============================================================================\n// CONTEXT\n// ============================================================================\n\ninterface GeneratorContext {\n provider: SupportedProvider;\n imports: ReturnType<typeof importGenerator>;\n importSource: string;\n generatedCustomTypes: Set<string>;\n idGeneratorImport?: { name: string; from: string };\n}\n\nfunction createContext(\n provider: SupportedProvider,\n idGeneratorImport?: { name: string; from: string },\n): GeneratorContext {\n return {\n provider,\n imports: importGenerator(),\n importSource: PROVIDER_IMPORTS[provider],\n generatedCustomTypes: new Set<string>(),\n idGeneratorImport,\n };\n}\n\n// ============================================================================\n// CUSTOM TYPE GENERATION\n// ============================================================================\n\ninterface CustomTypeOptions {\n dataType: string;\n driverDataType: string;\n databaseDataType: string;\n fromDriverCode: string;\n toDriverCode: string;\n}\n\nfunction generateCustomType(\n ctx: GeneratorContext,\n name: string,\n options: CustomTypeOptions,\n): string | undefined {\n if (ctx.generatedCustomTypes.has(name)) {\n return undefined;\n }\n\n ctx.imports.addImport(\"customType\", ctx.importSource);\n ctx.generatedCustomTypes.add(name);\n\n return `const ${name} = customType<\n {\n data: ${options.dataType};\n driverData: ${options.driverDataType};\n }\n>({\n dataType() {\n return \"${options.databaseDataType}\";\n },\n fromDriver(value) {\n ${options.fromDriverCode}\n },\n toDriver(value) {\n ${options.toDriverCode}\n }\n});`;\n}\n\nfunction generateBinaryCustomType(ctx: GeneratorContext, customTypes: string[]): string {\n const name = \"customBinary\";\n const code = generateCustomType(ctx, name, {\n dataType: \"Uint8Array\",\n driverDataType: \"Buffer\",\n databaseDataType: schemaToDBType({ type: \"binary\" }, ctx.provider),\n fromDriverCode: \"return new Uint8Array(value.buffer, value.byteOffset, value.byteLength)\",\n toDriverCode: `return value instanceof Buffer? value : Buffer.from(value)`,\n });\n\n if (code) {\n customTypes.push(code);\n }\n return name;\n}\n\n// ============================================================================\n// COLUMN TYPE MAPPING\n// ============================================================================\n\ninterface ColumnTypeFunction {\n name: string;\n isCustomType?: boolean;\n params?: string[];\n}\n\n/**\n * Maps SQL database types to Drizzle function names and parameters.\n * Uses schemaToDBType as the source of truth for type conversion.\n */\nfunction getColumnTypeFunction(\n ctx: GeneratorContext,\n column: AnyColumn,\n customTypes: string[],\n): ColumnTypeFunction {\n // Get the canonical database type from schemaToDBType\n const dbType = schemaToDBType(column, ctx.provider);\n\n // Map database types to Drizzle function names\n return mapDBTypeToDrizzleFunction(ctx, dbType, column, customTypes);\n}\n\n/**\n * Maps a database type string to a Drizzle function name and parameters.\n */\nfunction mapDBTypeToDrizzleFunction(\n ctx: GeneratorContext,\n dbType: DBTypeLiteral,\n column: AnyColumn,\n customTypes: string[],\n): ColumnTypeFunction {\n // Handle provider-specific types\n if (ctx.provider === \"postgresql\") {\n switch (dbType) {\n case \"bigserial\":\n // bigserial requires a mode parameter in Drizzle\n return { name: \"bigserial\", params: [`{ mode: \"number\" }`] };\n case \"serial\":\n return { name: \"serial\" };\n case \"boolean\":\n return { name: \"boolean\" };\n case \"bytea\":\n return { name: generateBinaryCustomType(ctx, customTypes), isCustomType: true };\n case \"json\":\n return { name: \"json\" };\n case \"text\":\n return { name: \"text\" };\n case \"bigint\":\n return { name: \"bigint\", params: [`{ mode: \"number\" }`] };\n default:\n if (dbType.startsWith(\"varchar(\")) {\n const length = parseVarchar(dbType);\n return { name: \"varchar\", params: [`{ length: ${length} }`] };\n }\n return { name: dbType };\n }\n }\n\n if (ctx.provider === \"mysql\") {\n switch (dbType) {\n case \"boolean\":\n return { name: \"boolean\" };\n case \"text\":\n return { name: \"text\" };\n case \"longblob\":\n return { name: generateBinaryCustomType(ctx, customTypes), isCustomType: true };\n case \"bigint\":\n // MySQL bigint requires mode parameter\n return { name: \"bigint\", params: [`{ mode: \"number\" }`] };\n case \"integer\":\n // MySQL uses \"int\" not \"integer\" in Drizzle ORM\n return { name: \"int\" };\n default:\n if (dbType.startsWith(\"varchar(\")) {\n const length = parseVarchar(dbType);\n return { name: \"varchar\", params: [`{ length: ${length} }`] };\n }\n return { name: dbType };\n }\n }\n\n if (ctx.provider === \"sqlite\") {\n switch (dbType) {\n case \"integer\":\n // Need to determine the mode based on the original column type\n if (column.type === \"bool\") {\n return { name: \"integer\", params: [`{ mode: \"boolean\" }`] };\n }\n if (column.type === \"timestamp\" || column.type === \"date\") {\n return { name: \"integer\", params: [`{ mode: \"timestamp\" }`] };\n }\n return { name: \"integer\" };\n case \"blob\":\n // Need to determine the mode based on the original column type\n if (column.type === \"bigint\") {\n return { name: \"blob\", params: [`{ mode: \"bigint\" }`] };\n }\n return { name: generateBinaryCustomType(ctx, customTypes), isCustomType: true };\n case \"text\":\n // Check if it's JSON\n if (column.type === \"json\") {\n return { name: \"blob\", params: [`{ mode: \"json\" }`] };\n }\n return { name: \"text\" };\n case \"real\":\n return { name: \"real\" };\n default:\n return { name: dbType };\n }\n }\n\n // Fallback for other providers\n return { name: dbType };\n}\n\n// ============================================================================\n// COLUMN GENERATION\n// ============================================================================\n\nfunction generateColumnDefinition(\n ctx: GeneratorContext,\n column: AnyColumn,\n customTypes: string[],\n): string {\n const parts: string[] = [];\n const typeFn = getColumnTypeFunction(ctx, column, customTypes);\n\n // Column type with parameters\n const params: string[] = [`\"${column.name}\"`, ...(typeFn.params ?? [])];\n if (!typeFn.isCustomType) {\n ctx.imports.addImport(typeFn.name, ctx.importSource);\n }\n parts.push(`${typeFn.name}(${params.join(\", \")})`);\n\n // Primary key for internal ID\n if (column instanceof InternalIdColumn || column.role === \"internal-id\") {\n if (ctx.provider === \"sqlite\") {\n // SQLite uses primaryKey({ autoIncrement: true })\n parts.push(\"primaryKey({ autoIncrement: true })\");\n } else if (ctx.provider === \"mysql\") {\n // MySQL uses primaryKey().autoincrement()\n parts.push(\"primaryKey()\");\n parts.push(\"autoincrement()\");\n } else {\n // PostgreSQL just uses primaryKey()\n parts.push(\"primaryKey()\");\n }\n }\n\n // Nullability\n if (!column.isNullable) {\n parts.push(\"notNull()\");\n }\n\n // Default values\n if (column.default) {\n if (\"value\" in column.default) {\n // Static defaults: defaultTo(value)\n let value: string;\n if (typeof column.default.value === \"bigint\") {\n ctx.imports.addImport(\"sql\", \"drizzle-orm\");\n value = `sql\\`${column.default.value.toString()}\\``;\n } else {\n value = JSON.stringify(column.default.value);\n }\n parts.push(`default(${value})`);\n } else if (\"dbSpecial\" in column.default) {\n // Database-level special functions: defaultTo(b => b.now())\n if (column.default.dbSpecial === \"now\") {\n parts.push(\"defaultNow()\");\n }\n } else if (\"runtime\" in column.default) {\n // Runtime defaults: defaultTo$()\n if (column.default.runtime === \"cuid\") {\n const idGen = ctx.idGeneratorImport ?? { name: \"createId\", from: \"@fragno-dev/db/id\" };\n ctx.imports.addImport(idGen.name, idGen.from);\n parts.push(`$defaultFn(() => ${idGen.name}())`);\n } else if (column.default.runtime === \"now\") {\n // Runtime-generated timestamp (not database-level)\n parts.push(\"$defaultFn(() => new Date())\");\n }\n // Note: Custom functions in defaultTo$(() => ...) are not supported in schema generation\n }\n }\n\n return ` ${column.ormName}: ${parts.join(\".\")}`;\n}\n\nfunction generateAllColumns(\n ctx: GeneratorContext,\n table: AnyTable,\n customTypes: string[],\n): string[] {\n return Object.values(table.columns).map((column) =>\n generateColumnDefinition(ctx, column, customTypes),\n );\n}\n\n// ============================================================================\n// CONSTRAINT GENERATION\n// ============================================================================\n\nfunction generateForeignKeys(ctx: GeneratorContext, table: AnyTable, namespace?: string): string[] {\n const mapper = namespace ? createTableNameMapper(namespace) : undefined;\n const keys: string[] = [];\n\n for (const relation of Object.values(table.relations)) {\n // Only \"one\" relations generate foreign keys\n // \"many\" relations don't have foreign keys (they're on the other side)\n if (relation.type === \"many\") {\n continue;\n }\n\n const columns: string[] = [];\n const foreignColumns: string[] = [];\n const isSelfReference = relation.table.ormName === table.ormName;\n\n for (const [localCol, refCol] of relation.on) {\n columns.push(`table.${localCol}`);\n // Foreign keys always reference internal IDs\n const actualRefCol = refCol === \"id\" ? \"_internalId\" : refCol;\n // For self-referencing foreign keys, use table parameter instead of table constant\n if (isSelfReference) {\n foreignColumns.push(`table.${actualRefCol}`);\n } else {\n // Suffix the foreign table reference with namespace if provided\n const foreignTableRef = namespace\n ? `${relation.table.ormName}_${sanitizeNamespace(namespace)}`\n : relation.table.ormName;\n foreignColumns.push(`${foreignTableRef}.${actualRefCol}`);\n }\n }\n\n ctx.imports.addImport(\"foreignKey\", ctx.importSource);\n // Include namespace in FK name to avoid collisions\n const fkName =\n namespace && mapper\n ? \"fk_\" + mapper.toPhysical(`${table.ormName}_${relation.table.ormName}_${relation.name}`)\n : `${table.ormName}_${relation.table.ormName}_${relation.name}_fk`;\n\n keys.push(`foreignKey({\n columns: [${columns.join(\", \")}],\n foreignColumns: [${foreignColumns.join(\", \")}],\n name: \"${fkName}\"\n})`);\n }\n\n return keys;\n}\n\nfunction generateIndexes(ctx: GeneratorContext, table: AnyTable, namespace?: string): string[] {\n const indexes: string[] = [];\n\n for (const idx of Object.values(table.indexes)) {\n const columns = idx.columns.map((col) => `table.${col.ormName}`).join(\", \");\n\n // Include namespace in index name to avoid collisions\n const indexName = namespace ? `${idx.name}_${namespace}` : idx.name;\n\n if (idx.unique) {\n ctx.imports.addImport(\"uniqueIndex\", ctx.importSource);\n indexes.push(`uniqueIndex(\"${indexName}\").on(${columns})`);\n } else {\n ctx.imports.addImport(\"index\", ctx.importSource);\n indexes.push(`index(\"${indexName}\").on(${columns})`);\n }\n }\n\n return indexes;\n}\n\nfunction generateTableConstraints(\n ctx: GeneratorContext,\n table: AnyTable,\n namespace?: string,\n): string[] {\n return [...generateForeignKeys(ctx, table, namespace), ...generateIndexes(ctx, table, namespace)];\n}\n\n// ============================================================================\n// TABLE GENERATION\n// ============================================================================\n\nfunction generateTable(\n ctx: GeneratorContext,\n table: AnyTable,\n customTypes: string[],\n namespace?: string,\n): string {\n const tableFn = PROVIDER_TABLE_FUNCTIONS[ctx.provider];\n ctx.imports.addImport(tableFn, ctx.importSource);\n\n const columns = generateAllColumns(ctx, table, customTypes);\n const constraints = generateTableConstraints(ctx, table, namespace);\n\n // Suffix table name with namespace if provided, and sanitize for use as database table name\n // Database table names must also be valid identifiers to work with Drizzle's relational query system\n const physicalTableName = namespace\n ? `${table.ormName}_${sanitizeNamespace(namespace)}`\n : table.ormName;\n // Same sanitized name for TypeScript export\n const exportName = physicalTableName;\n\n const args: string[] = [`\"${physicalTableName}\"`, `{\\n${columns.join(\",\\n\")}\\n}`];\n\n if (constraints.length > 0) {\n args.push(`(table) => [\\n${ident(constraints.join(\",\\n\"))}\\n]`);\n }\n\n return `export const ${exportName} = ${tableFn}(${args.join(\", \")})`;\n}\n\n// ============================================================================\n// RELATION GENERATION\n// ============================================================================\n\nfunction generateRelation(\n ctx: GeneratorContext,\n table: AnyTable,\n namespace?: string,\n inverseRelations?: Array<{ fromTable: AnyTable; relation: Relation }>,\n): string | undefined {\n const relations: string[] = [];\n let hasOne = false;\n let hasMany = false;\n\n // Generate explicit relations defined on this table\n for (const relation of Object.values(table.relations)) {\n const options: string[] = [`relationName: \"${relation.id}\"`];\n\n // Track which relation types are used\n if (relation.type === \"one\") {\n hasOne = true;\n } else if (relation.type === \"many\") {\n hasMany = true;\n }\n\n // For \"one\" relations, specify fields and references\n if (relation.type === \"one\") {\n const fields: string[] = [];\n const references: string[] = [];\n\n // Use sanitized namespace for identifier references\n const tableRef = namespace\n ? `${table.ormName}_${sanitizeNamespace(namespace)}`\n : table.ormName;\n const relatedTableRef = namespace\n ? `${relation.table.ormName}_${sanitizeNamespace(namespace)}`\n : relation.table.ormName;\n\n for (const [left, right] of relation.on) {\n fields.push(`${tableRef}.${left}`);\n // Relations reference internal IDs\n const actualRight = right === \"id\" ? \"_internalId\" : right;\n references.push(`${relatedTableRef}.${actualRight}`);\n }\n\n options.push(`fields: [${fields.join(\", \")}]`, `references: [${references.join(\", \")}]`);\n }\n\n const relatedTableRef = namespace\n ? `${relation.table.ormName}_${sanitizeNamespace(namespace)}`\n : relation.table.ormName;\n\n const args: string[] = [relatedTableRef];\n if (options.length > 0) {\n args.push(`{\\n${ident(options.join(\",\\n\"))}\\n}`);\n }\n\n relations.push(ident(`${relation.name}: ${relation.type}(${args.join(\", \")})`));\n }\n\n // Generate inverse relations for tables that reference this table\n // Drizzle requires both sides of a relation to be defined\n if (inverseRelations && inverseRelations.length > 0) {\n for (const { fromTable, relation } of inverseRelations) {\n // Only generate inverse for \"one\" relations (they become \"many\" on this side)\n if (relation.type === \"one\") {\n hasMany = true;\n\n const fromTableRef = namespace\n ? `${fromTable.ormName}_${sanitizeNamespace(namespace)}`\n : fromTable.ormName;\n\n // Generate inverse relation name with consistent suffix\n // e.g., if session has \"sessionOwner\" relation to user, user gets \"sessionList\" inverse relation\n const inverseRelationName = `${fromTable.ormName}List`;\n\n const options: string[] = [`relationName: \"${relation.id}\"`];\n const args: string[] = [fromTableRef, `{\\n${ident(options.join(\",\\n\"))}\\n}`];\n\n relations.push(ident(`${inverseRelationName}: many(${args.join(\", \")})`));\n }\n }\n }\n\n if (relations.length === 0) {\n return undefined;\n }\n\n // Only include the relation types that are actually used\n const params: string[] = [];\n if (hasOne) {\n params.push(\"one\");\n }\n if (hasMany) {\n params.push(\"many\");\n }\n const relationParams = params.length > 0 ? `{ ${params.join(\", \")} }` : \"{}\";\n\n const tableRef = namespace ? `${table.ormName}_${sanitizeNamespace(namespace)}` : table.ormName;\n const relationsName = namespace\n ? `${table.ormName}_${sanitizeNamespace(namespace)}Relations`\n : `${table.ormName}Relations`;\n\n ctx.imports.addImport(\"relations\", \"drizzle-orm\");\n return `export const ${relationsName} = relations(${tableRef}, (${relationParams}) => ({\n${relations.join(\",\\n\")}\n}));`;\n}\n\n// ============================================================================\n// UTILITIES\n// ============================================================================\n\n/**\n * Generate a schema export object for a fragment\n * This groups all tables by their logical names for easier access\n */\nfunction generateFragmentSchemaExport(\n schema: AnySchema,\n namespace: string,\n tablesWithRelations?: Set<string>,\n): string {\n const drizzleEntries: string[] = [];\n\n for (const table of Object.values(schema.tables)) {\n const physicalExportName = namespace\n ? `${table.ormName}_${sanitizeNamespace(namespace)}`\n : table.ormName;\n\n // Add physical table name to drizzle schema\n drizzleEntries.push(` ${physicalExportName}: ${physicalExportName}`);\n\n // Include relations for this table if they exist (either explicit or inverse)\n if (tablesWithRelations?.has(table.name)) {\n const relationsName = namespace\n ? `${table.ormName}_${sanitizeNamespace(namespace)}Relations`\n : `${table.ormName}Relations`;\n\n drizzleEntries.push(` ${relationsName}: ${relationsName}`);\n }\n\n // Add convenience aliases WITH their relations to work around Drizzle bug\n // The key insight: Drizzle needs BOTH the table alias AND its relations alias\n // in the same schema object for relational queries to work\n if (namespace) {\n drizzleEntries.push(` ${table.ormName}: ${physicalExportName}`);\n\n // Also add the relations under the aliased name if they exist\n if (tablesWithRelations?.has(table.name)) {\n const physicalRelationsName = `${table.ormName}_${sanitizeNamespace(namespace)}Relations`;\n const aliasRelationsName = `${table.ormName}Relations`;\n drizzleEntries.push(` ${aliasRelationsName}: ${physicalRelationsName}`);\n }\n }\n }\n\n // Add schema version as a number\n drizzleEntries.push(` schemaVersion: ${schema.version}`);\n\n const exportName = namespace ? `${sanitizeNamespace(namespace)}_schema` : \"_schema\";\n\n return `export const ${exportName} = {\\n${drizzleEntries.join(\",\\n\")}\\n}`;\n}\n\n// ============================================================================\n// MAIN GENERATION\n// ============================================================================\n\nexport interface GenerateSchemaOptions {\n /** Custom ID generator import configuration */\n idGeneratorImport?: {\n /** Function name to import */\n name: string;\n /** Module to import from */\n from: string;\n };\n}\n\n/**\n * Generate a settings table for storing fragment versions\n */\n/**\n * Generate a schema file from one or more fragments with automatic de-duplication\n */\nexport function generateSchema(\n fragments: { namespace: string; schema: AnySchema }[],\n provider: SupportedProvider,\n options?: GenerateSchemaOptions,\n): string {\n const ctx = createContext(provider, options?.idGeneratorImport);\n const customTypes: string[] = [];\n const sections: string[] = [];\n\n for (const { schema, namespace } of fragments) {\n const fragmentTables: string[] = [];\n\n // Add section header\n fragmentTables.push(\"\");\n fragmentTables.push(\n \"// ============================================================================\",\n );\n fragmentTables.push(`// Fragment: ${namespace}`);\n fragmentTables.push(\n \"// ============================================================================\",\n );\n\n // Generate tables for this fragment\n for (const table of Object.values(schema.tables)) {\n const tableCode = generateTable(ctx, table, customTypes, namespace);\n fragmentTables.push(\"\");\n fragmentTables.push(tableCode);\n }\n\n // Build a map of inverse relations for tables that are referenced but don't have their own relations\n // This is needed for Drizzle's relational query API to work correctly\n const inverseRelations = new Map<string, Array<{ fromTable: AnyTable; relation: Relation }>>();\n for (const table of Object.values(schema.tables)) {\n for (const relation of Object.values(table.relations)) {\n // Track this relation as an inverse on the target table\n const targetTableName = relation.table.name;\n if (!inverseRelations.has(targetTableName)) {\n inverseRelations.set(targetTableName, []);\n }\n inverseRelations.get(targetTableName)!.push({ fromTable: table, relation });\n }\n }\n\n // Generate relations for all tables (both explicit and inverse)\n const tablesWithRelations = new Set<string>();\n for (const table of Object.values(schema.tables)) {\n const relationCode = generateRelation(\n ctx,\n table,\n namespace,\n inverseRelations.get(table.name),\n );\n if (relationCode) {\n fragmentTables.push(\"\");\n fragmentTables.push(relationCode);\n tablesWithRelations.add(table.name);\n }\n }\n\n // Generate schema export object (skip for empty namespace to avoid duplicate _schema exports)\n if (namespace !== \"\") {\n fragmentTables.push(\"\");\n fragmentTables.push(generateFragmentSchemaExport(schema, namespace, tablesWithRelations));\n }\n\n sections.push(...fragmentTables);\n }\n\n // Assemble final output\n const lines: string[] = [ctx.imports.format(), ...customTypes, ...sections];\n return lines.join(\"\\n\");\n}\n"],"mappings":"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"}
@@ -2,10 +2,11 @@ import { AnySchema } from "../../schema/create.js";
2
2
  import { Migrator } from "../../migration-engine/create.js";
3
3
  import { SQLProvider } from "../../shared/providers.js";
4
4
  import { AbstractQuery } from "../../query/query.js";
5
- import { DatabaseAdapter, fragnoDatabaseAdapterNameFakeSymbol, fragnoDatabaseAdapterVersionFakeSymbol } from "../adapters.js";
5
+ import { DatabaseAdapter, DatabaseContextStorage, fragnoDatabaseAdapterNameFakeSymbol, fragnoDatabaseAdapterVersionFakeSymbol } from "../adapters.js";
6
6
  import { TableNameMapper } from "./kysely-shared.js";
7
7
  import { KyselyUOWConfig } from "./kysely-query.js";
8
8
  import { Kysely } from "kysely";
9
+ import { RequestContextStorage } from "@fragno-dev/core/internal/request-context-storage";
9
10
 
10
11
  //#region src/adapters/kysely/kysely-adapter.d.ts
11
12
  type KyselyAny = Kysely<any>;
@@ -18,6 +19,7 @@ declare class KyselyAdapter implements DatabaseAdapter<KyselyUOWConfig> {
18
19
  constructor(config: KyselyConfig);
19
20
  get [fragnoDatabaseAdapterNameFakeSymbol](): string;
20
21
  get [fragnoDatabaseAdapterVersionFakeSymbol](): number;
22
+ get contextStorage(): RequestContextStorage<DatabaseContextStorage>;
21
23
  close(): Promise<void>;
22
24
  createTableNameMapper(namespace: string): TableNameMapper;
23
25
  createQueryEngine<T extends AnySchema>(schema: T, namespace: string): AbstractQuery<T, KyselyUOWConfig>;
@@ -1 +1 @@
1
- {"version":3,"file":"kysely-adapter.d.ts","names":[],"sources":["../../../src/adapters/kysely/kysely-adapter.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;KAoBK,SAAA,GAAY;UAEA,YAAA;MACX,mBAAmB,YAAY,QAAQ;EAHxC,QAAA,EAIO,WAJE;AAEd;AACM,cAIO,aAAA,YAAyB,eAJhC,CAIgD,eAJhD,CAAA,CAAA;EAAmB,CAAA,OAAA;EAAoB,WAAA,CAAA,MAAA,EASvB,YATuB;EAAR,KAc9B,mCAAA,GAd8B,EAAA,MAAA;EACzB,KAiBL,sCAAA,GAjBK,EAAA,MAAA;EAAW,KAAA,CAAA,CAAA,EAqBN,OArBM,CAAA,IAAA,CAAA;EAGV,qBAAc,CAAA,SAAA,EAAA,MAAA,CAAA,EAkBH,eAlBG;EAA2B,iBAAA,CAAA,UA0BxB,SA1BwB,CAAA,CAAA,MAAA,EA2B1C,CA3B0C,EAAA,SAAA,EAAA,MAAA,CAAA,EA6BjD,aA7BiD,CA6BnC,CA7BmC,EA6BhC,eA7BgC,CAAA;EAKhC,mBAAA,CAAA,CAAA,EAwCS,OAxCT,CAAA,OAAA,CAAA;EAKf,qBAAA,CAAA,MAAA,EA+CyB,SA/CzB,EAAA,SAAA,EAAA,MAAA,CAAA,EA+CwD,QA/CxD;EAIA,gBAAA,CAAA,SAAA,EAAA,MAAA,CAAA,EAqKsC,OArKtC,CAAA,MAAA,GAAA,SAAA,CAAA"}
1
+ {"version":3,"file":"kysely-adapter.d.ts","names":[],"sources":["../../../src/adapters/kysely/kysely-adapter.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;KAsBK,SAAA,GAAY;UAEA,YAAA;MACX,mBAAmB,YAAY,QAAQ;EAHxC,QAAA,EAIO,WAJE;AAEd;AACM,cAIO,aAAA,YAAyB,eAJhC,CAIgD,eAJhD,CAAA,CAAA;EAAmB,CAAA,OAAA;EAAoB,WAAA,CAAA,MAAA,EAUvB,YAVuB;EAAR,KAgB9B,mCAAA,GAhB8B,EAAA,MAAA;EACzB,KAmBL,sCAAA,GAnBK,EAAA,MAAA;EAAW,IAAA,cAAA,CAAA,CAAA,EAuBC,qBAvBD,CAuBuB,sBAvBvB,CAAA;EAGV,KAAA,CAAA,CAAA,EAwBI,OAxBU,CAAA,IAAA,CAAA;EAA2B,qBAAA,CAAA,SAAA,EAAA,MAAA,CAAA,EAwB9B,eAxB8B;EAMhC,iBAAA,CAAA,UA0BQ,SA1BR,CAAA,CAAA,MAAA,EA2BV,CA3BU,EAAA,SAAA,EAAA,MAAA,CAAA,EA6BjB,aA7BiB,CA6BH,CA7BG,EA6BA,eA7BA,CAAA;EAMf,mBAAA,CAAA,CAAA,EAuCwB,OAvCxB,CAAA,OAAA,CAAA;EAIA,qBAAA,CAAA,MAAA,EA+CyB,SA/CzB,EAAA,SAAA,EAAA,MAAA,CAAA,EA+CwD,QA/CxD;EAIuC,gBAAA,CAAA,SAAA,EAAA,MAAA,CAAA,EAqKD,OArKC,CAAA,MAAA,GAAA,SAAA,CAAA"}
@@ -1,5 +1,6 @@
1
+ import { RequestContextStorage } from "../../packages/fragno/dist/api/request-context-storage.js";
2
+ import { SETTINGS_TABLE_NAME } from "../../fragments/internal-fragment.js";
1
3
  import { fragnoDatabaseAdapterNameFakeSymbol, fragnoDatabaseAdapterVersionFakeSymbol } from "../adapters.js";
2
- import { SETTINGS_TABLE_NAME } from "../../shared/settings-schema.js";
3
4
  import { createMigrator } from "../../migration-engine/create.js";
4
5
  import { execute, preprocessOperations } from "./migration/execute.js";
5
6
  import { createTableNameMapper } from "./kysely-shared.js";
@@ -13,9 +14,11 @@ var KyselyAdapter = class {
13
14
  #connectionPool;
14
15
  #provider;
15
16
  #schemaNamespaceMap = /* @__PURE__ */ new WeakMap();
17
+ #contextStorage;
16
18
  constructor(config) {
17
19
  this.#connectionPool = createKyselyConnectionPool(config.db);
18
20
  this.#provider = config.provider;
21
+ this.#contextStorage = new RequestContextStorage();
19
22
  }
20
23
  get [fragnoDatabaseAdapterNameFakeSymbol]() {
21
24
  return "kysely";
@@ -23,6 +26,9 @@ var KyselyAdapter = class {
23
26
  get [fragnoDatabaseAdapterVersionFakeSymbol]() {
24
27
  return 0;
25
28
  }
29
+ get contextStorage() {
30
+ return this.#contextStorage;
31
+ }
26
32
  async close() {
27
33
  await this.#connectionPool.close();
28
34
  }
@@ -1 +1 @@
1
- {"version":3,"file":"kysely-adapter.js","names":["#connectionPool","#provider","#schemaNamespaceMap","db","config: KyselyConfig","parts: string[]"],"sources":["../../../src/adapters/kysely/kysely-adapter.ts"],"sourcesContent":["import { sql, type Kysely } from \"kysely\";\nimport type { SQLProvider } from \"../../shared/providers\";\nimport {\n fragnoDatabaseAdapterNameFakeSymbol,\n fragnoDatabaseAdapterVersionFakeSymbol,\n type DatabaseAdapter,\n} from \"../adapters\";\nimport { createMigrator, type Migrator } from \"../../migration-engine/create\";\nimport type { AnySchema } from \"../../schema/create\";\nimport type { CustomOperation, MigrationOperation } from \"../../migration-engine/shared\";\nimport { execute, preprocessOperations } from \"./migration/execute\";\nimport type { AbstractQuery } from \"../../query/query\";\nimport { fromKysely, type KyselyUOWConfig } from \"./kysely-query\";\nimport { createTableNameMapper } from \"./kysely-shared\";\nimport { createHash } from \"node:crypto\";\nimport { SETTINGS_TABLE_NAME } from \"../../shared/settings-schema\";\nimport type { ConnectionPool } from \"../../shared/connection-pool\";\nimport { createKyselyConnectionPool } from \"./kysely-connection-pool\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype KyselyAny = Kysely<any>;\n\nexport interface KyselyConfig {\n db: KyselyAny | (() => KyselyAny | Promise<KyselyAny>);\n provider: SQLProvider;\n}\n\nexport class KyselyAdapter implements DatabaseAdapter<KyselyUOWConfig> {\n #connectionPool: ConnectionPool<KyselyAny>;\n #provider: SQLProvider;\n #schemaNamespaceMap = new WeakMap<AnySchema, string>();\n\n constructor(config: KyselyConfig) {\n this.#connectionPool = createKyselyConnectionPool(config.db);\n this.#provider = config.provider;\n }\n\n get [fragnoDatabaseAdapterNameFakeSymbol](): string {\n return \"kysely\";\n }\n\n get [fragnoDatabaseAdapterVersionFakeSymbol](): number {\n return 0;\n }\n\n async close(): Promise<void> {\n await this.#connectionPool.close();\n }\n\n createTableNameMapper(namespace: string) {\n return createTableNameMapper(namespace);\n }\n\n createQueryEngine<T extends AnySchema>(\n schema: T,\n namespace: string,\n ): AbstractQuery<T, KyselyUOWConfig> {\n // Register schema-namespace mapping\n this.#schemaNamespaceMap.set(schema, namespace);\n\n // Only create mapper if namespace is non-empty\n const mapper = namespace ? createTableNameMapper(namespace) : undefined;\n return fromKysely(\n schema,\n this.#connectionPool,\n this.#provider,\n mapper,\n undefined,\n this.#schemaNamespaceMap,\n );\n }\n\n async isConnectionHealthy(): Promise<boolean> {\n const conn = await this.#connectionPool.connect();\n try {\n const result = await conn.db.executeQuery(sql`SELECT 1 as healthy`.compile(conn.db));\n return (result.rows[0] as Record<string, unknown>)[\"healthy\"] === 1;\n } catch {\n return false;\n } finally {\n await conn.release();\n }\n }\n\n createMigrationEngine(schema: AnySchema, namespace: string): Migrator {\n const mapper = namespace ? createTableNameMapper(namespace) : undefined;\n\n const preprocessMigrationOperations = (operations: MigrationOperation[], db: KyselyAny) => {\n // Preprocess operations using the provided db instance\n const config: KyselyConfig = {\n db,\n provider: this.#provider,\n };\n let preprocessed = preprocessOperations(operations, config);\n\n if (this.#provider === \"mysql\") {\n preprocessed.unshift({ type: \"custom\", sql: \"SET FOREIGN_KEY_CHECKS = 0\" });\n preprocessed.push({ type: \"custom\", sql: \"SET FOREIGN_KEY_CHECKS = 1\" });\n }\n\n return preprocessed;\n };\n\n // Convert operations to executable nodes bound to specific db instance\n const toExecutableNodes = (operations: MigrationOperation[], db: KyselyAny) => {\n const onCustomNode = (node: CustomOperation, db: KyselyAny) => {\n const statement = sql.raw(node[\"sql\"] as string);\n\n return {\n compile() {\n return statement.compile(db);\n },\n execute() {\n return statement.execute(db);\n },\n };\n };\n\n const config: KyselyConfig = { db, provider: this.#provider };\n return operations.flatMap((op) =>\n execute(op, config, (node) => onCustomNode(node, db), mapper),\n );\n };\n\n const migrator = createMigrator({\n schema,\n executor: async (operations) => {\n const conn = await this.#connectionPool.connect();\n try {\n // For SQLite, execute PRAGMA defer_foreign_keys BEFORE transaction\n if (this.#provider === \"sqlite\") {\n await sql.raw(\"PRAGMA defer_foreign_keys = ON\").execute(conn.db);\n }\n\n await conn.db.transaction().execute(async (tx) => {\n // Use the transaction instance for both preprocessing and execution\n const preprocessed = preprocessMigrationOperations(operations, tx);\n const nodes = toExecutableNodes(preprocessed, tx);\n for (const node of nodes) {\n try {\n await node.execute();\n } catch (e) {\n console.error(\"failed at\", node.compile(), e);\n throw e;\n }\n }\n });\n } finally {\n await conn.release();\n }\n },\n sql: {\n toSql: (operations) => {\n const parts: string[] = [];\n\n // Add SQLite PRAGMA at the beginning\n if (this.#provider === \"sqlite\") {\n parts.push(\"PRAGMA defer_foreign_keys = ON;\");\n }\n\n // Use getDatabaseSync for SQL generation (doesn't execute, just builds SQL strings)\n const db = this.#connectionPool.getDatabaseSync();\n const preprocessed = preprocessMigrationOperations(operations, db);\n const nodes = toExecutableNodes(preprocessed, db);\n const compiled = nodes.map((node) => `${node.compile().sql};`);\n\n parts.push(...compiled);\n\n return parts.join(\"\\n\\n\");\n },\n },\n\n settings: {\n getVersion: async () => {\n const conn = await this.#connectionPool.connect();\n try {\n const manager = createSettingsManager(conn.db, namespace);\n const v = await manager.get(`schema_version`);\n return v ? parseInt(v) : 0;\n } finally {\n await conn.release();\n }\n },\n updateSettingsInMigration: async (fromVersion, toVersion) => {\n const conn = await this.#connectionPool.connect();\n try {\n const manager = createSettingsManager(conn.db, namespace);\n return [\n {\n type: \"custom\",\n sql:\n fromVersion === 0\n ? manager.insert(`schema_version`, toVersion.toString())\n : manager.update(`schema_version`, toVersion.toString()),\n },\n ];\n } finally {\n await conn.release();\n }\n },\n },\n });\n\n return migrator;\n }\n\n async getSchemaVersion(namespace: string): Promise<string | undefined> {\n const conn = await this.#connectionPool.connect();\n try {\n const manager = createSettingsManager(conn.db, namespace);\n return await manager.get(`schema_version`);\n } finally {\n await conn.release();\n }\n }\n}\n\nfunction createSettingsManager(db: KyselyAny, namespace: string) {\n // Settings table is never namespaced, but keys include namespace prefix\n const tableName = SETTINGS_TABLE_NAME;\n\n return {\n async get(key: string): Promise<string | undefined> {\n try {\n const result = await db\n .selectFrom(tableName)\n .where(\"key\", \"=\", sql.lit(`${namespace}.${key}`))\n .select([\"value\"])\n .executeTakeFirstOrThrow();\n return result.value as string;\n } catch {\n return;\n }\n },\n\n insert(key: string, value: string) {\n return db\n .insertInto(tableName)\n .values({\n id: sql.lit(\n createHash(\"md5\").update(`${namespace}.${key}`).digest(\"base64url\").replace(/=/g, \"\"),\n ),\n key: sql.lit(`${namespace}.${key}`),\n value: sql.lit(value),\n })\n .compile().sql;\n },\n\n update(key: string, value: string) {\n return db\n .updateTable(tableName)\n .set({\n value: sql.lit(value),\n })\n .where(\"key\", \"=\", sql.lit(`${namespace}.${key}`))\n .compile().sql;\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"kysely-adapter.js","names":["#connectionPool","#provider","#contextStorage","#schemaNamespaceMap","db","config: KyselyConfig","parts: string[]"],"sources":["../../../src/adapters/kysely/kysely-adapter.ts"],"sourcesContent":["import { sql, type Kysely } from \"kysely\";\nimport type { SQLProvider } from \"../../shared/providers\";\nimport {\n fragnoDatabaseAdapterNameFakeSymbol,\n fragnoDatabaseAdapterVersionFakeSymbol,\n type DatabaseAdapter,\n type DatabaseContextStorage,\n} from \"../adapters\";\nimport { createMigrator, type Migrator } from \"../../migration-engine/create\";\nimport type { AnySchema } from \"../../schema/create\";\nimport type { CustomOperation, MigrationOperation } from \"../../migration-engine/shared\";\nimport { execute, preprocessOperations } from \"./migration/execute\";\nimport type { AbstractQuery } from \"../../query/query\";\nimport { fromKysely, type KyselyUOWConfig } from \"./kysely-query\";\nimport { createTableNameMapper } from \"./kysely-shared\";\nimport { createHash } from \"node:crypto\";\nimport { SETTINGS_TABLE_NAME } from \"../../fragments/internal-fragment\";\nimport type { ConnectionPool } from \"../../shared/connection-pool\";\nimport { createKyselyConnectionPool } from \"./kysely-connection-pool\";\nimport { RequestContextStorage } from \"@fragno-dev/core/internal/request-context-storage\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype KyselyAny = Kysely<any>;\n\nexport interface KyselyConfig {\n db: KyselyAny | (() => KyselyAny | Promise<KyselyAny>);\n provider: SQLProvider;\n}\n\nexport class KyselyAdapter implements DatabaseAdapter<KyselyUOWConfig> {\n #connectionPool: ConnectionPool<KyselyAny>;\n #provider: SQLProvider;\n #schemaNamespaceMap = new WeakMap<AnySchema, string>();\n #contextStorage: RequestContextStorage<DatabaseContextStorage>;\n\n constructor(config: KyselyConfig) {\n this.#connectionPool = createKyselyConnectionPool(config.db);\n this.#provider = config.provider;\n this.#contextStorage = new RequestContextStorage();\n }\n\n get [fragnoDatabaseAdapterNameFakeSymbol](): string {\n return \"kysely\";\n }\n\n get [fragnoDatabaseAdapterVersionFakeSymbol](): number {\n return 0;\n }\n\n get contextStorage(): RequestContextStorage<DatabaseContextStorage> {\n return this.#contextStorage;\n }\n\n async close(): Promise<void> {\n await this.#connectionPool.close();\n }\n\n createTableNameMapper(namespace: string) {\n return createTableNameMapper(namespace);\n }\n\n createQueryEngine<T extends AnySchema>(\n schema: T,\n namespace: string,\n ): AbstractQuery<T, KyselyUOWConfig> {\n // Register schema-namespace mapping\n this.#schemaNamespaceMap.set(schema, namespace);\n\n // Only create mapper if namespace is non-empty\n const mapper = namespace ? createTableNameMapper(namespace) : undefined;\n return fromKysely(\n schema,\n this.#connectionPool,\n this.#provider,\n mapper,\n undefined,\n this.#schemaNamespaceMap,\n );\n }\n\n async isConnectionHealthy(): Promise<boolean> {\n const conn = await this.#connectionPool.connect();\n try {\n const result = await conn.db.executeQuery(sql`SELECT 1 as healthy`.compile(conn.db));\n return (result.rows[0] as Record<string, unknown>)[\"healthy\"] === 1;\n } catch {\n return false;\n } finally {\n await conn.release();\n }\n }\n\n createMigrationEngine(schema: AnySchema, namespace: string): Migrator {\n const mapper = namespace ? createTableNameMapper(namespace) : undefined;\n\n const preprocessMigrationOperations = (operations: MigrationOperation[], db: KyselyAny) => {\n // Preprocess operations using the provided db instance\n const config: KyselyConfig = {\n db,\n provider: this.#provider,\n };\n let preprocessed = preprocessOperations(operations, config);\n\n if (this.#provider === \"mysql\") {\n preprocessed.unshift({ type: \"custom\", sql: \"SET FOREIGN_KEY_CHECKS = 0\" });\n preprocessed.push({ type: \"custom\", sql: \"SET FOREIGN_KEY_CHECKS = 1\" });\n }\n\n return preprocessed;\n };\n\n // Convert operations to executable nodes bound to specific db instance\n const toExecutableNodes = (operations: MigrationOperation[], db: KyselyAny) => {\n const onCustomNode = (node: CustomOperation, db: KyselyAny) => {\n const statement = sql.raw(node[\"sql\"] as string);\n\n return {\n compile() {\n return statement.compile(db);\n },\n execute() {\n return statement.execute(db);\n },\n };\n };\n\n const config: KyselyConfig = { db, provider: this.#provider };\n return operations.flatMap((op) =>\n execute(op, config, (node) => onCustomNode(node, db), mapper),\n );\n };\n\n const migrator = createMigrator({\n schema,\n executor: async (operations) => {\n const conn = await this.#connectionPool.connect();\n try {\n // For SQLite, execute PRAGMA defer_foreign_keys BEFORE transaction\n if (this.#provider === \"sqlite\") {\n await sql.raw(\"PRAGMA defer_foreign_keys = ON\").execute(conn.db);\n }\n\n await conn.db.transaction().execute(async (tx) => {\n // Use the transaction instance for both preprocessing and execution\n const preprocessed = preprocessMigrationOperations(operations, tx);\n const nodes = toExecutableNodes(preprocessed, tx);\n for (const node of nodes) {\n try {\n await node.execute();\n } catch (e) {\n console.error(\"failed at\", node.compile(), e);\n throw e;\n }\n }\n });\n } finally {\n await conn.release();\n }\n },\n sql: {\n toSql: (operations) => {\n const parts: string[] = [];\n\n // Add SQLite PRAGMA at the beginning\n if (this.#provider === \"sqlite\") {\n parts.push(\"PRAGMA defer_foreign_keys = ON;\");\n }\n\n // Use getDatabaseSync for SQL generation (doesn't execute, just builds SQL strings)\n const db = this.#connectionPool.getDatabaseSync();\n const preprocessed = preprocessMigrationOperations(operations, db);\n const nodes = toExecutableNodes(preprocessed, db);\n const compiled = nodes.map((node) => `${node.compile().sql};`);\n\n parts.push(...compiled);\n\n return parts.join(\"\\n\\n\");\n },\n },\n\n settings: {\n getVersion: async () => {\n const conn = await this.#connectionPool.connect();\n try {\n const manager = createSettingsManager(conn.db, namespace);\n const v = await manager.get(`schema_version`);\n return v ? parseInt(v) : 0;\n } finally {\n await conn.release();\n }\n },\n updateSettingsInMigration: async (fromVersion, toVersion) => {\n const conn = await this.#connectionPool.connect();\n try {\n const manager = createSettingsManager(conn.db, namespace);\n return [\n {\n type: \"custom\",\n sql:\n fromVersion === 0\n ? manager.insert(`schema_version`, toVersion.toString())\n : manager.update(`schema_version`, toVersion.toString()),\n },\n ];\n } finally {\n await conn.release();\n }\n },\n },\n });\n\n return migrator;\n }\n\n async getSchemaVersion(namespace: string): Promise<string | undefined> {\n const conn = await this.#connectionPool.connect();\n try {\n const manager = createSettingsManager(conn.db, namespace);\n return await manager.get(`schema_version`);\n } finally {\n await conn.release();\n }\n }\n}\n\nfunction createSettingsManager(db: KyselyAny, namespace: string) {\n // Settings table is never namespaced, but keys include namespace prefix\n const tableName = SETTINGS_TABLE_NAME;\n\n return {\n async get(key: string): Promise<string | undefined> {\n try {\n const result = await db\n .selectFrom(tableName)\n .where(\"key\", \"=\", sql.lit(`${namespace}.${key}`))\n .select([\"value\"])\n .executeTakeFirstOrThrow();\n return result.value as string;\n } catch {\n return;\n }\n },\n\n insert(key: string, value: string) {\n return db\n .insertInto(tableName)\n .values({\n id: sql.lit(\n createHash(\"md5\").update(`${namespace}.${key}`).digest(\"base64url\").replace(/=/g, \"\"),\n ),\n key: sql.lit(`${namespace}.${key}`),\n value: sql.lit(value),\n })\n .compile().sql;\n },\n\n update(key: string, value: string) {\n return db\n .updateTable(tableName)\n .set({\n value: sql.lit(value),\n })\n .where(\"key\", \"=\", sql.lit(`${namespace}.${key}`))\n .compile().sql;\n },\n };\n}\n"],"mappings":"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"}
@@ -317,5 +317,5 @@ function createKyselyQueryBuilder(kysely, provider, mapper) {
317
317
  }
318
318
 
319
319
  //#endregion
320
- export { createKyselyQueryBuilder };
320
+ export { buildWhere, createKyselyQueryBuilder };
321
321
  //# sourceMappingURL=kysely-query-builder.js.map
@@ -1,10 +1,11 @@
1
1
  import { buildCondition } from "../../query/condition-builder.js";
2
2
  import { buildFindOptions } from "../../query/orm/orm.js";
3
3
  import { createKyselyQueryBuilder } from "./kysely-query-builder.js";
4
+ import { createKysely } from "./kysely-shared.js";
4
5
 
5
6
  //#region src/adapters/kysely/kysely-query-compiler.ts
6
- function createKyselyQueryCompiler(schema, pool, provider, mapper) {
7
- const queryBuilder = createKyselyQueryBuilder(pool.getDatabaseSync(), provider, mapper);
7
+ function createKyselyQueryCompiler(schema, provider, mapper) {
8
+ const queryBuilder = createKyselyQueryBuilder(createKysely(provider), provider, mapper);
8
9
  function toTable(name) {
9
10
  const table = schema.tables[name];
10
11
  if (!table) throw new Error(`Invalid table name ${name}.`);
@@ -1 +1 @@
1
- {"version":3,"file":"kysely-query-compiler.js","names":[],"sources":["../../../src/adapters/kysely/kysely-query-compiler.ts"],"sourcesContent":["import type { CompiledQuery, Kysely } from \"kysely\";\nimport type { AnySchema, AnyTable } from \"../../schema/create\";\nimport { buildCondition } from \"../../query/condition-builder\";\nimport { buildFindOptions } from \"../../query/orm/orm\";\nimport { createKyselyQueryBuilder } from \"./kysely-query-builder\";\nimport type { ConditionBuilder, Condition } from \"../../query/condition-builder\";\nimport type { TableNameMapper } from \"./kysely-shared\";\nimport type { ConnectionPool } from \"../../shared/connection-pool\";\nimport type { SQLProvider } from \"../../shared/providers\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype KyselyAny = Kysely<any>;\n\n/**\n * Internal query compiler interface for Kysely\n * Used by the UOW compiler to generate compiled queries\n */\nexport interface KyselyQueryCompiler {\n count: (\n name: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n options?: { where?: (eb: ConditionBuilder<any>) => any },\n ) => CompiledQuery | null;\n findFirst: (name: string, options: any) => CompiledQuery | null; // eslint-disable-line @typescript-eslint/no-explicit-any\n findMany: (name: string, options?: any) => CompiledQuery | null; // eslint-disable-line @typescript-eslint/no-explicit-any\n create: (name: string, values: any) => CompiledQuery; // eslint-disable-line @typescript-eslint/no-explicit-any\n createMany: (name: string, values: any[]) => CompiledQuery; // eslint-disable-line @typescript-eslint/no-explicit-any\n updateMany: (name: string, options: { set: any; where?: any }) => CompiledQuery | null; // eslint-disable-line @typescript-eslint/no-explicit-any\n deleteMany: (name: string, options: { where?: any }) => CompiledQuery | null; // eslint-disable-line @typescript-eslint/no-explicit-any\n}\n\nexport function createKyselyQueryCompiler<T extends AnySchema>(\n schema: T,\n pool: ConnectionPool<KyselyAny>,\n provider: SQLProvider,\n mapper?: TableNameMapper,\n): KyselyQueryCompiler {\n // Get kysely instance for query building (compilation doesn't execute, just builds SQL)\n const kysely = pool.getDatabaseSync();\n const queryBuilder = createKyselyQueryBuilder(kysely, provider, mapper);\n\n function toTable(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 return {\n count(name, { where } = {}) {\n const table = toTable(name);\n let conditions = where ? buildCondition(table.columns, where) : undefined;\n if (conditions === true) {\n conditions = undefined;\n }\n if (conditions === false) {\n return null;\n }\n\n return queryBuilder.count(table, { where: conditions });\n },\n\n findFirst(name, options) {\n const table = toTable(name);\n // Safe cast: FindFirstOptions is structurally compatible with FindManyOptions\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const compiledOptions = buildFindOptions(table, options as any);\n if (compiledOptions === false) {\n return null;\n }\n\n return queryBuilder.findMany(table, {\n ...compiledOptions,\n limit: 1,\n });\n },\n\n findMany(name, options = {}) {\n const table = toTable(name);\n // Safe cast: FindManyOptions from compiler matches FindManyOptions from buildFindOptions\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const compiledOptions = buildFindOptions(table, options as any);\n if (compiledOptions === false) {\n return null;\n }\n\n return queryBuilder.findMany(table, compiledOptions);\n },\n\n create(name, values) {\n const table = toTable(name);\n return queryBuilder.create(table, values);\n },\n\n createMany(name, values) {\n const table = toTable(name);\n return queryBuilder.createMany(table, values);\n },\n\n updateMany(name, { set, where }) {\n const table = toTable(name);\n let conditions = where ? buildCondition(table.columns, where) : undefined;\n if (conditions === true) {\n conditions = undefined;\n }\n if (conditions === false) {\n return null;\n }\n\n // Safe: conditions is Condition | undefined after filtering out true/false\n return queryBuilder.updateMany(table, {\n set,\n where: conditions as Condition | undefined,\n });\n },\n\n deleteMany(name, { where }) {\n const table = toTable(name);\n let conditions = where ? buildCondition(table.columns, where) : undefined;\n if (conditions === true) {\n conditions = undefined;\n }\n if (conditions === false) {\n return null;\n }\n\n // Safe: conditions is Condition | undefined after filtering out true/false\n return queryBuilder.deleteMany(table, { where: conditions as Condition | undefined });\n },\n };\n}\n"],"mappings":";;;;;AA+BA,SAAgB,0BACd,QACA,MACA,UACA,QACqB;CAGrB,MAAM,eAAe,yBADN,KAAK,iBAAiB,EACiB,UAAU,OAAO;CAEvE,SAAS,QAAQ,MAAyB;EACxC,MAAM,QAAQ,OAAO,OAAO;AAC5B,MAAI,CAAC,MACH,OAAM,IAAI,MAAM,sBAAsB,KAAK,GAAG;AAEhD,SAAO;;AAGT,QAAO;EACL,MAAM,MAAM,EAAE,UAAU,EAAE,EAAE;GAC1B,MAAM,QAAQ,QAAQ,KAAK;GAC3B,IAAI,aAAa,QAAQ,eAAe,MAAM,SAAS,MAAM,GAAG;AAChE,OAAI,eAAe,KACjB,cAAa;AAEf,OAAI,eAAe,MACjB,QAAO;AAGT,UAAO,aAAa,MAAM,OAAO,EAAE,OAAO,YAAY,CAAC;;EAGzD,UAAU,MAAM,SAAS;GACvB,MAAM,QAAQ,QAAQ,KAAK;GAG3B,MAAM,kBAAkB,iBAAiB,OAAO,QAAe;AAC/D,OAAI,oBAAoB,MACtB,QAAO;AAGT,UAAO,aAAa,SAAS,OAAO;IAClC,GAAG;IACH,OAAO;IACR,CAAC;;EAGJ,SAAS,MAAM,UAAU,EAAE,EAAE;GAC3B,MAAM,QAAQ,QAAQ,KAAK;GAG3B,MAAM,kBAAkB,iBAAiB,OAAO,QAAe;AAC/D,OAAI,oBAAoB,MACtB,QAAO;AAGT,UAAO,aAAa,SAAS,OAAO,gBAAgB;;EAGtD,OAAO,MAAM,QAAQ;GACnB,MAAM,QAAQ,QAAQ,KAAK;AAC3B,UAAO,aAAa,OAAO,OAAO,OAAO;;EAG3C,WAAW,MAAM,QAAQ;GACvB,MAAM,QAAQ,QAAQ,KAAK;AAC3B,UAAO,aAAa,WAAW,OAAO,OAAO;;EAG/C,WAAW,MAAM,EAAE,KAAK,SAAS;GAC/B,MAAM,QAAQ,QAAQ,KAAK;GAC3B,IAAI,aAAa,QAAQ,eAAe,MAAM,SAAS,MAAM,GAAG;AAChE,OAAI,eAAe,KACjB,cAAa;AAEf,OAAI,eAAe,MACjB,QAAO;AAIT,UAAO,aAAa,WAAW,OAAO;IACpC;IACA,OAAO;IACR,CAAC;;EAGJ,WAAW,MAAM,EAAE,SAAS;GAC1B,MAAM,QAAQ,QAAQ,KAAK;GAC3B,IAAI,aAAa,QAAQ,eAAe,MAAM,SAAS,MAAM,GAAG;AAChE,OAAI,eAAe,KACjB,cAAa;AAEf,OAAI,eAAe,MACjB,QAAO;AAIT,UAAO,aAAa,WAAW,OAAO,EAAE,OAAO,YAAqC,CAAC;;EAExF"}
1
+ {"version":3,"file":"kysely-query-compiler.js","names":[],"sources":["../../../src/adapters/kysely/kysely-query-compiler.ts"],"sourcesContent":["import type { CompiledQuery } from \"kysely\";\nimport type { AnySchema, AnyTable } from \"../../schema/create\";\nimport { buildCondition } from \"../../query/condition-builder\";\nimport { buildFindOptions } from \"../../query/orm/orm\";\nimport { createKyselyQueryBuilder } from \"./kysely-query-builder\";\nimport type { ConditionBuilder, Condition } from \"../../query/condition-builder\";\nimport { createKysely, type TableNameMapper } from \"./kysely-shared\";\nimport type { SQLProvider } from \"../../shared/providers\";\n\n/**\n * Internal query compiler interface for Kysely\n * Used by the UOW compiler to generate compiled queries\n */\nexport interface KyselyQueryCompiler {\n count: (\n name: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n options?: { where?: (eb: ConditionBuilder<any>) => any },\n ) => CompiledQuery | null;\n findFirst: (name: string, options: any) => CompiledQuery | null; // eslint-disable-line @typescript-eslint/no-explicit-any\n findMany: (name: string, options?: any) => CompiledQuery | null; // eslint-disable-line @typescript-eslint/no-explicit-any\n create: (name: string, values: any) => CompiledQuery; // eslint-disable-line @typescript-eslint/no-explicit-any\n createMany: (name: string, values: any[]) => CompiledQuery; // eslint-disable-line @typescript-eslint/no-explicit-any\n updateMany: (name: string, options: { set: any; where?: any }) => CompiledQuery | null; // eslint-disable-line @typescript-eslint/no-explicit-any\n deleteMany: (name: string, options: { where?: any }) => CompiledQuery | null; // eslint-disable-line @typescript-eslint/no-explicit-any\n}\n\nexport function createKyselyQueryCompiler<T extends AnySchema>(\n schema: T,\n provider: SQLProvider,\n mapper?: TableNameMapper,\n): KyselyQueryCompiler {\n // Get kysely instance for query building (compilation doesn't execute, just builds SQL)\n const kysely = createKysely(provider);\n const queryBuilder = createKyselyQueryBuilder(kysely, provider, mapper);\n\n function toTable(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 return {\n count(name, { where } = {}) {\n const table = toTable(name);\n let conditions = where ? buildCondition(table.columns, where) : undefined;\n if (conditions === true) {\n conditions = undefined;\n }\n if (conditions === false) {\n return null;\n }\n\n return queryBuilder.count(table, { where: conditions });\n },\n\n findFirst(name, options) {\n const table = toTable(name);\n // Safe cast: FindFirstOptions is structurally compatible with FindManyOptions\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const compiledOptions = buildFindOptions(table, options as any);\n if (compiledOptions === false) {\n return null;\n }\n\n return queryBuilder.findMany(table, {\n ...compiledOptions,\n limit: 1,\n });\n },\n\n findMany(name, options = {}) {\n const table = toTable(name);\n // Safe cast: FindManyOptions from compiler matches FindManyOptions from buildFindOptions\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const compiledOptions = buildFindOptions(table, options as any);\n if (compiledOptions === false) {\n return null;\n }\n\n return queryBuilder.findMany(table, compiledOptions);\n },\n\n create(name, values) {\n const table = toTable(name);\n return queryBuilder.create(table, values);\n },\n\n createMany(name, values) {\n const table = toTable(name);\n return queryBuilder.createMany(table, values);\n },\n\n updateMany(name, { set, where }) {\n const table = toTable(name);\n let conditions = where ? buildCondition(table.columns, where) : undefined;\n if (conditions === true) {\n conditions = undefined;\n }\n if (conditions === false) {\n return null;\n }\n\n // Safe: conditions is Condition | undefined after filtering out true/false\n return queryBuilder.updateMany(table, {\n set,\n where: conditions as Condition | undefined,\n });\n },\n\n deleteMany(name, { where }) {\n const table = toTable(name);\n let conditions = where ? buildCondition(table.columns, where) : undefined;\n if (conditions === true) {\n conditions = undefined;\n }\n if (conditions === false) {\n return null;\n }\n\n // Safe: conditions is Condition | undefined after filtering out true/false\n return queryBuilder.deleteMany(table, { where: conditions as Condition | undefined });\n },\n };\n}\n"],"mappings":";;;;;;AA2BA,SAAgB,0BACd,QACA,UACA,QACqB;CAGrB,MAAM,eAAe,yBADN,aAAa,SAAS,EACiB,UAAU,OAAO;CAEvE,SAAS,QAAQ,MAAyB;EACxC,MAAM,QAAQ,OAAO,OAAO;AAC5B,MAAI,CAAC,MACH,OAAM,IAAI,MAAM,sBAAsB,KAAK,GAAG;AAEhD,SAAO;;AAGT,QAAO;EACL,MAAM,MAAM,EAAE,UAAU,EAAE,EAAE;GAC1B,MAAM,QAAQ,QAAQ,KAAK;GAC3B,IAAI,aAAa,QAAQ,eAAe,MAAM,SAAS,MAAM,GAAG;AAChE,OAAI,eAAe,KACjB,cAAa;AAEf,OAAI,eAAe,MACjB,QAAO;AAGT,UAAO,aAAa,MAAM,OAAO,EAAE,OAAO,YAAY,CAAC;;EAGzD,UAAU,MAAM,SAAS;GACvB,MAAM,QAAQ,QAAQ,KAAK;GAG3B,MAAM,kBAAkB,iBAAiB,OAAO,QAAe;AAC/D,OAAI,oBAAoB,MACtB,QAAO;AAGT,UAAO,aAAa,SAAS,OAAO;IAClC,GAAG;IACH,OAAO;IACR,CAAC;;EAGJ,SAAS,MAAM,UAAU,EAAE,EAAE;GAC3B,MAAM,QAAQ,QAAQ,KAAK;GAG3B,MAAM,kBAAkB,iBAAiB,OAAO,QAAe;AAC/D,OAAI,oBAAoB,MACtB,QAAO;AAGT,UAAO,aAAa,SAAS,OAAO,gBAAgB;;EAGtD,OAAO,MAAM,QAAQ;GACnB,MAAM,QAAQ,QAAQ,KAAK;AAC3B,UAAO,aAAa,OAAO,OAAO,OAAO;;EAG3C,WAAW,MAAM,QAAQ;GACvB,MAAM,QAAQ,QAAQ,KAAK;AAC3B,UAAO,aAAa,WAAW,OAAO,OAAO;;EAG/C,WAAW,MAAM,EAAE,KAAK,SAAS;GAC/B,MAAM,QAAQ,QAAQ,KAAK;GAC3B,IAAI,aAAa,QAAQ,eAAe,MAAM,SAAS,MAAM,GAAG;AAChE,OAAI,eAAe,KACjB,cAAa;AAEf,OAAI,eAAe,MACjB,QAAO;AAIT,UAAO,aAAa,WAAW,OAAO;IACpC;IACA,OAAO;IACR,CAAC;;EAGJ,WAAW,MAAM,EAAE,SAAS;GAC1B,MAAM,QAAQ,QAAQ,KAAK;GAC3B,IAAI,aAAa,QAAQ,eAAe,MAAM,SAAS,MAAM,GAAG;AAChE,OAAI,eAAe,KACjB,cAAa;AAEf,OAAI,eAAe,MACjB,QAAO;AAIT,UAAO,aAAa,WAAW,OAAO,EAAE,OAAO,YAAqC,CAAC;;EAExF"}
@@ -1,3 +1,4 @@
1
+ import "./kysely-shared.js";
1
2
  import { CompiledQuery, Kysely } from "kysely";
2
3
 
3
4
  //#region src/adapters/kysely/kysely-query.d.ts
@@ -1 +1 @@
1
- {"version":3,"file":"kysely-query.d.ts","names":[],"sources":["../../../src/adapters/kysely/kysely-query.ts"],"sourcesContent":[],"mappings":";;;;;;;UAwBiB,eAAA;;;;;oBAKG"}
1
+ {"version":3,"file":"kysely-query.d.ts","names":[],"sources":["../../../src/adapters/kysely/kysely-query.ts"],"sourcesContent":[],"mappings":";;;;;;;;UAwBiB,eAAA;;;;;oBAKG"}
@@ -57,7 +57,7 @@ var UpdateManySpecialBuilder = class {
57
57
  */
58
58
  function fromKysely(schema, pool, provider, mapper, uowConfig, schemaNamespaceMap) {
59
59
  function createUOW(opts) {
60
- const uowCompiler = createKyselyUOWCompiler(pool, provider, mapper);
60
+ const uowCompiler = createKyselyUOWCompiler(provider, mapper);
61
61
  const executor = {
62
62
  async executeRetrievalPhase(retrievalBatch) {
63
63
  if (opts.config?.dryRun) return retrievalBatch.map(() => []);
@@ -96,37 +96,44 @@ function fromKysely(schema, pool, provider, mapper, uowConfig, schemaNamespaceMa
96
96
  const decodedRows = rows.map((row) => decodeResult(row, op.table, provider));
97
97
  if (op.withCursor) {
98
98
  let cursor;
99
- if (decodedRows.length > 0 && op.options.orderByIndex && op.options.pageSize) {
100
- const lastItem = decodedRows[decodedRows.length - 1];
101
- const indexName = op.options.orderByIndex.indexName;
102
- let indexColumns;
103
- if (indexName === "_primary") indexColumns = [op.table.getIdColumn()];
104
- else {
105
- const index$1 = op.table.indexes[indexName];
106
- if (index$1) indexColumns = index$1.columns;
99
+ let hasNextPage = false;
100
+ let items = decodedRows;
101
+ if (op.options.pageSize && decodedRows.length > op.options.pageSize) {
102
+ hasNextPage = true;
103
+ items = decodedRows.slice(0, op.options.pageSize);
104
+ if (op.options.orderByIndex) {
105
+ const lastItem = items[items.length - 1];
106
+ const indexName = op.options.orderByIndex.indexName;
107
+ let indexColumns;
108
+ if (indexName === "_primary") indexColumns = [op.table.getIdColumn()];
109
+ else {
110
+ const index$1 = op.table.indexes[indexName];
111
+ if (index$1) indexColumns = index$1.columns;
112
+ }
113
+ if (indexColumns && lastItem) cursor = createCursorFromRecord(lastItem, indexColumns, {
114
+ indexName: op.options.orderByIndex.indexName,
115
+ orderDirection: op.options.orderByIndex.direction,
116
+ pageSize: op.options.pageSize
117
+ });
107
118
  }
108
- if (indexColumns && lastItem) cursor = createCursorFromRecord(lastItem, indexColumns, {
109
- indexName: op.options.orderByIndex.indexName,
110
- orderDirection: op.options.orderByIndex.direction,
111
- pageSize: op.options.pageSize
112
- });
113
119
  }
114
120
  return {
115
- items: decodedRows,
116
- cursor
121
+ items,
122
+ cursor,
123
+ hasNextPage
117
124
  };
118
125
  }
119
126
  return decodedRows;
120
127
  });
121
128
  };
122
129
  const { onQuery,...restUowConfig } = opts.config ?? {};
123
- return new UnitOfWork(schema, uowCompiler, executor, decoder, opts.name, {
130
+ return new UnitOfWork(uowCompiler, executor, decoder, opts.name, {
124
131
  ...restUowConfig,
125
132
  onQuery: (query) => {
126
133
  const actualQuery = query && typeof query === "object" && "expectedAffectedRows" in query ? query.query : query;
127
134
  opts.config?.onQuery?.(actualQuery);
128
135
  }
129
- }, schemaNamespaceMap);
136
+ }, schemaNamespaceMap).forSchema(schema);
130
137
  }
131
138
  return {
132
139
  async find(tableName, builderFn) {
@@ -1 +1 @@
1
- {"version":3,"file":"kysely-query.js","names":["#indexName","#condition","#setValues","executor: UOWExecutor<CompiledQuery, unknown>","decoder: UOWDecoder<unknown>","cursor: Cursor | undefined","index"],"sources":["../../../src/adapters/kysely/kysely-query.ts"],"sourcesContent":["import type { AbstractQuery, TableToUpdateValues } from \"../../query/query\";\nimport type { AnySchema, AnyTable } from \"../../schema/create\";\nimport type {\n CompiledMutation,\n UOWDecoder,\n UOWExecutor,\n ValidIndexName,\n} from \"../../query/unit-of-work\";\nimport { decodeResult } from \"../../query/result-transform\";\nimport { createKyselyUOWCompiler } from \"./kysely-uow-compiler\";\nimport { executeKyselyRetrievalPhase, executeKyselyMutationPhase } from \"./kysely-uow-executor\";\nimport { UnitOfWork } from \"../../query/unit-of-work\";\nimport type { CompiledQuery, Kysely } from \"kysely\";\nimport type { TableNameMapper } from \"./kysely-shared\";\nimport type { ConnectionPool } from \"../../shared/connection-pool\";\nimport type { SQLProvider } from \"../../shared/providers\";\nimport { createCursorFromRecord, Cursor, type CursorResult } from \"../../query/cursor\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype KyselyAny = Kysely<any>;\n\n/**\n * Configuration options for creating a Kysely Unit of Work\n */\nexport interface KyselyUOWConfig {\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: CompiledQuery) => void;\n /**\n * If true, the query will not be executed and the query will be returned. Not respected for UOWs\n * since those have to be manually executed.\n */\n dryRun?: boolean;\n}\n\n/**\n * Special builder for updateMany operations that captures configuration\n */\nclass UpdateManySpecialBuilder<TTable extends AnyTable> {\n #indexName?: string;\n #condition?: unknown;\n #setValues?: TableToUpdateValues<TTable>;\n\n whereIndex<TIndexName extends ValidIndexName<TTable>>(\n indexName: TIndexName,\n condition?: unknown,\n ): this {\n this.#indexName = indexName as string;\n this.#condition = condition;\n return this;\n }\n\n set(values: TableToUpdateValues<TTable>): this {\n this.#setValues = values;\n return this;\n }\n\n getConfig() {\n return {\n indexName: this.#indexName,\n condition: this.#condition,\n setValues: this.#setValues,\n };\n }\n}\n\n/**\n * Creates a Kysely-based query engine for the given schema.\n *\n * This is the main entry point for creating a database query interface using Kysely.\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 (postgresql, mysql, sqlite, etc.)\n * @param mapper - Optional table name mapper for namespace prefixing\n * @param uowConfig - Optional UOW configuration\n * @param schemaNamespaceMap - Optional WeakMap for schema-to-namespace lookups\n * @returns An AbstractQuery instance for performing database operations\n *\n * @example\n * ```ts\n * const pool = createSimpleConnectionPool(kysely);\n * const queryEngine = fromKysely(mySchema, pool, 'postgresql');\n *\n * const users = await queryEngine.findMany('users', {\n * where: (b) => b('age', '>', 18),\n * orderBy: [['name', 'asc']]\n * });\n * ```\n */\nexport function fromKysely<T extends AnySchema>(\n schema: T,\n pool: ConnectionPool<KyselyAny>,\n provider: SQLProvider,\n mapper?: TableNameMapper,\n uowConfig?: KyselyUOWConfig,\n schemaNamespaceMap?: WeakMap<AnySchema, string>,\n): AbstractQuery<T, KyselyUOWConfig> {\n function createUOW(opts: { name?: string; config?: KyselyUOWConfig }) {\n const uowCompiler = createKyselyUOWCompiler(pool, provider, mapper);\n\n const executor: UOWExecutor<CompiledQuery, unknown> = {\n async executeRetrievalPhase(retrievalBatch: CompiledQuery[]) {\n // In dryRun mode, skip execution and return empty results\n if (opts.config?.dryRun) {\n return retrievalBatch.map(() => []);\n }\n\n const conn = await pool.connect();\n try {\n return await executeKyselyRetrievalPhase(conn.db, retrievalBatch);\n } finally {\n await conn.release();\n }\n },\n async executeMutationPhase(mutationBatch: CompiledMutation<CompiledQuery>[]) {\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 return await executeKyselyMutationPhase(conn.db, mutationBatch);\n } finally {\n await conn.release();\n }\n },\n };\n\n // Create a decoder function to transform raw results into application format\n const decoder: UOWDecoder<unknown> = (rawResults, ops) => {\n if (rawResults.length !== ops.length) {\n throw new Error(\"rawResults and ops must have the same length\");\n }\n\n return rawResults.map((rows, index) => {\n const op = ops[index];\n if (!op) {\n throw new Error(\"op must be defined\");\n }\n\n // Handle count operations differently - return the count number directly\n if (op.type === \"count\") {\n const rowArray = rows as Record<string, unknown>[];\n const firstRow = rowArray[0];\n if (!firstRow) {\n return 0;\n }\n const count = Number(firstRow[\"count\"]);\n if (Number.isNaN(count)) {\n throw new Error(`Unexpected result for count, received: ${count}`);\n }\n return count;\n }\n\n // Each result is an array of rows - decode each row\n const rowArray = rows as Record<string, unknown>[];\n const decodedRows = rowArray.map((row) => decodeResult(row, op.table, provider));\n\n // If cursor generation is requested, wrap in CursorResult\n if (op.withCursor) {\n let cursor: Cursor | undefined;\n\n // Generate cursor from last item if results exist\n if (decodedRows.length > 0 && op.options.orderByIndex && op.options.pageSize) {\n const lastItem = decodedRows[decodedRows.length - 1];\n const indexName = op.options.orderByIndex.indexName;\n\n // Get index columns\n let indexColumns;\n if (indexName === \"_primary\") {\n indexColumns = [op.table.getIdColumn()];\n } else {\n const index = op.table.indexes[indexName];\n if (index) {\n indexColumns = index.columns;\n }\n }\n\n if (indexColumns && lastItem) {\n cursor = createCursorFromRecord(lastItem as Record<string, unknown>, indexColumns, {\n indexName: op.options.orderByIndex.indexName,\n orderDirection: op.options.orderByIndex.direction,\n pageSize: op.options.pageSize,\n });\n }\n }\n\n const result: CursorResult<unknown> = {\n items: decodedRows,\n cursor,\n };\n return result;\n }\n\n return decodedRows;\n });\n };\n\n const { onQuery, ...restUowConfig } = opts.config ?? {};\n\n return new UnitOfWork(\n schema,\n uowCompiler,\n executor,\n decoder,\n opts.name,\n {\n ...restUowConfig,\n onQuery: (query) => {\n // CompiledMutation has { query: CompiledQuery, expectedAffectedRows: number | null }\n // CompiledQuery has { query: QueryAST, sql: string, parameters: unknown[] }\n // Check for expectedAffectedRows to distinguish CompiledMutation from CompiledQuery\n const actualQuery =\n query && typeof query === \"object\" && \"expectedAffectedRows\" in query\n ? (query as CompiledMutation<CompiledQuery>).query\n : (query as CompiledQuery);\n\n opts.config?.onQuery?.(actualQuery);\n },\n },\n schemaNamespaceMap,\n );\n }\n\n return {\n async find(tableName, builderFn) {\n const uow = createUOW({ config: uowConfig });\n // Safe: builderFn returns a FindBuilder (or void), which matches UnitOfWork signature\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n uow.find(tableName, builderFn as any);\n // executeRetrieve returns an array of results (one per find operation)\n // Since we only have one find, unwrap the first result\n const [result]: unknown[][] = await uow.executeRetrieve();\n return result ?? [];\n },\n\n async findWithCursor(tableName, builderFn) {\n // Safe: builderFn returns a FindBuilder, which matches UnitOfWork signature\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const uow = createUOW({ config: uowConfig }).findWithCursor(tableName, builderFn as any);\n // executeRetrieve returns an array of results (one per find operation)\n // Since we only have one findWithCursor, unwrap the first result\n const [result] = await uow.executeRetrieve();\n return result as CursorResult<unknown>;\n },\n\n async findFirst(tableName, builderFn) {\n const uow = createUOW({ config: uowConfig });\n if (builderFn) {\n uow.find(tableName, (b) => {\n builderFn(b);\n return b.pageSize(1);\n });\n } else {\n uow.find(tableName, (b) => b.whereIndex(\"primary\").pageSize(1));\n }\n // executeRetrieve runs an array of `find` operation results, which each return an array of rows\n const [result]: unknown[][] = await uow.executeRetrieve();\n return result?.[0] ?? null;\n },\n\n async create(tableName, values) {\n const uow = createUOW({ config: uowConfig });\n uow.create(tableName, values);\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to create record\");\n }\n\n const createdIds = uow.getCreatedIds();\n const createdId = createdIds[0];\n if (!createdId) {\n throw new Error(\"Failed to get created ID\");\n }\n return createdId;\n },\n\n async createMany(tableName, valuesArray) {\n const uow = createUOW({ config: uowConfig });\n for (const values of valuesArray) {\n uow.create(tableName, values);\n }\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to create records\");\n }\n\n return uow.getCreatedIds();\n },\n\n async update(tableName, id, builderFn) {\n const uow = createUOW({ config: uowConfig });\n uow.update(tableName, id, builderFn);\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to update record (version conflict or record not found)\");\n }\n },\n\n async updateMany(tableName, builderFn) {\n const table = schema.tables[tableName];\n if (!table) {\n throw new Error(`Table ${tableName} not found in schema`);\n }\n\n const specialBuilder = new UpdateManySpecialBuilder<typeof table>();\n builderFn(specialBuilder);\n\n const { indexName, condition, setValues } = specialBuilder.getConfig();\n\n if (!indexName) {\n throw new Error(\"whereIndex() must be called in updateMany\");\n }\n if (!setValues) {\n throw new Error(\"set() must be called in updateMany\");\n }\n\n const findUow = createUOW({ config: uowConfig });\n findUow.find(tableName, (b) => {\n if (condition) {\n // Safe: condition is captured from whereIndex call with proper typing\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return b.whereIndex(indexName as ValidIndexName<typeof table>, condition as any);\n }\n return b.whereIndex(indexName as ValidIndexName<typeof table>);\n });\n const [records]: unknown[][] = await findUow.executeRetrieve();\n\n if (!records || records.length === 0) {\n return;\n }\n\n const updateUow = createUOW({ config: uowConfig });\n for (const record of records as Array<{ id: unknown }>) {\n updateUow.update(tableName, record.id as string, (b) => b.set(setValues));\n }\n const { success } = await updateUow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to update records (version conflict)\");\n }\n },\n\n async delete(tableName, id, builderFn) {\n const uow = createUOW({ config: uowConfig });\n uow.delete(tableName, id, builderFn);\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to delete record (version conflict or record not found)\");\n }\n },\n\n async deleteMany(tableName, builderFn) {\n const findUow = createUOW({ config: uowConfig });\n findUow.find(tableName, builderFn);\n const [records]: unknown[][] = await findUow.executeRetrieve();\n\n if (!records || records.length === 0) {\n return;\n }\n\n const deleteUow = createUOW({ config: uowConfig });\n for (const record of records as Array<{ id: unknown }>) {\n deleteUow.delete(tableName, record.id as string);\n }\n const { success } = await deleteUow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to delete records (version conflict)\");\n }\n },\n\n createUnitOfWork(name, nestedUowConfig) {\n return createUOW({\n name,\n config: {\n ...uowConfig,\n ...nestedUowConfig,\n },\n });\n },\n } as AbstractQuery<T, KyselyUOWConfig>;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"kysely-query.js","names":["#indexName","#condition","#setValues","executor: UOWExecutor<CompiledQuery, unknown>","decoder: UOWDecoder<unknown>","cursor: Cursor | undefined","index"],"sources":["../../../src/adapters/kysely/kysely-query.ts"],"sourcesContent":["import type { AbstractQuery, TableToUpdateValues } from \"../../query/query\";\nimport type { AnySchema, AnyTable } from \"../../schema/create\";\nimport type {\n CompiledMutation,\n UOWDecoder,\n UOWExecutor,\n ValidIndexName,\n} from \"../../query/unit-of-work\";\nimport { decodeResult } from \"../../query/result-transform\";\nimport { createKyselyUOWCompiler } from \"./kysely-uow-compiler\";\nimport { executeKyselyRetrievalPhase, executeKyselyMutationPhase } from \"./kysely-uow-executor\";\nimport { UnitOfWork } from \"../../query/unit-of-work\";\nimport type { CompiledQuery, Kysely } from \"kysely\";\nimport type { TableNameMapper } from \"./kysely-shared\";\nimport type { ConnectionPool } from \"../../shared/connection-pool\";\nimport type { SQLProvider } from \"../../shared/providers\";\nimport { createCursorFromRecord, Cursor, type CursorResult } from \"../../query/cursor\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype KyselyAny = Kysely<any>;\n\n/**\n * Configuration options for creating a Kysely Unit of Work\n */\nexport interface KyselyUOWConfig {\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: CompiledQuery) => void;\n /**\n * If true, the query will not be executed and the query will be returned. Not respected for UOWs\n * since those have to be manually executed.\n */\n dryRun?: boolean;\n}\n\n/**\n * Special builder for updateMany operations that captures configuration\n */\nclass UpdateManySpecialBuilder<TTable extends AnyTable> {\n #indexName?: string;\n #condition?: unknown;\n #setValues?: TableToUpdateValues<TTable>;\n\n whereIndex<TIndexName extends ValidIndexName<TTable>>(\n indexName: TIndexName,\n condition?: unknown,\n ): this {\n this.#indexName = indexName as string;\n this.#condition = condition;\n return this;\n }\n\n set(values: TableToUpdateValues<TTable>): this {\n this.#setValues = values;\n return this;\n }\n\n getConfig() {\n return {\n indexName: this.#indexName,\n condition: this.#condition,\n setValues: this.#setValues,\n };\n }\n}\n\n/**\n * Creates a Kysely-based query engine for the given schema.\n *\n * This is the main entry point for creating a database query interface using Kysely.\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 (postgresql, mysql, sqlite, etc.)\n * @param mapper - Optional table name mapper for namespace prefixing\n * @param uowConfig - Optional UOW configuration\n * @param schemaNamespaceMap - Optional WeakMap for schema-to-namespace lookups\n * @returns An AbstractQuery instance for performing database operations\n *\n * @example\n * ```ts\n * const pool = createSimpleConnectionPool(kysely);\n * const queryEngine = fromKysely(mySchema, pool, 'postgresql');\n *\n * const users = await queryEngine.findMany('users', {\n * where: (b) => b('age', '>', 18),\n * orderBy: [['name', 'asc']]\n * });\n * ```\n */\nexport function fromKysely<T extends AnySchema>(\n schema: T,\n pool: ConnectionPool<KyselyAny>,\n provider: SQLProvider,\n mapper?: TableNameMapper,\n uowConfig?: KyselyUOWConfig,\n schemaNamespaceMap?: WeakMap<AnySchema, string>,\n): AbstractQuery<T, KyselyUOWConfig> {\n function createUOW(opts: { name?: string; config?: KyselyUOWConfig }) {\n const uowCompiler = createKyselyUOWCompiler(provider, mapper);\n\n const executor: UOWExecutor<CompiledQuery, unknown> = {\n async executeRetrievalPhase(retrievalBatch: CompiledQuery[]) {\n // In dryRun mode, skip execution and return empty results\n if (opts.config?.dryRun) {\n return retrievalBatch.map(() => []);\n }\n\n const conn = await pool.connect();\n try {\n return await executeKyselyRetrievalPhase(conn.db, retrievalBatch);\n } finally {\n await conn.release();\n }\n },\n async executeMutationPhase(mutationBatch: CompiledMutation<CompiledQuery>[]) {\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 return await executeKyselyMutationPhase(conn.db, mutationBatch);\n } finally {\n await conn.release();\n }\n },\n };\n\n // Create a decoder function to transform raw results into application format\n const decoder: UOWDecoder<unknown> = (rawResults, ops) => {\n if (rawResults.length !== ops.length) {\n throw new Error(\"rawResults and ops must have the same length\");\n }\n\n return rawResults.map((rows, index) => {\n const op = ops[index];\n if (!op) {\n throw new Error(\"op must be defined\");\n }\n\n // Handle count operations differently - return the count number directly\n if (op.type === \"count\") {\n const rowArray = rows as Record<string, unknown>[];\n const firstRow = rowArray[0];\n if (!firstRow) {\n return 0;\n }\n const count = Number(firstRow[\"count\"]);\n if (Number.isNaN(count)) {\n throw new Error(`Unexpected result for count, received: ${count}`);\n }\n return count;\n }\n\n // Each result is an array of rows - decode each row\n const rowArray = rows as Record<string, unknown>[];\n const decodedRows = rowArray.map((row) => decodeResult(row, op.table, provider));\n\n // If cursor generation is requested, wrap in CursorResult\n if (op.withCursor) {\n let cursor: Cursor | undefined;\n let hasNextPage = false;\n let items = decodedRows;\n\n // Check if there are more results (we fetched pageSize + 1)\n if (op.options.pageSize && decodedRows.length > op.options.pageSize) {\n hasNextPage = true;\n // Trim to requested pageSize\n items = decodedRows.slice(0, op.options.pageSize);\n\n // Generate cursor from the last item we're returning\n if (op.options.orderByIndex) {\n const lastItem = items[items.length - 1];\n const indexName = op.options.orderByIndex.indexName;\n\n // Get index columns\n let indexColumns;\n if (indexName === \"_primary\") {\n indexColumns = [op.table.getIdColumn()];\n } else {\n const index = op.table.indexes[indexName];\n if (index) {\n indexColumns = index.columns;\n }\n }\n\n if (indexColumns && lastItem) {\n cursor = createCursorFromRecord(lastItem as Record<string, unknown>, indexColumns, {\n indexName: op.options.orderByIndex.indexName,\n orderDirection: op.options.orderByIndex.direction,\n pageSize: op.options.pageSize,\n });\n }\n }\n }\n\n const result: CursorResult<unknown> = {\n items,\n cursor,\n hasNextPage,\n };\n return result;\n }\n\n return decodedRows;\n });\n };\n\n const { onQuery, ...restUowConfig } = opts.config ?? {};\n\n return new UnitOfWork(\n uowCompiler,\n executor,\n decoder,\n opts.name,\n {\n ...restUowConfig,\n onQuery: (query) => {\n // CompiledMutation has { query: CompiledQuery, expectedAffectedRows: number | null }\n // CompiledQuery has { query: QueryAST, sql: string, parameters: unknown[] }\n // Check for expectedAffectedRows to distinguish CompiledMutation from CompiledQuery\n const actualQuery =\n query && typeof query === \"object\" && \"expectedAffectedRows\" in query\n ? (query as CompiledMutation<CompiledQuery>).query\n : (query as CompiledQuery);\n\n opts.config?.onQuery?.(actualQuery);\n },\n },\n schemaNamespaceMap,\n ).forSchema(schema);\n }\n\n return {\n async find(tableName, builderFn) {\n const uow = createUOW({ config: uowConfig });\n // Safe: builderFn returns a FindBuilder (or void), which matches UnitOfWork signature\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n uow.find(tableName, builderFn as any);\n // executeRetrieve returns an array of results (one per find operation)\n // Since we only have one find, unwrap the first result\n const [result]: unknown[][] = await uow.executeRetrieve();\n return result ?? [];\n },\n\n async findWithCursor(tableName, builderFn) {\n // Safe: builderFn returns a FindBuilder, which matches UnitOfWork signature\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const uow = createUOW({ config: uowConfig }).findWithCursor(tableName, builderFn as any);\n // executeRetrieve returns an array of results (one per find operation)\n // Since we only have one findWithCursor, unwrap the first result\n const [result] = await uow.executeRetrieve();\n return result as CursorResult<unknown>;\n },\n\n async findFirst(tableName, builderFn) {\n const uow = createUOW({ config: uowConfig });\n if (builderFn) {\n uow.find(tableName, (b) => {\n builderFn(b);\n return b.pageSize(1);\n });\n } else {\n uow.find(tableName, (b) => b.whereIndex(\"primary\").pageSize(1));\n }\n // executeRetrieve runs an array of `find` operation results, which each return an array of rows\n const [result]: unknown[][] = await uow.executeRetrieve();\n return result?.[0] ?? null;\n },\n\n async create(tableName, values) {\n const uow = createUOW({ config: uowConfig });\n uow.create(tableName, values);\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to create record\");\n }\n\n const createdIds = uow.getCreatedIds();\n const createdId = createdIds[0];\n if (!createdId) {\n throw new Error(\"Failed to get created ID\");\n }\n return createdId;\n },\n\n async createMany(tableName, valuesArray) {\n const uow = createUOW({ config: uowConfig });\n for (const values of valuesArray) {\n uow.create(tableName, values);\n }\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to create records\");\n }\n\n return uow.getCreatedIds();\n },\n\n async update(tableName, id, builderFn) {\n const uow = createUOW({ config: uowConfig });\n uow.update(tableName, id, builderFn);\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to update record (version conflict or record not found)\");\n }\n },\n\n async updateMany(tableName, builderFn) {\n const table = schema.tables[tableName];\n if (!table) {\n throw new Error(`Table ${tableName} not found in schema`);\n }\n\n const specialBuilder = new UpdateManySpecialBuilder<typeof table>();\n builderFn(specialBuilder);\n\n const { indexName, condition, setValues } = specialBuilder.getConfig();\n\n if (!indexName) {\n throw new Error(\"whereIndex() must be called in updateMany\");\n }\n if (!setValues) {\n throw new Error(\"set() must be called in updateMany\");\n }\n\n const findUow = createUOW({ config: uowConfig });\n findUow.find(tableName, (b) => {\n if (condition) {\n // Safe: condition is captured from whereIndex call with proper typing\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return b.whereIndex(indexName as ValidIndexName<typeof table>, condition as any);\n }\n return b.whereIndex(indexName as ValidIndexName<typeof table>);\n });\n const [records]: unknown[][] = await findUow.executeRetrieve();\n\n if (!records || records.length === 0) {\n return;\n }\n\n const updateUow = createUOW({ config: uowConfig });\n for (const record of records as Array<{ id: unknown }>) {\n updateUow.update(tableName, record.id as string, (b) => b.set(setValues));\n }\n const { success } = await updateUow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to update records (version conflict)\");\n }\n },\n\n async delete(tableName, id, builderFn) {\n const uow = createUOW({ config: uowConfig });\n uow.delete(tableName, id, builderFn);\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to delete record (version conflict or record not found)\");\n }\n },\n\n async deleteMany(tableName, builderFn) {\n const findUow = createUOW({ config: uowConfig });\n findUow.find(tableName, builderFn);\n const [records]: unknown[][] = await findUow.executeRetrieve();\n\n if (!records || records.length === 0) {\n return;\n }\n\n const deleteUow = createUOW({ config: uowConfig });\n for (const record of records as Array<{ id: unknown }>) {\n deleteUow.delete(tableName, record.id as string);\n }\n const { success } = await deleteUow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to delete records (version conflict)\");\n }\n },\n\n createUnitOfWork(name, nestedUowConfig) {\n return createUOW({\n name,\n config: {\n ...uowConfig,\n ...nestedUowConfig,\n },\n });\n },\n } as AbstractQuery<T, KyselyUOWConfig>;\n}\n"],"mappings":"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"}