@fragno-dev/db 0.1.1 → 0.1.2

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 (108) hide show
  1. package/.turbo/turbo-build.log +61 -53
  2. package/CHANGELOG.md +12 -0
  3. package/dist/adapters/adapters.d.ts +11 -1
  4. package/dist/adapters/adapters.d.ts.map +1 -1
  5. package/dist/adapters/drizzle/drizzle-adapter.d.ts +9 -2
  6. package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -1
  7. package/dist/adapters/drizzle/drizzle-adapter.js +21 -39
  8. package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -1
  9. package/dist/adapters/drizzle/drizzle-query.d.ts.map +1 -1
  10. package/dist/adapters/drizzle/drizzle-query.js +3 -2
  11. package/dist/adapters/drizzle/drizzle-query.js.map +1 -1
  12. package/dist/adapters/drizzle/drizzle-uow-compiler.js +8 -6
  13. package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +1 -1
  14. package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +1 -1
  15. package/dist/adapters/drizzle/drizzle-uow-executor.js.map +1 -1
  16. package/dist/adapters/drizzle/generate.js +107 -34
  17. package/dist/adapters/drizzle/generate.js.map +1 -1
  18. package/dist/adapters/drizzle/shared.js +14 -1
  19. package/dist/adapters/drizzle/shared.js.map +1 -1
  20. package/dist/adapters/kysely/kysely-adapter.d.ts +2 -1
  21. package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -1
  22. package/dist/adapters/kysely/kysely-adapter.js +25 -30
  23. package/dist/adapters/kysely/kysely-adapter.js.map +1 -1
  24. package/dist/adapters/kysely/kysely-query-builder.js +48 -44
  25. package/dist/adapters/kysely/kysely-query-builder.js.map +1 -1
  26. package/dist/adapters/kysely/kysely-query-compiler.js +2 -2
  27. package/dist/adapters/kysely/kysely-query-compiler.js.map +1 -1
  28. package/dist/adapters/kysely/kysely-query.js +3 -2
  29. package/dist/adapters/kysely/kysely-query.js.map +1 -1
  30. package/dist/adapters/kysely/kysely-shared.js +18 -0
  31. package/dist/adapters/kysely/kysely-shared.js.map +1 -0
  32. package/dist/adapters/kysely/kysely-uow-compiler.js +4 -3
  33. package/dist/adapters/kysely/kysely-uow-compiler.js.map +1 -1
  34. package/dist/adapters/kysely/migration/execute.js +15 -12
  35. package/dist/adapters/kysely/migration/execute.js.map +1 -1
  36. package/dist/migration-engine/auto-from-schema.js +2 -8
  37. package/dist/migration-engine/auto-from-schema.js.map +1 -1
  38. package/dist/migration-engine/create.d.ts +1 -5
  39. package/dist/migration-engine/create.js +1 -1
  40. package/dist/migration-engine/create.js.map +1 -1
  41. package/dist/migration-engine/generation-engine.d.ts +51 -0
  42. package/dist/migration-engine/generation-engine.d.ts.map +1 -0
  43. package/dist/migration-engine/generation-engine.js +165 -0
  44. package/dist/migration-engine/generation-engine.js.map +1 -0
  45. package/dist/migration-engine/shared.d.ts +5 -2
  46. package/dist/migration-engine/shared.d.ts.map +1 -1
  47. package/dist/migration-engine/shared.js.map +1 -1
  48. package/dist/mod.d.ts +0 -8
  49. package/dist/mod.d.ts.map +1 -1
  50. package/dist/mod.js +0 -32
  51. package/dist/mod.js.map +1 -1
  52. package/dist/query/condition-builder.js.map +1 -1
  53. package/dist/query/result-transform.js +2 -1
  54. package/dist/query/result-transform.js.map +1 -1
  55. package/dist/schema/create.d.ts +74 -16
  56. package/dist/schema/create.d.ts.map +1 -1
  57. package/dist/schema/create.js +76 -11
  58. package/dist/schema/create.js.map +1 -1
  59. package/dist/schema/serialize.js.map +1 -1
  60. package/dist/shared/settings-schema.js +36 -0
  61. package/dist/shared/settings-schema.js.map +1 -0
  62. package/dist/util/import-generator.js.map +1 -1
  63. package/dist/util/parse.js.map +1 -1
  64. package/package.json +8 -2
  65. package/src/adapters/adapters.ts +10 -3
  66. package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +11 -7
  67. package/src/adapters/drizzle/drizzle-adapter.test.ts +77 -29
  68. package/src/adapters/drizzle/drizzle-adapter.ts +31 -78
  69. package/src/adapters/drizzle/drizzle-query.ts +4 -7
  70. package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +9 -3
  71. package/src/adapters/drizzle/drizzle-uow-compiler.ts +12 -6
  72. package/src/adapters/drizzle/drizzle-uow-decoder.ts +1 -1
  73. package/src/adapters/drizzle/drizzle-uow-executor.ts +1 -1
  74. package/src/adapters/drizzle/generate.test.ts +573 -150
  75. package/src/adapters/drizzle/generate.ts +187 -36
  76. package/src/adapters/drizzle/migrate-drizzle.test.ts +30 -6
  77. package/src/adapters/drizzle/shared.ts +31 -1
  78. package/src/adapters/drizzle/test-utils.ts +3 -1
  79. package/src/adapters/kysely/kysely-adapter-pglite.test.ts +25 -27
  80. package/src/adapters/kysely/kysely-adapter.ts +35 -58
  81. package/src/adapters/kysely/kysely-query-builder.ts +75 -44
  82. package/src/adapters/kysely/kysely-query-compiler.ts +3 -1
  83. package/src/adapters/kysely/kysely-query.ts +8 -2
  84. package/src/adapters/kysely/kysely-shared.ts +23 -0
  85. package/src/adapters/kysely/kysely-uow-compiler.ts +5 -2
  86. package/src/adapters/kysely/migration/execute-mysql.test.ts +2 -2
  87. package/src/adapters/kysely/migration/execute-postgres.test.ts +19 -19
  88. package/src/adapters/kysely/migration/execute.ts +48 -17
  89. package/src/adapters/kysely/migration/kysely-migrator.test.ts +19 -37
  90. package/src/fragment.test.ts +1 -0
  91. package/src/migration-engine/auto-from-schema.ts +14 -18
  92. package/src/migration-engine/create.ts +1 -6
  93. package/src/migration-engine/generation-engine.test.ts +597 -0
  94. package/src/migration-engine/generation-engine.ts +356 -0
  95. package/src/migration-engine/shared.ts +1 -4
  96. package/src/mod.ts +0 -66
  97. package/src/query/condition-builder.ts +24 -8
  98. package/src/query/result-transform.ts +7 -1
  99. package/src/schema/create.test.ts +4 -1
  100. package/src/schema/create.ts +132 -24
  101. package/src/schema/serialize.ts +21 -7
  102. package/src/shared/settings-schema.ts +61 -0
  103. package/src/util/deep-equal.ts +21 -7
  104. package/src/util/import-generator.ts +3 -1
  105. package/src/util/parse.ts +3 -1
  106. package/tsdown.config.ts +1 -0
  107. package/.turbo/turbo-test.log +0 -37
  108. package/.turbo/turbo-types$colon$check.log +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"kysely-query.js","names":["executor: UOWExecutor<CompiledQuery, unknown>","decoder: UOWDecoder<T>","whereConfig: { indexName?: string; condition?: unknown }","setValues: unknown"],"sources":["../../../src/adapters/kysely/kysely-query.ts"],"sourcesContent":["import type { AbstractQuery } from \"../../query/query\";\nimport type { AnySchema } from \"../../schema/create\";\nimport type { KyselyConfig } from \"./kysely-adapter\";\nimport type { CompiledMutation, UOWDecoder, UOWExecutor } 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 } from \"kysely\";\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 config - Kysely configuration containing the database instance and provider\n * @returns An AbstractQuery instance for performing database operations\n *\n * @example\n * ```ts\n * const queryEngine = fromKysely(mySchema, {\n * db: kysely,\n * provider: 'postgresql'\n * });\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>(schema: T, config: KyselyConfig): AbstractQuery<T> {\n const { db: kysely, provider } = config;\n const uowCompiler = createKyselyUOWCompiler(schema, config);\n\n function createUOW(name?: string): UnitOfWork<T, []> {\n const executor: UOWExecutor<CompiledQuery, unknown> = {\n executeRetrievalPhase: (retrievalBatch: CompiledQuery[]) =>\n executeKyselyRetrievalPhase(kysely, retrievalBatch),\n executeMutationPhase: (mutationBatch: CompiledMutation<CompiledQuery>[]) =>\n executeKyselyMutationPhase(kysely, mutationBatch),\n };\n\n // Create a decoder function to transform raw results into application format\n const decoder: UOWDecoder<T> = (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 return rowArray.map((row) => decodeResult(row, op.table, provider));\n });\n };\n\n return new UnitOfWork(schema, uowCompiler, executor, decoder, name);\n }\n\n return {\n async find(tableName, builderFn) {\n const uow = createUOW();\n uow.find(tableName, builderFn);\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 findFirst(tableName, builderFn) {\n const uow = createUOW();\n if (builderFn) {\n uow.find(tableName, (b) => builderFn(b as never).pageSize(1));\n } else {\n uow.find(tableName, (b) => b.whereIndex(\"primary\").pageSize(1));\n }\n // executeRetrieve runs an array of `find` operation results, which each return an array of rows\n const [result]: unknown[][] = await uow.executeRetrieve();\n return result?.[0] ?? null;\n },\n\n async create(tableName, values) {\n const uow = createUOW();\n uow.create(tableName, values);\n const { success } = await uow.executeMutations();\n if (!success) {\n // This should not happen because we don't `.check()` this call.\n // TODO: Verify what happens when there are unique constraints\n throw new Error(\"Failed to create record\");\n }\n\n const [createdId] = uow.getCreatedIds();\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();\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();\n uow.update(tableName, id, builderFn as never);\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to update record (version conflict or record not found)\");\n }\n },\n\n async updateMany(tableName, builderFn) {\n // Create a special builder that captures both where and set operations\n let whereConfig: { indexName?: string; condition?: unknown } = {};\n let setValues: unknown;\n\n const specialBuilder = {\n whereIndex(indexName: string, condition?: unknown) {\n whereConfig = { indexName, condition };\n return this;\n },\n set(values: unknown) {\n setValues = values;\n return this;\n },\n };\n\n builderFn(specialBuilder);\n\n if (!whereConfig.indexName) {\n throw new Error(\"whereIndex() must be called in updateMany\");\n }\n if (!setValues) {\n throw new Error(\"set() must be called in updateMany\");\n }\n\n // First, find all matching records\n const findUow = createUOW();\n findUow.find(tableName, (b) => {\n if (whereConfig.condition) {\n return b.whereIndex(whereConfig.indexName as never, whereConfig.condition as never);\n }\n return b.whereIndex(whereConfig.indexName as never);\n });\n const findResults: unknown[][] = await findUow.executeRetrieve();\n const records = findResults[0];\n\n if (!records || records.length === 0) {\n return;\n }\n\n // Now update all found records\n const updateUow = createUOW();\n for (const record of records as never as Array<{ id: unknown }>) {\n updateUow.update(tableName as string, record.id as string, (b) =>\n b.set(setValues as never),\n );\n }\n const { success } = await updateUow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to update records (version conflict)\");\n }\n },\n\n async delete(tableName, id, builderFn) {\n const uow = createUOW();\n uow.delete(tableName, id, builderFn as never);\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to delete record (version conflict or record not found)\");\n }\n },\n\n async deleteMany(tableName, builderFn) {\n // Create a special builder that captures where configuration\n let whereConfig: { indexName?: string; condition?: unknown } = {};\n\n const specialBuilder = {\n whereIndex(indexName: string, condition?: unknown) {\n whereConfig = { indexName, condition };\n return this;\n },\n };\n\n // Safe: Call builderFn to capture the configuration\n builderFn(specialBuilder as never);\n\n if (!whereConfig.indexName) {\n throw new Error(\"whereIndex() must be called in deleteMany\");\n }\n\n // First, find all matching records\n const findUow = createUOW();\n findUow.find(tableName as string, (b) => {\n if (whereConfig.condition) {\n return b.whereIndex(whereConfig.indexName as never, whereConfig.condition as never);\n }\n return b.whereIndex(whereConfig.indexName as never);\n });\n const findResults2 = await findUow.executeRetrieve();\n const records = (findResults2 as unknown as [unknown])[0];\n\n // @ts-expect-error - Type narrowing doesn't work through unknown cast\n if (!records || records.length === 0) {\n return;\n }\n\n // Now delete all found records\n const deleteUow = createUOW();\n for (const record of records as never as Array<{ id: unknown }>) {\n deleteUow.delete(tableName as string, record.id as string);\n }\n const { success } = await deleteUow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to delete records (version conflict)\");\n }\n },\n\n createUnitOfWork(name) {\n return createUOW(name);\n },\n } as AbstractQuery<T>;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"kysely-query.js","names":["executor: UOWExecutor<CompiledQuery, unknown>","decoder: UOWDecoder<T>","whereConfig: { indexName?: string; condition?: unknown }","setValues: unknown"],"sources":["../../../src/adapters/kysely/kysely-query.ts"],"sourcesContent":["import type { AbstractQuery } from \"../../query/query\";\nimport type { AnySchema } from \"../../schema/create\";\nimport type { KyselyConfig } from \"./kysely-adapter\";\nimport type { CompiledMutation, UOWDecoder, UOWExecutor } 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 } from \"kysely\";\nimport type { TableNameMapper } from \"./kysely-shared\";\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 config - Kysely configuration containing the database instance and provider\n * @param mapper - Optional table name mapper for namespace prefixing\n * @returns An AbstractQuery instance for performing database operations\n *\n * @example\n * ```ts\n * const queryEngine = fromKysely(mySchema, {\n * db: kysely,\n * provider: 'postgresql'\n * });\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 config: KyselyConfig,\n mapper?: TableNameMapper,\n): AbstractQuery<T> {\n const { db: kysely, provider } = config;\n const uowCompiler = createKyselyUOWCompiler(schema, config, mapper);\n\n function createUOW(name?: string): UnitOfWork<T, []> {\n const executor: UOWExecutor<CompiledQuery, unknown> = {\n executeRetrievalPhase: (retrievalBatch: CompiledQuery[]) =>\n executeKyselyRetrievalPhase(kysely, retrievalBatch),\n executeMutationPhase: (mutationBatch: CompiledMutation<CompiledQuery>[]) =>\n executeKyselyMutationPhase(kysely, mutationBatch),\n };\n\n // Create a decoder function to transform raw results into application format\n const decoder: UOWDecoder<T> = (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 return rowArray.map((row) => decodeResult(row, op.table, provider));\n });\n };\n\n return new UnitOfWork(schema, uowCompiler, executor, decoder, name);\n }\n\n return {\n async find(tableName, builderFn) {\n const uow = createUOW();\n uow.find(tableName, builderFn);\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 findFirst(tableName, builderFn) {\n const uow = createUOW();\n if (builderFn) {\n uow.find(tableName, (b) => builderFn(b as never).pageSize(1));\n } else {\n uow.find(tableName, (b) => b.whereIndex(\"primary\").pageSize(1));\n }\n // executeRetrieve runs an array of `find` operation results, which each return an array of rows\n const [result]: unknown[][] = await uow.executeRetrieve();\n return result?.[0] ?? null;\n },\n\n async create(tableName, values) {\n const uow = createUOW();\n uow.create(tableName, values);\n const { success } = await uow.executeMutations();\n if (!success) {\n // This should not happen because we don't `.check()` this call.\n // TODO: Verify what happens when there are unique constraints\n throw new Error(\"Failed to create record\");\n }\n\n const [createdId] = uow.getCreatedIds();\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();\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();\n uow.update(tableName, id, builderFn as never);\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to update record (version conflict or record not found)\");\n }\n },\n\n async updateMany(tableName, builderFn) {\n // Create a special builder that captures both where and set operations\n let whereConfig: { indexName?: string; condition?: unknown } = {};\n let setValues: unknown;\n\n const specialBuilder = {\n whereIndex(indexName: string, condition?: unknown) {\n whereConfig = { indexName, condition };\n return this;\n },\n set(values: unknown) {\n setValues = values;\n return this;\n },\n };\n\n builderFn(specialBuilder);\n\n if (!whereConfig.indexName) {\n throw new Error(\"whereIndex() must be called in updateMany\");\n }\n if (!setValues) {\n throw new Error(\"set() must be called in updateMany\");\n }\n\n // First, find all matching records\n const findUow = createUOW();\n findUow.find(tableName, (b) => {\n if (whereConfig.condition) {\n return b.whereIndex(whereConfig.indexName as never, whereConfig.condition as never);\n }\n return b.whereIndex(whereConfig.indexName as never);\n });\n const findResults: unknown[][] = await findUow.executeRetrieve();\n const records = findResults[0];\n\n if (!records || records.length === 0) {\n return;\n }\n\n // Now update all found records\n const updateUow = createUOW();\n for (const record of records as never as Array<{ id: unknown }>) {\n updateUow.update(tableName as string, record.id as string, (b) =>\n b.set(setValues as never),\n );\n }\n const { success } = await updateUow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to update records (version conflict)\");\n }\n },\n\n async delete(tableName, id, builderFn) {\n const uow = createUOW();\n uow.delete(tableName, id, builderFn as never);\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to delete record (version conflict or record not found)\");\n }\n },\n\n async deleteMany(tableName, builderFn) {\n // Create a special builder that captures where configuration\n let whereConfig: { indexName?: string; condition?: unknown } = {};\n\n const specialBuilder = {\n whereIndex(indexName: string, condition?: unknown) {\n whereConfig = { indexName, condition };\n return this;\n },\n };\n\n // Safe: Call builderFn to capture the configuration\n builderFn(specialBuilder as never);\n\n if (!whereConfig.indexName) {\n throw new Error(\"whereIndex() must be called in deleteMany\");\n }\n\n // First, find all matching records\n const findUow = createUOW();\n findUow.find(tableName as string, (b) => {\n if (whereConfig.condition) {\n return b.whereIndex(whereConfig.indexName as never, whereConfig.condition as never);\n }\n return b.whereIndex(whereConfig.indexName as never);\n });\n const findResults2 = await findUow.executeRetrieve();\n const records = (findResults2 as unknown as [unknown])[0];\n\n // @ts-expect-error - Type narrowing doesn't work through unknown cast\n if (!records || records.length === 0) {\n return;\n }\n\n // Now delete all found records\n const deleteUow = createUOW();\n for (const record of records as never as Array<{ id: unknown }>) {\n deleteUow.delete(tableName as string, record.id as string);\n }\n const { success } = await deleteUow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to delete records (version conflict)\");\n }\n },\n\n createUnitOfWork(name) {\n return createUOW(name);\n },\n } as AbstractQuery<T>;\n}\n"],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ //#region src/adapters/kysely/kysely-shared.ts
2
+ /**
3
+ * Creates a table name mapper for a given namespace.
4
+ * Physical names have format: {logicalName}_{namespace}
5
+ */
6
+ function createTableNameMapper(namespace) {
7
+ return {
8
+ toPhysical: (logicalName) => `${logicalName}_${namespace}`,
9
+ toLogical: (physicalName) => {
10
+ if (physicalName.endsWith(`_${namespace}`)) return physicalName.slice(0, -(namespace.length + 1));
11
+ return physicalName;
12
+ }
13
+ };
14
+ }
15
+
16
+ //#endregion
17
+ export { createTableNameMapper };
18
+ //# sourceMappingURL=kysely-shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kysely-shared.js","names":[],"sources":["../../../src/adapters/kysely/kysely-shared.ts"],"sourcesContent":["/**\n * Maps logical table names (used by fragment authors) to physical table names (with namespace suffix)\n */\nexport interface TableNameMapper {\n toPhysical(logicalName: string): string;\n toLogical(physicalName: string): string;\n}\n\n/**\n * Creates a table name mapper for a given namespace.\n * Physical names have format: {logicalName}_{namespace}\n */\nexport function createTableNameMapper(namespace: string): TableNameMapper {\n return {\n toPhysical: (logicalName: string) => `${logicalName}_${namespace}`,\n toLogical: (physicalName: string) => {\n if (physicalName.endsWith(`_${namespace}`)) {\n return physicalName.slice(0, -(namespace.length + 1));\n }\n return physicalName;\n },\n };\n}\n"],"mappings":";;;;;AAYA,SAAgB,sBAAsB,WAAoC;AACxE,QAAO;EACL,aAAa,gBAAwB,GAAG,YAAY,GAAG;EACvD,YAAY,iBAAyB;AACnC,OAAI,aAAa,SAAS,IAAI,YAAY,CACxC,QAAO,aAAa,MAAM,GAAG,EAAE,UAAU,SAAS,GAAG;AAEvD,UAAO;;EAEV"}
@@ -12,11 +12,12 @@ import { createKyselyQueryCompiler } from "./kysely-query-compiler.js";
12
12
  *
13
13
  * @param schema - The database schema
14
14
  * @param config - Kysely configuration
15
+ * @param mapper - Optional table name mapper for namespace prefixing
15
16
  * @returns A UOWCompiler instance for Kysely
16
17
  */
17
- function createKyselyUOWCompiler(schema, config) {
18
- const queryCompiler = createKyselyQueryCompiler(schema, config);
19
- const queryBuilder = createKyselyQueryBuilder(config.db, config.provider);
18
+ function createKyselyUOWCompiler(schema, config, mapper) {
19
+ const queryCompiler = createKyselyQueryCompiler(schema, config, mapper);
20
+ const queryBuilder = createKyselyQueryBuilder(config.db, config.provider, mapper);
20
21
  const { provider } = config;
21
22
  function toTable(name) {
22
23
  const table = schema.tables[name];
@@ -1 +1 @@
1
- {"version":3,"file":"kysely-uow-compiler.js","names":["indexColumns: AnyColumn[]","orderDirection: \"asc\" | \"desc\"","orderBy: [AnyColumn, \"asc\" | \"desc\"][] | undefined","cursorCondition: Condition | undefined","combinedWhere: Condition | undefined"],"sources":["../../../src/adapters/kysely/kysely-uow-compiler.ts"],"sourcesContent":["import type { CompiledQuery } from \"kysely\";\nimport type { AnyColumn, AnySchema, FragnoId } from \"../../schema/create\";\nimport type {\n CompiledMutation,\n MutationOperation,\n RetrievalOperation,\n UOWCompiler,\n} from \"../../query/unit-of-work\";\nimport type { KyselyConfig } from \"./kysely-adapter\";\nimport { createKyselyQueryCompiler } from \"./kysely-query-compiler\";\nimport { createKyselyQueryBuilder } from \"./kysely-query-builder\";\nimport { buildCondition, type Condition } from \"../../query/condition-builder\";\nimport { decodeCursor, serializeCursorValues } from \"../../query/cursor\";\nimport type { AnySelectClause } from \"../../query/query\";\n\n/**\n * Create a Kysely-specific Unit of Work compiler\n *\n * This compiler translates UOW operations into Kysely CompiledQuery objects\n * that can be executed as a batch/transaction.\n *\n * @param schema - The database schema\n * @param config - Kysely configuration\n * @returns A UOWCompiler instance for Kysely\n */\nexport function createKyselyUOWCompiler<TSchema extends AnySchema>(\n schema: TSchema,\n config: KyselyConfig,\n): UOWCompiler<TSchema, CompiledQuery> {\n const queryCompiler = createKyselyQueryCompiler(schema, config);\n const queryBuilder = createKyselyQueryBuilder(config.db, config.provider);\n const { provider } = config;\n\n function toTable(name: unknown) {\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 compileRetrievalOperation(op: RetrievalOperation<TSchema>): CompiledQuery | null {\n switch (op.type) {\n case \"count\": {\n return queryCompiler.count(op.table.name, {\n where: op.options.where,\n });\n }\n\n case \"find\": {\n // Map UOW FindOptions to query compiler's FindManyOptions\n const {\n useIndex: _useIndex,\n orderByIndex,\n joins: join,\n after,\n before,\n pageSize,\n ...findManyOptions\n } = op.options;\n\n // Get index columns for ordering and cursor pagination\n let indexColumns: AnyColumn[] = [];\n let orderDirection: \"asc\" | \"desc\" = \"asc\";\n\n if (orderByIndex) {\n const index = op.table.indexes[orderByIndex.indexName];\n orderDirection = orderByIndex.direction;\n\n if (!index) {\n // If _primary index doesn't exist, fall back to internal ID column\n // (which is the actual primary key and maintains insertion order)\n if (orderByIndex.indexName === \"_primary\") {\n indexColumns = [op.table.getIdColumn()];\n } else {\n throw new Error(\n `Index \"${orderByIndex.indexName}\" not found on table \"${op.table.name}\"`,\n );\n }\n } else {\n // Order by all columns in the index with the specified direction\n indexColumns = index.columns;\n }\n }\n\n // Convert orderByIndex to orderBy format\n let orderBy: [AnyColumn, \"asc\" | \"desc\"][] | undefined;\n if (indexColumns.length > 0) {\n orderBy = indexColumns.map((col) => [col, orderDirection]);\n }\n\n // Handle cursor pagination - build a cursor condition\n let cursorCondition: Condition | undefined;\n\n if ((after || before) && indexColumns.length > 0) {\n const cursor = after || before;\n const cursorData = decodeCursor(cursor!);\n const serializedValues = serializeCursorValues(cursorData, indexColumns, provider);\n\n // Build tuple comparison for cursor pagination\n // For \"after\" with \"asc\": (col1, col2, ...) > (val1, val2, ...)\n // For \"before\" with \"desc\": reverse the comparison\n const isAfter = !!after;\n const useGreaterThan =\n (isAfter && orderDirection === \"asc\") || (!isAfter && orderDirection === \"desc\");\n\n if (indexColumns.length === 1) {\n // Simple single-column case\n const col = indexColumns[0]!;\n const val = serializedValues[col.ormName];\n const operator = useGreaterThan ? \">\" : \"<\";\n cursorCondition = {\n type: \"compare\",\n a: col,\n operator,\n b: val,\n };\n } else {\n // Multi-column tuple comparison - not yet supported for Kysely\n throw new Error(\n \"Multi-column cursor pagination is not yet supported in Kysely Unit of Work implementation\",\n );\n }\n }\n\n // Combine user where clause with cursor condition\n let combinedWhere: Condition | undefined;\n if (findManyOptions.where) {\n const whereResult = buildCondition(op.table.columns, findManyOptions.where);\n if (whereResult === true) {\n combinedWhere = undefined;\n } else if (whereResult === false) {\n return null;\n } else {\n combinedWhere = whereResult;\n }\n }\n\n if (cursorCondition) {\n if (combinedWhere) {\n combinedWhere = {\n type: \"and\",\n items: [combinedWhere, cursorCondition],\n };\n } else {\n combinedWhere = cursorCondition;\n }\n }\n\n // When we have joins or need to bypass buildFindOptions, use queryBuilder directly\n if (join && join.length > 0) {\n return queryBuilder.findMany(op.table, {\n // Safe cast: select from UOW matches SimplifyFindOptions requirement\n select: (findManyOptions.select ?? true) as AnySelectClause,\n where: combinedWhere,\n orderBy,\n limit: pageSize,\n join,\n });\n }\n\n return queryCompiler.findMany(op.table.name, {\n ...findManyOptions,\n where: combinedWhere ? () => combinedWhere! : undefined,\n orderBy: orderBy?.map(([col, dir]) => [col.ormName, dir]),\n limit: pageSize,\n });\n }\n }\n },\n\n compileMutationOperation(\n op: MutationOperation<TSchema>,\n ): CompiledMutation<CompiledQuery> | null {\n switch (op.type) {\n case \"create\":\n // queryCompiler.create() calls encodeValues() which handles runtime defaults\n return {\n query: queryCompiler.create(op.table, op.values),\n expectedAffectedRows: null, // creates don't need affected row checks\n };\n\n case \"update\": {\n const table = toTable(op.table);\n const idColumn = table.getIdColumn();\n const versionColumn = table.getVersionColumn();\n\n const externalId = typeof op.id === \"string\" ? op.id : op.id.externalId;\n const versionToCheck = getVersionToCheck(op.id, op.checkVersion);\n\n // Build WHERE clause that filters by ID and optionally by version\n const whereClause =\n versionToCheck !== undefined\n ? () =>\n buildCondition(table.columns, (eb) =>\n eb.and(\n eb(idColumn.ormName, \"=\", externalId),\n eb(versionColumn.ormName, \"=\", versionToCheck),\n ),\n )\n : () => buildCondition(table.columns, (eb) => eb(idColumn.ormName, \"=\", externalId));\n\n const query = queryCompiler.updateMany(op.table, {\n where: whereClause,\n set: op.set,\n });\n\n return query\n ? {\n query,\n expectedAffectedRows: op.checkVersion ? 1 : null,\n }\n : null;\n }\n\n case \"delete\": {\n const table = toTable(op.table);\n const idColumn = table.getIdColumn();\n const versionColumn = table.getVersionColumn();\n\n // Extract external ID based on whether op.id is FragnoId or string\n const externalId = typeof op.id === \"string\" ? op.id : op.id.externalId;\n const versionToCheck = getVersionToCheck(op.id, op.checkVersion);\n\n // Build WHERE clause that filters by ID and optionally by version\n const whereClause =\n versionToCheck !== undefined\n ? () =>\n buildCondition(table.columns, (eb) =>\n eb.and(\n eb(idColumn.ormName, \"=\", externalId),\n eb(versionColumn.ormName, \"=\", versionToCheck),\n ),\n )\n : () => buildCondition(table.columns, (eb) => eb(idColumn.ormName, \"=\", externalId));\n\n const query = queryCompiler.deleteMany(op.table, {\n where: whereClause,\n });\n\n return query\n ? {\n query,\n expectedAffectedRows: op.checkVersion ? 1 : null,\n }\n : null;\n }\n }\n },\n };\n}\n\n/**\n * Get the version to check for a given ID and checkVersion flag.\n * @returns The version to check or undefined if no check is required.\n * @throws Error if the ID is a string and checkVersion is true.\n */\nfunction getVersionToCheck(id: FragnoId | string, checkVersion: boolean): number | undefined {\n if (!checkVersion) {\n return undefined;\n }\n\n if (typeof id === \"string\") {\n throw new Error(\n `Cannot use checkVersion with a string ID. Version checking requires a FragnoId with version information.`,\n );\n }\n\n return id.version;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"kysely-uow-compiler.js","names":["indexColumns: AnyColumn[]","orderDirection: \"asc\" | \"desc\"","orderBy: [AnyColumn, \"asc\" | \"desc\"][] | undefined","cursorCondition: Condition | undefined","combinedWhere: Condition | undefined"],"sources":["../../../src/adapters/kysely/kysely-uow-compiler.ts"],"sourcesContent":["import type { CompiledQuery } from \"kysely\";\nimport type { AnyColumn, AnySchema, FragnoId } from \"../../schema/create\";\nimport type {\n CompiledMutation,\n MutationOperation,\n RetrievalOperation,\n UOWCompiler,\n} from \"../../query/unit-of-work\";\nimport type { KyselyConfig } from \"./kysely-adapter\";\nimport { createKyselyQueryCompiler } from \"./kysely-query-compiler\";\nimport { createKyselyQueryBuilder } from \"./kysely-query-builder\";\nimport { buildCondition, type Condition } from \"../../query/condition-builder\";\nimport { decodeCursor, serializeCursorValues } from \"../../query/cursor\";\nimport type { AnySelectClause } from \"../../query/query\";\nimport type { TableNameMapper } from \"./kysely-shared\";\n\n/**\n * Create a Kysely-specific Unit of Work compiler\n *\n * This compiler translates UOW operations into Kysely CompiledQuery objects\n * that can be executed as a batch/transaction.\n *\n * @param schema - The database schema\n * @param config - Kysely configuration\n * @param mapper - Optional table name mapper for namespace prefixing\n * @returns A UOWCompiler instance for Kysely\n */\nexport function createKyselyUOWCompiler<TSchema extends AnySchema>(\n schema: TSchema,\n config: KyselyConfig,\n mapper?: TableNameMapper,\n): UOWCompiler<TSchema, CompiledQuery> {\n const queryCompiler = createKyselyQueryCompiler(schema, config, mapper);\n const queryBuilder = createKyselyQueryBuilder(config.db, config.provider, mapper);\n const { provider } = config;\n\n function toTable(name: unknown) {\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 compileRetrievalOperation(op: RetrievalOperation<TSchema>): CompiledQuery | null {\n switch (op.type) {\n case \"count\": {\n return queryCompiler.count(op.table.name, {\n where: op.options.where,\n });\n }\n\n case \"find\": {\n // Map UOW FindOptions to query compiler's FindManyOptions\n const {\n useIndex: _useIndex,\n orderByIndex,\n joins: join,\n after,\n before,\n pageSize,\n ...findManyOptions\n } = op.options;\n\n // Get index columns for ordering and cursor pagination\n let indexColumns: AnyColumn[] = [];\n let orderDirection: \"asc\" | \"desc\" = \"asc\";\n\n if (orderByIndex) {\n const index = op.table.indexes[orderByIndex.indexName];\n orderDirection = orderByIndex.direction;\n\n if (!index) {\n // If _primary index doesn't exist, fall back to internal ID column\n // (which is the actual primary key and maintains insertion order)\n if (orderByIndex.indexName === \"_primary\") {\n indexColumns = [op.table.getIdColumn()];\n } else {\n throw new Error(\n `Index \"${orderByIndex.indexName}\" not found on table \"${op.table.name}\"`,\n );\n }\n } else {\n // Order by all columns in the index with the specified direction\n indexColumns = index.columns;\n }\n }\n\n // Convert orderByIndex to orderBy format\n let orderBy: [AnyColumn, \"asc\" | \"desc\"][] | undefined;\n if (indexColumns.length > 0) {\n orderBy = indexColumns.map((col) => [col, orderDirection]);\n }\n\n // Handle cursor pagination - build a cursor condition\n let cursorCondition: Condition | undefined;\n\n if ((after || before) && indexColumns.length > 0) {\n const cursor = after || before;\n const cursorData = decodeCursor(cursor!);\n const serializedValues = serializeCursorValues(cursorData, indexColumns, provider);\n\n // Build tuple comparison for cursor pagination\n // For \"after\" with \"asc\": (col1, col2, ...) > (val1, val2, ...)\n // For \"before\" with \"desc\": reverse the comparison\n const isAfter = !!after;\n const useGreaterThan =\n (isAfter && orderDirection === \"asc\") || (!isAfter && orderDirection === \"desc\");\n\n if (indexColumns.length === 1) {\n // Simple single-column case\n const col = indexColumns[0]!;\n const val = serializedValues[col.ormName];\n const operator = useGreaterThan ? \">\" : \"<\";\n cursorCondition = {\n type: \"compare\",\n a: col,\n operator,\n b: val,\n };\n } else {\n // Multi-column tuple comparison - not yet supported for Kysely\n throw new Error(\n \"Multi-column cursor pagination is not yet supported in Kysely Unit of Work implementation\",\n );\n }\n }\n\n // Combine user where clause with cursor condition\n let combinedWhere: Condition | undefined;\n if (findManyOptions.where) {\n const whereResult = buildCondition(op.table.columns, findManyOptions.where);\n if (whereResult === true) {\n combinedWhere = undefined;\n } else if (whereResult === false) {\n return null;\n } else {\n combinedWhere = whereResult;\n }\n }\n\n if (cursorCondition) {\n if (combinedWhere) {\n combinedWhere = {\n type: \"and\",\n items: [combinedWhere, cursorCondition],\n };\n } else {\n combinedWhere = cursorCondition;\n }\n }\n\n // When we have joins or need to bypass buildFindOptions, use queryBuilder directly\n if (join && join.length > 0) {\n return queryBuilder.findMany(op.table, {\n // Safe cast: select from UOW matches SimplifyFindOptions requirement\n select: (findManyOptions.select ?? true) as AnySelectClause,\n where: combinedWhere,\n orderBy,\n limit: pageSize,\n join,\n });\n }\n\n return queryCompiler.findMany(op.table.name, {\n ...findManyOptions,\n where: combinedWhere ? () => combinedWhere! : undefined,\n orderBy: orderBy?.map(([col, dir]) => [col.ormName, dir]),\n limit: pageSize,\n });\n }\n }\n },\n\n compileMutationOperation(\n op: MutationOperation<TSchema>,\n ): CompiledMutation<CompiledQuery> | null {\n switch (op.type) {\n case \"create\":\n // queryCompiler.create() calls encodeValues() which handles runtime defaults\n return {\n query: queryCompiler.create(op.table, op.values),\n expectedAffectedRows: null, // creates don't need affected row checks\n };\n\n case \"update\": {\n const table = toTable(op.table);\n const idColumn = table.getIdColumn();\n const versionColumn = table.getVersionColumn();\n\n const externalId = typeof op.id === \"string\" ? op.id : op.id.externalId;\n const versionToCheck = getVersionToCheck(op.id, op.checkVersion);\n\n // Build WHERE clause that filters by ID and optionally by version\n const whereClause =\n versionToCheck !== undefined\n ? () =>\n buildCondition(table.columns, (eb) =>\n eb.and(\n eb(idColumn.ormName, \"=\", externalId),\n eb(versionColumn.ormName, \"=\", versionToCheck),\n ),\n )\n : () => buildCondition(table.columns, (eb) => eb(idColumn.ormName, \"=\", externalId));\n\n const query = queryCompiler.updateMany(op.table, {\n where: whereClause,\n set: op.set,\n });\n\n return query\n ? {\n query,\n expectedAffectedRows: op.checkVersion ? 1 : null,\n }\n : null;\n }\n\n case \"delete\": {\n const table = toTable(op.table);\n const idColumn = table.getIdColumn();\n const versionColumn = table.getVersionColumn();\n\n // Extract external ID based on whether op.id is FragnoId or string\n const externalId = typeof op.id === \"string\" ? op.id : op.id.externalId;\n const versionToCheck = getVersionToCheck(op.id, op.checkVersion);\n\n // Build WHERE clause that filters by ID and optionally by version\n const whereClause =\n versionToCheck !== undefined\n ? () =>\n buildCondition(table.columns, (eb) =>\n eb.and(\n eb(idColumn.ormName, \"=\", externalId),\n eb(versionColumn.ormName, \"=\", versionToCheck),\n ),\n )\n : () => buildCondition(table.columns, (eb) => eb(idColumn.ormName, \"=\", externalId));\n\n const query = queryCompiler.deleteMany(op.table, {\n where: whereClause,\n });\n\n return query\n ? {\n query,\n expectedAffectedRows: op.checkVersion ? 1 : null,\n }\n : null;\n }\n }\n },\n };\n}\n\n/**\n * Get the version to check for a given ID and checkVersion flag.\n * @returns The version to check or undefined if no check is required.\n * @throws Error if the ID is a string and checkVersion is true.\n */\nfunction getVersionToCheck(id: FragnoId | string, checkVersion: boolean): number | undefined {\n if (!checkVersion) {\n return undefined;\n }\n\n if (typeof id === \"string\") {\n throw new Error(\n `Cannot use checkVersion with a string ID. Version checking requires a FragnoId with version information.`,\n );\n }\n\n return id.version;\n}\n"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { SETTINGS_TABLE_NAME } from "../../../shared/settings-schema.js";
1
2
  import { schemaToDBType } from "../../../schema/serialize.js";
2
3
  import { isUpdated } from "../../../migration-engine/shared.js";
3
4
  import { sql } from "kysely";
@@ -84,42 +85,43 @@ function executeColumn(tableName, operation, config) {
84
85
  }
85
86
  }
86
87
  }
87
- function execute(operation, config, onCustomNode) {
88
+ function execute(operation, config, onCustomNode, mapper) {
88
89
  const { db, provider } = config;
90
+ const getTableName = (tableName) => tableName === SETTINGS_TABLE_NAME ? tableName : mapper ? mapper.toPhysical(tableName) : tableName;
89
91
  function createTable(tableName, columns) {
90
- let builder = db.schema.createTable(tableName);
92
+ let builder = db.schema.createTable(getTableName(tableName));
91
93
  for (const columnInfo of columns) builder = builder.addColumn(columnInfo.name, sql.raw(schemaToDBType(columnInfo, provider)), getColumnBuilderCallback(columnInfo, provider));
92
94
  return builder;
93
95
  }
94
96
  switch (operation.type) {
95
97
  case "create-table": return createTable(operation.name, operation.columns);
96
98
  case "rename-table":
97
- if (provider === "mssql") return rawToNode(db, sql`EXEC sp_rename ${sql.lit(operation.from)}, ${sql.lit(operation.to)}`);
98
- return db.schema.alterTable(operation.from).renameTo(operation.to);
99
+ if (provider === "mssql") return rawToNode(db, sql`EXEC sp_rename ${sql.lit(getTableName(operation.from))}, ${sql.lit(getTableName(operation.to))}`);
100
+ return db.schema.alterTable(getTableName(operation.from)).renameTo(getTableName(operation.to));
99
101
  case "alter-table": {
100
102
  const results = [];
101
- for (const op of operation.value) results.push(...executeColumn(operation.name, op, config));
103
+ for (const op of operation.value) results.push(...executeColumn(getTableName(operation.name), op, config));
102
104
  return results;
103
105
  }
104
- case "drop-table": return db.schema.dropTable(operation.name);
106
+ case "drop-table": return db.schema.dropTable(getTableName(operation.name));
105
107
  case "custom": return onCustomNode(operation);
106
108
  case "add-foreign-key": {
107
109
  if (provider === "sqlite") throw new Error(errors.SQLiteUpdateForeignKeys);
108
110
  const { table, value } = operation;
109
111
  const action = getForeignKeyAction(provider);
110
- return db.schema.alterTable(table).addForeignKeyConstraint(value.name, value.columns, value.referencedTable, value.referencedColumns, (b) => b.onUpdate(action).onDelete(action));
112
+ return db.schema.alterTable(getTableName(table)).addForeignKeyConstraint(value.name, value.columns, getTableName(value.referencedTable), value.referencedColumns, (b) => b.onUpdate(action).onDelete(action));
111
113
  }
112
114
  case "drop-foreign-key": {
113
115
  if (provider === "sqlite") throw new Error(errors.SQLiteUpdateForeignKeys);
114
116
  const { table, name } = operation;
115
- let query = db.schema.alterTable(table).dropConstraint(name);
117
+ let query = db.schema.alterTable(getTableName(table)).dropConstraint(name);
116
118
  if (provider !== "mysql") query = query.ifExists();
117
119
  return query;
118
120
  }
119
121
  case "add-index":
120
- if (operation.unique) return createUniqueIndex(db, operation.name, operation.table, operation.columns, provider);
121
- return db.schema.createIndex(operation.name).on(operation.table).columns(operation.columns);
122
- case "drop-index": return dropUniqueIndex(db, operation.name, operation.table, provider);
122
+ if (operation.unique) return createUniqueIndex(db, operation.name, getTableName(operation.table), operation.columns, provider);
123
+ return db.schema.createIndex(operation.name).on(getTableName(operation.table)).columns(operation.columns);
124
+ case "drop-index": return dropUniqueIndex(db, operation.name, getTableName(operation.table), provider);
123
125
  }
124
126
  }
125
127
  function getColumnBuilderCallback(col, provider) {
@@ -167,8 +169,9 @@ function defaultValueToDB(column, provider) {
167
169
  const value = column.default;
168
170
  if (!value) return;
169
171
  if (provider === "mysql" && column.type === "string") return;
170
- if ("runtime" in value && value.runtime === "now") return sql`CURRENT_TIMESTAMP`;
171
172
  if ("value" in value && value.value !== void 0) return sql.lit(value.value);
173
+ if ("dbSpecial" in value && value.dbSpecial === "now") return sql`CURRENT_TIMESTAMP`;
174
+ if ("runtime" in value) return;
172
175
  }
173
176
 
174
177
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"execute.js","names":["results: ExecuteNode[]"],"sources":["../../../../src/adapters/kysely/migration/execute.ts"],"sourcesContent":["import {\n type ColumnBuilderCallback,\n type Compilable,\n type CreateTableBuilder,\n type Kysely,\n type RawBuilder,\n sql,\n} from \"kysely\";\nimport {\n type CustomOperation,\n isUpdated,\n type ColumnOperation,\n type MigrationOperation,\n type ColumnInfo,\n} from \"../../../migration-engine/shared\";\nimport type { SQLProvider } from \"../../../shared/providers\";\nimport { schemaToDBType } from \"../../../schema/serialize\";\nimport type { KyselyConfig } from \"../kysely-adapter\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype KyselyAny = Kysely<any>;\n\nexport type ExecuteNode = Compilable & {\n execute(): Promise<unknown>;\n};\n\nconst errors = {\n IdColumnUpdate:\n \"ID columns cannot be updated. Not every database supports updating primary keys and often requires workarounds.\",\n SQLiteUpdateColumn: \"SQLite doesn't support updating columns. Recreate the table instead.\",\n SQLiteUpdateForeignKeys:\n \"SQLite doesn't support modifying foreign keys directly. Use `recreate-table` instead.\",\n} as const;\n\n/**\n * Returns the appropriate foreign key action based on the provider.\n * MSSQL doesn't support RESTRICT, so we use NO ACTION (functionally equivalent).\n */\nfunction getForeignKeyAction(provider: SQLProvider): \"restrict\" | \"no action\" {\n return provider === \"mssql\" ? \"no action\" : \"restrict\";\n}\n\n/**\n * Generates MSSQL default constraint name following the DF_tableName_columnName pattern.\n */\nfunction getMssqlDefaultConstraintName(tableName: string, columnName: string): string {\n const MSSQL_DEFAULT_CONSTRAINT_PREFIX = \"DF\" as const;\n return `${MSSQL_DEFAULT_CONSTRAINT_PREFIX}_${tableName}_${columnName}`;\n}\n\nfunction createUniqueIndex(\n db: KyselyAny,\n name: string,\n tableName: string,\n cols: string[],\n provider: SQLProvider,\n) {\n const query = db.schema.createIndex(name).on(tableName).columns(cols).unique();\n\n if (provider === \"mssql\") {\n // MSSQL: ignore null values in unique indexes by default\n return query.where((b) => {\n return b.and(cols.map((col) => b(col, \"is not\", null)));\n });\n }\n\n return query;\n}\n\nfunction dropUniqueIndex(db: KyselyAny, name: string, tableName: string, provider: SQLProvider) {\n let query = db.schema.dropIndex(name).ifExists();\n\n if (provider === \"cockroachdb\") {\n query = query.cascade();\n }\n\n if (provider === \"mssql\") {\n query = query.on(tableName);\n }\n\n return query;\n}\n\nfunction executeColumn(\n tableName: string,\n operation: ColumnOperation,\n config: KyselyConfig,\n): ExecuteNode[] {\n const { db, provider } = config;\n const next = () => db.schema.alterTable(tableName);\n const results: ExecuteNode[] = [];\n\n switch (operation.type) {\n case \"rename-column\":\n results.push(next().renameColumn(operation.from, operation.to));\n return results;\n\n case \"drop-column\":\n results.push(next().dropColumn(operation.name));\n\n return results;\n case \"create-column\": {\n const col = operation.value;\n\n results.push(\n next().addColumn(\n col.name,\n sql.raw(schemaToDBType(col, provider)),\n getColumnBuilderCallback(col, provider),\n ),\n );\n\n return results;\n }\n case \"update-column\": {\n const col = operation.value;\n\n if (col.role === \"external-id\" || col.role === \"internal-id\") {\n throw new Error(errors.IdColumnUpdate);\n }\n if (provider === \"sqlite\") {\n throw new Error(errors.SQLiteUpdateColumn);\n }\n\n if (!isUpdated(operation)) {\n return results;\n }\n if (provider === \"mysql\") {\n results.push(\n next().modifyColumn(\n operation.name,\n sql.raw(schemaToDBType(col, provider)),\n getColumnBuilderCallback(col, provider),\n ),\n );\n return results;\n }\n\n // MSSQL requires dropping and recreating default constraints when changing data type or default value\n const mssqlRecreateDefaultConstraint = operation.updateDataType || operation.updateDefault;\n\n if (provider === \"mssql\" && mssqlRecreateDefaultConstraint) {\n results.push(rawToNode(db, mssqlDropDefaultConstraint(tableName, col.name)));\n }\n\n // TODO: We should maybe do some of these operations in a single query\n\n if (operation.updateDataType) {\n const dbType = sql.raw(schemaToDBType(col, provider));\n\n if (provider === \"postgresql\" || provider === \"cockroachdb\") {\n // PostgreSQL/CockroachDB: Use explicit USING clause for type conversion\n results.push(\n rawToNode(\n db,\n sql`ALTER TABLE ${sql.ref(tableName)} ALTER COLUMN ${sql.ref(operation.name)} TYPE ${dbType} USING (${sql.ref(operation.name)}::${dbType})`,\n ),\n );\n } else {\n results.push(next().alterColumn(operation.name, (b) => b.setDataType(dbType)));\n }\n }\n\n if (operation.updateNullable) {\n results.push(\n next().alterColumn(operation.name, (build) =>\n col.isNullable ? build.dropNotNull() : build.setNotNull(),\n ),\n );\n }\n\n if (provider === \"mssql\" && mssqlRecreateDefaultConstraint) {\n const defaultValue = defaultValueToDB(col, provider);\n\n if (defaultValue) {\n const constraintName = getMssqlDefaultConstraintName(tableName, col.name);\n\n results.push(\n rawToNode(\n db,\n sql`ALTER TABLE ${sql.ref(tableName)} ADD CONSTRAINT ${sql.ref(constraintName)} DEFAULT ${defaultValue} FOR ${sql.ref(col.name)}`,\n ),\n );\n }\n } else if (operation.updateDefault) {\n const defaultValue = defaultValueToDB(col, provider);\n\n results.push(\n next().alterColumn(operation.name, (build) => {\n if (!defaultValue) {\n return build.dropDefault();\n }\n return build.setDefault(defaultValue);\n }),\n );\n }\n\n return results;\n }\n }\n}\n\nexport function execute(\n operation: MigrationOperation,\n config: KyselyConfig,\n onCustomNode: (op: CustomOperation) => ExecuteNode | ExecuteNode[],\n): ExecuteNode | ExecuteNode[] {\n const { db, provider } = config;\n\n function createTable(tableName: string, columns: ColumnInfo[]) {\n let builder = db.schema.createTable(tableName) as CreateTableBuilder<string, string>;\n\n // Add columns from the column info array\n for (const columnInfo of columns) {\n builder = builder.addColumn(\n columnInfo.name,\n sql.raw(schemaToDBType(columnInfo, provider)),\n getColumnBuilderCallback(columnInfo, provider),\n );\n }\n\n return builder;\n }\n\n switch (operation.type) {\n case \"create-table\":\n return createTable(operation.name, operation.columns);\n case \"rename-table\":\n if (provider === \"mssql\") {\n return rawToNode(\n db,\n sql`EXEC sp_rename ${sql.lit(operation.from)}, ${sql.lit(operation.to)}`,\n );\n }\n\n return db.schema.alterTable(operation.from).renameTo(operation.to);\n case \"alter-table\": {\n const results: ExecuteNode[] = [];\n\n for (const op of operation.value) {\n results.push(...executeColumn(operation.name, op, config));\n }\n\n return results;\n }\n case \"drop-table\":\n return db.schema.dropTable(operation.name);\n case \"custom\":\n return onCustomNode(operation);\n case \"add-foreign-key\": {\n if (provider === \"sqlite\") {\n throw new Error(errors.SQLiteUpdateForeignKeys);\n }\n\n const { table, value } = operation;\n const action = getForeignKeyAction(provider);\n\n return db.schema\n .alterTable(table)\n .addForeignKeyConstraint(\n value.name,\n value.columns,\n value.referencedTable,\n value.referencedColumns,\n (b) => b.onUpdate(action).onDelete(action),\n );\n }\n case \"drop-foreign-key\": {\n if (provider === \"sqlite\") {\n throw new Error(errors.SQLiteUpdateForeignKeys);\n }\n\n const { table, name } = operation;\n let query = db.schema.alterTable(table).dropConstraint(name);\n\n // MySQL doesn't support IF EXISTS for dropping constraints\n if (provider !== \"mysql\") {\n query = query.ifExists();\n }\n\n return query;\n }\n case \"add-index\": {\n if (operation.unique) {\n return createUniqueIndex(db, operation.name, operation.table, operation.columns, provider);\n }\n return db.schema.createIndex(operation.name).on(operation.table).columns(operation.columns);\n }\n case \"drop-index\": {\n return dropUniqueIndex(db, operation.name, operation.table, provider);\n }\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\nfunction getColumnBuilderCallback(col: ColumnInfo, provider: SQLProvider): ColumnBuilderCallback {\n return (build) => {\n if (!col.isNullable) {\n build = build.notNull();\n }\n\n // Internal ID is the primary key with auto-increment\n if (col.role === \"internal-id\") {\n build = build.primaryKey();\n // Auto-increment for internal ID\n if (provider === \"postgresql\" || provider === \"cockroachdb\") {\n // SERIAL/BIGSERIAL handles auto-increment\n // Already handled in schemaToDBType\n } else if (provider === \"mysql\") {\n build = build.autoIncrement();\n } else if (provider === \"sqlite\") {\n build = build.autoIncrement();\n } else if (provider === \"mssql\") {\n build = build.identity();\n }\n }\n\n // External ID must be unique\n if (col.role === \"external-id\") {\n build = build.unique();\n }\n\n const defaultValue = defaultValueToDB(col, provider);\n if (defaultValue) {\n build = build.defaultTo(defaultValue);\n }\n return build;\n };\n}\n\nfunction rawToNode(db: KyselyAny, raw: RawBuilder<unknown>): ExecuteNode {\n return {\n compile() {\n return raw.compile(db);\n },\n execute() {\n return raw.execute(db);\n },\n };\n}\n\nfunction mssqlDropDefaultConstraint(tableName: string, columnName: string) {\n return sql`\nDECLARE @ConstraintName NVARCHAR(200);\n\nSELECT @ConstraintName = dc.name\nFROM sys.default_constraints dc\nJOIN sys.columns c ON dc.parent_object_id = c.object_id AND dc.parent_column_id = c.column_id\nJOIN sys.tables t ON t.object_id = c.object_id\nJOIN sys.schemas s ON t.schema_id = s.schema_id\nWHERE s.name = 'dbo' AND t.name = ${sql.lit(tableName)} AND c.name = ${sql.lit(columnName)};\n\nIF @ConstraintName IS NOT NULL\nBEGIN\n EXEC('ALTER TABLE [dbo].[' + ${sql.lit(tableName)} + '] DROP CONSTRAINT [' + @ConstraintName + ']');\nEND`;\n}\n\nfunction defaultValueToDB(column: ColumnInfo, provider: SQLProvider) {\n const value = column.default;\n if (!value) {\n return undefined;\n }\n\n // MySQL doesn't support default values for TEXT columns\n if (provider === \"mysql\" && column.type === \"string\") {\n return undefined;\n }\n\n if (\"runtime\" in value && value.runtime === \"now\") {\n return sql`CURRENT_TIMESTAMP`;\n }\n\n if (\"value\" in value && value.value !== undefined) {\n return sql.lit(value.value);\n }\n\n return undefined;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"execute.js","names":["results: ExecuteNode[]"],"sources":["../../../../src/adapters/kysely/migration/execute.ts"],"sourcesContent":["import {\n type ColumnBuilderCallback,\n type Compilable,\n type CreateTableBuilder,\n type Kysely,\n type RawBuilder,\n sql,\n} from \"kysely\";\nimport {\n type CustomOperation,\n isUpdated,\n type ColumnOperation,\n type MigrationOperation,\n type ColumnInfo,\n} from \"../../../migration-engine/shared\";\nimport type { SQLProvider } from \"../../../shared/providers\";\nimport { schemaToDBType } from \"../../../schema/serialize\";\nimport type { KyselyConfig } from \"../kysely-adapter\";\nimport type { TableNameMapper } from \"../kysely-shared\";\nimport { SETTINGS_TABLE_NAME } from \"../../../shared/settings-schema\";\n\nexport type ExecuteNode = Compilable & {\n execute(): Promise<unknown>;\n};\n\ntype KyselyAny = Kysely<any>; // eslint-disable-line @typescript-eslint/no-explicit-any\n\nconst errors = {\n IdColumnUpdate:\n \"ID columns cannot be updated. Not every database supports updating primary keys and often requires workarounds.\",\n SQLiteUpdateColumn: \"SQLite doesn't support updating columns. Recreate the table instead.\",\n SQLiteUpdateForeignKeys:\n \"SQLite doesn't support modifying foreign keys directly. Use `recreate-table` instead.\",\n} as const;\n\n/**\n * Returns the appropriate foreign key action based on the provider.\n * MSSQL doesn't support RESTRICT, so we use NO ACTION (functionally equivalent).\n */\nfunction getForeignKeyAction(provider: SQLProvider): \"restrict\" | \"no action\" {\n return provider === \"mssql\" ? \"no action\" : \"restrict\";\n}\n\n/**\n * Generates MSSQL default constraint name following the DF_tableName_columnName pattern.\n */\nfunction getMssqlDefaultConstraintName(tableName: string, columnName: string): string {\n const MSSQL_DEFAULT_CONSTRAINT_PREFIX = \"DF\" as const;\n return `${MSSQL_DEFAULT_CONSTRAINT_PREFIX}_${tableName}_${columnName}`;\n}\n\nfunction createUniqueIndex(\n db: KyselyAny,\n name: string,\n tableName: string,\n cols: string[],\n provider: SQLProvider,\n) {\n const query = db.schema.createIndex(name).on(tableName).columns(cols).unique();\n\n if (provider === \"mssql\") {\n // MSSQL: ignore null values in unique indexes by default\n return query.where((b) => {\n return b.and(cols.map((col) => b(col, \"is not\", null)));\n });\n }\n\n return query;\n}\n\nfunction dropUniqueIndex(db: KyselyAny, name: string, tableName: string, provider: SQLProvider) {\n let query = db.schema.dropIndex(name).ifExists();\n\n if (provider === \"cockroachdb\") {\n query = query.cascade();\n }\n\n if (provider === \"mssql\") {\n query = query.on(tableName);\n }\n\n return query;\n}\n\nfunction executeColumn(\n tableName: string,\n operation: ColumnOperation,\n config: KyselyConfig,\n): ExecuteNode[] {\n const { db, provider } = config;\n const next = () => db.schema.alterTable(tableName);\n const results: ExecuteNode[] = [];\n\n switch (operation.type) {\n case \"rename-column\":\n results.push(next().renameColumn(operation.from, operation.to));\n return results;\n\n case \"drop-column\":\n results.push(next().dropColumn(operation.name));\n\n return results;\n case \"create-column\": {\n const col = operation.value;\n\n results.push(\n next().addColumn(\n col.name,\n sql.raw(schemaToDBType(col, provider)),\n getColumnBuilderCallback(col, provider),\n ),\n );\n\n return results;\n }\n case \"update-column\": {\n const col = operation.value;\n\n if (col.role === \"external-id\" || col.role === \"internal-id\") {\n throw new Error(errors.IdColumnUpdate);\n }\n if (provider === \"sqlite\") {\n throw new Error(errors.SQLiteUpdateColumn);\n }\n\n if (!isUpdated(operation)) {\n return results;\n }\n if (provider === \"mysql\") {\n results.push(\n next().modifyColumn(\n operation.name,\n sql.raw(schemaToDBType(col, provider)),\n getColumnBuilderCallback(col, provider),\n ),\n );\n return results;\n }\n\n // MSSQL requires dropping and recreating default constraints when changing data type or default value\n const mssqlRecreateDefaultConstraint = operation.updateDataType || operation.updateDefault;\n\n if (provider === \"mssql\" && mssqlRecreateDefaultConstraint) {\n results.push(rawToNode(db, mssqlDropDefaultConstraint(tableName, col.name)));\n }\n\n // TODO: We should maybe do some of these operations in a single query\n\n if (operation.updateDataType) {\n const dbType = sql.raw(schemaToDBType(col, provider));\n\n if (provider === \"postgresql\" || provider === \"cockroachdb\") {\n // PostgreSQL/CockroachDB: Use explicit USING clause for type conversion\n results.push(\n rawToNode(\n db,\n sql`ALTER TABLE ${sql.ref(tableName)} ALTER COLUMN ${sql.ref(operation.name)} TYPE ${dbType} USING (${sql.ref(operation.name)}::${dbType})`,\n ),\n );\n } else {\n results.push(next().alterColumn(operation.name, (b) => b.setDataType(dbType)));\n }\n }\n\n if (operation.updateNullable) {\n results.push(\n next().alterColumn(operation.name, (build) =>\n col.isNullable ? build.dropNotNull() : build.setNotNull(),\n ),\n );\n }\n\n if (provider === \"mssql\" && mssqlRecreateDefaultConstraint) {\n const defaultValue = defaultValueToDB(col, provider);\n\n if (defaultValue) {\n const constraintName = getMssqlDefaultConstraintName(tableName, col.name);\n\n results.push(\n rawToNode(\n db,\n sql`ALTER TABLE ${sql.ref(tableName)} ADD CONSTRAINT ${sql.ref(constraintName)} DEFAULT ${defaultValue} FOR ${sql.ref(col.name)}`,\n ),\n );\n }\n } else if (operation.updateDefault) {\n const defaultValue = defaultValueToDB(col, provider);\n\n results.push(\n next().alterColumn(operation.name, (build) => {\n if (!defaultValue) {\n return build.dropDefault();\n }\n return build.setDefault(defaultValue);\n }),\n );\n }\n\n return results;\n }\n }\n}\n\nexport function execute(\n operation: MigrationOperation,\n config: KyselyConfig,\n onCustomNode: (op: CustomOperation) => ExecuteNode | ExecuteNode[],\n mapper?: TableNameMapper,\n): ExecuteNode | ExecuteNode[] {\n const { db, provider } = config;\n\n // Settings table is never namespaced\n const getTableName = (tableName: string) =>\n tableName === SETTINGS_TABLE_NAME\n ? tableName\n : mapper\n ? mapper.toPhysical(tableName)\n : tableName;\n\n function createTable(tableName: string, columns: ColumnInfo[]) {\n let builder = db.schema.createTable(getTableName(tableName)) as CreateTableBuilder<\n string,\n string\n >;\n\n // Add columns from the column info array\n for (const columnInfo of columns) {\n builder = builder.addColumn(\n columnInfo.name,\n sql.raw(schemaToDBType(columnInfo, provider)),\n getColumnBuilderCallback(columnInfo, provider),\n );\n }\n\n return builder;\n }\n\n switch (operation.type) {\n case \"create-table\":\n return createTable(operation.name, operation.columns);\n case \"rename-table\":\n if (provider === \"mssql\") {\n return rawToNode(\n db,\n sql`EXEC sp_rename ${sql.lit(getTableName(operation.from))}, ${sql.lit(getTableName(operation.to))}`,\n );\n }\n\n return db.schema\n .alterTable(getTableName(operation.from))\n .renameTo(getTableName(operation.to));\n case \"alter-table\": {\n const results: ExecuteNode[] = [];\n\n for (const op of operation.value) {\n results.push(...executeColumn(getTableName(operation.name), op, config));\n }\n\n return results;\n }\n case \"drop-table\":\n return db.schema.dropTable(getTableName(operation.name));\n case \"custom\":\n return onCustomNode(operation);\n case \"add-foreign-key\": {\n if (provider === \"sqlite\") {\n throw new Error(errors.SQLiteUpdateForeignKeys);\n }\n\n const { table, value } = operation;\n const action = getForeignKeyAction(provider);\n\n return db.schema\n .alterTable(getTableName(table))\n .addForeignKeyConstraint(\n value.name,\n value.columns,\n getTableName(value.referencedTable),\n value.referencedColumns,\n (b) => b.onUpdate(action).onDelete(action),\n );\n }\n case \"drop-foreign-key\": {\n if (provider === \"sqlite\") {\n throw new Error(errors.SQLiteUpdateForeignKeys);\n }\n\n const { table, name } = operation;\n let query = db.schema.alterTable(getTableName(table)).dropConstraint(name);\n\n // MySQL doesn't support IF EXISTS for dropping constraints\n if (provider !== \"mysql\") {\n query = query.ifExists();\n }\n\n return query;\n }\n case \"add-index\": {\n if (operation.unique) {\n return createUniqueIndex(\n db,\n operation.name,\n getTableName(operation.table),\n operation.columns,\n provider,\n );\n }\n return db.schema\n .createIndex(operation.name)\n .on(getTableName(operation.table))\n .columns(operation.columns);\n }\n case \"drop-index\": {\n return dropUniqueIndex(db, operation.name, getTableName(operation.table), provider);\n }\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\nfunction getColumnBuilderCallback(col: ColumnInfo, provider: SQLProvider): ColumnBuilderCallback {\n return (build) => {\n if (!col.isNullable) {\n build = build.notNull();\n }\n\n // Internal ID is the primary key with auto-increment\n if (col.role === \"internal-id\") {\n build = build.primaryKey();\n // Auto-increment for internal ID\n if (provider === \"postgresql\" || provider === \"cockroachdb\") {\n // SERIAL/BIGSERIAL handles auto-increment\n // Already handled in schemaToDBType\n } else if (provider === \"mysql\") {\n build = build.autoIncrement();\n } else if (provider === \"sqlite\") {\n build = build.autoIncrement();\n } else if (provider === \"mssql\") {\n build = build.identity();\n }\n }\n\n // External ID must be unique\n if (col.role === \"external-id\") {\n build = build.unique();\n }\n\n const defaultValue = defaultValueToDB(col, provider);\n if (defaultValue) {\n build = build.defaultTo(defaultValue);\n }\n return build;\n };\n}\n\nfunction rawToNode(db: KyselyAny, raw: RawBuilder<unknown>): ExecuteNode {\n return {\n compile() {\n return raw.compile(db);\n },\n execute() {\n return raw.execute(db);\n },\n };\n}\n\nfunction mssqlDropDefaultConstraint(tableName: string, columnName: string) {\n return sql`\nDECLARE @ConstraintName NVARCHAR(200);\n\nSELECT @ConstraintName = dc.name\nFROM sys.default_constraints dc\nJOIN sys.columns c ON dc.parent_object_id = c.object_id AND dc.parent_column_id = c.column_id\nJOIN sys.tables t ON t.object_id = c.object_id\nJOIN sys.schemas s ON t.schema_id = s.schema_id\nWHERE s.name = 'dbo' AND t.name = ${sql.lit(tableName)} AND c.name = ${sql.lit(columnName)};\n\nIF @ConstraintName IS NOT NULL\nBEGIN\n EXEC('ALTER TABLE [dbo].[' + ${sql.lit(tableName)} + '] DROP CONSTRAINT [' + @ConstraintName + ']');\nEND`;\n}\n\nfunction defaultValueToDB(column: ColumnInfo, provider: SQLProvider) {\n const value = column.default;\n if (!value) {\n return undefined;\n }\n\n // MySQL doesn't support default values for TEXT columns\n if (provider === \"mysql\" && column.type === \"string\") {\n return undefined;\n }\n\n // Static default values: defaultTo(value)\n if (\"value\" in value && value.value !== undefined) {\n return sql.lit(value.value);\n }\n\n // Database-level special functions: defaultTo(b => b.now())\n if (\"dbSpecial\" in value && value.dbSpecial === \"now\") {\n return sql`CURRENT_TIMESTAMP`;\n }\n\n // Runtime defaults (defaultTo$) are NOT generated in SQL - they're handled in application code\n if (\"runtime\" in value) {\n return undefined;\n }\n\n return undefined;\n}\n"],"mappings":"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"}
@@ -41,10 +41,7 @@ function generateMigrationFromSchema(targetSchema, fromVersion, toVersion) {
41
41
  type: col.type,
42
42
  isNullable: col.isNullable,
43
43
  role: col.role,
44
- default: col.default ? {
45
- value: "value" in col.default ? col.default.value : void 0,
46
- runtime: "runtime" in col.default ? typeof col.default.runtime === "string" ? col.default.runtime : void 0 : void 0
47
- } : void 0
44
+ default: col.default ? "value" in col.default ? { value: col.default.value } : "dbSpecial" in col.default ? { dbSpecial: col.default.dbSpecial } : "runtime" in col.default && typeof col.default.runtime === "string" ? { runtime: col.default.runtime } : void 0 : void 0
48
45
  });
49
46
  }
50
47
  migrationOperations.push({
@@ -83,10 +80,7 @@ function generateMigrationFromSchema(targetSchema, fromVersion, toVersion) {
83
80
  type: col.type,
84
81
  isNullable: col.isNullable,
85
82
  role: col.role,
86
- default: col.default ? {
87
- value: "value" in col.default ? col.default.value : void 0,
88
- runtime: "runtime" in col.default ? typeof col.default.runtime === "string" ? col.default.runtime : void 0 : void 0
89
- } : void 0
83
+ default: col.default ? "value" in col.default ? { value: col.default.value } : "dbSpecial" in col.default ? { dbSpecial: col.default.dbSpecial } : "runtime" in col.default && typeof col.default.runtime === "string" ? { runtime: col.default.runtime } : void 0 : void 0
90
84
  }
91
85
  };
92
86
  })
@@ -1 +1 @@
1
- {"version":3,"file":"auto-from-schema.js","names":["migrationOperations: MigrationOperation[]","columns: ColumnInfo[]"],"sources":["../../src/migration-engine/auto-from-schema.ts"],"sourcesContent":["import { type AnySchema } from \"../schema/create\";\nimport type { MigrationOperation, ColumnInfo } from \"./shared\";\n\n/**\n * Generate migration operations from a schema's operation history\n *\n * The schema version number represents the cumulative number of operations applied.\n * This function takes operations from the schema between fromVersion and toVersion,\n * and converts them into migration operations.\n *\n * @param targetSchema - The schema containing the operations history\n * @param fromVersion - The current database version (e.g., 0)\n * @param toVersion - The target version to migrate to (e.g., 5)\n * @param options - Migration generation options\n * @returns Array of migration operations to apply\n *\n * @example\n * ```ts\n * const mySchema = schema(s => s\n * .addTable(\"users\", t => t.addColumn(\"id\", idColumn())) // version 1\n * .addTable(\"posts\", t => t.addColumn(\"id\", idColumn())) // version 2\n * );\n *\n * // Generate operations from version 0 to 1 (only creates users table)\n * const operations = generateMigrationFromSchema(mySchema, 0, 1);\n * ```\n */\nexport function generateMigrationFromSchema(\n targetSchema: AnySchema,\n fromVersion: number,\n toVersion: number,\n): MigrationOperation[] {\n if (fromVersion < 0) {\n throw new Error(`fromVersion cannot be negative: ${fromVersion}`);\n }\n\n if (fromVersion > targetSchema.version) {\n throw new Error(\n `fromVersion (${fromVersion}) exceeds schema version (${targetSchema.version})`,\n );\n }\n\n if (toVersion > targetSchema.version) {\n throw new Error(`toVersion (${toVersion}) exceeds schema version (${targetSchema.version})`);\n }\n\n if (toVersion < fromVersion) {\n throw new Error(\n `Cannot migrate backwards: toVersion (${toVersion}) < fromVersion (${fromVersion})`,\n );\n }\n\n // Get operations between fromVersion and toVersion\n // Operations are 1-indexed (operation 0 is version 0→1)\n const relevantOperations = targetSchema.operations.slice(fromVersion, toVersion);\n\n // Convert schema operations to migration operations\n const migrationOperations: MigrationOperation[] = [];\n\n for (const op of relevantOperations) {\n if (op.type === \"add-table\") {\n // Collect columns for create-table operation\n const columns: ColumnInfo[] = [];\n\n for (const subOp of op.operations) {\n if (subOp.type === \"add-column\") {\n const col = subOp.column;\n columns.push({\n name: subOp.columnName,\n type: col.type,\n isNullable: col.isNullable,\n role: col.role,\n default: col.default\n ? {\n value: \"value\" in col.default ? col.default.value : undefined,\n runtime:\n \"runtime\" in col.default\n ? typeof col.default.runtime === \"string\"\n ? col.default.runtime\n : undefined\n : undefined,\n }\n : undefined,\n });\n }\n }\n\n migrationOperations.push({\n type: \"create-table\",\n name: op.tableName,\n columns,\n });\n\n // Add indexes and foreign keys as separate operations\n for (const subOp of op.operations) {\n if (subOp.type === \"add-index\") {\n migrationOperations.push({\n type: \"add-index\",\n table: op.tableName,\n name: subOp.name,\n columns: subOp.columns,\n unique: subOp.unique,\n });\n } else if (subOp.type === \"add-foreign-key\") {\n migrationOperations.push({\n type: \"add-foreign-key\",\n table: op.tableName,\n value: {\n name: subOp.name,\n columns: subOp.columns,\n referencedTable: subOp.referencedTable,\n referencedColumns: subOp.referencedColumns,\n },\n });\n }\n }\n } else if (op.type === \"alter-table\") {\n const columnOps = op.operations.filter((o) => o.type === \"add-column\");\n\n if (columnOps.length > 0) {\n migrationOperations.push({\n type: \"alter-table\",\n name: op.tableName,\n value: columnOps.map((o) => {\n const col = o.column;\n return {\n type: \"create-column\" as const,\n value: {\n name: o.columnName,\n type: col.type,\n isNullable: col.isNullable,\n role: col.role,\n default: col.default\n ? {\n value: \"value\" in col.default ? col.default.value : undefined,\n runtime:\n \"runtime\" in col.default\n ? typeof col.default.runtime === \"string\"\n ? col.default.runtime\n : undefined\n : undefined,\n }\n : undefined,\n },\n };\n }),\n });\n }\n\n // Add indexes as separate operations\n for (const subOp of op.operations) {\n if (subOp.type === \"add-index\") {\n migrationOperations.push({\n type: \"add-index\",\n table: op.tableName,\n name: subOp.name,\n columns: subOp.columns,\n unique: subOp.unique,\n });\n }\n }\n } else if (op.type === \"add-reference\") {\n migrationOperations.push({\n type: \"add-foreign-key\",\n table: op.tableName,\n value: {\n name: `${op.tableName}_${op.config.to.table}_${op.referenceName}_fk`,\n columns: [op.config.from.column],\n referencedTable: op.config.to.table,\n referencedColumns: [op.config.to.column],\n },\n });\n }\n }\n\n return migrationOperations;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,4BACd,cACA,aACA,WACsB;AACtB,KAAI,cAAc,EAChB,OAAM,IAAI,MAAM,mCAAmC,cAAc;AAGnE,KAAI,cAAc,aAAa,QAC7B,OAAM,IAAI,MACR,gBAAgB,YAAY,4BAA4B,aAAa,QAAQ,GAC9E;AAGH,KAAI,YAAY,aAAa,QAC3B,OAAM,IAAI,MAAM,cAAc,UAAU,4BAA4B,aAAa,QAAQ,GAAG;AAG9F,KAAI,YAAY,YACd,OAAM,IAAI,MACR,wCAAwC,UAAU,mBAAmB,YAAY,GAClF;CAKH,MAAM,qBAAqB,aAAa,WAAW,MAAM,aAAa,UAAU;CAGhF,MAAMA,sBAA4C,EAAE;AAEpD,MAAK,MAAM,MAAM,mBACf,KAAI,GAAG,SAAS,aAAa;EAE3B,MAAMC,UAAwB,EAAE;AAEhC,OAAK,MAAM,SAAS,GAAG,WACrB,KAAI,MAAM,SAAS,cAAc;GAC/B,MAAM,MAAM,MAAM;AAClB,WAAQ,KAAK;IACX,MAAM,MAAM;IACZ,MAAM,IAAI;IACV,YAAY,IAAI;IAChB,MAAM,IAAI;IACV,SAAS,IAAI,UACT;KACE,OAAO,WAAW,IAAI,UAAU,IAAI,QAAQ,QAAQ;KACpD,SACE,aAAa,IAAI,UACb,OAAO,IAAI,QAAQ,YAAY,WAC7B,IAAI,QAAQ,UACZ,SACF;KACP,GACD;IACL,CAAC;;AAIN,sBAAoB,KAAK;GACvB,MAAM;GACN,MAAM,GAAG;GACT;GACD,CAAC;AAGF,OAAK,MAAM,SAAS,GAAG,WACrB,KAAI,MAAM,SAAS,YACjB,qBAAoB,KAAK;GACvB,MAAM;GACN,OAAO,GAAG;GACV,MAAM,MAAM;GACZ,SAAS,MAAM;GACf,QAAQ,MAAM;GACf,CAAC;WACO,MAAM,SAAS,kBACxB,qBAAoB,KAAK;GACvB,MAAM;GACN,OAAO,GAAG;GACV,OAAO;IACL,MAAM,MAAM;IACZ,SAAS,MAAM;IACf,iBAAiB,MAAM;IACvB,mBAAmB,MAAM;IAC1B;GACF,CAAC;YAGG,GAAG,SAAS,eAAe;EACpC,MAAM,YAAY,GAAG,WAAW,QAAQ,MAAM,EAAE,SAAS,aAAa;AAEtE,MAAI,UAAU,SAAS,EACrB,qBAAoB,KAAK;GACvB,MAAM;GACN,MAAM,GAAG;GACT,OAAO,UAAU,KAAK,MAAM;IAC1B,MAAM,MAAM,EAAE;AACd,WAAO;KACL,MAAM;KACN,OAAO;MACL,MAAM,EAAE;MACR,MAAM,IAAI;MACV,YAAY,IAAI;MAChB,MAAM,IAAI;MACV,SAAS,IAAI,UACT;OACE,OAAO,WAAW,IAAI,UAAU,IAAI,QAAQ,QAAQ;OACpD,SACE,aAAa,IAAI,UACb,OAAO,IAAI,QAAQ,YAAY,WAC7B,IAAI,QAAQ,UACZ,SACF;OACP,GACD;MACL;KACF;KACD;GACH,CAAC;AAIJ,OAAK,MAAM,SAAS,GAAG,WACrB,KAAI,MAAM,SAAS,YACjB,qBAAoB,KAAK;GACvB,MAAM;GACN,OAAO,GAAG;GACV,MAAM,MAAM;GACZ,SAAS,MAAM;GACf,QAAQ,MAAM;GACf,CAAC;YAGG,GAAG,SAAS,gBACrB,qBAAoB,KAAK;EACvB,MAAM;EACN,OAAO,GAAG;EACV,OAAO;GACL,MAAM,GAAG,GAAG,UAAU,GAAG,GAAG,OAAO,GAAG,MAAM,GAAG,GAAG,cAAc;GAChE,SAAS,CAAC,GAAG,OAAO,KAAK,OAAO;GAChC,iBAAiB,GAAG,OAAO,GAAG;GAC9B,mBAAmB,CAAC,GAAG,OAAO,GAAG,OAAO;GACzC;EACF,CAAC;AAIN,QAAO"}
1
+ {"version":3,"file":"auto-from-schema.js","names":["migrationOperations: MigrationOperation[]","columns: ColumnInfo[]"],"sources":["../../src/migration-engine/auto-from-schema.ts"],"sourcesContent":["import { type AnySchema } from \"../schema/create\";\nimport type { MigrationOperation, ColumnInfo } from \"./shared\";\n\n/**\n * Generate migration operations from a schema's operation history\n *\n * The schema version number represents the cumulative number of operations applied.\n * This function takes operations from the schema between fromVersion and toVersion,\n * and converts them into migration operations.\n *\n * @param targetSchema - The schema containing the operations history\n * @param fromVersion - The current database version (e.g., 0)\n * @param toVersion - The target version to migrate to (e.g., 5)\n * @param options - Migration generation options\n * @returns Array of migration operations to apply\n *\n * @example\n * ```ts\n * const mySchema = schema(s => s\n * .addTable(\"users\", t => t.addColumn(\"id\", idColumn())) // version 1\n * .addTable(\"posts\", t => t.addColumn(\"id\", idColumn())) // version 2\n * );\n *\n * // Generate operations from version 0 to 1 (only creates users table)\n * const operations = generateMigrationFromSchema(mySchema, 0, 1);\n * ```\n */\nexport function generateMigrationFromSchema(\n targetSchema: AnySchema,\n fromVersion: number,\n toVersion: number,\n): MigrationOperation[] {\n if (fromVersion < 0) {\n throw new Error(`fromVersion cannot be negative: ${fromVersion}`);\n }\n\n if (fromVersion > targetSchema.version) {\n throw new Error(\n `fromVersion (${fromVersion}) exceeds schema version (${targetSchema.version})`,\n );\n }\n\n if (toVersion > targetSchema.version) {\n throw new Error(`toVersion (${toVersion}) exceeds schema version (${targetSchema.version})`);\n }\n\n if (toVersion < fromVersion) {\n throw new Error(\n `Cannot migrate backwards: toVersion (${toVersion}) < fromVersion (${fromVersion})`,\n );\n }\n\n // Get operations between fromVersion and toVersion\n // Operations are 1-indexed (operation 0 is version 0→1)\n const relevantOperations = targetSchema.operations.slice(fromVersion, toVersion);\n\n // Convert schema operations to migration operations\n const migrationOperations: MigrationOperation[] = [];\n\n for (const op of relevantOperations) {\n if (op.type === \"add-table\") {\n // Collect columns for create-table operation\n const columns: ColumnInfo[] = [];\n\n for (const subOp of op.operations) {\n if (subOp.type === \"add-column\") {\n const col = subOp.column;\n columns.push({\n name: subOp.columnName,\n type: col.type,\n isNullable: col.isNullable,\n role: col.role,\n default: col.default\n ? \"value\" in col.default\n ? { value: col.default.value }\n : \"dbSpecial\" in col.default\n ? { dbSpecial: col.default.dbSpecial }\n : \"runtime\" in col.default && typeof col.default.runtime === \"string\"\n ? { runtime: col.default.runtime }\n : undefined\n : undefined,\n });\n }\n }\n\n migrationOperations.push({\n type: \"create-table\",\n name: op.tableName,\n columns,\n });\n\n // Add indexes and foreign keys as separate operations\n for (const subOp of op.operations) {\n if (subOp.type === \"add-index\") {\n migrationOperations.push({\n type: \"add-index\",\n table: op.tableName,\n name: subOp.name,\n columns: subOp.columns,\n unique: subOp.unique,\n });\n } else if (subOp.type === \"add-foreign-key\") {\n migrationOperations.push({\n type: \"add-foreign-key\",\n table: op.tableName,\n value: {\n name: subOp.name,\n columns: subOp.columns,\n referencedTable: subOp.referencedTable,\n referencedColumns: subOp.referencedColumns,\n },\n });\n }\n }\n } else if (op.type === \"alter-table\") {\n const columnOps = op.operations.filter((o) => o.type === \"add-column\");\n\n if (columnOps.length > 0) {\n migrationOperations.push({\n type: \"alter-table\",\n name: op.tableName,\n value: columnOps.map((o) => {\n const col = o.column;\n return {\n type: \"create-column\" as const,\n value: {\n name: o.columnName,\n type: col.type,\n isNullable: col.isNullable,\n role: col.role,\n default: col.default\n ? \"value\" in col.default\n ? { value: col.default.value }\n : \"dbSpecial\" in col.default\n ? { dbSpecial: col.default.dbSpecial }\n : \"runtime\" in col.default && typeof col.default.runtime === \"string\"\n ? { runtime: col.default.runtime }\n : undefined\n : undefined,\n },\n };\n }),\n });\n }\n\n // Add indexes as separate operations\n for (const subOp of op.operations) {\n if (subOp.type === \"add-index\") {\n migrationOperations.push({\n type: \"add-index\",\n table: op.tableName,\n name: subOp.name,\n columns: subOp.columns,\n unique: subOp.unique,\n });\n }\n }\n } else if (op.type === \"add-reference\") {\n migrationOperations.push({\n type: \"add-foreign-key\",\n table: op.tableName,\n value: {\n name: `${op.tableName}_${op.config.to.table}_${op.referenceName}_fk`,\n columns: [op.config.from.column],\n referencedTable: op.config.to.table,\n referencedColumns: [op.config.to.column],\n },\n });\n }\n }\n\n return migrationOperations;\n}\n"],"mappings":"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"}
@@ -31,11 +31,7 @@ interface Migrator {
31
31
  prepareMigrationTo: (toVersion: number, options?: MigrateOptions & {
32
32
  fromVersion?: number;
33
33
  }) => Promise<PreparedMigration>;
34
- /**
35
- * Get default file name for migration SQL
36
- */
37
- getDefaultFileName?: (namespace: string, fromVersion: number, toVersion: number) => string;
38
34
  }
39
35
  //#endregion
40
- export { Migrator };
36
+ export { Migrator, PreparedMigration };
41
37
  //# sourceMappingURL=create.d.ts.map
@@ -35,7 +35,7 @@ function createMigrator({ settings, generateMigrationFromSchema: generateMigrati
35
35
  }
36
36
  return generated;
37
37
  } };
38
- let operations = updateVersion ? [...await settings.updateSettingsInMigration(fromVersion, toVersion), ...await context.auto()] : await context.auto();
38
+ let operations = updateVersion ? [...await context.auto(), ...await settings.updateSettingsInMigration(fromVersion, toVersion)] : await context.auto();
39
39
  for (const transformer of transformers) {
40
40
  if (!transformer.afterAll) continue;
41
41
  operations = transformer.afterAll(operations, {
@@ -1 +1 @@
1
- {"version":3,"file":"create.js","names":["defaultGenerateMigrationFromSchema","context: MigrationContext","generateMigrationFromSchema"],"sources":["../../src/migration-engine/create.ts"],"sourcesContent":["import { type MigrationOperation } from \"./shared\";\nimport type { AnySchema } from \"../schema/create\";\nimport { generateMigrationFromSchema as defaultGenerateMigrationFromSchema } from \"./auto-from-schema\";\n\ntype Awaitable<T> = T | Promise<T>;\n\ninterface MigrationContext {\n auto: () => Promise<MigrationOperation[]>;\n}\n\nexport type CustomMigrationFn = (context: MigrationContext) => Awaitable<MigrationOperation[]>;\n\nexport interface MigrateOptions {\n /**\n * Update internal settings, it's true by default.\n * We don't recommend to disable it other than testing purposes.\n */\n updateSettings?: boolean;\n}\n\nexport interface PreparedMigration {\n operations: MigrationOperation[];\n getSQL?: () => string;\n execute: () => Promise<void>;\n}\n\nexport interface Migrator {\n /**\n * Get current version (returns 0 if not initialized)\n */\n getVersion: () => Promise<number>;\n\n /**\n * Migrate to the latest schema version\n */\n prepareMigration: (options?: MigrateOptions) => Promise<PreparedMigration>;\n\n /**\n * Migrate to a specific version (only forward migrations allowed)\n * @param toVersion - Target version to migrate to\n * @param options - Migration options including optional fromVersion\n */\n prepareMigrationTo: (\n toVersion: number,\n options?: MigrateOptions & { fromVersion?: number },\n ) => Promise<PreparedMigration>;\n\n /**\n * Get default file name for migration SQL\n */\n getDefaultFileName?: (namespace: string, fromVersion: number, toVersion: number) => string;\n}\n\nexport interface MigrationEngineOptions {\n /**\n * The target schema to migrate to\n */\n schema: AnySchema;\n\n executor: (operations: MigrationOperation[]) => Promise<void>;\n\n generateMigrationFromSchema?: typeof defaultGenerateMigrationFromSchema;\n\n settings: {\n /**\n * Get current version from database (0 if not initialized)\n */\n getVersion: () => Promise<number>;\n\n updateSettingsInMigration: (\n fromVersion: number,\n toVersion: number,\n ) => Awaitable<MigrationOperation[]>;\n };\n\n sql?: {\n toSql: (operations: MigrationOperation[]) => string;\n };\n\n transformers?: MigrationTransformer[];\n}\n\nexport interface MigrationTransformer {\n /**\n * Run after auto-generating migration operations\n */\n afterAuto?: (\n operations: MigrationOperation[],\n context: {\n options: MigrateOptions;\n fromVersion: number;\n toVersion: number;\n schema: AnySchema;\n },\n ) => MigrationOperation[];\n\n /**\n * Run on all migration operations\n */\n afterAll?: (\n operations: MigrationOperation[],\n context: {\n fromVersion: number;\n toVersion: number;\n schema: AnySchema;\n },\n ) => MigrationOperation[];\n}\n\nexport function createMigrator({\n settings,\n generateMigrationFromSchema = defaultGenerateMigrationFromSchema,\n schema: targetSchema,\n executor,\n sql: sqlConfig,\n transformers = [],\n}: MigrationEngineOptions): Migrator {\n const instance: Migrator = {\n getVersion() {\n return settings.getVersion();\n },\n async prepareMigration(options = {}) {\n return this.prepareMigrationTo(targetSchema.version, options);\n },\n async prepareMigrationTo(toVersion, options = {}) {\n const { updateSettings: updateVersion = true, fromVersion: providedFromVersion } = options;\n\n // Use provided fromVersion if available, otherwise query the database\n const fromVersion = providedFromVersion ?? (await settings.getVersion());\n\n if (toVersion < 0) {\n throw new Error(`Cannot migrate to negative version: ${toVersion}`);\n }\n\n if (fromVersion < 0) {\n throw new Error(`Cannot migrate from negative version: ${fromVersion}`);\n }\n\n if (toVersion < fromVersion) {\n throw new Error(\n `Cannot migrate backwards: current version is ${fromVersion}, target is ${toVersion}. Only forward migrations are supported.`,\n );\n }\n\n if (toVersion > targetSchema.version) {\n throw new Error(\n `Cannot migrate to version ${toVersion}: schema only has version ${targetSchema.version}`,\n );\n }\n\n if (fromVersion > targetSchema.version) {\n throw new Error(\n `Cannot migrate from version ${fromVersion}: schema only has version ${targetSchema.version}`,\n );\n }\n\n if (toVersion === fromVersion) {\n // Already at target version, return empty migration\n return {\n operations: [],\n getSQL: sqlConfig ? () => sqlConfig.toSql([]) : undefined,\n execute: async () => {},\n };\n }\n\n const context: MigrationContext = {\n async auto() {\n let generated = generateMigrationFromSchema(targetSchema, fromVersion, toVersion);\n\n for (const transformer of transformers) {\n if (!transformer.afterAuto) {\n continue;\n }\n\n generated = transformer.afterAuto(generated, {\n fromVersion,\n toVersion,\n schema: targetSchema,\n options,\n });\n }\n\n return generated;\n },\n };\n\n let operations = updateVersion\n ? [\n ...(await settings.updateSettingsInMigration(fromVersion, toVersion)),\n ...(await context.auto()),\n ]\n : await context.auto();\n\n for (const transformer of transformers) {\n if (!transformer.afterAll) {\n continue;\n }\n operations = transformer.afterAll(operations, {\n fromVersion,\n toVersion,\n schema: targetSchema,\n });\n }\n\n return {\n operations,\n getSQL: sqlConfig ? () => sqlConfig.toSql(operations) : undefined,\n execute: () => executor(operations),\n };\n },\n };\n\n return instance;\n}\n"],"mappings":";;;AA6GA,SAAgB,eAAe,EAC7B,UACA,6DAA8BA,6BAC9B,QAAQ,cACR,UACA,KAAK,WACL,eAAe,EAAE,IACkB;AAgGnC,QA/F2B;EACzB,aAAa;AACX,UAAO,SAAS,YAAY;;EAE9B,MAAM,iBAAiB,UAAU,EAAE,EAAE;AACnC,UAAO,KAAK,mBAAmB,aAAa,SAAS,QAAQ;;EAE/D,MAAM,mBAAmB,WAAW,UAAU,EAAE,EAAE;GAChD,MAAM,EAAE,gBAAgB,gBAAgB,MAAM,aAAa,wBAAwB;GAGnF,MAAM,cAAc,uBAAwB,MAAM,SAAS,YAAY;AAEvE,OAAI,YAAY,EACd,OAAM,IAAI,MAAM,uCAAuC,YAAY;AAGrE,OAAI,cAAc,EAChB,OAAM,IAAI,MAAM,yCAAyC,cAAc;AAGzE,OAAI,YAAY,YACd,OAAM,IAAI,MACR,gDAAgD,YAAY,cAAc,UAAU,0CACrF;AAGH,OAAI,YAAY,aAAa,QAC3B,OAAM,IAAI,MACR,6BAA6B,UAAU,4BAA4B,aAAa,UACjF;AAGH,OAAI,cAAc,aAAa,QAC7B,OAAM,IAAI,MACR,+BAA+B,YAAY,4BAA4B,aAAa,UACrF;AAGH,OAAI,cAAc,YAEhB,QAAO;IACL,YAAY,EAAE;IACd,QAAQ,kBAAkB,UAAU,MAAM,EAAE,CAAC,GAAG;IAChD,SAAS,YAAY;IACtB;GAGH,MAAMC,UAA4B,EAChC,MAAM,OAAO;IACX,IAAI,YAAYC,8BAA4B,cAAc,aAAa,UAAU;AAEjF,SAAK,MAAM,eAAe,cAAc;AACtC,SAAI,CAAC,YAAY,UACf;AAGF,iBAAY,YAAY,UAAU,WAAW;MAC3C;MACA;MACA,QAAQ;MACR;MACD,CAAC;;AAGJ,WAAO;MAEV;GAED,IAAI,aAAa,gBACb,CACE,GAAI,MAAM,SAAS,0BAA0B,aAAa,UAAU,EACpE,GAAI,MAAM,QAAQ,MAAM,CACzB,GACD,MAAM,QAAQ,MAAM;AAExB,QAAK,MAAM,eAAe,cAAc;AACtC,QAAI,CAAC,YAAY,SACf;AAEF,iBAAa,YAAY,SAAS,YAAY;KAC5C;KACA;KACA,QAAQ;KACT,CAAC;;AAGJ,UAAO;IACL;IACA,QAAQ,kBAAkB,UAAU,MAAM,WAAW,GAAG;IACxD,eAAe,SAAS,WAAW;IACpC;;EAEJ"}
1
+ {"version":3,"file":"create.js","names":["defaultGenerateMigrationFromSchema","context: MigrationContext","generateMigrationFromSchema"],"sources":["../../src/migration-engine/create.ts"],"sourcesContent":["import { type MigrationOperation } from \"./shared\";\nimport type { AnySchema } from \"../schema/create\";\nimport { generateMigrationFromSchema as defaultGenerateMigrationFromSchema } from \"./auto-from-schema\";\n\ntype Awaitable<T> = T | Promise<T>;\n\ninterface MigrationContext {\n auto: () => Promise<MigrationOperation[]>;\n}\n\nexport type CustomMigrationFn = (context: MigrationContext) => Awaitable<MigrationOperation[]>;\n\nexport interface MigrateOptions {\n /**\n * Update internal settings, it's true by default.\n * We don't recommend to disable it other than testing purposes.\n */\n updateSettings?: boolean;\n}\n\nexport interface PreparedMigration {\n operations: MigrationOperation[];\n getSQL?: () => string;\n execute: () => Promise<void>;\n}\n\nexport interface Migrator {\n /**\n * Get current version (returns 0 if not initialized)\n */\n getVersion: () => Promise<number>;\n\n /**\n * Migrate to the latest schema version\n */\n prepareMigration: (options?: MigrateOptions) => Promise<PreparedMigration>;\n\n /**\n * Migrate to a specific version (only forward migrations allowed)\n * @param toVersion - Target version to migrate to\n * @param options - Migration options including optional fromVersion\n */\n prepareMigrationTo: (\n toVersion: number,\n options?: MigrateOptions & { fromVersion?: number },\n ) => Promise<PreparedMigration>;\n}\n\nexport interface MigrationEngineOptions {\n /**\n * The target schema to migrate to\n */\n schema: AnySchema;\n\n executor: (operations: MigrationOperation[]) => Promise<void>;\n\n generateMigrationFromSchema?: typeof defaultGenerateMigrationFromSchema;\n\n settings: {\n /**\n * Get current version from database (0 if not initialized)\n */\n getVersion: () => Promise<number>;\n\n updateSettingsInMigration: (\n fromVersion: number,\n toVersion: number,\n ) => Awaitable<MigrationOperation[]>;\n };\n\n sql?: {\n toSql: (operations: MigrationOperation[]) => string;\n };\n\n transformers?: MigrationTransformer[];\n}\n\nexport interface MigrationTransformer {\n /**\n * Run after auto-generating migration operations\n */\n afterAuto?: (\n operations: MigrationOperation[],\n context: {\n options: MigrateOptions;\n fromVersion: number;\n toVersion: number;\n schema: AnySchema;\n },\n ) => MigrationOperation[];\n\n /**\n * Run on all migration operations\n */\n afterAll?: (\n operations: MigrationOperation[],\n context: {\n fromVersion: number;\n toVersion: number;\n schema: AnySchema;\n },\n ) => MigrationOperation[];\n}\n\nexport function createMigrator({\n settings,\n generateMigrationFromSchema = defaultGenerateMigrationFromSchema,\n schema: targetSchema,\n executor,\n sql: sqlConfig,\n transformers = [],\n}: MigrationEngineOptions): Migrator {\n const instance: Migrator = {\n getVersion() {\n return settings.getVersion();\n },\n async prepareMigration(options = {}) {\n return this.prepareMigrationTo(targetSchema.version, options);\n },\n async prepareMigrationTo(toVersion, options = {}) {\n const { updateSettings: updateVersion = true, fromVersion: providedFromVersion } = options;\n\n // Use provided fromVersion if available, otherwise query the database\n const fromVersion = providedFromVersion ?? (await settings.getVersion());\n\n if (toVersion < 0) {\n throw new Error(`Cannot migrate to negative version: ${toVersion}`);\n }\n\n if (fromVersion < 0) {\n throw new Error(`Cannot migrate from negative version: ${fromVersion}`);\n }\n\n if (toVersion < fromVersion) {\n throw new Error(\n `Cannot migrate backwards: current version is ${fromVersion}, target is ${toVersion}. Only forward migrations are supported.`,\n );\n }\n\n if (toVersion > targetSchema.version) {\n throw new Error(\n `Cannot migrate to version ${toVersion}: schema only has version ${targetSchema.version}`,\n );\n }\n\n if (fromVersion > targetSchema.version) {\n throw new Error(\n `Cannot migrate from version ${fromVersion}: schema only has version ${targetSchema.version}`,\n );\n }\n\n if (toVersion === fromVersion) {\n // Already at target version, return empty migration\n return {\n operations: [],\n getSQL: sqlConfig ? () => sqlConfig.toSql([]) : undefined,\n execute: async () => {},\n };\n }\n\n const context: MigrationContext = {\n async auto() {\n let generated = generateMigrationFromSchema(targetSchema, fromVersion, toVersion);\n\n for (const transformer of transformers) {\n if (!transformer.afterAuto) {\n continue;\n }\n\n generated = transformer.afterAuto(generated, {\n fromVersion,\n toVersion,\n schema: targetSchema,\n options,\n });\n }\n\n return generated;\n },\n };\n\n let operations = updateVersion\n ? [\n ...(await context.auto()),\n ...(await settings.updateSettingsInMigration(fromVersion, toVersion)),\n ]\n : await context.auto();\n\n for (const transformer of transformers) {\n if (!transformer.afterAll) {\n continue;\n }\n operations = transformer.afterAll(operations, {\n fromVersion,\n toVersion,\n schema: targetSchema,\n });\n }\n\n return {\n operations,\n getSQL: sqlConfig ? () => sqlConfig.toSql(operations) : undefined,\n execute: () => executor(operations),\n };\n },\n };\n\n return instance;\n}\n"],"mappings":";;;AAwGA,SAAgB,eAAe,EAC7B,UACA,6DAA8BA,6BAC9B,QAAQ,cACR,UACA,KAAK,WACL,eAAe,EAAE,IACkB;AAgGnC,QA/F2B;EACzB,aAAa;AACX,UAAO,SAAS,YAAY;;EAE9B,MAAM,iBAAiB,UAAU,EAAE,EAAE;AACnC,UAAO,KAAK,mBAAmB,aAAa,SAAS,QAAQ;;EAE/D,MAAM,mBAAmB,WAAW,UAAU,EAAE,EAAE;GAChD,MAAM,EAAE,gBAAgB,gBAAgB,MAAM,aAAa,wBAAwB;GAGnF,MAAM,cAAc,uBAAwB,MAAM,SAAS,YAAY;AAEvE,OAAI,YAAY,EACd,OAAM,IAAI,MAAM,uCAAuC,YAAY;AAGrE,OAAI,cAAc,EAChB,OAAM,IAAI,MAAM,yCAAyC,cAAc;AAGzE,OAAI,YAAY,YACd,OAAM,IAAI,MACR,gDAAgD,YAAY,cAAc,UAAU,0CACrF;AAGH,OAAI,YAAY,aAAa,QAC3B,OAAM,IAAI,MACR,6BAA6B,UAAU,4BAA4B,aAAa,UACjF;AAGH,OAAI,cAAc,aAAa,QAC7B,OAAM,IAAI,MACR,+BAA+B,YAAY,4BAA4B,aAAa,UACrF;AAGH,OAAI,cAAc,YAEhB,QAAO;IACL,YAAY,EAAE;IACd,QAAQ,kBAAkB,UAAU,MAAM,EAAE,CAAC,GAAG;IAChD,SAAS,YAAY;IACtB;GAGH,MAAMC,UAA4B,EAChC,MAAM,OAAO;IACX,IAAI,YAAYC,8BAA4B,cAAc,aAAa,UAAU;AAEjF,SAAK,MAAM,eAAe,cAAc;AACtC,SAAI,CAAC,YAAY,UACf;AAGF,iBAAY,YAAY,UAAU,WAAW;MAC3C;MACA;MACA,QAAQ;MACR;MACD,CAAC;;AAGJ,WAAO;MAEV;GAED,IAAI,aAAa,gBACb,CACE,GAAI,MAAM,QAAQ,MAAM,EACxB,GAAI,MAAM,SAAS,0BAA0B,aAAa,UAAU,CACrE,GACD,MAAM,QAAQ,MAAM;AAExB,QAAK,MAAM,eAAe,cAAc;AACtC,QAAI,CAAC,YAAY,SACf;AAEF,iBAAa,YAAY,SAAS,YAAY;KAC5C;KACA;KACA,QAAQ;KACT,CAAC;;AAGJ,UAAO;IACL;IACA,QAAQ,kBAAkB,UAAU,MAAM,WAAW,GAAG;IACxD,eAAe,SAAS,WAAW;IACpC;;EAEJ"}
@@ -0,0 +1,51 @@
1
+ import { AnySchema } from "../schema/create.js";
2
+ import { PreparedMigration } from "./create.js";
3
+ import { FragnoDatabase } from "../mod.js";
4
+
5
+ //#region src/migration-engine/generation-engine.d.ts
6
+ interface GenerationEngineResult {
7
+ schema: string;
8
+ path: string;
9
+ namespace: string;
10
+ }
11
+ interface GenerationInternalResult {
12
+ schema: string;
13
+ path: string;
14
+ namespace: string;
15
+ fromVersion: number;
16
+ toVersion: number;
17
+ preparedMigration?: PreparedMigration;
18
+ }
19
+ interface ExecuteMigrationResult {
20
+ namespace: string;
21
+ didMigrate: boolean;
22
+ fromVersion: number;
23
+ toVersion: number;
24
+ }
25
+ declare function generateMigrationsOrSchema<const TDatabases extends FragnoDatabase<AnySchema>[]>(databases: TDatabases, options?: {
26
+ path?: string;
27
+ toVersion?: number;
28
+ fromVersion?: number;
29
+ }): Promise<GenerationEngineResult[]>;
30
+ /**
31
+ * Execute migrations for all fragments in the correct order.
32
+ * Migrates settings table first, then fragments alphabetically.
33
+ *
34
+ * @param databases - Array of FragnoDatabase instances to migrate
35
+ * @returns Array of execution results for each migration
36
+ */
37
+ declare function executeMigrations<const TDatabases extends FragnoDatabase<AnySchema>[]>(databases: TDatabases): Promise<ExecuteMigrationResult[]>;
38
+ /**
39
+ * Post-processes migration files to add ordering and standardize naming.
40
+ *
41
+ * Sorts files with settings namespace first, then alphabetically by namespace,
42
+ * and assigns ordering numbers. Transforms filenames to format:
43
+ * `<date>_<n>_f<from>_t<to>_<namespace>.sql`
44
+ *
45
+ * @param files - Array of generated migration files with version information
46
+ * @returns Array of files with standardized paths and ordering
47
+ */
48
+ declare function postProcessMigrationFilenames(files: GenerationInternalResult[]): GenerationEngineResult[];
49
+ //#endregion
50
+ export { ExecuteMigrationResult, GenerationEngineResult, GenerationInternalResult, executeMigrations, generateMigrationsOrSchema, postProcessMigrationFilenames };
51
+ //# sourceMappingURL=generation-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generation-engine.d.ts","names":[],"sources":["../../src/migration-engine/generation-engine.ts"],"sourcesContent":[],"mappings":";;;;;UASiB,sBAAA;;EAAA,IAAA,EAAA,MAAA;EAMA,SAAA,EAAA,MAAA;AASjB;AAOsB,UAhBL,wBAAA,CAgB+B;EACN,MAAA,EAAA,MAAA;EAAf,IAAA,EAAA,MAAA;EAEd,SAAA,EAAA,MAAA;EAMF,WAAA,EAAA,MAAA;EAAR,SAAA,EAAA,MAAA;EAAO,iBAAA,CAAA,EAnBY,iBAmBZ;AAiJV;AAAgF,UAjK/D,sBAAA,CAiK+D;EAAf,SAAA,EAAA,MAAA;EACpD,UAAA,EAAA,OAAA;EACF,WAAA,EAAA,MAAA;EAAR,SAAA,EAAA,MAAA;;AAiIa,iBA7RM,0BA8Rb,CAAA,yBA7RkB,cA8RxB,CA9RuC,SA8RjB,CAAA,EAAA,CAAA,CAAA,SAAA,EA5RZ,UA4RY,EAAA,QAAA,EAAA;;;;IAtRtB,QAAQ;;;;;;;;iBAiJW,2CAA2C,eAAe,yBACnE,aACV,QAAQ;;;;;;;;;;;iBAiIK,6BAAA,QACP,6BACN"}