@prisma-next/family-sql 0.3.0-dev.12 → 0.3.0-dev.123

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 (101) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +34 -7
  3. package/dist/assembly-Dzumaba1.mjs +159 -0
  4. package/dist/assembly-Dzumaba1.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-BKuHINR7.d.mts +411 -0
  9. package/dist/control-instance-BKuHINR7.d.mts.map +1 -0
  10. package/dist/control.d.mts +128 -0
  11. package/dist/control.d.mts.map +1 -0
  12. package/dist/control.mjs +683 -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-C3Pit9o4.mjs +1085 -0
  26. package/dist/verify-sql-schema-C3Pit9o4.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 +35 -46
  33. package/src/core/assembly.ts +265 -59
  34. package/src/core/control-adapter.ts +15 -0
  35. package/src/core/{descriptor.ts → control-descriptor.ts} +15 -11
  36. package/src/core/{instance.ts → control-instance.ts} +106 -248
  37. package/src/core/migrations/contract-to-schema-ir.ts +265 -0
  38. package/src/core/migrations/types.ts +193 -168
  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 +201 -105
  42. package/src/core/schema-verify/verify-sql-schema.ts +918 -413
  43. package/src/core/verify.ts +4 -13
  44. package/src/exports/control.ts +29 -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 +1 -1
  48. package/dist/chunk-BHEGVBY7.js +0 -772
  49. package/dist/chunk-BHEGVBY7.js.map +0 -1
  50. package/dist/chunk-SQ2VWYDV.js +0 -589
  51. package/dist/chunk-SQ2VWYDV.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 -24
  59. package/dist/core/descriptor.d.ts.map +0 -1
  60. package/dist/core/instance.d.ts +0 -140
  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
@@ -0,0 +1,265 @@
1
+ import type { TargetBoundComponentDescriptor } from '@prisma-next/contract/framework-components';
2
+ import type { ColumnDefault } from '@prisma-next/contract/types';
3
+ import type { MigrationPlannerConflict } from '@prisma-next/core-control-plane/types';
4
+ import type {
5
+ ForeignKey,
6
+ Index,
7
+ SqlContract,
8
+ SqlStorage,
9
+ StorageColumn,
10
+ StorageTable,
11
+ UniqueConstraint,
12
+ } from '@prisma-next/sql-contract/types';
13
+ import { defaultIndexName } from '@prisma-next/sql-schema-ir/naming';
14
+ import type {
15
+ DependencyIR,
16
+ SqlAnnotations,
17
+ SqlColumnIR,
18
+ SqlForeignKeyIR,
19
+ SqlIndexIR,
20
+ SqlSchemaIR,
21
+ SqlTableIR,
22
+ SqlUniqueIR,
23
+ } from '@prisma-next/sql-schema-ir/types';
24
+ import { ifDefined } from '@prisma-next/utils/defined';
25
+ import { collectInitDependencies } from './types';
26
+
27
+ /**
28
+ * Target-specific callback that expands a column's base `nativeType` and optional
29
+ * `typeParams` into the fully-qualified type string used by the database
30
+ * (e.g. `character` + `{ length: 36 }` → `character(36)`).
31
+ *
32
+ * This lives in the family layer as a callback rather than importing a concrete
33
+ * implementation because each target (Postgres, MySQL, SQLite, …) has its own
34
+ * parameterization syntax. The target wires its expander when calling
35
+ * `contractToSchemaIR`, keeping the family layer target-agnostic.
36
+ */
37
+ export type NativeTypeExpander = (input: {
38
+ readonly nativeType: string;
39
+ readonly codecId?: string;
40
+ readonly typeParams?: Record<string, unknown>;
41
+ }) => string;
42
+
43
+ /**
44
+ * Target-specific callback that renders a `ColumnDefault` into the raw SQL literal
45
+ * string stored in `SqlColumnIR.default`.
46
+ *
47
+ * Default value serialization is target-specific (quoting, casting, type syntax vary
48
+ * between Postgres, MySQL, SQLite, …). This callback follows the same IoC pattern as
49
+ * `NativeTypeExpander`: the target provides its renderer when calling
50
+ * `contractToSchemaIR`, keeping the family layer target-agnostic.
51
+ */
52
+ export type DefaultRenderer = (def: ColumnDefault, column: StorageColumn) => string;
53
+
54
+ function convertColumn(
55
+ name: string,
56
+ column: StorageColumn,
57
+ expandNativeType: NativeTypeExpander | undefined,
58
+ renderDefault: DefaultRenderer | undefined,
59
+ ): SqlColumnIR {
60
+ const nativeType = expandNativeType
61
+ ? expandNativeType({
62
+ nativeType: column.nativeType,
63
+ codecId: column.codecId,
64
+ ...ifDefined('typeParams', column.typeParams),
65
+ })
66
+ : column.nativeType;
67
+ return {
68
+ name,
69
+ nativeType,
70
+ nullable: column.nullable,
71
+ ...ifDefined(
72
+ 'default',
73
+ column.default != null && renderDefault ? renderDefault(column.default, column) : undefined,
74
+ ),
75
+ };
76
+ }
77
+
78
+ function convertUnique(unique: UniqueConstraint): SqlUniqueIR {
79
+ return {
80
+ columns: unique.columns,
81
+ ...ifDefined('name', unique.name),
82
+ };
83
+ }
84
+
85
+ function convertIndex(index: Index): SqlIndexIR {
86
+ return {
87
+ columns: index.columns,
88
+ unique: false,
89
+ ...ifDefined('name', index.name),
90
+ };
91
+ }
92
+
93
+ function convertForeignKey(fk: ForeignKey): SqlForeignKeyIR {
94
+ return {
95
+ columns: fk.columns,
96
+ referencedTable: fk.references.table,
97
+ referencedColumns: fk.references.columns,
98
+ ...ifDefined('name', fk.name),
99
+ };
100
+ }
101
+
102
+ function convertTable(
103
+ name: string,
104
+ table: StorageTable,
105
+ expandNativeType: NativeTypeExpander | undefined,
106
+ renderDefault: DefaultRenderer | undefined,
107
+ ): SqlTableIR {
108
+ const columns: Record<string, SqlColumnIR> = {};
109
+ for (const [colName, colDef] of Object.entries(table.columns)) {
110
+ columns[colName] = convertColumn(colName, colDef, expandNativeType, renderDefault);
111
+ }
112
+
113
+ const satisfiedIndexColumns = new Set([
114
+ ...table.indexes.map((idx) => idx.columns.join(',')),
115
+ ...table.uniques.map((unique) => unique.columns.join(',')),
116
+ ...(table.primaryKey ? [table.primaryKey.columns.join(',')] : []),
117
+ ]);
118
+ const fkBackingIndexes: SqlIndexIR[] = [];
119
+ for (const fk of table.foreignKeys) {
120
+ if (fk.index === false) continue;
121
+ const key = fk.columns.join(',');
122
+ if (satisfiedIndexColumns.has(key)) continue;
123
+ fkBackingIndexes.push({
124
+ columns: fk.columns,
125
+ unique: false,
126
+ name: defaultIndexName(name, fk.columns),
127
+ });
128
+ satisfiedIndexColumns.add(key);
129
+ }
130
+
131
+ return {
132
+ name,
133
+ columns,
134
+ ...ifDefined('primaryKey', table.primaryKey),
135
+ foreignKeys: table.foreignKeys.map(convertForeignKey),
136
+ uniques: table.uniques.map(convertUnique),
137
+ indexes: [...table.indexes.map(convertIndex), ...fkBackingIndexes],
138
+ };
139
+ }
140
+
141
+ /**
142
+ * Detects destructive changes between two contract storages.
143
+ *
144
+ * The additive-only planner silently ignores removals (tables, columns).
145
+ * This function detects those removals so callers can report them as conflicts
146
+ * rather than silently producing an empty plan.
147
+ *
148
+ * Returns an empty array if no destructive changes are found.
149
+ */
150
+ export function detectDestructiveChanges(
151
+ from: SqlStorage | null,
152
+ to: SqlStorage,
153
+ ): readonly MigrationPlannerConflict[] {
154
+ if (!from) return [];
155
+
156
+ const hasOwn = (value: object, key: string): boolean => Object.hasOwn(value, key);
157
+
158
+ const conflicts: MigrationPlannerConflict[] = [];
159
+
160
+ for (const tableName of Object.keys(from.tables)) {
161
+ if (!hasOwn(to.tables, tableName)) {
162
+ conflicts.push({
163
+ kind: 'tableRemoved',
164
+ summary: `Table "${tableName}" was removed`,
165
+ });
166
+ continue;
167
+ }
168
+
169
+ const toTable = to.tables[tableName] as StorageTable;
170
+ const fromTable = from.tables[tableName];
171
+ if (!fromTable) continue;
172
+
173
+ for (const columnName of Object.keys(fromTable.columns)) {
174
+ if (!hasOwn(toTable.columns, columnName)) {
175
+ conflicts.push({
176
+ kind: 'columnRemoved',
177
+ summary: `Column "${tableName}"."${columnName}" was removed`,
178
+ });
179
+ }
180
+ }
181
+ }
182
+
183
+ return conflicts;
184
+ }
185
+
186
+ export interface ContractToSchemaIROptions {
187
+ readonly annotationNamespace: string;
188
+ readonly expandNativeType?: NativeTypeExpander;
189
+ readonly renderDefault?: DefaultRenderer;
190
+ readonly frameworkComponents?: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;
191
+ }
192
+
193
+ /**
194
+ * Converts an `SqlContract` to `SqlSchemaIR`.
195
+ *
196
+ * Reads `contract.storage` for tables, `contract.storage.types` for type
197
+ * annotations, and derives database dependencies from `frameworkComponents`
198
+ * (each component's `databaseDependencies.init[].id`).
199
+ * Storage-type annotations are written under `options.annotationNamespace`.
200
+ *
201
+ * Drops codec metadata (`codecId`, `typeRef`) since the schema IR only represents
202
+ * structural information. When `expandNativeType` is provided, parameterized types
203
+ * are expanded (e.g. `character` + `{ length: 36 }` → `character(36)`) so the
204
+ * resulting IR compares correctly against the "to" contract during planning.
205
+ *
206
+ * Returns an empty schema IR when `contract` is `null` (new project).
207
+ */
208
+ export function contractToSchemaIR(
209
+ contract: SqlContract<SqlStorage> | null,
210
+ options: ContractToSchemaIROptions,
211
+ ): SqlSchemaIR {
212
+ if (options.annotationNamespace.length === 0) {
213
+ throw new Error('annotationNamespace must be a non-empty string');
214
+ }
215
+
216
+ if (!contract) {
217
+ return { tables: {}, dependencies: [] };
218
+ }
219
+
220
+ const storage = contract.storage;
221
+ const tables: Record<string, SqlTableIR> = {};
222
+ for (const [tableName, tableDef] of Object.entries(storage.tables)) {
223
+ tables[tableName] = convertTable(
224
+ tableName,
225
+ tableDef,
226
+ options.expandNativeType,
227
+ options.renderDefault,
228
+ );
229
+ }
230
+
231
+ const dependencies = deduplicateDependencyIRs(
232
+ collectInitDependencies(options.frameworkComponents ?? []),
233
+ );
234
+ const annotations = deriveAnnotations(storage, options.annotationNamespace);
235
+
236
+ return {
237
+ tables,
238
+ dependencies,
239
+ ...ifDefined('annotations', annotations),
240
+ };
241
+ }
242
+
243
+ function deduplicateDependencyIRs(
244
+ deps: readonly { readonly id: string }[],
245
+ ): readonly DependencyIR[] {
246
+ const seen = new Set<string>();
247
+ const result: DependencyIR[] = [];
248
+ for (const dep of deps) {
249
+ if (dep.id.trim().length === 0) {
250
+ throw new Error('Dependency id must be a non-empty string');
251
+ }
252
+ if (seen.has(dep.id)) continue;
253
+ seen.add(dep.id);
254
+ result.push({ id: dep.id });
255
+ }
256
+ return result;
257
+ }
258
+
259
+ function deriveAnnotations(
260
+ storage: SqlStorage,
261
+ annotationNamespace: string,
262
+ ): SqlAnnotations | undefined {
263
+ if (!storage.types || Object.keys(storage.types).length === 0) return undefined;
264
+ return { [annotationNamespace]: { storageTypes: storage.types } };
265
+ }