@prisma-next/sql-contract-ts 0.3.0-pr.99.6 → 0.4.0-dev.1
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 +206 -73
- package/dist/config-types.d.mts +8 -0
- package/dist/config-types.d.mts.map +1 -0
- package/dist/config-types.mjs +14 -0
- package/dist/config-types.mjs.map +1 -0
- package/dist/contract-builder.d.mts +769 -0
- package/dist/contract-builder.d.mts.map +1 -0
- package/dist/contract-builder.mjs +1288 -0
- package/dist/contract-builder.mjs.map +1 -0
- package/package.json +19 -16
- package/schemas/data-contract-sql-v1.json +189 -23
- package/src/authoring-helper-runtime.ts +139 -0
- package/src/authoring-type-utils.ts +168 -0
- package/src/build-contract.ts +463 -0
- package/src/composed-authoring-helpers.ts +256 -0
- package/src/config-types.ts +11 -0
- package/src/contract-builder.ts +232 -551
- package/src/contract-definition.ts +103 -0
- package/src/contract-dsl.ts +1492 -0
- package/src/contract-lowering.ts +703 -0
- package/src/contract-types.ts +534 -0
- package/src/contract-warnings.ts +242 -0
- package/src/exports/config-types.ts +2 -0
- package/src/exports/contract-builder.ts +23 -2
- package/dist/chunk-HTNUNGA2.js +0 -346
- package/dist/chunk-HTNUNGA2.js.map +0 -1
- package/dist/contract-builder.d.ts +0 -101
- package/dist/contract-builder.d.ts.map +0 -1
- package/dist/contract.d.ts +0 -50
- package/dist/contract.d.ts.map +0 -1
- package/dist/exports/contract-builder.d.ts +0 -3
- package/dist/exports/contract-builder.d.ts.map +0 -1
- package/dist/exports/contract-builder.js +0 -231
- package/dist/exports/contract-builder.js.map +0 -1
- package/dist/exports/contract.d.ts +0 -2
- package/dist/exports/contract.d.ts.map +0 -1
- package/dist/exports/contract.js +0 -9
- package/dist/exports/contract.js.map +0 -1
- package/src/contract.ts +0 -582
- package/src/exports/contract.ts +0 -1
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
import {
|
|
2
|
+
computeExecutionHash,
|
|
3
|
+
computeProfileHash,
|
|
4
|
+
computeStorageHash,
|
|
5
|
+
} from '@prisma-next/contract/hashing';
|
|
6
|
+
import {
|
|
7
|
+
type ColumnDefault,
|
|
8
|
+
type ColumnDefaultLiteralInputValue,
|
|
9
|
+
type Contract,
|
|
10
|
+
type ContractField,
|
|
11
|
+
type ContractModel,
|
|
12
|
+
type ContractRelation,
|
|
13
|
+
type ContractValueObject,
|
|
14
|
+
coreHash,
|
|
15
|
+
type ExecutionMutationDefault,
|
|
16
|
+
type ExecutionMutationDefaultValue,
|
|
17
|
+
type JsonValue,
|
|
18
|
+
type StorageHashBase,
|
|
19
|
+
} from '@prisma-next/contract/types';
|
|
20
|
+
import type { CodecLookup } from '@prisma-next/framework-components/codec';
|
|
21
|
+
import {
|
|
22
|
+
applyFkDefaults,
|
|
23
|
+
type SqlStorage,
|
|
24
|
+
type StorageColumn,
|
|
25
|
+
type StorageTable,
|
|
26
|
+
type StorageTypeInstance,
|
|
27
|
+
} from '@prisma-next/sql-contract/types';
|
|
28
|
+
import { validateStorageSemantics } from '@prisma-next/sql-contract/validators';
|
|
29
|
+
import { ifDefined } from '@prisma-next/utils/defined';
|
|
30
|
+
import type {
|
|
31
|
+
ContractDefinition,
|
|
32
|
+
FieldNode,
|
|
33
|
+
ModelNode,
|
|
34
|
+
ValueObjectFieldNode,
|
|
35
|
+
} from './contract-definition';
|
|
36
|
+
|
|
37
|
+
type DomainFieldRef =
|
|
38
|
+
| { readonly kind: 'scalar'; readonly many?: boolean }
|
|
39
|
+
| { readonly kind: 'valueObject'; readonly name: string; readonly many?: boolean };
|
|
40
|
+
|
|
41
|
+
function encodeDefaultLiteralValue(
|
|
42
|
+
value: ColumnDefaultLiteralInputValue,
|
|
43
|
+
codecId: string,
|
|
44
|
+
codecLookup?: CodecLookup,
|
|
45
|
+
): JsonValue {
|
|
46
|
+
const codec = codecLookup?.get(codecId);
|
|
47
|
+
if (codec) {
|
|
48
|
+
return codec.encodeJson(value);
|
|
49
|
+
}
|
|
50
|
+
return value as JsonValue;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function encodeColumnDefault(
|
|
54
|
+
defaultInput: ColumnDefault,
|
|
55
|
+
codecId: string,
|
|
56
|
+
codecLookup?: CodecLookup,
|
|
57
|
+
): ColumnDefault {
|
|
58
|
+
if (defaultInput.kind === 'function') {
|
|
59
|
+
return { kind: 'function', expression: defaultInput.expression };
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
kind: 'literal',
|
|
63
|
+
value: encodeDefaultLiteralValue(defaultInput.value, codecId, codecLookup),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function assertStorageSemantics(storage: SqlStorage): void {
|
|
68
|
+
const semanticErrors = validateStorageSemantics(storage);
|
|
69
|
+
if (semanticErrors.length > 0) {
|
|
70
|
+
throw new Error(`Contract semantic validation failed: ${semanticErrors.join('; ')}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function assertKnownTargetModel(
|
|
75
|
+
modelsByName: ReadonlyMap<string, ModelNode>,
|
|
76
|
+
sourceModelName: string,
|
|
77
|
+
targetModelName: string,
|
|
78
|
+
context: string,
|
|
79
|
+
): ModelNode {
|
|
80
|
+
const targetModel = modelsByName.get(targetModelName);
|
|
81
|
+
if (!targetModel) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
`${context} on model "${sourceModelName}" references unknown model "${targetModelName}"`,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
return targetModel;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function assertTargetTableMatches(
|
|
90
|
+
sourceModelName: string,
|
|
91
|
+
targetModel: ModelNode,
|
|
92
|
+
referencedTableName: string,
|
|
93
|
+
context: string,
|
|
94
|
+
): void {
|
|
95
|
+
if (targetModel.tableName !== referencedTableName) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
`${context} on model "${sourceModelName}" references table "${referencedTableName}" but model "${targetModel.modelName}" maps to "${targetModel.tableName}"`,
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function isValueObjectField(
|
|
103
|
+
field: FieldNode | ValueObjectFieldNode,
|
|
104
|
+
): field is ValueObjectFieldNode {
|
|
105
|
+
return 'valueObjectName' in field;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const JSONB_CODEC_ID = 'pg/jsonb@1';
|
|
109
|
+
const JSONB_NATIVE_TYPE = 'jsonb';
|
|
110
|
+
|
|
111
|
+
function buildStorageColumn(
|
|
112
|
+
field: FieldNode | ValueObjectFieldNode,
|
|
113
|
+
codecLookup?: CodecLookup,
|
|
114
|
+
): StorageColumn {
|
|
115
|
+
if (isValueObjectField(field)) {
|
|
116
|
+
const encodedDefault =
|
|
117
|
+
field.default !== undefined
|
|
118
|
+
? encodeColumnDefault(field.default, JSONB_CODEC_ID, codecLookup)
|
|
119
|
+
: undefined;
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
nativeType: JSONB_NATIVE_TYPE,
|
|
123
|
+
codecId: JSONB_CODEC_ID,
|
|
124
|
+
nullable: field.nullable,
|
|
125
|
+
...ifDefined('default', encodedDefault),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (field.many) {
|
|
130
|
+
return {
|
|
131
|
+
nativeType: JSONB_NATIVE_TYPE,
|
|
132
|
+
codecId: JSONB_CODEC_ID,
|
|
133
|
+
nullable: field.nullable,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const codecId = field.descriptor.codecId;
|
|
138
|
+
const encodedDefault =
|
|
139
|
+
field.default !== undefined
|
|
140
|
+
? encodeColumnDefault(field.default, codecId, codecLookup)
|
|
141
|
+
: undefined;
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
nativeType: field.descriptor.nativeType,
|
|
145
|
+
codecId,
|
|
146
|
+
nullable: field.nullable,
|
|
147
|
+
...ifDefined('typeParams', field.descriptor.typeParams),
|
|
148
|
+
...ifDefined('default', encodedDefault),
|
|
149
|
+
...ifDefined('typeRef', field.descriptor.typeRef),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function buildDomainField(
|
|
154
|
+
field: FieldNode | ValueObjectFieldNode,
|
|
155
|
+
column: StorageColumn,
|
|
156
|
+
): ContractField {
|
|
157
|
+
if (isValueObjectField(field)) {
|
|
158
|
+
return {
|
|
159
|
+
type: { kind: 'valueObject', name: field.valueObjectName },
|
|
160
|
+
nullable: field.nullable,
|
|
161
|
+
...(field.many ? { many: true } : {}),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
type: {
|
|
167
|
+
kind: 'scalar',
|
|
168
|
+
codecId: column.codecId,
|
|
169
|
+
...ifDefined('typeParams', column.typeParams),
|
|
170
|
+
},
|
|
171
|
+
nullable: column.nullable,
|
|
172
|
+
...(field.many ? { many: true } : {}),
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function buildSqlContractFromDefinition(
|
|
177
|
+
definition: ContractDefinition,
|
|
178
|
+
codecLookup?: CodecLookup,
|
|
179
|
+
): Contract<SqlStorage> {
|
|
180
|
+
const target = definition.target.targetId;
|
|
181
|
+
const targetFamily = 'sql';
|
|
182
|
+
const modelsByName = new Map(definition.models.map((m) => [m.modelName, m]));
|
|
183
|
+
|
|
184
|
+
const storageTables: Record<string, StorageTable> = {};
|
|
185
|
+
const executionDefaults: ExecutionMutationDefault[] = [];
|
|
186
|
+
const models: Record<string, ContractModel> = {};
|
|
187
|
+
const roots: Record<string, string> = {};
|
|
188
|
+
|
|
189
|
+
for (const semanticModel of definition.models) {
|
|
190
|
+
const tableName = semanticModel.tableName;
|
|
191
|
+
roots[tableName] = semanticModel.modelName;
|
|
192
|
+
|
|
193
|
+
// --- Build storage table ---
|
|
194
|
+
|
|
195
|
+
const columns: Record<string, StorageColumn> = {};
|
|
196
|
+
const fieldToColumn: Record<string, string> = {};
|
|
197
|
+
const domainFields: Record<string, ContractField> = {};
|
|
198
|
+
const domainFieldRefs: Record<string, DomainFieldRef> = {};
|
|
199
|
+
|
|
200
|
+
for (const field of semanticModel.fields) {
|
|
201
|
+
if (field.executionDefault) {
|
|
202
|
+
if (field.default !== undefined) {
|
|
203
|
+
throw new Error(
|
|
204
|
+
`Field "${semanticModel.modelName}.${field.fieldName}" cannot define both default and executionDefault.`,
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
if (field.nullable) {
|
|
208
|
+
throw new Error(
|
|
209
|
+
`Field "${semanticModel.modelName}.${field.fieldName}" cannot be nullable when executionDefault is present.`,
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const column = buildStorageColumn(field, codecLookup);
|
|
215
|
+
columns[field.columnName] = column;
|
|
216
|
+
fieldToColumn[field.fieldName] = field.columnName;
|
|
217
|
+
|
|
218
|
+
domainFields[field.fieldName] = buildDomainField(field, column);
|
|
219
|
+
|
|
220
|
+
if (isValueObjectField(field)) {
|
|
221
|
+
domainFieldRefs[field.fieldName] = {
|
|
222
|
+
kind: 'valueObject',
|
|
223
|
+
name: field.valueObjectName,
|
|
224
|
+
...(field.many ? { many: true } : {}),
|
|
225
|
+
};
|
|
226
|
+
} else if (field.many) {
|
|
227
|
+
domainFieldRefs[field.fieldName] = { kind: 'scalar', many: true };
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if ('executionDefault' in field && field.executionDefault) {
|
|
231
|
+
executionDefaults.push({
|
|
232
|
+
ref: { table: tableName, column: field.columnName },
|
|
233
|
+
onCreate: field.executionDefault as ExecutionMutationDefaultValue,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (semanticModel.id) {
|
|
239
|
+
const fieldsByColumnName = new Map(
|
|
240
|
+
semanticModel.fields.map((field) => [field.columnName, field]),
|
|
241
|
+
);
|
|
242
|
+
for (const columnName of semanticModel.id.columns) {
|
|
243
|
+
const field = fieldsByColumnName.get(columnName);
|
|
244
|
+
if (field?.nullable) {
|
|
245
|
+
throw new Error(
|
|
246
|
+
`Model "${semanticModel.modelName}" uses nullable field "${field.fieldName}" in its identity.`,
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const foreignKeys = (semanticModel.foreignKeys ?? []).map((fk) => {
|
|
253
|
+
const targetModel = assertKnownTargetModel(
|
|
254
|
+
modelsByName,
|
|
255
|
+
semanticModel.modelName,
|
|
256
|
+
fk.references.model,
|
|
257
|
+
'Foreign key',
|
|
258
|
+
);
|
|
259
|
+
assertTargetTableMatches(
|
|
260
|
+
semanticModel.modelName,
|
|
261
|
+
targetModel,
|
|
262
|
+
fk.references.table,
|
|
263
|
+
'Foreign key',
|
|
264
|
+
);
|
|
265
|
+
return {
|
|
266
|
+
columns: fk.columns,
|
|
267
|
+
references: { table: fk.references.table, columns: fk.references.columns },
|
|
268
|
+
...applyFkDefaults(
|
|
269
|
+
{
|
|
270
|
+
...ifDefined('constraint', fk.constraint),
|
|
271
|
+
...ifDefined('index', fk.index),
|
|
272
|
+
},
|
|
273
|
+
definition.foreignKeyDefaults,
|
|
274
|
+
),
|
|
275
|
+
...ifDefined('name', fk.name),
|
|
276
|
+
...ifDefined('onDelete', fk.onDelete),
|
|
277
|
+
...ifDefined('onUpdate', fk.onUpdate),
|
|
278
|
+
};
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
storageTables[tableName] = {
|
|
282
|
+
columns,
|
|
283
|
+
uniques: (semanticModel.uniques ?? []).map((u) => ({
|
|
284
|
+
columns: u.columns,
|
|
285
|
+
...ifDefined('name', u.name),
|
|
286
|
+
})),
|
|
287
|
+
indexes: (semanticModel.indexes ?? []).map((i) => ({
|
|
288
|
+
columns: i.columns,
|
|
289
|
+
...ifDefined('name', i.name),
|
|
290
|
+
...ifDefined('using', i.using),
|
|
291
|
+
...ifDefined('config', i.config),
|
|
292
|
+
})),
|
|
293
|
+
foreignKeys,
|
|
294
|
+
...(semanticModel.id
|
|
295
|
+
? {
|
|
296
|
+
primaryKey: {
|
|
297
|
+
columns: semanticModel.id.columns,
|
|
298
|
+
...ifDefined('name', semanticModel.id.name),
|
|
299
|
+
},
|
|
300
|
+
}
|
|
301
|
+
: {}),
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
// --- Build contract model ---
|
|
305
|
+
|
|
306
|
+
const storageFields: Record<string, { readonly column: string }> = {};
|
|
307
|
+
for (const [fieldName, columnName] of Object.entries(fieldToColumn)) {
|
|
308
|
+
storageFields[fieldName] = { column: columnName };
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const columnToField = new Map(
|
|
312
|
+
Object.entries(fieldToColumn).map(([field, col]) => [col, field]),
|
|
313
|
+
);
|
|
314
|
+
const modelRelations: Record<string, ContractRelation> = {};
|
|
315
|
+
for (const relation of semanticModel.relations ?? []) {
|
|
316
|
+
const targetModel = assertKnownTargetModel(
|
|
317
|
+
modelsByName,
|
|
318
|
+
semanticModel.modelName,
|
|
319
|
+
relation.toModel,
|
|
320
|
+
'Relation',
|
|
321
|
+
);
|
|
322
|
+
assertTargetTableMatches(semanticModel.modelName, targetModel, relation.toTable, 'Relation');
|
|
323
|
+
|
|
324
|
+
if (relation.cardinality === 'N:M' && !relation.through) {
|
|
325
|
+
throw new Error(
|
|
326
|
+
`Relation "${semanticModel.modelName}.${relation.fieldName}" with cardinality "N:M" requires through metadata`,
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const targetColumnToField = new Map(
|
|
331
|
+
targetModel.fields.map((f) => [f.columnName, f.fieldName]),
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
modelRelations[relation.fieldName] = {
|
|
335
|
+
to: relation.toModel,
|
|
336
|
+
// RelationDefinition.cardinality includes 'N:M' which isn't in
|
|
337
|
+
// ContractReferenceRelation yet — cast is needed until the contract
|
|
338
|
+
// type is extended to cover many-to-many.
|
|
339
|
+
cardinality: relation.cardinality as ContractRelation['cardinality'],
|
|
340
|
+
on: {
|
|
341
|
+
localFields: relation.on.parentColumns.map((col) => columnToField.get(col) ?? col),
|
|
342
|
+
targetFields: relation.on.childColumns.map((col) => targetColumnToField.get(col) ?? col),
|
|
343
|
+
},
|
|
344
|
+
...(relation.through
|
|
345
|
+
? {
|
|
346
|
+
through: {
|
|
347
|
+
table: relation.through.table,
|
|
348
|
+
parentCols: relation.through.parentColumns,
|
|
349
|
+
childCols: relation.through.childColumns,
|
|
350
|
+
},
|
|
351
|
+
}
|
|
352
|
+
: undefined),
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
models[semanticModel.modelName] = {
|
|
357
|
+
storage: {
|
|
358
|
+
table: tableName,
|
|
359
|
+
fields: storageFields,
|
|
360
|
+
},
|
|
361
|
+
fields: domainFields,
|
|
362
|
+
relations: modelRelations,
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// --- Assemble contract ---
|
|
367
|
+
|
|
368
|
+
const storageTypes = (definition.storageTypes ?? {}) as Record<string, StorageTypeInstance>;
|
|
369
|
+
const storageWithoutHash = {
|
|
370
|
+
tables: storageTables,
|
|
371
|
+
types: storageTypes,
|
|
372
|
+
};
|
|
373
|
+
const storageHash: StorageHashBase<string> = definition.storageHash
|
|
374
|
+
? coreHash(definition.storageHash)
|
|
375
|
+
: computeStorageHash({ target, targetFamily, storage: storageWithoutHash });
|
|
376
|
+
const storage: SqlStorage = { ...storageWithoutHash, storageHash };
|
|
377
|
+
|
|
378
|
+
const executionSection =
|
|
379
|
+
executionDefaults.length > 0
|
|
380
|
+
? {
|
|
381
|
+
mutations: {
|
|
382
|
+
defaults: executionDefaults.sort((a, b) => {
|
|
383
|
+
const tableCompare = a.ref.table.localeCompare(b.ref.table);
|
|
384
|
+
if (tableCompare !== 0) {
|
|
385
|
+
return tableCompare;
|
|
386
|
+
}
|
|
387
|
+
return a.ref.column.localeCompare(b.ref.column);
|
|
388
|
+
}),
|
|
389
|
+
},
|
|
390
|
+
}
|
|
391
|
+
: undefined;
|
|
392
|
+
|
|
393
|
+
const extensionNamespaces = definition.extensionPacks
|
|
394
|
+
? Object.values(definition.extensionPacks).map((pack) => pack.id)
|
|
395
|
+
: undefined;
|
|
396
|
+
|
|
397
|
+
const extensionPacks: Record<string, unknown> = { ...(definition.extensionPacks || {}) };
|
|
398
|
+
if (extensionNamespaces) {
|
|
399
|
+
for (const namespace of extensionNamespaces) {
|
|
400
|
+
if (!Object.hasOwn(extensionPacks, namespace)) {
|
|
401
|
+
extensionPacks[namespace] = {};
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const capabilities: Record<string, Record<string, boolean>> = definition.capabilities || {};
|
|
407
|
+
const profileHash = computeProfileHash({ target, targetFamily, capabilities });
|
|
408
|
+
|
|
409
|
+
const executionWithHash = executionSection
|
|
410
|
+
? {
|
|
411
|
+
...executionSection,
|
|
412
|
+
executionHash: computeExecutionHash({ target, targetFamily, execution: executionSection }),
|
|
413
|
+
}
|
|
414
|
+
: undefined;
|
|
415
|
+
|
|
416
|
+
const valueObjects: Record<string, ContractValueObject> | undefined =
|
|
417
|
+
definition.valueObjects && definition.valueObjects.length > 0
|
|
418
|
+
? Object.fromEntries(
|
|
419
|
+
definition.valueObjects.map((vo) => [
|
|
420
|
+
vo.name,
|
|
421
|
+
{
|
|
422
|
+
fields: Object.fromEntries(
|
|
423
|
+
vo.fields.map((f) => [
|
|
424
|
+
f.fieldName,
|
|
425
|
+
isValueObjectField(f)
|
|
426
|
+
? {
|
|
427
|
+
type: { kind: 'valueObject' as const, name: f.valueObjectName },
|
|
428
|
+
nullable: f.nullable,
|
|
429
|
+
...(f.many ? { many: true } : {}),
|
|
430
|
+
}
|
|
431
|
+
: {
|
|
432
|
+
type: {
|
|
433
|
+
kind: 'scalar' as const,
|
|
434
|
+
codecId: f.descriptor.codecId,
|
|
435
|
+
...ifDefined('typeParams', f.descriptor.typeParams),
|
|
436
|
+
},
|
|
437
|
+
nullable: f.nullable,
|
|
438
|
+
},
|
|
439
|
+
]),
|
|
440
|
+
),
|
|
441
|
+
},
|
|
442
|
+
]),
|
|
443
|
+
)
|
|
444
|
+
: undefined;
|
|
445
|
+
|
|
446
|
+
const contract: Contract<SqlStorage> = {
|
|
447
|
+
target,
|
|
448
|
+
targetFamily,
|
|
449
|
+
models,
|
|
450
|
+
roots,
|
|
451
|
+
storage,
|
|
452
|
+
...(executionWithHash ? { execution: executionWithHash } : {}),
|
|
453
|
+
...ifDefined('valueObjects', valueObjects),
|
|
454
|
+
extensionPacks,
|
|
455
|
+
capabilities,
|
|
456
|
+
profileHash,
|
|
457
|
+
meta: {},
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
assertStorageSemantics(contract.storage);
|
|
461
|
+
|
|
462
|
+
return contract;
|
|
463
|
+
}
|