@prisma-next/sql-contract-emitter 0.3.0-dev.13 → 0.3.0-dev.146
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +2 -2
- package/dist/index.d.mts +18 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +167 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +22 -13
- package/src/index.ts +149 -277
- package/dist/index.d.ts +0 -14
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -379
- package/dist/index.js.map +0 -1
package/src/index.ts
CHANGED
|
@@ -1,23 +1,38 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import
|
|
1
|
+
import type { Contract, ContractModel } from '@prisma-next/contract/types';
|
|
2
|
+
import {
|
|
3
|
+
generateCodecTypeIntersection,
|
|
4
|
+
serializeObjectKey,
|
|
5
|
+
serializeValue,
|
|
6
|
+
} from '@prisma-next/emitter/domain-type-generation';
|
|
3
7
|
import type {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from '@prisma-next/
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
GenerateContractTypesOptions,
|
|
9
|
+
ValidationContext,
|
|
10
|
+
} from '@prisma-next/framework-components/emission';
|
|
11
|
+
import type { SqlModelStorage, SqlStorage, StorageTable } from '@prisma-next/sql-contract/types';
|
|
12
|
+
import { assertDefined } from '@prisma-next/utils/assertions';
|
|
13
|
+
|
|
14
|
+
function serializeTypeParamsLiteral(params: Record<string, unknown> | undefined): string {
|
|
15
|
+
if (!params || Object.keys(params).length === 0) {
|
|
16
|
+
return 'Record<string, never>';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const entries: string[] = [];
|
|
20
|
+
for (const [key, value] of Object.entries(params)) {
|
|
21
|
+
entries.push(`readonly ${serializeObjectKey(key)}: ${serializeValue(value)}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return `{ ${entries.join('; ')} }`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const sqlEmission = {
|
|
11
28
|
id: 'sql',
|
|
12
29
|
|
|
13
|
-
validateTypes(
|
|
14
|
-
const storage =
|
|
30
|
+
validateTypes(contract: Contract, _ctx: ValidationContext): void {
|
|
31
|
+
const storage = contract.storage as unknown as SqlStorage | undefined;
|
|
15
32
|
if (!storage || !storage.tables) {
|
|
16
33
|
return;
|
|
17
34
|
}
|
|
18
35
|
|
|
19
|
-
// Validate codec ID format (ns/name@version). Adapter-provided codecs are available regardless of contract.extensionPacks (which is for framework extensions); TypeScript prevents invalid usage and runtime validates availability.
|
|
20
|
-
|
|
21
36
|
const typeIdRegex = /^([^/]+)\/([^@]+)@(\d+)$/;
|
|
22
37
|
|
|
23
38
|
for (const [tableName, tableUnknown] of Object.entries(storage.tables)) {
|
|
@@ -39,22 +54,21 @@ export const sqlTargetFamilyHook = {
|
|
|
39
54
|
}
|
|
40
55
|
},
|
|
41
56
|
|
|
42
|
-
validateStructure(
|
|
43
|
-
if (
|
|
44
|
-
throw new Error(`Expected targetFamily "sql", got "${
|
|
57
|
+
validateStructure(contract: Contract): void {
|
|
58
|
+
if (contract.targetFamily !== 'sql') {
|
|
59
|
+
throw new Error(`Expected targetFamily "sql", got "${contract.targetFamily}"`);
|
|
45
60
|
}
|
|
46
61
|
|
|
47
|
-
const storage =
|
|
62
|
+
const storage = contract.storage as unknown as SqlStorage | undefined;
|
|
48
63
|
if (!storage || !storage.tables) {
|
|
49
64
|
throw new Error('SQL contract must have storage.tables');
|
|
50
65
|
}
|
|
51
66
|
|
|
52
|
-
const models =
|
|
67
|
+
const models = contract.models as Record<string, ContractModel<SqlModelStorage>>;
|
|
53
68
|
const tableNames = new Set(Object.keys(storage.tables));
|
|
54
69
|
|
|
55
70
|
if (models) {
|
|
56
|
-
for (const [modelName,
|
|
57
|
-
const model = modelUnknown as ModelDefinition;
|
|
71
|
+
for (const [modelName, model] of Object.entries(models)) {
|
|
58
72
|
if (!model.storage?.table) {
|
|
59
73
|
throw new Error(`Model "${modelName}" is missing storage.table`);
|
|
60
74
|
}
|
|
@@ -64,22 +78,20 @@ export const sqlTargetFamilyHook = {
|
|
|
64
78
|
throw new Error(`Model "${modelName}" references non-existent table "${tableName}"`);
|
|
65
79
|
}
|
|
66
80
|
|
|
67
|
-
const table = storage.tables[tableName];
|
|
68
|
-
|
|
69
|
-
throw new Error(`Model "${modelName}" references non-existent table "${tableName}"`);
|
|
70
|
-
}
|
|
81
|
+
const table: StorageTable | undefined = storage.tables[tableName];
|
|
82
|
+
assertDefined(table, `Model "${modelName}" references non-existent table "${tableName}"`);
|
|
71
83
|
|
|
72
84
|
if (!table.primaryKey) {
|
|
73
85
|
throw new Error(`Model "${modelName}" table "${tableName}" is missing a primary key`);
|
|
74
86
|
}
|
|
75
87
|
|
|
76
88
|
const columnNames = new Set(Object.keys(table.columns));
|
|
77
|
-
|
|
78
|
-
|
|
89
|
+
const storageFields = model.storage.fields;
|
|
90
|
+
if (!storageFields || Object.keys(storageFields).length === 0) {
|
|
91
|
+
throw new Error(`Model "${modelName}" is missing storage.fields`);
|
|
79
92
|
}
|
|
80
93
|
|
|
81
|
-
for (const [fieldName,
|
|
82
|
-
const field = fieldUnknown as ModelField;
|
|
94
|
+
for (const [fieldName, field] of Object.entries(storageFields)) {
|
|
83
95
|
if (!field.column) {
|
|
84
96
|
throw new Error(`Model "${modelName}" field "${fieldName}" is missing column property`);
|
|
85
97
|
}
|
|
@@ -103,10 +115,6 @@ export const sqlTargetFamilyHook = {
|
|
|
103
115
|
const table = tableUnknown as StorageTable;
|
|
104
116
|
const columnNames = new Set(Object.keys(table.columns));
|
|
105
117
|
|
|
106
|
-
// Column structure (nullable, nativeType, codecId) and table arrays (uniques, indexes, foreignKeys)
|
|
107
|
-
// are validated by Arktype schema validation - no need to re-check here.
|
|
108
|
-
// We only validate logical consistency (foreign key references, model references, etc.)
|
|
109
|
-
|
|
110
118
|
if (!Array.isArray(table.uniques)) {
|
|
111
119
|
throw new Error(
|
|
112
120
|
`Table "${tableName}" is missing required field "uniques" (must be an array)`,
|
|
@@ -168,12 +176,11 @@ export const sqlTargetFamilyHook = {
|
|
|
168
176
|
);
|
|
169
177
|
}
|
|
170
178
|
|
|
171
|
-
const referencedTable = storage.tables[fk.references.table];
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
179
|
+
const referencedTable: StorageTable | undefined = storage.tables[fk.references.table];
|
|
180
|
+
assertDefined(
|
|
181
|
+
referencedTable,
|
|
182
|
+
`Table "${tableName}" foreignKey references non-existent table "${fk.references.table}"`,
|
|
183
|
+
);
|
|
177
184
|
|
|
178
185
|
const referencedColumnNames = new Set(Object.keys(referencedTable.columns));
|
|
179
186
|
for (const colName of fk.references.columns) {
|
|
@@ -193,76 +200,50 @@ export const sqlTargetFamilyHook = {
|
|
|
193
200
|
}
|
|
194
201
|
},
|
|
195
202
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
codecTypeImports: ReadonlyArray<TypesImportSpec>,
|
|
199
|
-
operationTypeImports: ReadonlyArray<TypesImportSpec>,
|
|
200
|
-
): string {
|
|
201
|
-
const allImports = [...codecTypeImports, ...operationTypeImports];
|
|
202
|
-
const importLines = allImports.map(
|
|
203
|
-
(imp) => `import type { ${imp.named} as ${imp.alias} } from '${imp.package}';`,
|
|
204
|
-
);
|
|
205
|
-
|
|
206
|
-
const codecTypes = codecTypeImports.map((imp) => imp.alias).join(' & ');
|
|
207
|
-
const operationTypes = operationTypeImports.map((imp) => imp.alias).join(' & ');
|
|
208
|
-
|
|
209
|
-
const storage = ir.storage as SqlStorage;
|
|
210
|
-
const models = ir.models as Record<string, ModelDefinition>;
|
|
211
|
-
|
|
212
|
-
const storageType = this.generateStorageType(storage);
|
|
213
|
-
const modelsType = this.generateModelsType(models, storage);
|
|
214
|
-
const relationsType = this.generateRelationsType(ir.relations);
|
|
215
|
-
const mappingsType = this.generateMappingsType(models, storage, codecTypes, operationTypes);
|
|
216
|
-
|
|
217
|
-
return `// ⚠️ GENERATED FILE - DO NOT EDIT
|
|
218
|
-
// This file is automatically generated by 'prisma-next emit'.
|
|
219
|
-
// To regenerate, run: prisma-next emit
|
|
220
|
-
${importLines.join('\n')}
|
|
221
|
-
|
|
222
|
-
import type { SqlContract, SqlStorage, SqlMappings, ModelDefinition } from '@prisma-next/sql-contract/types';
|
|
223
|
-
|
|
224
|
-
export type CodecTypes = ${codecTypes || 'Record<string, never>'};
|
|
225
|
-
export type LaneCodecTypes = CodecTypes;
|
|
226
|
-
export type OperationTypes = ${operationTypes || 'Record<string, never>'};
|
|
227
|
-
|
|
228
|
-
export type Contract = SqlContract<
|
|
229
|
-
${storageType},
|
|
230
|
-
${modelsType},
|
|
231
|
-
${relationsType},
|
|
232
|
-
${mappingsType}
|
|
233
|
-
>;
|
|
234
|
-
|
|
235
|
-
export type Tables = Contract['storage']['tables'];
|
|
236
|
-
export type Models = Contract['models'];
|
|
237
|
-
export type Relations = Contract['relations'];
|
|
238
|
-
`;
|
|
239
|
-
},
|
|
240
|
-
|
|
241
|
-
generateStorageType(storage: SqlStorage): string {
|
|
203
|
+
generateStorageType(contract: Contract, storageHashTypeName: string): string {
|
|
204
|
+
const storage = contract.storage as unknown as SqlStorage;
|
|
242
205
|
const tables: string[] = [];
|
|
243
|
-
for (const [tableName, table] of Object.entries(storage.tables))
|
|
206
|
+
for (const [tableName, table] of Object.entries(storage.tables).sort(([a], [b]) =>
|
|
207
|
+
a.localeCompare(b),
|
|
208
|
+
)) {
|
|
244
209
|
const columns: string[] = [];
|
|
245
210
|
for (const [colName, col] of Object.entries(table.columns)) {
|
|
246
211
|
const nullable = col.nullable ? 'true' : 'false';
|
|
247
|
-
const nativeType =
|
|
248
|
-
const codecId =
|
|
212
|
+
const nativeType = serializeValue(col.nativeType);
|
|
213
|
+
const codecId = serializeValue(col.codecId);
|
|
214
|
+
const defaultSpec = col.default
|
|
215
|
+
? col.default.kind === 'literal'
|
|
216
|
+
? `; readonly default: { readonly kind: 'literal'; readonly value: DefaultLiteralValue<${codecId}, ${serializeValue(
|
|
217
|
+
col.default.value,
|
|
218
|
+
)}> }`
|
|
219
|
+
: `; readonly default: { readonly kind: 'function'; readonly expression: ${serializeValue(
|
|
220
|
+
col.default.expression,
|
|
221
|
+
)} }`
|
|
222
|
+
: '';
|
|
223
|
+
const typeParamsSpec =
|
|
224
|
+
col.typeParams && Object.keys(col.typeParams).length > 0
|
|
225
|
+
? `; readonly typeParams: ${serializeTypeParamsLiteral(col.typeParams)}`
|
|
226
|
+
: '';
|
|
227
|
+
const typeRefSpec = col.typeRef ? `; readonly typeRef: ${serializeValue(col.typeRef)}` : '';
|
|
249
228
|
columns.push(
|
|
250
|
-
`readonly ${colName}: { readonly nativeType: ${nativeType}; readonly codecId: ${codecId}; readonly nullable: ${nullable} }`,
|
|
229
|
+
`readonly ${colName}: { readonly nativeType: ${nativeType}; readonly codecId: ${codecId}; readonly nullable: ${nullable}${defaultSpec}${typeParamsSpec}${typeRefSpec} }`,
|
|
251
230
|
);
|
|
252
231
|
}
|
|
253
232
|
|
|
254
233
|
const tableParts: string[] = [`columns: { ${columns.join('; ')} }`];
|
|
255
234
|
|
|
256
235
|
if (table.primaryKey) {
|
|
257
|
-
const pkCols = table.primaryKey.columns.map((c) =>
|
|
258
|
-
const pkName = table.primaryKey.name
|
|
236
|
+
const pkCols = table.primaryKey.columns.map((c) => serializeValue(c)).join(', ');
|
|
237
|
+
const pkName = table.primaryKey.name
|
|
238
|
+
? `; readonly name: ${serializeValue(table.primaryKey.name)}`
|
|
239
|
+
: '';
|
|
259
240
|
tableParts.push(`primaryKey: { readonly columns: readonly [${pkCols}]${pkName} }`);
|
|
260
241
|
}
|
|
261
242
|
|
|
262
243
|
const uniques = table.uniques
|
|
263
244
|
.map((u) => {
|
|
264
|
-
const cols = u.columns.map((c: string) =>
|
|
265
|
-
const name = u.name ? `; readonly name:
|
|
245
|
+
const cols = u.columns.map((c: string) => serializeValue(c)).join(', ');
|
|
246
|
+
const name = u.name ? `; readonly name: ${serializeValue(u.name)}` : '';
|
|
266
247
|
return `{ readonly columns: readonly [${cols}]${name} }`;
|
|
267
248
|
})
|
|
268
249
|
.join(', ');
|
|
@@ -270,19 +251,22 @@ export type Relations = Contract['relations'];
|
|
|
270
251
|
|
|
271
252
|
const indexes = table.indexes
|
|
272
253
|
.map((i) => {
|
|
273
|
-
const cols = i.columns.map((c: string) =>
|
|
274
|
-
const name = i.name ? `; readonly name:
|
|
275
|
-
|
|
254
|
+
const cols = i.columns.map((c: string) => serializeValue(c)).join(', ');
|
|
255
|
+
const name = i.name ? `; readonly name: ${serializeValue(i.name)}` : '';
|
|
256
|
+
const using = i.using !== undefined ? `; readonly using: ${serializeValue(i.using)}` : '';
|
|
257
|
+
const config =
|
|
258
|
+
i.config !== undefined ? `; readonly config: ${serializeValue(i.config)}` : '';
|
|
259
|
+
return `{ readonly columns: readonly [${cols}]${name}${using}${config} }`;
|
|
276
260
|
})
|
|
277
261
|
.join(', ');
|
|
278
262
|
tableParts.push(`indexes: readonly [${indexes}]`);
|
|
279
263
|
|
|
280
264
|
const fks = table.foreignKeys
|
|
281
265
|
.map((fk) => {
|
|
282
|
-
const cols = fk.columns.map((c: string) =>
|
|
283
|
-
const refCols = fk.references.columns.map((c: string) =>
|
|
284
|
-
const name = fk.name ? `; readonly name:
|
|
285
|
-
return `{ readonly columns: readonly [${cols}]; readonly references: { readonly table:
|
|
266
|
+
const cols = fk.columns.map((c: string) => serializeValue(c)).join(', ');
|
|
267
|
+
const refCols = fk.references.columns.map((c: string) => serializeValue(c)).join(', ');
|
|
268
|
+
const name = fk.name ? `; readonly name: ${serializeValue(fk.name)}` : '';
|
|
269
|
+
return `{ readonly columns: readonly [${cols}]; readonly references: { readonly table: ${serializeValue(fk.references.table)}; readonly columns: readonly [${refCols}] }${name}; readonly constraint: ${fk.constraint}; readonly index: ${fk.index} }`;
|
|
286
270
|
})
|
|
287
271
|
.join(', ');
|
|
288
272
|
tableParts.push(`foreignKeys: readonly [${fks}]`);
|
|
@@ -290,196 +274,84 @@ export type Relations = Contract['relations'];
|
|
|
290
274
|
tables.push(`readonly ${tableName}: { ${tableParts.join('; ')} }`);
|
|
291
275
|
}
|
|
292
276
|
|
|
293
|
-
|
|
294
|
-
},
|
|
295
|
-
|
|
296
|
-
generateModelsType(
|
|
297
|
-
models: Record<string, ModelDefinition> | undefined,
|
|
298
|
-
storage: SqlStorage,
|
|
299
|
-
): string {
|
|
300
|
-
if (!models) {
|
|
301
|
-
return 'Record<string, never>';
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
const modelTypes: string[] = [];
|
|
305
|
-
for (const [modelName, model] of Object.entries(models)) {
|
|
306
|
-
const fields: string[] = [];
|
|
307
|
-
const tableName = model.storage.table;
|
|
308
|
-
const table = storage.tables[tableName];
|
|
309
|
-
|
|
310
|
-
if (table) {
|
|
311
|
-
for (const [fieldName, field] of Object.entries(model.fields)) {
|
|
312
|
-
const column = table.columns[field.column];
|
|
313
|
-
if (!column) {
|
|
314
|
-
fields.push(`readonly ${fieldName}: { readonly column: '${field.column}' }`);
|
|
315
|
-
continue;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
const typeId = column.codecId;
|
|
319
|
-
const nullable = column.nullable ?? false;
|
|
320
|
-
const jsType = nullable
|
|
321
|
-
? `CodecTypes['${typeId}']['output'] | null`
|
|
322
|
-
: `CodecTypes['${typeId}']['output']`;
|
|
323
|
-
|
|
324
|
-
fields.push(`readonly ${fieldName}: ${jsType}`);
|
|
325
|
-
}
|
|
326
|
-
} else {
|
|
327
|
-
for (const [fieldName, field] of Object.entries(model.fields)) {
|
|
328
|
-
fields.push(`readonly ${fieldName}: { readonly column: '${field.column}' }`);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
const relations: string[] = [];
|
|
333
|
-
for (const [relName, rel] of Object.entries(model.relations)) {
|
|
334
|
-
if (typeof rel === 'object' && rel !== null && 'on' in rel) {
|
|
335
|
-
const on = rel.on as { parentCols?: string[]; childCols?: string[] };
|
|
336
|
-
if (on.parentCols && on.childCols) {
|
|
337
|
-
const parentCols = on.parentCols.map((c) => `'${c}'`).join(', ');
|
|
338
|
-
const childCols = on.childCols.map((c) => `'${c}'`).join(', ');
|
|
339
|
-
relations.push(
|
|
340
|
-
`readonly ${relName}: { readonly on: { readonly parentCols: readonly [${parentCols}]; readonly childCols: readonly [${childCols}] } }`,
|
|
341
|
-
);
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
const modelParts: string[] = [
|
|
347
|
-
`storage: { readonly table: '${tableName}' }`,
|
|
348
|
-
`fields: { ${fields.join('; ')} }`,
|
|
349
|
-
];
|
|
277
|
+
const typesType = generateStorageTypesType(storage.types);
|
|
350
278
|
|
|
351
|
-
|
|
352
|
-
modelParts.push(`relations: { ${relations.join('; ')} }`);
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
modelTypes.push(`readonly ${modelName}: { ${modelParts.join('; ')} }`);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
return `{ ${modelTypes.join('; ')} }`;
|
|
279
|
+
return `{ readonly tables: { ${tables.join('; ')} }; readonly types: ${typesType}; readonly storageHash: ${storageHashTypeName} }`;
|
|
359
280
|
},
|
|
360
281
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
const relationEntries: string[] = [];
|
|
373
|
-
for (const [relName, relValue] of Object.entries(rels)) {
|
|
374
|
-
if (typeof relValue !== 'object' || relValue === null) {
|
|
375
|
-
relationEntries.push(`readonly ${relName}: unknown`);
|
|
376
|
-
continue;
|
|
377
|
-
}
|
|
378
|
-
const { to, cardinality, on, through } = relValue as {
|
|
379
|
-
readonly to?: string;
|
|
380
|
-
readonly cardinality?: string;
|
|
381
|
-
readonly on?: {
|
|
382
|
-
readonly parentCols?: readonly string[];
|
|
383
|
-
readonly childCols?: readonly string[];
|
|
384
|
-
};
|
|
385
|
-
readonly through?: {
|
|
386
|
-
readonly table: string;
|
|
387
|
-
readonly parentCols: readonly string[];
|
|
388
|
-
readonly childCols: readonly string[];
|
|
389
|
-
};
|
|
390
|
-
};
|
|
391
|
-
|
|
392
|
-
const parts: string[] = [];
|
|
393
|
-
if (to) {
|
|
394
|
-
parts.push(`readonly to: '${to}'`);
|
|
395
|
-
}
|
|
396
|
-
if (cardinality) {
|
|
397
|
-
parts.push(`readonly cardinality: '${cardinality}'`);
|
|
398
|
-
}
|
|
399
|
-
if (on?.parentCols && on.childCols) {
|
|
400
|
-
const parentCols = on.parentCols.map((c) => `'${c}'`).join(', ');
|
|
401
|
-
const childCols = on.childCols.map((c) => `'${c}'`).join(', ');
|
|
402
|
-
parts.push(
|
|
403
|
-
`readonly on: { readonly parentCols: readonly [${parentCols}]; readonly childCols: readonly [${childCols}] }`,
|
|
404
|
-
);
|
|
405
|
-
}
|
|
406
|
-
if (through) {
|
|
407
|
-
const parentCols = through.parentCols.map((c) => `'${c}'`).join(', ');
|
|
408
|
-
const childCols = through.childCols.map((c) => `'${c}'`).join(', ');
|
|
409
|
-
parts.push(
|
|
410
|
-
`readonly through: { readonly table: '${through.table}'; readonly parentCols: readonly [${parentCols}]; readonly childCols: readonly [${childCols}] }`,
|
|
411
|
-
);
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
relationEntries.push(
|
|
415
|
-
parts.length > 0
|
|
416
|
-
? `readonly ${relName}: { ${parts.join('; ')} }`
|
|
417
|
-
: `readonly ${relName}: unknown`,
|
|
282
|
+
generateModelStorageType(_modelName: string, model: ContractModel): string {
|
|
283
|
+
const sqlModel = model as ContractModel<SqlModelStorage>;
|
|
284
|
+
const tableName = sqlModel.storage.table;
|
|
285
|
+
const storageFields = sqlModel.storage.fields;
|
|
286
|
+
|
|
287
|
+
const storageParts = [`readonly table: ${serializeValue(tableName)}`];
|
|
288
|
+
if (Object.keys(storageFields).length > 0) {
|
|
289
|
+
const fieldParts: string[] = [];
|
|
290
|
+
for (const [fieldName, field] of Object.entries(storageFields)) {
|
|
291
|
+
fieldParts.push(
|
|
292
|
+
`readonly ${serializeObjectKey(fieldName)}: { readonly column: ${serializeValue(field.column)} }`,
|
|
418
293
|
);
|
|
419
294
|
}
|
|
420
|
-
|
|
295
|
+
storageParts.push(`readonly fields: { ${fieldParts.join('; ')} }`);
|
|
421
296
|
}
|
|
422
297
|
|
|
423
|
-
return `{ ${
|
|
298
|
+
return `{ ${storageParts.join('; ')} }`;
|
|
424
299
|
},
|
|
425
300
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
const modelToTable: string[] = [];
|
|
437
|
-
const tableToModel: string[] = [];
|
|
438
|
-
const fieldToColumn: string[] = [];
|
|
439
|
-
const columnToField: string[] = [];
|
|
440
|
-
|
|
441
|
-
for (const [modelName, model] of Object.entries(models)) {
|
|
442
|
-
const tableName = model.storage.table;
|
|
443
|
-
modelToTable.push(`readonly ${modelName}: '${tableName}'`);
|
|
444
|
-
tableToModel.push(`readonly ${tableName}: '${modelName}'`);
|
|
445
|
-
|
|
446
|
-
const fieldMap: string[] = [];
|
|
447
|
-
for (const [fieldName, field] of Object.entries(model.fields)) {
|
|
448
|
-
fieldMap.push(`readonly ${fieldName}: '${field.column}'`);
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
if (fieldMap.length > 0) {
|
|
452
|
-
fieldToColumn.push(`readonly ${modelName}: { ${fieldMap.join('; ')} }`);
|
|
453
|
-
}
|
|
301
|
+
getFamilyImports(): string[] {
|
|
302
|
+
return [
|
|
303
|
+
'import type {',
|
|
304
|
+
' ContractWithTypeMaps,',
|
|
305
|
+
' TypeMaps as TypeMapsType,',
|
|
306
|
+
"} from '@prisma-next/sql-contract/types';",
|
|
307
|
+
];
|
|
308
|
+
},
|
|
454
309
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
310
|
+
getFamilyTypeAliases(options?: GenerateContractTypesOptions): string {
|
|
311
|
+
const queryOperationTypeImports = options?.queryOperationTypeImports ?? [];
|
|
312
|
+
const queryOperationTypes = generateCodecTypeIntersection(
|
|
313
|
+
queryOperationTypeImports,
|
|
314
|
+
'QueryOperationTypes',
|
|
315
|
+
);
|
|
460
316
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
317
|
+
return [
|
|
318
|
+
'export type LaneCodecTypes = CodecTypes;',
|
|
319
|
+
`export type QueryOperationTypes = ${queryOperationTypes};`,
|
|
320
|
+
'type DefaultLiteralValue<CodecId extends string, _Encoded> =',
|
|
321
|
+
' CodecId extends keyof CodecTypes',
|
|
322
|
+
" ? CodecTypes[CodecId]['output']",
|
|
323
|
+
' : _Encoded;',
|
|
324
|
+
].join('\n');
|
|
325
|
+
},
|
|
466
326
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
}
|
|
471
|
-
if (tableToModel.length > 0) {
|
|
472
|
-
parts.push(`tableToModel: { ${tableToModel.join('; ')} }`);
|
|
473
|
-
}
|
|
474
|
-
if (fieldToColumn.length > 0) {
|
|
475
|
-
parts.push(`fieldToColumn: { ${fieldToColumn.join('; ')} }`);
|
|
476
|
-
}
|
|
477
|
-
if (columnToField.length > 0) {
|
|
478
|
-
parts.push(`columnToField: { ${columnToField.join('; ')} }`);
|
|
479
|
-
}
|
|
480
|
-
parts.push(`codecTypes: ${codecTypes || 'Record<string, never>'}`);
|
|
481
|
-
parts.push(`operationTypes: ${operationTypes || 'Record<string, never>'}`);
|
|
327
|
+
getTypeMapsExpression(): string {
|
|
328
|
+
return 'TypeMapsType<CodecTypes, OperationTypes, QueryOperationTypes, FieldOutputTypes>';
|
|
329
|
+
},
|
|
482
330
|
|
|
483
|
-
|
|
331
|
+
getContractWrapper(contractBaseName: string, typeMapsName: string): string {
|
|
332
|
+
return [
|
|
333
|
+
`export type Contract = ContractWithTypeMaps<${contractBaseName}, ${typeMapsName}>;`,
|
|
334
|
+
'',
|
|
335
|
+
"export type Tables = Contract['storage']['tables'];",
|
|
336
|
+
"export type Models = Contract['models'];",
|
|
337
|
+
].join('\n');
|
|
484
338
|
},
|
|
485
339
|
} as const;
|
|
340
|
+
|
|
341
|
+
function generateStorageTypesType(types: SqlStorage['types']): string {
|
|
342
|
+
if (!types || Object.keys(types).length === 0) {
|
|
343
|
+
return 'Record<string, never>';
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const typeEntries: string[] = [];
|
|
347
|
+
for (const [typeName, typeInstance] of Object.entries(types)) {
|
|
348
|
+
const codecId = serializeValue(typeInstance.codecId);
|
|
349
|
+
const nativeType = serializeValue(typeInstance.nativeType);
|
|
350
|
+
const typeParamsStr = serializeTypeParamsLiteral(typeInstance.typeParams);
|
|
351
|
+
typeEntries.push(
|
|
352
|
+
`readonly ${typeName}: { readonly codecId: ${codecId}; readonly nativeType: ${nativeType}; readonly typeParams: ${typeParamsStr} }`,
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
return `{ ${typeEntries.join('; ')} }`;
|
|
357
|
+
}
|
package/dist/index.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { ContractIR } from '@prisma-next/contract/ir';
|
|
2
|
-
import type { TypesImportSpec, ValidationContext } from '@prisma-next/contract/types';
|
|
3
|
-
import type { ModelDefinition, SqlStorage } from '@prisma-next/sql-contract/types';
|
|
4
|
-
export declare const sqlTargetFamilyHook: {
|
|
5
|
-
readonly id: "sql";
|
|
6
|
-
readonly validateTypes: (ir: ContractIR, _ctx: ValidationContext) => void;
|
|
7
|
-
readonly validateStructure: (ir: ContractIR) => void;
|
|
8
|
-
readonly generateContractTypes: (ir: ContractIR, codecTypeImports: ReadonlyArray<TypesImportSpec>, operationTypeImports: ReadonlyArray<TypesImportSpec>) => string;
|
|
9
|
-
readonly generateStorageType: (storage: SqlStorage) => string;
|
|
10
|
-
readonly generateModelsType: (models: Record<string, ModelDefinition> | undefined, storage: SqlStorage) => string;
|
|
11
|
-
readonly generateRelationsType: (relations: Record<string, unknown> | undefined) => string;
|
|
12
|
-
readonly generateMappingsType: (models: Record<string, ModelDefinition> | undefined, storage: SqlStorage, codecTypes: string, operationTypes: string) => string;
|
|
13
|
-
};
|
|
14
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACtF,OAAO,KAAK,EACV,eAAe,EAEf,UAAU,EAEX,MAAM,iCAAiC,CAAC;AAEzC,eAAO,MAAM,mBAAmB;;iCAGZ,UAAU,QAAQ,iBAAiB,KAAG,IAAI;qCA6BtC,UAAU,KAAG,IAAI;yCA2JjC,UAAU,oBACI,aAAa,CAAC,eAAe,CAAC,wBAC1B,aAAa,CAAC,eAAe,CAAC,KACnD,MAAM;4CAyCoB,UAAU,KAAG,MAAM;0CAwDtC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,WAC1C,UAAU,KAClB,MAAM;gDA8DwB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,KAAG,MAAM;4CAkEnE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,WAC1C,UAAU,cACP,MAAM,kBACF,MAAM,KACrB,MAAM;CAsDD,CAAC"}
|