@prisma-next/sql-contract-ts 0.3.0-dev.34 → 0.3.0-dev.36
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/README.md +8 -11
- package/dist/contract-builder.d.mts +105 -0
- package/dist/contract-builder.d.mts.map +1 -0
- package/dist/contract-builder.mjs +344 -0
- package/dist/contract-builder.mjs.map +1 -0
- package/package.json +23 -15
- package/schemas/data-contract-sql-v1.json +106 -3
- package/src/contract-builder.ts +140 -25
- package/src/contract.ts +50 -7
- 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 -232
- 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/exports/contract.ts +0 -1
package/src/contract-builder.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { ExtensionPackRef, TargetPackRef } from '@prisma-next/contract/framework-components';
|
|
2
|
+
import type { ExecutionMutationDefault } from '@prisma-next/contract/types';
|
|
2
3
|
import type {
|
|
3
4
|
ColumnBuilderState,
|
|
5
|
+
ContractBuilderState,
|
|
4
6
|
ModelBuilderState,
|
|
5
7
|
RelationDefinition,
|
|
6
8
|
TableBuilderState,
|
|
@@ -23,7 +25,9 @@ import type {
|
|
|
23
25
|
SqlContract,
|
|
24
26
|
SqlMappings,
|
|
25
27
|
SqlStorage,
|
|
28
|
+
StorageTypeInstance,
|
|
26
29
|
} from '@prisma-next/sql-contract/types';
|
|
30
|
+
import { ifDefined } from '@prisma-next/utils/defined';
|
|
27
31
|
import { computeMappings } from './contract';
|
|
28
32
|
|
|
29
33
|
/**
|
|
@@ -33,8 +37,8 @@ import { computeMappings } from './contract';
|
|
|
33
37
|
* produces. `codecTypes` uses the generic `CodecTypes` parameter; `operationTypes` is always
|
|
34
38
|
* empty since operations are added via extensions at runtime.
|
|
35
39
|
*
|
|
36
|
-
* **Difference from
|
|
37
|
-
* `
|
|
40
|
+
* **Difference from ExecutionContext**: This is a compile-time type for contract construction.
|
|
41
|
+
* `ExecutionContext` is a runtime object with populated registries for query execution.
|
|
38
42
|
*
|
|
39
43
|
* @template C - The `CodecTypes` generic parameter passed to `defineContract<CodecTypes>()`
|
|
40
44
|
*/
|
|
@@ -80,6 +84,7 @@ type BuildStorage<
|
|
|
80
84
|
readonly string[] | undefined
|
|
81
85
|
>
|
|
82
86
|
>,
|
|
87
|
+
Types extends Record<string, StorageTypeInstance>,
|
|
83
88
|
> = {
|
|
84
89
|
readonly tables: {
|
|
85
90
|
readonly [K in keyof Tables]: BuildStorageTable<
|
|
@@ -88,6 +93,7 @@ type BuildStorage<
|
|
|
88
93
|
ExtractPrimaryKey<Tables[K]>
|
|
89
94
|
>;
|
|
90
95
|
};
|
|
96
|
+
readonly types: Types;
|
|
91
97
|
};
|
|
92
98
|
|
|
93
99
|
type BuildStorageTables<
|
|
@@ -128,10 +134,21 @@ class SqlContractBuilder<
|
|
|
128
134
|
string,
|
|
129
135
|
ModelBuilderState<string, string, Record<string, string>, Record<string, RelationDefinition>>
|
|
130
136
|
> = Record<never, never>,
|
|
131
|
-
|
|
137
|
+
Types extends Record<string, StorageTypeInstance> = Record<never, never>,
|
|
138
|
+
StorageHash extends string | undefined = undefined,
|
|
132
139
|
ExtensionPacks extends Record<string, unknown> | undefined = undefined,
|
|
133
140
|
Capabilities extends Record<string, Record<string, boolean>> | undefined = undefined,
|
|
134
|
-
> extends ContractBuilder<Target, Tables, Models,
|
|
141
|
+
> extends ContractBuilder<Target, Tables, Models, StorageHash, ExtensionPacks, Capabilities> {
|
|
142
|
+
protected declare readonly state: ContractBuilderState<
|
|
143
|
+
Target,
|
|
144
|
+
Tables,
|
|
145
|
+
Models,
|
|
146
|
+
StorageHash,
|
|
147
|
+
ExtensionPacks,
|
|
148
|
+
Capabilities
|
|
149
|
+
> & {
|
|
150
|
+
readonly storageTypes?: Types;
|
|
151
|
+
};
|
|
135
152
|
/**
|
|
136
153
|
* This method is responsible for normalizing the contract IR by setting default values
|
|
137
154
|
* for all required fields:
|
|
@@ -152,7 +169,7 @@ class SqlContractBuilder<
|
|
|
152
169
|
*/
|
|
153
170
|
build(): Target extends string
|
|
154
171
|
? SqlContract<
|
|
155
|
-
BuildStorage<Tables>,
|
|
172
|
+
BuildStorage<Tables, Types>,
|
|
156
173
|
BuildModels<Models>,
|
|
157
174
|
BuildRelations<Models>,
|
|
158
175
|
ContractBuilderMappings<CodecTypes>
|
|
@@ -160,7 +177,7 @@ class SqlContractBuilder<
|
|
|
160
177
|
readonly schemaVersion: '1';
|
|
161
178
|
readonly target: Target;
|
|
162
179
|
readonly targetFamily: 'sql';
|
|
163
|
-
readonly
|
|
180
|
+
readonly storageHash: StorageHash extends string ? StorageHash : string;
|
|
164
181
|
} & (ExtensionPacks extends Record<string, unknown>
|
|
165
182
|
? { readonly extensionPacks: ExtensionPacks }
|
|
166
183
|
: Record<string, never>) &
|
|
@@ -171,7 +188,7 @@ class SqlContractBuilder<
|
|
|
171
188
|
// Type helper to ensure literal types are preserved in return type
|
|
172
189
|
type BuiltContract = Target extends string
|
|
173
190
|
? SqlContract<
|
|
174
|
-
BuildStorage<Tables>,
|
|
191
|
+
BuildStorage<Tables, Types>,
|
|
175
192
|
BuildModels<Models>,
|
|
176
193
|
BuildRelations<Models>,
|
|
177
194
|
ContractBuilderMappings<CodecTypes>
|
|
@@ -179,7 +196,7 @@ class SqlContractBuilder<
|
|
|
179
196
|
readonly schemaVersion: '1';
|
|
180
197
|
readonly target: Target;
|
|
181
198
|
readonly targetFamily: 'sql';
|
|
182
|
-
readonly
|
|
199
|
+
readonly storageHash: StorageHash extends string ? StorageHash : string;
|
|
183
200
|
} & (ExtensionPacks extends Record<string, unknown>
|
|
184
201
|
? { readonly extensionPacks: ExtensionPacks }
|
|
185
202
|
: Record<string, never>) &
|
|
@@ -194,6 +211,7 @@ class SqlContractBuilder<
|
|
|
194
211
|
const target = this.state.target as Target & string;
|
|
195
212
|
|
|
196
213
|
const storageTables = {} as Partial<Mutable<BuildStorageTables<Tables>>>;
|
|
214
|
+
const executionDefaults: ExecutionMutationDefault[] = [];
|
|
197
215
|
|
|
198
216
|
for (const tableName of Object.keys(this.state.tables) as Array<keyof Tables & string>) {
|
|
199
217
|
const tableState = this.state.tables[tableName];
|
|
@@ -215,17 +233,27 @@ class SqlContractBuilder<
|
|
|
215
233
|
if (!columnState) continue;
|
|
216
234
|
const codecId = columnState.type;
|
|
217
235
|
const nativeType = columnState.nativeType;
|
|
236
|
+
const typeRef = columnState.typeRef;
|
|
218
237
|
|
|
219
238
|
columns[columnName as keyof ColumnDefs] = {
|
|
220
239
|
nativeType,
|
|
221
240
|
codecId,
|
|
222
241
|
nullable: (columnState.nullable ?? false) as ColumnDefs[keyof ColumnDefs]['nullable'] &
|
|
223
242
|
boolean,
|
|
224
|
-
...(
|
|
243
|
+
...ifDefined('typeParams', columnState.typeParams),
|
|
244
|
+
...ifDefined('default', columnState.default),
|
|
245
|
+
...ifDefined('typeRef', typeRef),
|
|
225
246
|
} as BuildStorageColumn<
|
|
226
247
|
ColumnDefs[keyof ColumnDefs]['nullable'] & boolean,
|
|
227
248
|
ColumnDefs[keyof ColumnDefs]['type']
|
|
228
249
|
>;
|
|
250
|
+
|
|
251
|
+
if ('executionDefault' in columnState && columnState.executionDefault) {
|
|
252
|
+
executionDefaults.push({
|
|
253
|
+
ref: { table: tableName, column: columnName },
|
|
254
|
+
onCreate: columnState.executionDefault,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
229
257
|
}
|
|
230
258
|
|
|
231
259
|
// Build uniques from table state
|
|
@@ -270,7 +298,26 @@ class SqlContractBuilder<
|
|
|
270
298
|
(storageTables as Mutable<BuildStorageTables<Tables>>)[tableName] = table;
|
|
271
299
|
}
|
|
272
300
|
|
|
273
|
-
const
|
|
301
|
+
const storageTypes = (this.state.storageTypes ?? {}) as Types;
|
|
302
|
+
const storage: BuildStorage<Tables, Types> = {
|
|
303
|
+
tables: storageTables as BuildStorageTables<Tables>,
|
|
304
|
+
types: storageTypes,
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
const execution =
|
|
308
|
+
executionDefaults.length > 0
|
|
309
|
+
? {
|
|
310
|
+
mutations: {
|
|
311
|
+
defaults: executionDefaults.sort((a, b) => {
|
|
312
|
+
const tableCompare = a.ref.table.localeCompare(b.ref.table);
|
|
313
|
+
if (tableCompare !== 0) {
|
|
314
|
+
return tableCompare;
|
|
315
|
+
}
|
|
316
|
+
return a.ref.column.localeCompare(b.ref.column);
|
|
317
|
+
}),
|
|
318
|
+
},
|
|
319
|
+
}
|
|
320
|
+
: undefined;
|
|
274
321
|
|
|
275
322
|
// Build models - construct as partial first, then assert full type
|
|
276
323
|
const modelsPartial: Partial<BuildModels<Models>> = {};
|
|
@@ -374,11 +421,12 @@ class SqlContractBuilder<
|
|
|
374
421
|
schemaVersion: '1' as const,
|
|
375
422
|
target,
|
|
376
423
|
targetFamily: 'sql' as const,
|
|
377
|
-
|
|
424
|
+
storageHash: this.state.storageHash || 'sha256:ts-builder-placeholder',
|
|
378
425
|
models,
|
|
379
426
|
relations: relationsPartial,
|
|
380
427
|
storage,
|
|
381
428
|
mappings,
|
|
429
|
+
...(execution ? { execution } : {}),
|
|
382
430
|
extensionPacks,
|
|
383
431
|
capabilities: this.state.capabilities || {},
|
|
384
432
|
meta: {},
|
|
@@ -391,7 +439,8 @@ class SqlContractBuilder<
|
|
|
391
439
|
Target,
|
|
392
440
|
Tables,
|
|
393
441
|
Models,
|
|
394
|
-
|
|
442
|
+
Types,
|
|
443
|
+
StorageHash,
|
|
395
444
|
ExtensionPacks,
|
|
396
445
|
Capabilities
|
|
397
446
|
>['build']
|
|
@@ -400,13 +449,23 @@ class SqlContractBuilder<
|
|
|
400
449
|
|
|
401
450
|
override target<T extends string>(
|
|
402
451
|
packRef: TargetPackRef<'sql', T>,
|
|
403
|
-
): SqlContractBuilder<
|
|
452
|
+
): SqlContractBuilder<
|
|
453
|
+
CodecTypes,
|
|
454
|
+
T,
|
|
455
|
+
Tables,
|
|
456
|
+
Models,
|
|
457
|
+
Types,
|
|
458
|
+
StorageHash,
|
|
459
|
+
ExtensionPacks,
|
|
460
|
+
Capabilities
|
|
461
|
+
> {
|
|
404
462
|
return new SqlContractBuilder<
|
|
405
463
|
CodecTypes,
|
|
406
464
|
T,
|
|
407
465
|
Tables,
|
|
408
466
|
Models,
|
|
409
|
-
|
|
467
|
+
Types,
|
|
468
|
+
StorageHash,
|
|
410
469
|
ExtensionPacks,
|
|
411
470
|
Capabilities
|
|
412
471
|
>({
|
|
@@ -422,7 +481,8 @@ class SqlContractBuilder<
|
|
|
422
481
|
Target,
|
|
423
482
|
Tables,
|
|
424
483
|
Models,
|
|
425
|
-
|
|
484
|
+
Types,
|
|
485
|
+
StorageHash,
|
|
426
486
|
ExtensionPacks,
|
|
427
487
|
Capabilities
|
|
428
488
|
> {
|
|
@@ -461,7 +521,8 @@ class SqlContractBuilder<
|
|
|
461
521
|
Target,
|
|
462
522
|
Tables,
|
|
463
523
|
Models,
|
|
464
|
-
|
|
524
|
+
Types,
|
|
525
|
+
StorageHash,
|
|
465
526
|
ExtensionPacks,
|
|
466
527
|
Capabilities
|
|
467
528
|
>({
|
|
@@ -472,27 +533,46 @@ class SqlContractBuilder<
|
|
|
472
533
|
|
|
473
534
|
override capabilities<C extends Record<string, Record<string, boolean>>>(
|
|
474
535
|
capabilities: C,
|
|
475
|
-
): SqlContractBuilder<CodecTypes, Target, Tables, Models,
|
|
476
|
-
return new SqlContractBuilder<
|
|
536
|
+
): SqlContractBuilder<CodecTypes, Target, Tables, Models, Types, StorageHash, ExtensionPacks, C> {
|
|
537
|
+
return new SqlContractBuilder<
|
|
538
|
+
CodecTypes,
|
|
539
|
+
Target,
|
|
540
|
+
Tables,
|
|
541
|
+
Models,
|
|
542
|
+
Types,
|
|
543
|
+
StorageHash,
|
|
544
|
+
ExtensionPacks,
|
|
545
|
+
C
|
|
546
|
+
>({
|
|
477
547
|
...this.state,
|
|
478
548
|
capabilities,
|
|
479
549
|
});
|
|
480
550
|
}
|
|
481
551
|
|
|
482
|
-
override
|
|
552
|
+
override storageHash<H extends string>(
|
|
483
553
|
hash: H,
|
|
484
|
-
): SqlContractBuilder<
|
|
554
|
+
): SqlContractBuilder<
|
|
555
|
+
CodecTypes,
|
|
556
|
+
Target,
|
|
557
|
+
Tables,
|
|
558
|
+
Models,
|
|
559
|
+
Types,
|
|
560
|
+
H,
|
|
561
|
+
ExtensionPacks,
|
|
562
|
+
Capabilities
|
|
563
|
+
> {
|
|
485
564
|
return new SqlContractBuilder<
|
|
486
565
|
CodecTypes,
|
|
487
566
|
Target,
|
|
488
567
|
Tables,
|
|
489
568
|
Models,
|
|
569
|
+
Types,
|
|
490
570
|
H,
|
|
491
571
|
ExtensionPacks,
|
|
492
572
|
Capabilities
|
|
493
573
|
>({
|
|
494
574
|
...this.state,
|
|
495
|
-
|
|
575
|
+
storageHash: hash,
|
|
496
576
|
});
|
|
497
577
|
}
|
|
498
578
|
|
|
@@ -511,7 +591,8 @@ class SqlContractBuilder<
|
|
|
511
591
|
Target,
|
|
512
592
|
Tables & Record<TableName, ReturnType<T['build']>>,
|
|
513
593
|
Models,
|
|
514
|
-
|
|
594
|
+
Types,
|
|
595
|
+
StorageHash,
|
|
515
596
|
ExtensionPacks,
|
|
516
597
|
Capabilities
|
|
517
598
|
> {
|
|
@@ -525,7 +606,8 @@ class SqlContractBuilder<
|
|
|
525
606
|
Target,
|
|
526
607
|
Tables & Record<TableName, ReturnType<T['build']>>,
|
|
527
608
|
Models,
|
|
528
|
-
|
|
609
|
+
Types,
|
|
610
|
+
StorageHash,
|
|
529
611
|
ExtensionPacks,
|
|
530
612
|
Capabilities
|
|
531
613
|
>({
|
|
@@ -555,7 +637,8 @@ class SqlContractBuilder<
|
|
|
555
637
|
Target,
|
|
556
638
|
Tables,
|
|
557
639
|
Models & Record<ModelName, ReturnType<M['build']>>,
|
|
558
|
-
|
|
640
|
+
Types,
|
|
641
|
+
StorageHash,
|
|
559
642
|
ExtensionPacks,
|
|
560
643
|
Capabilities
|
|
561
644
|
> {
|
|
@@ -569,7 +652,8 @@ class SqlContractBuilder<
|
|
|
569
652
|
Target,
|
|
570
653
|
Tables,
|
|
571
654
|
Models & Record<ModelName, ReturnType<M['build']>>,
|
|
572
|
-
|
|
655
|
+
Types,
|
|
656
|
+
StorageHash,
|
|
573
657
|
ExtensionPacks,
|
|
574
658
|
Capabilities
|
|
575
659
|
>({
|
|
@@ -578,6 +662,37 @@ class SqlContractBuilder<
|
|
|
578
662
|
Record<ModelName, ReturnType<M['build']>>,
|
|
579
663
|
});
|
|
580
664
|
}
|
|
665
|
+
|
|
666
|
+
storageType<Name extends string, Type extends StorageTypeInstance>(
|
|
667
|
+
name: Name,
|
|
668
|
+
typeInstance: Type,
|
|
669
|
+
): SqlContractBuilder<
|
|
670
|
+
CodecTypes,
|
|
671
|
+
Target,
|
|
672
|
+
Tables,
|
|
673
|
+
Models,
|
|
674
|
+
Types & Record<Name, Type>,
|
|
675
|
+
StorageHash,
|
|
676
|
+
ExtensionPacks,
|
|
677
|
+
Capabilities
|
|
678
|
+
> {
|
|
679
|
+
return new SqlContractBuilder<
|
|
680
|
+
CodecTypes,
|
|
681
|
+
Target,
|
|
682
|
+
Tables,
|
|
683
|
+
Models,
|
|
684
|
+
Types & Record<Name, Type>,
|
|
685
|
+
StorageHash,
|
|
686
|
+
ExtensionPacks,
|
|
687
|
+
Capabilities
|
|
688
|
+
>({
|
|
689
|
+
...this.state,
|
|
690
|
+
storageTypes: {
|
|
691
|
+
...(this.state.storageTypes ?? {}),
|
|
692
|
+
[name]: typeInstance,
|
|
693
|
+
},
|
|
694
|
+
});
|
|
695
|
+
}
|
|
581
696
|
}
|
|
582
697
|
|
|
583
698
|
export function defineContract<
|
package/src/contract.ts
CHANGED
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
StorageTypeInstance,
|
|
15
15
|
UniqueConstraint,
|
|
16
16
|
} from '@prisma-next/sql-contract/types';
|
|
17
|
+
import { ColumnDefaultSchema } from '@prisma-next/sql-contract/validators';
|
|
17
18
|
import { type } from 'arktype';
|
|
18
19
|
import type { O } from 'ts-toolbelt';
|
|
19
20
|
|
|
@@ -21,12 +22,14 @@ import type { O } from 'ts-toolbelt';
|
|
|
21
22
|
* Structural validation schema for SqlContract using Arktype.
|
|
22
23
|
* This validates the shape and types of the contract structure.
|
|
23
24
|
*/
|
|
25
|
+
|
|
24
26
|
const StorageColumnSchema = type.declare<StorageColumn>().type({
|
|
25
27
|
nativeType: 'string',
|
|
26
28
|
codecId: 'string',
|
|
27
29
|
nullable: 'boolean',
|
|
28
30
|
'typeParams?': 'Record<string, unknown>',
|
|
29
31
|
'typeRef?': 'string',
|
|
32
|
+
'default?': ColumnDefaultSchema,
|
|
30
33
|
});
|
|
31
34
|
|
|
32
35
|
const StorageTypeInstanceSchema = type.declare<StorageTypeInstance>().type({
|
|
@@ -88,6 +91,27 @@ const ModelSchema = type.declare<ModelDefinition>().type({
|
|
|
88
91
|
relations: type({ '[string]': 'unknown' }),
|
|
89
92
|
});
|
|
90
93
|
|
|
94
|
+
const ExecutionMutationDefaultValueSchema = type({
|
|
95
|
+
kind: "'generator'",
|
|
96
|
+
id: "'ulid' | 'nanoid' | 'uuidv7' | 'uuidv4' | 'cuid2' | 'ksuid'",
|
|
97
|
+
'params?': 'Record<string, unknown>',
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const ExecutionMutationDefaultSchema = type({
|
|
101
|
+
ref: {
|
|
102
|
+
table: 'string',
|
|
103
|
+
column: 'string',
|
|
104
|
+
},
|
|
105
|
+
'onCreate?': ExecutionMutationDefaultValueSchema,
|
|
106
|
+
'onUpdate?': ExecutionMutationDefaultValueSchema,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const ExecutionSchema = type({
|
|
110
|
+
mutations: {
|
|
111
|
+
defaults: ExecutionMutationDefaultSchema.array().readonly(),
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
|
|
91
115
|
/**
|
|
92
116
|
* Complete SqlContract schema for structural validation.
|
|
93
117
|
* This validates the entire contract structure at once.
|
|
@@ -96,7 +120,8 @@ const SqlContractSchema = type({
|
|
|
96
120
|
'schemaVersion?': "'1'",
|
|
97
121
|
target: 'string',
|
|
98
122
|
targetFamily: "'sql'",
|
|
99
|
-
|
|
123
|
+
storageHash: 'string',
|
|
124
|
+
'executionHash?': 'string',
|
|
100
125
|
'profileHash?': 'string',
|
|
101
126
|
'capabilities?': 'Record<string, Record<string, boolean>>',
|
|
102
127
|
'extensionPacks?': 'Record<string, unknown>',
|
|
@@ -104,6 +129,7 @@ const SqlContractSchema = type({
|
|
|
104
129
|
'sources?': 'Record<string, unknown>',
|
|
105
130
|
models: type({ '[string]': ModelSchema }),
|
|
106
131
|
storage: StorageSchema,
|
|
132
|
+
'execution?': ExecutionSchema,
|
|
107
133
|
});
|
|
108
134
|
|
|
109
135
|
/**
|
|
@@ -198,13 +224,15 @@ export function computeMappings(
|
|
|
198
224
|
* This checks that references (e.g., foreign keys, primary keys, uniques) point to storage objects that already exist.
|
|
199
225
|
* Structural validation is expected to have already completed before this helper runs.
|
|
200
226
|
*
|
|
227
|
+
* Rule: keep this focused on structural consistency only; capability/feature
|
|
228
|
+
* gating (e.g., defaults.*) belongs in migration/runtime verification, not here.
|
|
229
|
+
*
|
|
201
230
|
* @param structurallyValidatedContract - The contract whose structure has already been validated
|
|
202
231
|
* @throws Error if logical validation fails
|
|
203
232
|
*/
|
|
204
233
|
function validateContractLogic(structurallyValidatedContract: SqlContract<SqlStorage>): void {
|
|
205
234
|
const { storage, models } = structurallyValidatedContract;
|
|
206
235
|
const tableNames = new Set(Object.keys(storage.tables));
|
|
207
|
-
const typeInstanceNames = new Set(Object.keys(storage.types ?? {}));
|
|
208
236
|
|
|
209
237
|
// Validate storage.types if present
|
|
210
238
|
if (storage.types) {
|
|
@@ -235,11 +263,26 @@ function validateContractLogic(structurallyValidatedContract: SqlContract<SqlSto
|
|
|
235
263
|
);
|
|
236
264
|
}
|
|
237
265
|
|
|
238
|
-
// Validate typeRef points to an existing storage.types key
|
|
239
|
-
if (column.typeRef !== undefined
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
266
|
+
// Validate typeRef points to an existing storage.types key and matches codecId/nativeType
|
|
267
|
+
if (column.typeRef !== undefined) {
|
|
268
|
+
const referencedType = storage.types?.[column.typeRef];
|
|
269
|
+
if (!referencedType) {
|
|
270
|
+
throw new Error(
|
|
271
|
+
`Column "${columnName}" in table "${tableName}" references non-existent type instance "${column.typeRef}" (not found in storage.types)`,
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (column.codecId !== referencedType.codecId) {
|
|
276
|
+
throw new Error(
|
|
277
|
+
`Column "${columnName}" in table "${tableName}" has codecId "${column.codecId}" but references type instance "${column.typeRef}" with codecId "${referencedType.codecId}"`,
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (column.nativeType !== referencedType.nativeType) {
|
|
282
|
+
throw new Error(
|
|
283
|
+
`Column "${columnName}" in table "${tableName}" has nativeType "${column.nativeType}" but references type instance "${column.typeRef}" with nativeType "${referencedType.nativeType}"`,
|
|
284
|
+
);
|
|
285
|
+
}
|
|
243
286
|
}
|
|
244
287
|
}
|
|
245
288
|
}
|