@prisma-next/family-sql 0.3.0-dev.7 → 0.3.0-dev.71

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 (102) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +15 -6
  3. package/dist/assembly-BVS641kd.mjs +106 -0
  4. package/dist/assembly-BVS641kd.mjs.map +1 -0
  5. package/dist/control-adapter.d.mts +60 -0
  6. package/dist/control-adapter.d.mts.map +1 -0
  7. package/dist/control-adapter.mjs +1 -0
  8. package/dist/control-instance-62RsSxEp.d.mts +291 -0
  9. package/dist/control-instance-62RsSxEp.d.mts.map +1 -0
  10. package/dist/control.d.mts +106 -0
  11. package/dist/control.d.mts.map +1 -0
  12. package/dist/control.mjs +640 -0
  13. package/dist/control.mjs.map +1 -0
  14. package/dist/runtime.d.mts +27 -0
  15. package/dist/runtime.d.mts.map +1 -0
  16. package/dist/runtime.mjs +38 -0
  17. package/dist/runtime.mjs.map +1 -0
  18. package/dist/schema-verify.d.mts +48 -0
  19. package/dist/schema-verify.d.mts.map +1 -0
  20. package/dist/schema-verify.mjs +4 -0
  21. package/dist/test-utils.d.mts +2 -0
  22. package/dist/test-utils.mjs +3 -0
  23. package/dist/verify-BfMETJcM.mjs +108 -0
  24. package/dist/verify-BfMETJcM.mjs.map +1 -0
  25. package/dist/verify-sql-schema-CpAVEi8A.mjs +1058 -0
  26. package/dist/verify-sql-schema-CpAVEi8A.mjs.map +1 -0
  27. package/dist/verify-sql-schema-DhHnkpPa.d.mts +67 -0
  28. package/dist/verify-sql-schema-DhHnkpPa.d.mts.map +1 -0
  29. package/dist/verify.d.mts +31 -0
  30. package/dist/verify.d.mts.map +1 -0
  31. package/dist/verify.mjs +3 -0
  32. package/package.json +36 -47
  33. package/src/core/assembly.ts +158 -59
  34. package/src/core/control-adapter.ts +15 -0
  35. package/src/core/control-descriptor.ts +37 -0
  36. package/src/core/{instance.ts → control-instance.ts} +108 -241
  37. package/src/core/migrations/contract-to-schema-ir.ts +181 -0
  38. package/src/core/migrations/types.ts +63 -165
  39. package/src/core/runtime-descriptor.ts +19 -41
  40. package/src/core/runtime-instance.ts +11 -133
  41. package/src/core/schema-verify/verify-helpers.ts +187 -97
  42. package/src/core/schema-verify/verify-sql-schema.ts +910 -392
  43. package/src/core/verify.ts +4 -13
  44. package/src/exports/control.ts +15 -6
  45. package/src/exports/runtime.ts +2 -6
  46. package/src/exports/schema-verify.ts +10 -2
  47. package/src/exports/test-utils.ts +0 -1
  48. package/dist/chunk-6K3RPBDP.js +0 -580
  49. package/dist/chunk-6K3RPBDP.js.map +0 -1
  50. package/dist/chunk-BHEGVBY7.js +0 -772
  51. package/dist/chunk-BHEGVBY7.js.map +0 -1
  52. package/dist/chunk-SU7LN2UH.js +0 -96
  53. package/dist/chunk-SU7LN2UH.js.map +0 -1
  54. package/dist/core/assembly.d.ts +0 -25
  55. package/dist/core/assembly.d.ts.map +0 -1
  56. package/dist/core/control-adapter.d.ts +0 -42
  57. package/dist/core/control-adapter.d.ts.map +0 -1
  58. package/dist/core/descriptor.d.ts +0 -31
  59. package/dist/core/descriptor.d.ts.map +0 -1
  60. package/dist/core/instance.d.ts +0 -142
  61. package/dist/core/instance.d.ts.map +0 -1
  62. package/dist/core/migrations/plan-helpers.d.ts +0 -20
  63. package/dist/core/migrations/plan-helpers.d.ts.map +0 -1
  64. package/dist/core/migrations/policies.d.ts +0 -6
  65. package/dist/core/migrations/policies.d.ts.map +0 -1
  66. package/dist/core/migrations/types.d.ts +0 -280
  67. package/dist/core/migrations/types.d.ts.map +0 -1
  68. package/dist/core/runtime-descriptor.d.ts +0 -19
  69. package/dist/core/runtime-descriptor.d.ts.map +0 -1
  70. package/dist/core/runtime-instance.d.ts +0 -54
  71. package/dist/core/runtime-instance.d.ts.map +0 -1
  72. package/dist/core/schema-verify/verify-helpers.d.ts +0 -50
  73. package/dist/core/schema-verify/verify-helpers.d.ts.map +0 -1
  74. package/dist/core/schema-verify/verify-sql-schema.d.ts +0 -45
  75. package/dist/core/schema-verify/verify-sql-schema.d.ts.map +0 -1
  76. package/dist/core/verify.d.ts +0 -39
  77. package/dist/core/verify.d.ts.map +0 -1
  78. package/dist/exports/control-adapter.d.ts +0 -2
  79. package/dist/exports/control-adapter.d.ts.map +0 -1
  80. package/dist/exports/control-adapter.js +0 -1
  81. package/dist/exports/control-adapter.js.map +0 -1
  82. package/dist/exports/control.d.ts +0 -13
  83. package/dist/exports/control.d.ts.map +0 -1
  84. package/dist/exports/control.js +0 -149
  85. package/dist/exports/control.js.map +0 -1
  86. package/dist/exports/runtime.d.ts +0 -8
  87. package/dist/exports/runtime.d.ts.map +0 -1
  88. package/dist/exports/runtime.js +0 -64
  89. package/dist/exports/runtime.js.map +0 -1
  90. package/dist/exports/schema-verify.d.ts +0 -11
  91. package/dist/exports/schema-verify.d.ts.map +0 -1
  92. package/dist/exports/schema-verify.js +0 -11
  93. package/dist/exports/schema-verify.js.map +0 -1
  94. package/dist/exports/test-utils.d.ts +0 -7
  95. package/dist/exports/test-utils.d.ts.map +0 -1
  96. package/dist/exports/test-utils.js +0 -17
  97. package/dist/exports/test-utils.js.map +0 -1
  98. package/dist/exports/verify.d.ts +0 -2
  99. package/dist/exports/verify.d.ts.map +0 -1
  100. package/dist/exports/verify.js +0 -11
  101. package/dist/exports/verify.js.map +0 -1
  102. package/src/core/descriptor.ts +0 -37
@@ -0,0 +1,640 @@
1
+ import { a as extractOperationTypeImports, i as extractExtensionIds, n as extractCodecControlHooks, o as extractParameterizedRenderers, r as extractCodecTypeImports, s as extractParameterizedTypeImports, t as assembleOperationRegistry } from "./assembly-BVS641kd.mjs";
2
+ import { t as verifySqlSchema } from "./verify-sql-schema-CpAVEi8A.mjs";
3
+ import { r as readMarker, t as collectSupportedCodecTypeIds } from "./verify-BfMETJcM.mjs";
4
+ import { sqlTargetFamilyHook } from "@prisma-next/sql-contract-emitter";
5
+ import { emit } from "@prisma-next/core-control-plane/emission";
6
+ import { validateContract } from "@prisma-next/sql-contract/validate";
7
+ import { ensureSchemaStatement, ensureTableStatement, writeContractMarker } from "@prisma-next/sql-runtime";
8
+ import { ifDefined } from "@prisma-next/utils/defined";
9
+ import { notOk, ok } from "@prisma-next/utils/result";
10
+
11
+ //#region src/core/control-instance.ts
12
+ function extractCodecTypeIdsFromContract(contract) {
13
+ const typeIds = /* @__PURE__ */ new Set();
14
+ if (typeof contract === "object" && contract !== null && "storage" in contract && typeof contract.storage === "object" && contract.storage !== null && "tables" in contract.storage) {
15
+ const storage = contract.storage;
16
+ if (storage.tables && typeof storage.tables === "object") {
17
+ for (const table of Object.values(storage.tables)) if (typeof table === "object" && table !== null && "columns" in table && typeof table.columns === "object" && table.columns !== null) {
18
+ const columns = table.columns;
19
+ for (const column of Object.values(columns)) if (column && typeof column === "object" && "codecId" in column && typeof column.codecId === "string") typeIds.add(column.codecId);
20
+ }
21
+ }
22
+ }
23
+ return Array.from(typeIds).sort();
24
+ }
25
+ function createVerifyResult(options) {
26
+ const contract = { storageHash: options.contractStorageHash };
27
+ if (options.contractProfileHash) contract.profileHash = options.contractProfileHash;
28
+ const target = { expected: options.expectedTargetId };
29
+ if (options.actualTargetId) target.actual = options.actualTargetId;
30
+ const meta = { contractPath: options.contractPath };
31
+ if (options.configPath) meta.configPath = options.configPath;
32
+ const result = {
33
+ ok: options.ok,
34
+ summary: options.summary,
35
+ contract,
36
+ target,
37
+ meta,
38
+ timings: { total: options.totalTime }
39
+ };
40
+ if (options.code) result.code = options.code;
41
+ if (options.marker) result.marker = {
42
+ storageHash: options.marker.storageHash,
43
+ profileHash: options.marker.profileHash
44
+ };
45
+ if (options.missingCodecs) result.missingCodecs = options.missingCodecs;
46
+ if (options.codecCoverageSkipped) result.codecCoverageSkipped = options.codecCoverageSkipped;
47
+ return result;
48
+ }
49
+ function isSqlControlAdapter(value) {
50
+ return typeof value === "object" && value !== null && "introspect" in value && typeof value.introspect === "function";
51
+ }
52
+ function buildSqlTypeMetadataRegistry(options) {
53
+ const { target, adapter, extensionPacks: extensions } = options;
54
+ const registry = /* @__PURE__ */ new Map();
55
+ const targetId = adapter.targetId;
56
+ const descriptors = [
57
+ target,
58
+ adapter,
59
+ ...extensions
60
+ ];
61
+ for (const descriptor of descriptors) {
62
+ const storageTypes = descriptor.types?.storage;
63
+ if (!storageTypes) continue;
64
+ for (const storageType of storageTypes) if (storageType.familyId === "sql" && storageType.targetId === targetId) registry.set(storageType.typeId, {
65
+ typeId: storageType.typeId,
66
+ familyId: "sql",
67
+ targetId: storageType.targetId,
68
+ ...storageType.nativeType !== void 0 ? { nativeType: storageType.nativeType } : {}
69
+ });
70
+ }
71
+ return registry;
72
+ }
73
+ function createSqlFamilyInstance(options) {
74
+ const { target, adapter, extensionPacks: extensions = [] } = options;
75
+ const descriptors = [
76
+ target,
77
+ adapter,
78
+ ...extensions
79
+ ];
80
+ const operationRegistry = assembleOperationRegistry(descriptors);
81
+ const codecTypeImports = extractCodecTypeImports(descriptors);
82
+ const operationTypeImports = extractOperationTypeImports(descriptors);
83
+ const extensionIds = extractExtensionIds(adapter, target, extensions);
84
+ const parameterizedRenderers = extractParameterizedRenderers(descriptors);
85
+ const parameterizedTypeImports = extractParameterizedTypeImports(descriptors);
86
+ const typeMetadataRegistry = buildSqlTypeMetadataRegistry({
87
+ target,
88
+ adapter,
89
+ extensionPacks: extensions
90
+ });
91
+ function stripMappings(contract) {
92
+ if (typeof contract === "object" && contract !== null && "mappings" in contract) {
93
+ const { mappings: _mappings, ...contractIR } = contract;
94
+ return contractIR;
95
+ }
96
+ return contract;
97
+ }
98
+ function normalizeProviderContractIR(contract) {
99
+ const { mappings: _mappings, ...contractIR } = validateContract(stripMappings(contract));
100
+ return contractIR;
101
+ }
102
+ return {
103
+ familyId: "sql",
104
+ operationRegistry,
105
+ codecTypeImports,
106
+ operationTypeImports,
107
+ extensionIds,
108
+ typeMetadataRegistry,
109
+ validateContractIR(contractJson) {
110
+ return normalizeProviderContractIR(contractJson);
111
+ },
112
+ async verify(verifyOptions) {
113
+ const { driver, contractIR, expectedTargetId, contractPath, configPath } = verifyOptions;
114
+ const startTime = Date.now();
115
+ if (typeof contractIR !== "object" || contractIR === null || !("storageHash" in contractIR) || !("target" in contractIR) || typeof contractIR.storageHash !== "string" || typeof contractIR.target !== "string") throw new Error("Contract is missing required fields: storageHash or target");
116
+ const contractStorageHash = contractIR.storageHash;
117
+ const contractProfileHash = "profileHash" in contractIR && typeof contractIR.profileHash === "string" ? contractIR.profileHash : void 0;
118
+ const contractTarget = contractIR.target;
119
+ const marker = await readMarker(driver);
120
+ let missingCodecs;
121
+ let codecCoverageSkipped = false;
122
+ const supportedTypeIds = collectSupportedCodecTypeIds([
123
+ adapter,
124
+ target,
125
+ ...extensions
126
+ ]);
127
+ if (supportedTypeIds.length === 0) codecCoverageSkipped = true;
128
+ else {
129
+ const supportedSet = new Set(supportedTypeIds);
130
+ const missing = extractCodecTypeIdsFromContract(contractIR).filter((id) => !supportedSet.has(id));
131
+ if (missing.length > 0) missingCodecs = missing;
132
+ }
133
+ if (!marker) return createVerifyResult({
134
+ ok: false,
135
+ code: "PN-RTM-3001",
136
+ summary: "Marker missing",
137
+ contractStorageHash,
138
+ expectedTargetId,
139
+ contractPath,
140
+ totalTime: Date.now() - startTime,
141
+ ...contractProfileHash ? { contractProfileHash } : {},
142
+ ...missingCodecs ? { missingCodecs } : {},
143
+ ...codecCoverageSkipped ? { codecCoverageSkipped } : {},
144
+ ...configPath ? { configPath } : {}
145
+ });
146
+ if (contractTarget !== expectedTargetId) return createVerifyResult({
147
+ ok: false,
148
+ code: "PN-RTM-3003",
149
+ summary: "Target mismatch",
150
+ contractStorageHash,
151
+ marker,
152
+ expectedTargetId,
153
+ actualTargetId: contractTarget,
154
+ contractPath,
155
+ totalTime: Date.now() - startTime,
156
+ ...contractProfileHash ? { contractProfileHash } : {},
157
+ ...missingCodecs ? { missingCodecs } : {},
158
+ ...codecCoverageSkipped ? { codecCoverageSkipped } : {},
159
+ ...configPath ? { configPath } : {}
160
+ });
161
+ if (marker.storageHash !== contractStorageHash) return createVerifyResult({
162
+ ok: false,
163
+ code: "PN-RTM-3002",
164
+ summary: "Hash mismatch",
165
+ contractStorageHash,
166
+ marker,
167
+ expectedTargetId,
168
+ contractPath,
169
+ totalTime: Date.now() - startTime,
170
+ ...contractProfileHash ? { contractProfileHash } : {},
171
+ ...missingCodecs ? { missingCodecs } : {},
172
+ ...codecCoverageSkipped ? { codecCoverageSkipped } : {},
173
+ ...configPath ? { configPath } : {}
174
+ });
175
+ if (contractProfileHash && marker.profileHash !== contractProfileHash) return createVerifyResult({
176
+ ok: false,
177
+ code: "PN-RTM-3002",
178
+ summary: "Hash mismatch",
179
+ contractStorageHash,
180
+ contractProfileHash,
181
+ marker,
182
+ expectedTargetId,
183
+ contractPath,
184
+ totalTime: Date.now() - startTime,
185
+ ...missingCodecs ? { missingCodecs } : {},
186
+ ...codecCoverageSkipped ? { codecCoverageSkipped } : {},
187
+ ...configPath ? { configPath } : {}
188
+ });
189
+ return createVerifyResult({
190
+ ok: true,
191
+ summary: "Database matches contract",
192
+ contractStorageHash,
193
+ marker,
194
+ expectedTargetId,
195
+ contractPath,
196
+ totalTime: Date.now() - startTime,
197
+ ...contractProfileHash ? { contractProfileHash } : {},
198
+ ...missingCodecs ? { missingCodecs } : {},
199
+ ...codecCoverageSkipped ? { codecCoverageSkipped } : {},
200
+ ...configPath ? { configPath } : {}
201
+ });
202
+ },
203
+ async schemaVerify(options$1) {
204
+ const { driver, contractIR, strict, context, frameworkComponents } = options$1;
205
+ const contract = validateContract(contractIR);
206
+ const controlAdapter = adapter.create();
207
+ if (!isSqlControlAdapter(controlAdapter)) throw new Error("Adapter does not implement SqlControlAdapter.introspect()");
208
+ return verifySqlSchema({
209
+ contract,
210
+ schema: await controlAdapter.introspect(driver, contractIR),
211
+ strict,
212
+ ...ifDefined("context", context),
213
+ typeMetadataRegistry,
214
+ frameworkComponents,
215
+ ...ifDefined("normalizeDefault", controlAdapter.normalizeDefault),
216
+ ...ifDefined("normalizeNativeType", controlAdapter.normalizeNativeType)
217
+ });
218
+ },
219
+ async sign(options$1) {
220
+ const { driver, contractIR, contractPath, configPath } = options$1;
221
+ const startTime = Date.now();
222
+ const contract = validateContract(contractIR);
223
+ const contractStorageHash = contract.storageHash;
224
+ const contractProfileHash = "profileHash" in contract && typeof contract.profileHash === "string" ? contract.profileHash : contractStorageHash;
225
+ const contractTarget = contract.target;
226
+ await driver.query(ensureSchemaStatement.sql, ensureSchemaStatement.params);
227
+ await driver.query(ensureTableStatement.sql, ensureTableStatement.params);
228
+ const existingMarker = await readMarker(driver);
229
+ let markerCreated = false;
230
+ let markerUpdated = false;
231
+ let previousHashes;
232
+ if (!existingMarker) {
233
+ const write = writeContractMarker({
234
+ storageHash: contractStorageHash,
235
+ profileHash: contractProfileHash,
236
+ contractJson: contractIR,
237
+ canonicalVersion: 1
238
+ });
239
+ await driver.query(write.insert.sql, write.insert.params);
240
+ markerCreated = true;
241
+ } else {
242
+ const existingStorageHash = existingMarker.storageHash;
243
+ const existingProfileHash = existingMarker.profileHash;
244
+ if (!(existingStorageHash === contractStorageHash) || !(existingProfileHash === contractProfileHash)) {
245
+ previousHashes = {
246
+ storageHash: existingStorageHash,
247
+ profileHash: existingProfileHash
248
+ };
249
+ const write = writeContractMarker({
250
+ storageHash: contractStorageHash,
251
+ profileHash: contractProfileHash,
252
+ contractJson: contractIR,
253
+ canonicalVersion: existingMarker.canonicalVersion ?? 1
254
+ });
255
+ await driver.query(write.update.sql, write.update.params);
256
+ markerUpdated = true;
257
+ }
258
+ }
259
+ let summary;
260
+ if (markerCreated) summary = "Database signed (marker created)";
261
+ else if (markerUpdated) summary = `Database signed (marker updated from ${previousHashes?.storageHash ?? "unknown"})`;
262
+ else summary = "Database already signed with this contract";
263
+ const totalTime = Date.now() - startTime;
264
+ return {
265
+ ok: true,
266
+ summary,
267
+ contract: {
268
+ storageHash: contractStorageHash,
269
+ profileHash: contractProfileHash
270
+ },
271
+ target: {
272
+ expected: contractTarget,
273
+ actual: contractTarget
274
+ },
275
+ marker: {
276
+ created: markerCreated,
277
+ updated: markerUpdated,
278
+ ...previousHashes ? { previous: previousHashes } : {}
279
+ },
280
+ meta: {
281
+ contractPath,
282
+ ...configPath ? { configPath } : {}
283
+ },
284
+ timings: { total: totalTime }
285
+ };
286
+ },
287
+ async readMarker(options$1) {
288
+ return readMarker(options$1.driver);
289
+ },
290
+ async introspect(options$1) {
291
+ const { driver, contractIR } = options$1;
292
+ const controlAdapter = adapter.create();
293
+ if (!isSqlControlAdapter(controlAdapter)) throw new Error("Adapter does not implement SqlControlAdapter.introspect()");
294
+ return controlAdapter.introspect(driver, contractIR);
295
+ },
296
+ toSchemaView(schema) {
297
+ const rootLabel = "contract";
298
+ const tableNodes = Object.entries(schema.tables).map(([tableName, table]) => {
299
+ const children = [];
300
+ const columnNodes = [];
301
+ for (const [columnName, column] of Object.entries(table.columns)) {
302
+ const label = `${columnName}: ${column.nativeType} (${column.nullable ? "nullable" : "not nullable"})`;
303
+ columnNodes.push({
304
+ kind: "field",
305
+ id: `column-${tableName}-${columnName}`,
306
+ label,
307
+ meta: {
308
+ nativeType: column.nativeType,
309
+ nullable: column.nullable,
310
+ ...ifDefined("default", column.default)
311
+ }
312
+ });
313
+ }
314
+ if (columnNodes.length > 0) children.push({
315
+ kind: "collection",
316
+ id: `columns-${tableName}`,
317
+ label: "columns",
318
+ children: columnNodes
319
+ });
320
+ if (table.primaryKey) {
321
+ const pkColumns = table.primaryKey.columns.join(", ");
322
+ children.push({
323
+ kind: "index",
324
+ id: `primary-key-${tableName}`,
325
+ label: `primary key: ${pkColumns}`,
326
+ meta: {
327
+ columns: table.primaryKey.columns,
328
+ ...table.primaryKey.name ? { name: table.primaryKey.name } : {}
329
+ }
330
+ });
331
+ }
332
+ for (const unique of table.uniques) {
333
+ const name = unique.name ?? `${tableName}_${unique.columns.join("_")}_unique`;
334
+ const label = `unique ${name}`;
335
+ children.push({
336
+ kind: "index",
337
+ id: `unique-${tableName}-${name}`,
338
+ label,
339
+ meta: {
340
+ columns: unique.columns,
341
+ unique: true
342
+ }
343
+ });
344
+ }
345
+ for (const index of table.indexes) {
346
+ const name = index.name ?? `${tableName}_${index.columns.join("_")}_idx`;
347
+ const label = index.unique ? `unique index ${name}` : `index ${name}`;
348
+ children.push({
349
+ kind: "index",
350
+ id: `index-${tableName}-${name}`,
351
+ label,
352
+ meta: {
353
+ columns: index.columns,
354
+ unique: index.unique
355
+ }
356
+ });
357
+ }
358
+ const tableMeta = {};
359
+ if (table.primaryKey) {
360
+ tableMeta["primaryKey"] = table.primaryKey.columns;
361
+ if (table.primaryKey.name) tableMeta["primaryKeyName"] = table.primaryKey.name;
362
+ }
363
+ if (table.foreignKeys.length > 0) tableMeta["foreignKeys"] = table.foreignKeys.map((fk) => ({
364
+ columns: fk.columns,
365
+ referencedTable: fk.referencedTable,
366
+ referencedColumns: fk.referencedColumns,
367
+ ...fk.name ? { name: fk.name } : {}
368
+ }));
369
+ return {
370
+ kind: "entity",
371
+ id: `table-${tableName}`,
372
+ label: `table ${tableName}`,
373
+ ...Object.keys(tableMeta).length > 0 ? { meta: tableMeta } : {},
374
+ ...children.length > 0 ? { children } : {}
375
+ };
376
+ });
377
+ const extensionNodes = schema.extensions.map((extName) => ({
378
+ kind: "extension",
379
+ id: `extension-${extName}`,
380
+ label: `${extName} extension is enabled`
381
+ }));
382
+ const rootChildren = [...tableNodes, ...extensionNodes];
383
+ return { root: {
384
+ kind: "root",
385
+ id: "sql-schema",
386
+ label: rootLabel,
387
+ ...rootChildren.length > 0 ? { children: rootChildren } : {}
388
+ } };
389
+ },
390
+ async emitContract({ contractIR }) {
391
+ const result = await emit(normalizeProviderContractIR(contractIR), {
392
+ outputDir: "",
393
+ operationRegistry,
394
+ codecTypeImports,
395
+ operationTypeImports,
396
+ extensionIds,
397
+ parameterizedRenderers,
398
+ parameterizedTypeImports
399
+ }, sqlTargetFamilyHook);
400
+ return {
401
+ contractJson: result.contractJson,
402
+ contractDts: result.contractDts,
403
+ storageHash: result.storageHash,
404
+ ...result.executionHash ? { executionHash: result.executionHash } : {},
405
+ profileHash: result.profileHash
406
+ };
407
+ }
408
+ };
409
+ }
410
+
411
+ //#endregion
412
+ //#region src/core/control-descriptor.ts
413
+ var SqlFamilyDescriptor = class {
414
+ kind = "family";
415
+ id = "sql";
416
+ familyId = "sql";
417
+ version = "0.0.1";
418
+ hook = sqlTargetFamilyHook;
419
+ create(stack) {
420
+ const target = stack.target;
421
+ const adapter = stack.adapter;
422
+ const extensionPacks = stack.extensionPacks;
423
+ return createSqlFamilyInstance({
424
+ target,
425
+ adapter,
426
+ extensionPacks
427
+ });
428
+ }
429
+ };
430
+
431
+ //#endregion
432
+ //#region src/core/migrations/contract-to-schema-ir.ts
433
+ function convertDefault(def) {
434
+ if (def.kind === "function") return def.expression;
435
+ if (typeof def.value === "string") return `'${def.value.replaceAll("'", "''")}'`;
436
+ return String(def.value);
437
+ }
438
+ function convertColumn(name, column, expandNativeType) {
439
+ return {
440
+ name,
441
+ nativeType: expandNativeType ? expandNativeType({
442
+ nativeType: column.nativeType,
443
+ codecId: column.codecId,
444
+ ...ifDefined("typeParams", column.typeParams)
445
+ }) : column.nativeType,
446
+ nullable: column.nullable,
447
+ ...column.default != null ? { default: convertDefault(column.default) } : {}
448
+ };
449
+ }
450
+ function convertUnique(unique) {
451
+ return {
452
+ columns: unique.columns,
453
+ ...unique.name != null ? { name: unique.name } : {}
454
+ };
455
+ }
456
+ function convertIndex(index) {
457
+ return {
458
+ columns: index.columns,
459
+ unique: false,
460
+ ...index.name != null ? { name: index.name } : {}
461
+ };
462
+ }
463
+ function convertForeignKey(fk) {
464
+ return {
465
+ columns: fk.columns,
466
+ referencedTable: fk.references.table,
467
+ referencedColumns: fk.references.columns,
468
+ ...fk.name != null ? { name: fk.name } : {}
469
+ };
470
+ }
471
+ function convertTable(name, table, expandNativeType) {
472
+ const columns = {};
473
+ for (const [colName, colDef] of Object.entries(table.columns)) columns[colName] = convertColumn(colName, colDef, expandNativeType);
474
+ return {
475
+ name,
476
+ columns,
477
+ ...table.primaryKey != null ? { primaryKey: table.primaryKey } : {},
478
+ foreignKeys: table.foreignKeys.map(convertForeignKey),
479
+ uniques: table.uniques.map(convertUnique),
480
+ indexes: table.indexes.map(convertIndex)
481
+ };
482
+ }
483
+ /**
484
+ * Detects destructive changes between two contract storages.
485
+ *
486
+ * The additive-only planner silently ignores removals (tables, columns).
487
+ * This function detects those removals so callers can report them as conflicts
488
+ * rather than silently producing an empty plan.
489
+ *
490
+ * Returns an empty array if no destructive changes are found.
491
+ */
492
+ function detectDestructiveChanges(from, to) {
493
+ if (!from) return [];
494
+ const hasOwn = (value, key) => Object.hasOwn(value, key);
495
+ const conflicts = [];
496
+ for (const tableName of Object.keys(from.tables)) {
497
+ if (!hasOwn(to.tables, tableName)) {
498
+ conflicts.push({
499
+ kind: "tableRemoved",
500
+ summary: `Table "${tableName}" was removed`
501
+ });
502
+ continue;
503
+ }
504
+ const toTable = to.tables[tableName];
505
+ const fromTable = from.tables[tableName];
506
+ if (!fromTable) continue;
507
+ for (const columnName of Object.keys(fromTable.columns)) if (!hasOwn(toTable.columns, columnName)) conflicts.push({
508
+ kind: "columnRemoved",
509
+ summary: `Column "${tableName}"."${columnName}" was removed`
510
+ });
511
+ }
512
+ return conflicts;
513
+ }
514
+ /**
515
+ * Converts a contract's `SqlStorage` to `SqlSchemaIR`.
516
+ *
517
+ * Drops codec metadata (`codecId`, `typeRef`) since the schema IR only represents structural
518
+ * information. When `expandNativeType` is provided, parameterized types are expanded
519
+ * (e.g. `character` + `{ length: 36 }` → `character(36)`) so the resulting IR compares
520
+ * correctly against the "to" contract during planning.
521
+ *
522
+ * `extensions` is always `[]` — the planner resolves extension dependencies from framework
523
+ * components, and an empty array means "nothing installed yet" which is correct for the
524
+ * "from" side of a diff.
525
+ */
526
+ function contractToSchemaIR(storage, expandNativeType) {
527
+ const tables = {};
528
+ for (const [tableName, tableDef] of Object.entries(storage.tables)) tables[tableName] = convertTable(tableName, tableDef, expandNativeType);
529
+ return {
530
+ tables,
531
+ extensions: []
532
+ };
533
+ }
534
+
535
+ //#endregion
536
+ //#region src/core/migrations/plan-helpers.ts
537
+ const readOnlyEmptyObject = Object.freeze({});
538
+ function cloneRecord(value) {
539
+ if (value === readOnlyEmptyObject) return value;
540
+ return Object.freeze({ ...value });
541
+ }
542
+ function freezeSteps(steps) {
543
+ if (steps.length === 0) return Object.freeze([]);
544
+ return Object.freeze(steps.map((step) => Object.freeze({
545
+ description: step.description,
546
+ sql: step.sql,
547
+ ...step.meta ? { meta: cloneRecord(step.meta) } : {}
548
+ })));
549
+ }
550
+ function freezeDetailsValue(value) {
551
+ if (value === null || value === void 0) return value;
552
+ if (typeof value !== "object") return value;
553
+ if (Array.isArray(value)) return Object.freeze([...value]);
554
+ return Object.freeze({ ...value });
555
+ }
556
+ function freezeTargetDetails(target) {
557
+ return Object.freeze({
558
+ id: target.id,
559
+ ...target.details !== void 0 ? { details: freezeDetailsValue(target.details) } : {}
560
+ });
561
+ }
562
+ function freezeOperation(operation) {
563
+ return Object.freeze({
564
+ id: operation.id,
565
+ label: operation.label,
566
+ ...operation.summary ? { summary: operation.summary } : {},
567
+ operationClass: operation.operationClass,
568
+ target: freezeTargetDetails(operation.target),
569
+ precheck: freezeSteps(operation.precheck),
570
+ execute: freezeSteps(operation.execute),
571
+ postcheck: freezeSteps(operation.postcheck),
572
+ ...operation.meta ? { meta: cloneRecord(operation.meta) } : {}
573
+ });
574
+ }
575
+ function freezeOperations(operations) {
576
+ if (operations.length === 0) return Object.freeze([]);
577
+ return Object.freeze(operations.map((operation) => freezeOperation(operation)));
578
+ }
579
+ function createMigrationPlan(options) {
580
+ return Object.freeze({
581
+ targetId: options.targetId,
582
+ ...options.origin !== void 0 ? { origin: options.origin ? Object.freeze({ ...options.origin }) : null } : {},
583
+ destination: Object.freeze({ ...options.destination }),
584
+ operations: freezeOperations(options.operations),
585
+ ...options.meta ? { meta: cloneRecord(options.meta) } : {}
586
+ });
587
+ }
588
+ function plannerSuccess(plan) {
589
+ return Object.freeze({
590
+ kind: "success",
591
+ plan
592
+ });
593
+ }
594
+ function plannerFailure(conflicts) {
595
+ return Object.freeze({
596
+ kind: "failure",
597
+ conflicts: Object.freeze(conflicts.map((conflict) => Object.freeze({
598
+ kind: conflict.kind,
599
+ summary: conflict.summary,
600
+ ...conflict.why ? { why: conflict.why } : {},
601
+ ...conflict.location ? { location: Object.freeze({ ...conflict.location }) } : {},
602
+ ...conflict.meta ? { meta: cloneRecord(conflict.meta) } : {}
603
+ })))
604
+ });
605
+ }
606
+ /**
607
+ * Creates a successful migration runner result.
608
+ */
609
+ function runnerSuccess(value) {
610
+ return ok(Object.freeze({
611
+ operationsPlanned: value.operationsPlanned,
612
+ operationsExecuted: value.operationsExecuted
613
+ }));
614
+ }
615
+ /**
616
+ * Creates a failed migration runner result.
617
+ */
618
+ function runnerFailure(code, summary, options) {
619
+ return notOk(Object.freeze({
620
+ code,
621
+ summary,
622
+ ...options?.why ? { why: options.why } : {},
623
+ ...options?.meta ? { meta: cloneRecord(options.meta) } : {}
624
+ }));
625
+ }
626
+
627
+ //#endregion
628
+ //#region src/core/migrations/policies.ts
629
+ /**
630
+ * Policy used by `db init`: additive-only operations, no widening/destructive steps.
631
+ */
632
+ const INIT_ADDITIVE_POLICY = Object.freeze({ allowedOperationClasses: Object.freeze(["additive"]) });
633
+
634
+ //#endregion
635
+ //#region src/exports/control.ts
636
+ var control_default = new SqlFamilyDescriptor();
637
+
638
+ //#endregion
639
+ export { INIT_ADDITIVE_POLICY, contractToSchemaIR, createMigrationPlan, control_default as default, detectDestructiveChanges, extractCodecControlHooks, plannerFailure, plannerSuccess, runnerFailure, runnerSuccess };
640
+ //# sourceMappingURL=control.mjs.map