@prisma-next/sql-contract-ts 0.3.0-dev.5 → 0.3.0-dev.50

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.
@@ -1,6 +1,17 @@
1
1
  import type { ExtensionPackRef, TargetPackRef } from '@prisma-next/contract/framework-components';
2
+ import type {
3
+ ColumnDefault,
4
+ ColumnDefaultLiteralInputValue,
5
+ ColumnDefaultLiteralValue,
6
+ ExecutionMutationDefault,
7
+ ExecutionMutationDefaultValue,
8
+ TaggedRaw,
9
+ } from '@prisma-next/contract/types';
2
10
  import type {
3
11
  ColumnBuilderState,
12
+ ColumnTypeDescriptor,
13
+ ContractBuilderState,
14
+ ForeignKeyDefaultsState,
4
15
  ModelBuilderState,
5
16
  RelationDefinition,
6
17
  TableBuilderState,
@@ -10,21 +21,114 @@ import {
10
21
  type BuildRelations,
11
22
  type BuildStorageColumn,
12
23
  ContractBuilder,
24
+ createTable,
13
25
  type ExtractColumns,
14
26
  type ExtractPrimaryKey,
15
27
  ModelBuilder,
16
28
  type Mutable,
17
29
  TableBuilder,
18
30
  } from '@prisma-next/contract-authoring';
19
- import type {
20
- ModelDefinition,
21
- ModelField,
22
- SqlContract,
23
- SqlMappings,
24
- SqlStorage,
31
+ import {
32
+ applyFkDefaults,
33
+ type ModelDefinition,
34
+ type ModelField,
35
+ type ReferentialAction,
36
+ type SqlContract,
37
+ type SqlMappings,
38
+ type SqlStorage,
39
+ type StorageTypeInstance,
25
40
  } from '@prisma-next/sql-contract/types';
41
+ import { ifDefined } from '@prisma-next/utils/defined';
26
42
  import { computeMappings } from './contract';
27
43
 
44
+ type ColumnDefaultForCodec<
45
+ CodecTypes extends Record<string, { output: unknown }>,
46
+ CodecId extends string,
47
+ > =
48
+ | {
49
+ readonly kind: 'literal';
50
+ readonly value: CodecId extends keyof CodecTypes ? CodecTypes[CodecId]['output'] : unknown;
51
+ }
52
+ | { readonly kind: 'function'; readonly expression: string };
53
+
54
+ type SqlNullableColumnOptions<
55
+ Descriptor extends ColumnTypeDescriptor,
56
+ CodecTypes extends Record<string, { output: unknown }>,
57
+ > = {
58
+ readonly type: Descriptor;
59
+ readonly nullable: true;
60
+ readonly typeParams?: Record<string, unknown>;
61
+ readonly default?: ColumnDefaultForCodec<CodecTypes, Descriptor['codecId']>;
62
+ };
63
+
64
+ type SqlNonNullableColumnOptions<
65
+ Descriptor extends ColumnTypeDescriptor,
66
+ CodecTypes extends Record<string, { output: unknown }>,
67
+ > = {
68
+ readonly type: Descriptor;
69
+ readonly nullable?: false;
70
+ readonly typeParams?: Record<string, unknown>;
71
+ readonly default?: ColumnDefaultForCodec<CodecTypes, Descriptor['codecId']>;
72
+ };
73
+
74
+ type SqlGeneratedColumnOptions<
75
+ Descriptor extends ColumnTypeDescriptor,
76
+ CodecTypes extends Record<string, { output: unknown }>,
77
+ > = Omit<SqlNonNullableColumnOptions<Descriptor, CodecTypes>, 'default' | 'nullable'> & {
78
+ readonly nullable?: false;
79
+ readonly generated: ExecutionMutationDefaultValue;
80
+ };
81
+
82
+ type SqlColumnOptions<
83
+ Descriptor extends ColumnTypeDescriptor,
84
+ CodecTypes extends Record<string, { output: unknown }>,
85
+ > =
86
+ | SqlNullableColumnOptions<Descriptor, CodecTypes>
87
+ | SqlNonNullableColumnOptions<Descriptor, CodecTypes>;
88
+
89
+ export interface SqlTableBuilder<
90
+ Name extends string,
91
+ CodecTypes extends Record<string, { output: unknown }>,
92
+ Columns extends Record<string, ColumnBuilderState<string, boolean, string>> = Record<
93
+ never,
94
+ ColumnBuilderState<string, boolean, string>
95
+ >,
96
+ PrimaryKey extends readonly string[] | undefined = undefined,
97
+ > extends Omit<TableBuilder<Name, Columns, PrimaryKey>, 'column' | 'generated'> {
98
+ column<ColName extends string, Descriptor extends ColumnTypeDescriptor>(
99
+ name: ColName,
100
+ options: SqlNullableColumnOptions<Descriptor, CodecTypes>,
101
+ ): TableBuilder<
102
+ Name,
103
+ Columns & Record<ColName, ColumnBuilderState<ColName, true, Descriptor['codecId']>>,
104
+ PrimaryKey
105
+ >;
106
+ column<ColName extends string, Descriptor extends ColumnTypeDescriptor>(
107
+ name: ColName,
108
+ options: SqlNonNullableColumnOptions<Descriptor, CodecTypes>,
109
+ ): TableBuilder<
110
+ Name,
111
+ Columns & Record<ColName, ColumnBuilderState<ColName, false, Descriptor['codecId']>>,
112
+ PrimaryKey
113
+ >;
114
+ column<ColName extends string, Descriptor extends ColumnTypeDescriptor>(
115
+ name: ColName,
116
+ options: SqlColumnOptions<Descriptor, CodecTypes>,
117
+ ): TableBuilder<
118
+ Name,
119
+ Columns & Record<ColName, ColumnBuilderState<ColName, boolean, Descriptor['codecId']>>,
120
+ PrimaryKey
121
+ >;
122
+ generated<ColName extends string, Descriptor extends ColumnTypeDescriptor>(
123
+ name: ColName,
124
+ options: SqlGeneratedColumnOptions<Descriptor, CodecTypes>,
125
+ ): TableBuilder<
126
+ Name,
127
+ Columns & Record<ColName, ColumnBuilderState<ColName, false, Descriptor['codecId']>>,
128
+ PrimaryKey
129
+ >;
130
+ }
131
+
28
132
  /**
29
133
  * Type-level mappings structure for contracts built via `defineContract()`.
30
134
  *
@@ -32,8 +136,8 @@ import { computeMappings } from './contract';
32
136
  * produces. `codecTypes` uses the generic `CodecTypes` parameter; `operationTypes` is always
33
137
  * empty since operations are added via extensions at runtime.
34
138
  *
35
- * **Difference from RuntimeContext**: This is a compile-time type for contract construction.
36
- * `RuntimeContext` is a runtime object with populated registries for query execution.
139
+ * **Difference from ExecutionContext**: This is a compile-time type for contract construction.
140
+ * `ExecutionContext` is a runtime object with populated registries for query execution.
37
141
  *
38
142
  * @template C - The `CodecTypes` generic parameter passed to `defineContract<CodecTypes>()`
39
143
  */
@@ -59,11 +163,19 @@ type BuildStorageTable<
59
163
  ? BuildStorageColumn<Null & boolean, TType>
60
164
  : never;
61
165
  };
62
- readonly uniques: ReadonlyArray<never>;
63
- readonly indexes: ReadonlyArray<never>;
64
- readonly foreignKeys: ReadonlyArray<never>;
166
+ readonly uniques: ReadonlyArray<{ readonly columns: readonly string[]; readonly name?: string }>;
167
+ readonly indexes: ReadonlyArray<{ readonly columns: readonly string[]; readonly name?: string }>;
168
+ readonly foreignKeys: ReadonlyArray<{
169
+ readonly columns: readonly string[];
170
+ readonly references: { readonly table: string; readonly columns: readonly string[] };
171
+ readonly name?: string;
172
+ readonly onDelete?: ReferentialAction;
173
+ readonly onUpdate?: ReferentialAction;
174
+ readonly constraint: boolean;
175
+ readonly index: boolean;
176
+ }>;
65
177
  } & (PK extends readonly string[]
66
- ? { readonly primaryKey: { readonly columns: PK } }
178
+ ? { readonly primaryKey: { readonly columns: PK; readonly name?: string } }
67
179
  : Record<string, never>);
68
180
 
69
181
  type BuildStorage<
@@ -75,6 +187,7 @@ type BuildStorage<
75
187
  readonly string[] | undefined
76
188
  >
77
189
  >,
190
+ Types extends Record<string, StorageTypeInstance>,
78
191
  > = {
79
192
  readonly tables: {
80
193
  readonly [K in keyof Tables]: BuildStorageTable<
@@ -83,6 +196,7 @@ type BuildStorage<
83
196
  ExtractPrimaryKey<Tables[K]>
84
197
  >;
85
198
  };
199
+ readonly types: Types;
86
200
  };
87
201
 
88
202
  type BuildStorageTables<
@@ -108,6 +222,52 @@ export interface ColumnBuilder<Name extends string, Nullable extends boolean, Ty
108
222
  build(): ColumnBuilderState<Name, Nullable, Type>;
109
223
  }
110
224
 
225
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
226
+ if (typeof value !== 'object' || value === null) return false;
227
+ const proto = Object.getPrototypeOf(value);
228
+ return proto === Object.prototype || proto === null;
229
+ }
230
+
231
+ function isJsonValue(value: unknown): value is ColumnDefaultLiteralValue {
232
+ if (value === null) return true;
233
+ const valueType = typeof value;
234
+ if (valueType === 'string' || valueType === 'number' || valueType === 'boolean') return true;
235
+ if (Array.isArray(value)) {
236
+ return value.every((item) => isJsonValue(item));
237
+ }
238
+ if (isPlainObject(value)) {
239
+ return Object.values(value).every((item) => isJsonValue(item));
240
+ }
241
+ return false;
242
+ }
243
+
244
+ function encodeDefaultLiteralValue(
245
+ value: ColumnDefaultLiteralInputValue,
246
+ ): ColumnDefaultLiteralValue {
247
+ if (typeof value === 'bigint') {
248
+ return { $type: 'bigint', value: value.toString() };
249
+ }
250
+ if (value instanceof Date) {
251
+ return value.toISOString();
252
+ }
253
+ if (isJsonValue(value)) {
254
+ if (isPlainObject(value) && '$type' in value) {
255
+ return { $type: 'raw', value } satisfies TaggedRaw;
256
+ }
257
+ return value;
258
+ }
259
+ throw new Error(
260
+ 'Unsupported column default literal value: expected JSON-safe value, bigint, or Date.',
261
+ );
262
+ }
263
+
264
+ function encodeColumnDefault(defaultInput: ColumnDefault): ColumnDefault {
265
+ if (defaultInput.kind === 'function') {
266
+ return { kind: 'function', expression: defaultInput.expression };
267
+ }
268
+ return { kind: 'literal', value: encodeDefaultLiteralValue(defaultInput.value) };
269
+ }
270
+
111
271
  class SqlContractBuilder<
112
272
  CodecTypes extends Record<string, { output: unknown }> = Record<string, never>,
113
273
  Target extends string | undefined = undefined,
@@ -123,10 +283,21 @@ class SqlContractBuilder<
123
283
  string,
124
284
  ModelBuilderState<string, string, Record<string, string>, Record<string, RelationDefinition>>
125
285
  > = Record<never, never>,
126
- CoreHash extends string | undefined = undefined,
286
+ Types extends Record<string, StorageTypeInstance> = Record<never, never>,
287
+ StorageHash extends string | undefined = undefined,
127
288
  ExtensionPacks extends Record<string, unknown> | undefined = undefined,
128
289
  Capabilities extends Record<string, Record<string, boolean>> | undefined = undefined,
129
- > extends ContractBuilder<Target, Tables, Models, CoreHash, ExtensionPacks, Capabilities> {
290
+ > extends ContractBuilder<Target, Tables, Models, StorageHash, ExtensionPacks, Capabilities> {
291
+ protected declare readonly state: ContractBuilderState<
292
+ Target,
293
+ Tables,
294
+ Models,
295
+ StorageHash,
296
+ ExtensionPacks,
297
+ Capabilities
298
+ > & {
299
+ readonly storageTypes?: Types;
300
+ };
130
301
  /**
131
302
  * This method is responsible for normalizing the contract IR by setting default values
132
303
  * for all required fields:
@@ -147,7 +318,7 @@ class SqlContractBuilder<
147
318
  */
148
319
  build(): Target extends string
149
320
  ? SqlContract<
150
- BuildStorage<Tables>,
321
+ BuildStorage<Tables, Types>,
151
322
  BuildModels<Models>,
152
323
  BuildRelations<Models>,
153
324
  ContractBuilderMappings<CodecTypes>
@@ -155,7 +326,7 @@ class SqlContractBuilder<
155
326
  readonly schemaVersion: '1';
156
327
  readonly target: Target;
157
328
  readonly targetFamily: 'sql';
158
- readonly coreHash: CoreHash extends string ? CoreHash : string;
329
+ readonly storageHash: StorageHash extends string ? StorageHash : string;
159
330
  } & (ExtensionPacks extends Record<string, unknown>
160
331
  ? { readonly extensionPacks: ExtensionPacks }
161
332
  : Record<string, never>) &
@@ -166,7 +337,7 @@ class SqlContractBuilder<
166
337
  // Type helper to ensure literal types are preserved in return type
167
338
  type BuiltContract = Target extends string
168
339
  ? SqlContract<
169
- BuildStorage<Tables>,
340
+ BuildStorage<Tables, Types>,
170
341
  BuildModels<Models>,
171
342
  BuildRelations<Models>,
172
343
  ContractBuilderMappings<CodecTypes>
@@ -174,7 +345,7 @@ class SqlContractBuilder<
174
345
  readonly schemaVersion: '1';
175
346
  readonly target: Target;
176
347
  readonly targetFamily: 'sql';
177
- readonly coreHash: CoreHash extends string ? CoreHash : string;
348
+ readonly storageHash: StorageHash extends string ? StorageHash : string;
178
349
  } & (ExtensionPacks extends Record<string, unknown>
179
350
  ? { readonly extensionPacks: ExtensionPacks }
180
351
  : Record<string, never>) &
@@ -189,6 +360,7 @@ class SqlContractBuilder<
189
360
  const target = this.state.target as Target & string;
190
361
 
191
362
  const storageTables = {} as Partial<Mutable<BuildStorageTables<Tables>>>;
363
+ const executionDefaults: ExecutionMutationDefault[] = [];
192
364
 
193
365
  for (const tableName of Object.keys(this.state.tables) as Array<keyof Tables & string>) {
194
366
  const tableState = this.state.tables[tableName];
@@ -210,18 +382,56 @@ class SqlContractBuilder<
210
382
  if (!columnState) continue;
211
383
  const codecId = columnState.type;
212
384
  const nativeType = columnState.nativeType;
385
+ const typeRef = columnState.typeRef;
386
+
387
+ const encodedDefault =
388
+ columnState.default !== undefined
389
+ ? encodeColumnDefault(columnState.default as ColumnDefault)
390
+ : undefined;
213
391
 
214
392
  columns[columnName as keyof ColumnDefs] = {
215
393
  nativeType,
216
394
  codecId,
217
395
  nullable: (columnState.nullable ?? false) as ColumnDefs[keyof ColumnDefs]['nullable'] &
218
396
  boolean,
397
+ ...ifDefined('typeParams', columnState.typeParams),
398
+ ...ifDefined('default', encodedDefault),
399
+ ...ifDefined('typeRef', typeRef),
219
400
  } as BuildStorageColumn<
220
401
  ColumnDefs[keyof ColumnDefs]['nullable'] & boolean,
221
402
  ColumnDefs[keyof ColumnDefs]['type']
222
403
  >;
404
+
405
+ if ('executionDefault' in columnState && columnState.executionDefault) {
406
+ executionDefaults.push({
407
+ ref: { table: tableName, column: columnName },
408
+ onCreate: columnState.executionDefault,
409
+ });
410
+ }
223
411
  }
224
412
 
413
+ // Build uniques from table state
414
+ const uniques = (tableState.uniques ?? []).map((u) => ({
415
+ columns: u.columns,
416
+ ...(u.name ? { name: u.name } : {}),
417
+ }));
418
+
419
+ // Build indexes from table state
420
+ const indexes = (tableState.indexes ?? []).map((i) => ({
421
+ columns: i.columns,
422
+ ...(i.name ? { name: i.name } : {}),
423
+ }));
424
+
425
+ // Build foreign keys from table state, materializing defaults
426
+ const foreignKeys = (tableState.foreignKeys ?? []).map((fk) => ({
427
+ columns: fk.columns,
428
+ references: fk.references,
429
+ ...applyFkDefaults(fk, this.state.foreignKeyDefaults),
430
+ ...(fk.name ? { name: fk.name } : {}),
431
+ ...(fk.onDelete !== undefined ? { onDelete: fk.onDelete } : {}),
432
+ ...(fk.onUpdate !== undefined ? { onUpdate: fk.onUpdate } : {}),
433
+ }));
434
+
225
435
  const table = {
226
436
  columns: columns as {
227
437
  [K in keyof ColumnDefs]: BuildStorageColumn<
@@ -229,13 +439,14 @@ class SqlContractBuilder<
229
439
  ColumnDefs[K]['type']
230
440
  >;
231
441
  },
232
- uniques: [],
233
- indexes: [],
234
- foreignKeys: [],
442
+ uniques,
443
+ indexes,
444
+ foreignKeys,
235
445
  ...(tableState.primaryKey
236
446
  ? {
237
447
  primaryKey: {
238
448
  columns: tableState.primaryKey,
449
+ ...(tableState.primaryKeyName ? { name: tableState.primaryKeyName } : {}),
239
450
  },
240
451
  }
241
452
  : {}),
@@ -244,7 +455,26 @@ class SqlContractBuilder<
244
455
  (storageTables as Mutable<BuildStorageTables<Tables>>)[tableName] = table;
245
456
  }
246
457
 
247
- const storage = { tables: storageTables as BuildStorageTables<Tables> } as BuildStorage<Tables>;
458
+ const storageTypes = (this.state.storageTypes ?? {}) as Types;
459
+ const storage: BuildStorage<Tables, Types> = {
460
+ tables: storageTables as BuildStorageTables<Tables>,
461
+ types: storageTypes,
462
+ };
463
+
464
+ const execution =
465
+ executionDefaults.length > 0
466
+ ? {
467
+ mutations: {
468
+ defaults: executionDefaults.sort((a, b) => {
469
+ const tableCompare = a.ref.table.localeCompare(b.ref.table);
470
+ if (tableCompare !== 0) {
471
+ return tableCompare;
472
+ }
473
+ return a.ref.column.localeCompare(b.ref.column);
474
+ }),
475
+ },
476
+ }
477
+ : undefined;
248
478
 
249
479
  // Build models - construct as partial first, then assert full type
250
480
  const modelsPartial: Partial<BuildModels<Models>> = {};
@@ -348,11 +578,12 @@ class SqlContractBuilder<
348
578
  schemaVersion: '1' as const,
349
579
  target,
350
580
  targetFamily: 'sql' as const,
351
- coreHash: this.state.coreHash || 'sha256:ts-builder-placeholder',
581
+ storageHash: this.state.storageHash || 'sha256:ts-builder-placeholder',
352
582
  models,
353
583
  relations: relationsPartial,
354
584
  storage,
355
585
  mappings,
586
+ ...(execution ? { execution } : {}),
356
587
  extensionPacks,
357
588
  capabilities: this.state.capabilities || {},
358
589
  meta: {},
@@ -365,7 +596,8 @@ class SqlContractBuilder<
365
596
  Target,
366
597
  Tables,
367
598
  Models,
368
- CoreHash,
599
+ Types,
600
+ StorageHash,
369
601
  ExtensionPacks,
370
602
  Capabilities
371
603
  >['build']
@@ -374,13 +606,23 @@ class SqlContractBuilder<
374
606
 
375
607
  override target<T extends string>(
376
608
  packRef: TargetPackRef<'sql', T>,
377
- ): SqlContractBuilder<CodecTypes, T, Tables, Models, CoreHash, ExtensionPacks, Capabilities> {
609
+ ): SqlContractBuilder<
610
+ CodecTypes,
611
+ T,
612
+ Tables,
613
+ Models,
614
+ Types,
615
+ StorageHash,
616
+ ExtensionPacks,
617
+ Capabilities
618
+ > {
378
619
  return new SqlContractBuilder<
379
620
  CodecTypes,
380
621
  T,
381
622
  Tables,
382
623
  Models,
383
- CoreHash,
624
+ Types,
625
+ StorageHash,
384
626
  ExtensionPacks,
385
627
  Capabilities
386
628
  >({
@@ -396,7 +638,8 @@ class SqlContractBuilder<
396
638
  Target,
397
639
  Tables,
398
640
  Models,
399
- CoreHash,
641
+ Types,
642
+ StorageHash,
400
643
  ExtensionPacks,
401
644
  Capabilities
402
645
  > {
@@ -411,19 +654,19 @@ class SqlContractBuilder<
411
654
 
412
655
  if (packRef.kind !== 'extension') {
413
656
  throw new Error(
414
- `extensionPacks() only accepts extension pack refs. Received kind \"${packRef.kind}\".`,
657
+ `extensionPacks() only accepts extension pack refs. Received kind "${packRef.kind}".`,
415
658
  );
416
659
  }
417
660
 
418
661
  if (packRef.familyId !== 'sql') {
419
662
  throw new Error(
420
- `extension pack \"${packRef.id}\" targets family \"${packRef.familyId}\" but this builder targets \"sql\".`,
663
+ `extension pack "${packRef.id}" targets family "${packRef.familyId}" but this builder targets "sql".`,
421
664
  );
422
665
  }
423
666
 
424
667
  if (packRef.targetId && packRef.targetId !== this.state.target) {
425
668
  throw new Error(
426
- `extension pack \"${packRef.id}\" targets \"${packRef.targetId}\" but builder target is \"${this.state.target}\".`,
669
+ `extension pack "${packRef.id}" targets "${packRef.targetId}" but builder target is "${this.state.target}".`,
427
670
  );
428
671
  }
429
672
 
@@ -435,7 +678,8 @@ class SqlContractBuilder<
435
678
  Target,
436
679
  Tables,
437
680
  Models,
438
- CoreHash,
681
+ Types,
682
+ StorageHash,
439
683
  ExtensionPacks,
440
684
  Capabilities
441
685
  >({
@@ -446,27 +690,46 @@ class SqlContractBuilder<
446
690
 
447
691
  override capabilities<C extends Record<string, Record<string, boolean>>>(
448
692
  capabilities: C,
449
- ): SqlContractBuilder<CodecTypes, Target, Tables, Models, CoreHash, ExtensionPacks, C> {
450
- return new SqlContractBuilder<CodecTypes, Target, Tables, Models, CoreHash, ExtensionPacks, C>({
693
+ ): SqlContractBuilder<CodecTypes, Target, Tables, Models, Types, StorageHash, ExtensionPacks, C> {
694
+ return new SqlContractBuilder<
695
+ CodecTypes,
696
+ Target,
697
+ Tables,
698
+ Models,
699
+ Types,
700
+ StorageHash,
701
+ ExtensionPacks,
702
+ C
703
+ >({
451
704
  ...this.state,
452
705
  capabilities,
453
706
  });
454
707
  }
455
708
 
456
- override coreHash<H extends string>(
709
+ override storageHash<H extends string>(
457
710
  hash: H,
458
- ): SqlContractBuilder<CodecTypes, Target, Tables, Models, H, ExtensionPacks, Capabilities> {
711
+ ): SqlContractBuilder<
712
+ CodecTypes,
713
+ Target,
714
+ Tables,
715
+ Models,
716
+ Types,
717
+ H,
718
+ ExtensionPacks,
719
+ Capabilities
720
+ > {
459
721
  return new SqlContractBuilder<
460
722
  CodecTypes,
461
723
  Target,
462
724
  Tables,
463
725
  Models,
726
+ Types,
464
727
  H,
465
728
  ExtensionPacks,
466
729
  Capabilities
467
730
  >({
468
731
  ...this.state,
469
- coreHash: hash,
732
+ storageHash: hash,
470
733
  });
471
734
  }
472
735
 
@@ -485,12 +748,18 @@ class SqlContractBuilder<
485
748
  Target,
486
749
  Tables & Record<TableName, ReturnType<T['build']>>,
487
750
  Models,
488
- CoreHash,
751
+ Types,
752
+ StorageHash,
489
753
  ExtensionPacks,
490
754
  Capabilities
491
755
  > {
492
- const tableBuilder = new TableBuilder<TableName>(name);
493
- const result = callback(tableBuilder);
756
+ const tableBuilder = createTable(name);
757
+ const result = callback(
758
+ tableBuilder as unknown as SqlTableBuilder<
759
+ TableName,
760
+ CodecTypes
761
+ > as unknown as TableBuilder<TableName>,
762
+ );
494
763
  const finalBuilder = result instanceof TableBuilder ? result : tableBuilder;
495
764
  const tableState = finalBuilder.build();
496
765
 
@@ -499,7 +768,8 @@ class SqlContractBuilder<
499
768
  Target,
500
769
  Tables & Record<TableName, ReturnType<T['build']>>,
501
770
  Models,
502
- CoreHash,
771
+ Types,
772
+ StorageHash,
503
773
  ExtensionPacks,
504
774
  Capabilities
505
775
  >({
@@ -529,7 +799,8 @@ class SqlContractBuilder<
529
799
  Target,
530
800
  Tables,
531
801
  Models & Record<ModelName, ReturnType<M['build']>>,
532
- CoreHash,
802
+ Types,
803
+ StorageHash,
533
804
  ExtensionPacks,
534
805
  Capabilities
535
806
  > {
@@ -543,7 +814,8 @@ class SqlContractBuilder<
543
814
  Target,
544
815
  Tables,
545
816
  Models & Record<ModelName, ReturnType<M['build']>>,
546
- CoreHash,
817
+ Types,
818
+ StorageHash,
547
819
  ExtensionPacks,
548
820
  Capabilities
549
821
  >({
@@ -552,6 +824,64 @@ class SqlContractBuilder<
552
824
  Record<ModelName, ReturnType<M['build']>>,
553
825
  });
554
826
  }
827
+
828
+ override foreignKeyDefaults(
829
+ config: ForeignKeyDefaultsState,
830
+ ): SqlContractBuilder<
831
+ CodecTypes,
832
+ Target,
833
+ Tables,
834
+ Models,
835
+ Types,
836
+ StorageHash,
837
+ ExtensionPacks,
838
+ Capabilities
839
+ > {
840
+ return new SqlContractBuilder<
841
+ CodecTypes,
842
+ Target,
843
+ Tables,
844
+ Models,
845
+ Types,
846
+ StorageHash,
847
+ ExtensionPacks,
848
+ Capabilities
849
+ >({
850
+ ...this.state,
851
+ foreignKeyDefaults: config,
852
+ });
853
+ }
854
+
855
+ storageType<Name extends string, Type extends StorageTypeInstance>(
856
+ name: Name,
857
+ typeInstance: Type,
858
+ ): SqlContractBuilder<
859
+ CodecTypes,
860
+ Target,
861
+ Tables,
862
+ Models,
863
+ Types & Record<Name, Type>,
864
+ StorageHash,
865
+ ExtensionPacks,
866
+ Capabilities
867
+ > {
868
+ return new SqlContractBuilder<
869
+ CodecTypes,
870
+ Target,
871
+ Tables,
872
+ Models,
873
+ Types & Record<Name, Type>,
874
+ StorageHash,
875
+ ExtensionPacks,
876
+ Capabilities
877
+ >({
878
+ ...this.state,
879
+ storageTypes: {
880
+ ...(this.state.storageTypes ?? {}),
881
+ [name]: typeInstance,
882
+ },
883
+ });
884
+ }
555
885
  }
556
886
 
557
887
  export function defineContract<