@prisma-next/sql-contract-ts 0.14.0-dev.3 → 0.14.0-dev.31

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/package.json CHANGED
@@ -1,27 +1,27 @@
1
1
  {
2
2
  "name": "@prisma-next/sql-contract-ts",
3
- "version": "0.14.0-dev.3",
3
+ "version": "0.14.0-dev.31",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "description": "SQL-specific TypeScript contract authoring surface for Prisma Next",
8
8
  "dependencies": {
9
- "@prisma-next/config": "0.14.0-dev.3",
10
- "@prisma-next/contract": "0.14.0-dev.3",
11
- "@prisma-next/contract-authoring": "0.14.0-dev.3",
12
- "@prisma-next/framework-components": "0.14.0-dev.3",
13
- "@prisma-next/sql-contract": "0.14.0-dev.3",
14
- "@prisma-next/utils": "0.14.0-dev.3",
9
+ "@prisma-next/config": "0.14.0-dev.31",
10
+ "@prisma-next/contract": "0.14.0-dev.31",
11
+ "@prisma-next/contract-authoring": "0.14.0-dev.31",
12
+ "@prisma-next/framework-components": "0.14.0-dev.31",
13
+ "@prisma-next/sql-contract": "0.14.0-dev.31",
14
+ "@prisma-next/utils": "0.14.0-dev.31",
15
15
  "arktype": "^2.2.0",
16
16
  "pathe": "^2.0.3",
17
17
  "ts-toolbelt": "^9.6.0"
18
18
  },
19
19
  "devDependencies": {
20
- "@prisma-next/test-utils": "0.14.0-dev.3",
21
- "@prisma-next/tsconfig": "0.14.0-dev.3",
20
+ "@prisma-next/test-utils": "0.14.0-dev.31",
21
+ "@prisma-next/tsconfig": "0.14.0-dev.31",
22
22
  "@types/pg": "8.20.0",
23
23
  "pg": "8.21.0",
24
- "@prisma-next/tsdown": "0.14.0-dev.3",
24
+ "@prisma-next/tsdown": "0.14.0-dev.31",
25
25
  "tsdown": "0.22.1",
26
26
  "typescript": "5.9.3",
27
27
  "vitest": "4.1.8"
@@ -33,9 +33,8 @@ import {
33
33
  } from '@prisma-next/sql-contract/index-types';
34
34
  import {
35
35
  applyFkDefaults,
36
- buildSqlNamespace,
37
36
  type CheckConstraintInput,
38
- type SqlNamespaceTablesInput,
37
+ type SqlNamespaceInput,
39
38
  SqlStorage,
40
39
  type SqlStorageInput,
41
40
  type StorageColumn,
@@ -308,18 +307,15 @@ function ensureUnboundNamespaceSlot(
308
307
  if (Object.hasOwn(namespaces, UNBOUND_NAMESPACE_ID)) {
309
308
  return namespaces;
310
309
  }
311
- const unboundInput: SqlNamespaceTablesInput = {
310
+ const unboundInput: SqlNamespaceInput = {
312
311
  id: UNBOUND_NAMESPACE_ID,
313
312
  entries: { table: {} },
314
313
  };
315
- const unbound = createNamespace ? createNamespace(unboundInput) : buildSqlNamespace(unboundInput);
316
- return blindCast<
317
- SqlStorageInput['namespaces'],
318
- 'createNamespace may return a target namespace concretion; the unbound slot matches SqlNamespace at runtime'
319
- >({
314
+ const unbound = createNamespace(unboundInput);
315
+ return {
320
316
  [UNBOUND_NAMESPACE_ID]: unbound,
321
317
  ...namespaces,
322
- });
318
+ };
323
319
  }
324
320
 
325
321
  export function buildSqlContractFromDefinition(
@@ -729,25 +725,20 @@ export function buildSqlContractFromDefinition(
729
725
  }
730
726
 
731
727
  const { createNamespace } = definition;
732
- const namespaces = blindCast<
733
- SqlStorageInput['namespaces'],
734
- 'contract authoring materialises each namespace coordinate from the model set and explicit namespace list'
735
- >(
736
- Object.fromEntries(
737
- [...namespaceCoordinateIds].sort().map((id) => {
738
- const valueSetEntries = storageValueSetsByNs[id];
739
- const nsInput: SqlNamespaceTablesInput = {
740
- id,
741
- entries: {
742
- table: tablesByNamespace[id] ?? {},
743
- ...(valueSetEntries !== undefined && Object.keys(valueSetEntries).length > 0
744
- ? { valueSet: valueSetEntries }
745
- : {}),
746
- },
747
- };
748
- return [id, createNamespace ? createNamespace(nsInput) : buildSqlNamespace(nsInput)];
749
- }),
750
- ),
728
+ const namespaces: SqlStorageInput['namespaces'] = Object.fromEntries(
729
+ [...namespaceCoordinateIds].sort().map((id) => {
730
+ const valueSetEntries = storageValueSetsByNs[id];
731
+ const nsInput: SqlNamespaceInput = {
732
+ id,
733
+ entries: {
734
+ table: tablesByNamespace[id] ?? {},
735
+ ...(valueSetEntries !== undefined && Object.keys(valueSetEntries).length > 0
736
+ ? { valueSet: valueSetEntries }
737
+ : {}),
738
+ },
739
+ };
740
+ return [id, createNamespace(nsInput)];
741
+ }),
751
742
  );
752
743
  const storageWithoutHash = {
753
744
  ...(Object.keys(documentTypes).length > 0 ? { types: documentTypes } : {}),
@@ -3,6 +3,7 @@ import type { ContractConfig } from '@prisma-next/config/config-types';
3
3
  import { applySpecifierDefaultControlPolicy } from '@prisma-next/contract/apply-specifier-default-control-policy';
4
4
  import type { Contract, ControlPolicy } from '@prisma-next/contract/types';
5
5
  import type { TargetPackRef } from '@prisma-next/framework-components/components';
6
+ import type { SqlNamespaceBase, SqlNamespaceInput } from '@prisma-next/sql-contract/types';
6
7
  import { ifDefined } from '@prisma-next/utils/defined';
7
8
  import { ok } from '@prisma-next/utils/result';
8
9
  import { extname } from 'pathe';
@@ -27,12 +28,18 @@ export interface TypeScriptContractSpecifierOptions {
27
28
  export function emptyContract(options: {
28
29
  readonly output?: string;
29
30
  readonly target: TargetPackRef<'sql', string>;
31
+ readonly createNamespace: (input: SqlNamespaceInput) => SqlNamespaceBase;
30
32
  readonly defaultControlPolicy?: ControlPolicy;
31
33
  }): ContractConfig {
32
34
  return {
33
35
  source: {
36
+ sourceFormat: 'typescript',
34
37
  load: async () => {
35
- const built = buildSqlContractFromDefinition({ target: options.target, models: [] });
38
+ const built = buildSqlContractFromDefinition({
39
+ target: options.target,
40
+ createNamespace: options.createNamespace,
41
+ models: [],
42
+ });
36
43
  return ok(applySpecifierDefaultControlPolicy(built, options.defaultControlPolicy));
37
44
  },
38
45
  },
@@ -47,6 +54,7 @@ export function typescriptContract(
47
54
  ): ContractConfig {
48
55
  return {
49
56
  source: {
57
+ sourceFormat: 'typescript',
50
58
  load: async () =>
51
59
  ok(applySpecifierDefaultControlPolicy(contract, options?.defaultControlPolicy)),
52
60
  },
@@ -63,6 +71,7 @@ export function typescriptContractFromPath(
63
71
  ): ContractConfig {
64
72
  return {
65
73
  source: {
74
+ sourceFormat: 'typescript',
66
75
  inputs: [contractPath],
67
76
  load: async (context) => {
68
77
  const [absolutePath] = context.resolvedInputs;
@@ -6,8 +6,11 @@ import type {
6
6
  FamilyPackRef,
7
7
  TargetPackRef,
8
8
  } from '@prisma-next/framework-components/components';
9
- import type { Namespace } from '@prisma-next/framework-components/ir';
10
- import type { SqlNamespaceTablesInput, StorageTypeInstance } from '@prisma-next/sql-contract/types';
9
+ import type {
10
+ SqlNamespaceBase,
11
+ SqlNamespaceInput,
12
+ StorageTypeInstance,
13
+ } from '@prisma-next/sql-contract/types';
11
14
  import { blindCast } from '@prisma-next/utils/casts';
12
15
  import { ifDefined } from '@prisma-next/utils/defined';
13
16
  import { buildSqlContractFromDefinition } from './build-contract';
@@ -68,7 +71,7 @@ type ContractDefinition<
68
71
  readonly foreignKeyDefaults?: ForeignKeyDefaults;
69
72
  readonly defaultControlPolicy?: ControlPolicy;
70
73
  readonly namespaces?: Namespaces;
71
- readonly createNamespace?: (input: SqlNamespaceTablesInput) => Namespace;
74
+ readonly createNamespace: (input: SqlNamespaceInput) => SqlNamespaceBase;
72
75
  readonly types?: Types;
73
76
  readonly models?: Models;
74
77
  readonly codecLookup?: CodecLookup;
@@ -93,7 +96,7 @@ type ContractScaffold<
93
96
  readonly foreignKeyDefaults?: ForeignKeyDefaults;
94
97
  readonly defaultControlPolicy?: ControlPolicy;
95
98
  readonly namespaces?: Namespaces;
96
- readonly createNamespace?: (input: SqlNamespaceTablesInput) => Namespace;
99
+ readonly createNamespace: (input: SqlNamespaceInput) => SqlNamespaceBase;
97
100
  readonly types?: never;
98
101
  readonly models?: never;
99
102
  readonly codecLookup?: CodecLookup;
@@ -314,7 +317,7 @@ type BoundDefinitionInput<
314
317
  readonly foreignKeyDefaults?: ForeignKeyDefaults;
315
318
  readonly defaultControlPolicy?: ControlPolicy;
316
319
  readonly namespaces?: Namespaces;
317
- readonly createNamespace?: (input: SqlNamespaceTablesInput) => Namespace;
320
+ readonly createNamespace: (input: SqlNamespaceInput) => SqlNamespaceBase;
318
321
  readonly types?: Types;
319
322
  readonly models?: Models;
320
323
  readonly codecLookup?: CodecLookup;
@@ -6,10 +6,10 @@ import type {
6
6
  import type { ForeignKeyDefaultsState } from '@prisma-next/contract-authoring';
7
7
  import type { ColumnTypeDescriptor } from '@prisma-next/framework-components/codec';
8
8
  import type { ExtensionPackRef, TargetPackRef } from '@prisma-next/framework-components/components';
9
- import type { Namespace } from '@prisma-next/framework-components/ir';
10
9
  import type {
11
10
  ReferentialAction,
12
- SqlNamespaceTablesInput,
11
+ SqlNamespaceBase,
12
+ SqlNamespaceInput,
13
13
  StorageTypeInstance,
14
14
  } from '@prisma-next/sql-contract/types';
15
15
  import type { EnumTypeHandle } from './enum-type';
@@ -175,8 +175,8 @@ export interface ContractDefinition {
175
175
  * `SqlStorage.namespaces` together with `createNamespace`.
176
176
  */
177
177
  readonly namespaces?: readonly string[];
178
- /** Target-supplied factory that materialises a `Namespace` concretion for a declared namespace coordinate. */
179
- readonly createNamespace?: (input: SqlNamespaceTablesInput) => Namespace;
178
+ /** Target-supplied factory that materialises a `SqlNamespaceBase` concretion for a declared namespace coordinate. */
179
+ readonly createNamespace: (input: SqlNamespaceInput) => SqlNamespaceBase;
180
180
  readonly models: readonly ModelNode[];
181
181
  readonly valueObjects?: readonly ValueObjectNode[];
182
182
  /**
@@ -15,8 +15,11 @@ import type {
15
15
  FamilyPackRef,
16
16
  TargetPackRef,
17
17
  } from '@prisma-next/framework-components/components';
18
- import type { Namespace } from '@prisma-next/framework-components/ir';
19
- import type { SqlNamespaceTablesInput, StorageTypeInstance } from '@prisma-next/sql-contract/types';
18
+ import type {
19
+ SqlNamespaceBase,
20
+ SqlNamespaceInput,
21
+ StorageTypeInstance,
22
+ } from '@prisma-next/sql-contract/types';
20
23
  import { blindCast } from '@prisma-next/utils/casts';
21
24
  import { ifDefined } from '@prisma-next/utils/defined';
22
25
  import type { NamedConstraintSpec } from './authoring-type-utils';
@@ -43,6 +46,7 @@ export type ScalarFieldState<
43
46
  ColumnName extends string | undefined = string | undefined,
44
47
  IdSpec extends NamedConstraintSpec | undefined = undefined,
45
48
  UniqueSpec extends NamedConstraintSpec | undefined = undefined,
49
+ Many extends boolean = false,
46
50
  > = {
47
51
  readonly kind: 'scalar';
48
52
  readonly descriptor?: (ColumnTypeDescriptor & { readonly codecId: CodecId }) | undefined;
@@ -51,6 +55,7 @@ export type ScalarFieldState<
51
55
  readonly columnName?: ColumnName | undefined;
52
56
  readonly default?: ColumnDefault | undefined;
53
57
  readonly executionDefaults?: ExecutionMutationDefaultPhases | undefined;
58
+ readonly many?: Many extends true ? true : undefined;
54
59
  } & (IdSpec extends NamedConstraintSpec ? { readonly id: IdSpec } : { readonly id?: undefined }) &
55
60
  (UniqueSpec extends NamedConstraintSpec
56
61
  ? { readonly unique: UniqueSpec }
@@ -64,6 +69,7 @@ type AnyScalarFieldState = {
64
69
  readonly columnName?: string | undefined;
65
70
  readonly default?: ColumnDefault | undefined;
66
71
  readonly executionDefaults?: ExecutionMutationDefaultPhases | undefined;
72
+ readonly many?: boolean | undefined;
67
73
  readonly id?: NamedConstraintSpec | undefined;
68
74
  readonly unique?: NamedConstraintSpec | undefined;
69
75
  };
@@ -75,7 +81,8 @@ type HasNamedConstraintId<State extends AnyScalarFieldState> =
75
81
  boolean,
76
82
  string | undefined,
77
83
  infer IdSpec,
78
- NamedConstraintSpec | undefined
84
+ NamedConstraintSpec | undefined,
85
+ boolean
79
86
  >
80
87
  ? IdSpec extends NamedConstraintSpec
81
88
  ? true
@@ -89,7 +96,8 @@ type HasNamedConstraintUnique<State extends AnyScalarFieldState> =
89
96
  boolean,
90
97
  string | undefined,
91
98
  NamedConstraintSpec | undefined,
92
- infer UniqueSpec
99
+ infer UniqueSpec,
100
+ boolean
93
101
  >
94
102
  ? UniqueSpec extends NamedConstraintSpec
95
103
  ? true
@@ -115,7 +123,8 @@ type ApplyFieldSqlSpec<
115
123
  infer Nullable,
116
124
  infer ColumnName,
117
125
  infer IdSpec,
118
- infer UniqueSpec
126
+ infer UniqueSpec,
127
+ infer Many
119
128
  >
120
129
  ? ScalarFieldState<
121
130
  CodecId,
@@ -131,9 +140,10 @@ type ApplyFieldSqlSpec<
131
140
  ? UniqueSpec extends NamedConstraintSpec
132
141
  ? NamedConstraintSpec<UniqueName>
133
142
  : UniqueSpec
134
- : UniqueSpec
143
+ : UniqueSpec,
144
+ Many
135
145
  >
136
- : never;
146
+ : AnyScalarFieldState;
137
147
 
138
148
  export type GeneratedFieldSpec = {
139
149
  readonly type: ColumnTypeDescriptor;
@@ -171,10 +181,11 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
171
181
  boolean,
172
182
  infer ColumnName,
173
183
  infer IdSpec,
174
- infer UniqueSpec
184
+ infer UniqueSpec,
185
+ infer Many
175
186
  >
176
- ? ScalarFieldState<CodecId, TypeRef, true, ColumnName, IdSpec, UniqueSpec>
177
- : never
187
+ ? ScalarFieldState<CodecId, TypeRef, true, ColumnName, IdSpec, UniqueSpec, Many>
188
+ : AnyScalarFieldState
178
189
  > {
179
190
  return new ScalarFieldBuilder({
180
191
  ...this.state,
@@ -185,10 +196,11 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
185
196
  boolean,
186
197
  infer ColumnName,
187
198
  infer IdSpec,
188
- infer UniqueSpec
199
+ infer UniqueSpec,
200
+ infer Many
189
201
  >
190
- ? ScalarFieldState<CodecId, TypeRef, true, ColumnName, IdSpec, UniqueSpec>
191
- : never);
202
+ ? ScalarFieldState<CodecId, TypeRef, true, ColumnName, IdSpec, UniqueSpec, Many>
203
+ : AnyScalarFieldState);
192
204
  }
193
205
 
194
206
  column<ColumnName extends string>(
@@ -200,10 +212,11 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
200
212
  infer Nullable,
201
213
  string | undefined,
202
214
  infer IdSpec,
203
- infer UniqueSpec
215
+ infer UniqueSpec,
216
+ infer Many
204
217
  >
205
- ? ScalarFieldState<CodecId, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec>
206
- : never
218
+ ? ScalarFieldState<CodecId, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec, Many>
219
+ : AnyScalarFieldState
207
220
  > {
208
221
  return new ScalarFieldBuilder({
209
222
  ...this.state,
@@ -214,10 +227,45 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
214
227
  infer Nullable,
215
228
  string | undefined,
216
229
  infer IdSpec,
217
- infer UniqueSpec
230
+ infer UniqueSpec,
231
+ infer Many
218
232
  >
219
- ? ScalarFieldState<CodecId, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec>
220
- : never);
233
+ ? ScalarFieldState<CodecId, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec, Many>
234
+ : AnyScalarFieldState);
235
+ }
236
+
237
+ many(): ScalarFieldBuilder<
238
+ State extends ScalarFieldState<
239
+ infer CodecId,
240
+ infer TypeRef,
241
+ infer Nullable,
242
+ infer ColumnName,
243
+ infer IdSpec,
244
+ infer UniqueSpec,
245
+ boolean
246
+ >
247
+ ? ScalarFieldState<CodecId, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec, true>
248
+ : AnyScalarFieldState
249
+ > {
250
+ return new ScalarFieldBuilder(
251
+ blindCast<
252
+ State extends ScalarFieldState<
253
+ infer CodecId,
254
+ infer TypeRef,
255
+ infer Nullable,
256
+ infer ColumnName,
257
+ infer IdSpec,
258
+ infer UniqueSpec,
259
+ boolean
260
+ >
261
+ ? ScalarFieldState<CodecId, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec, true>
262
+ : AnyScalarFieldState,
263
+ 'object spread does not narrow the generic State conditional; runtime shape is correct'
264
+ >({
265
+ ...this.state,
266
+ many: true,
267
+ }),
268
+ );
221
269
  }
222
270
 
223
271
  default(value: ColumnDefaultLiteralInputValue | ColumnDefault): ScalarFieldBuilder<State> {
@@ -243,7 +291,8 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
243
291
  infer Nullable,
244
292
  infer ColumnName,
245
293
  NamedConstraintSpec | undefined,
246
- infer UniqueSpec
294
+ infer UniqueSpec,
295
+ infer Many
247
296
  >
248
297
  ? ScalarFieldState<
249
298
  CodecId,
@@ -251,9 +300,10 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
251
300
  Nullable,
252
301
  ColumnName,
253
302
  NamedConstraintSpec<Name>,
254
- UniqueSpec
303
+ UniqueSpec,
304
+ Many
255
305
  >
256
- : never
306
+ : AnyScalarFieldState
257
307
  > {
258
308
  return new ScalarFieldBuilder({
259
309
  ...this.state,
@@ -264,7 +314,8 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
264
314
  infer Nullable,
265
315
  infer ColumnName,
266
316
  NamedConstraintSpec | undefined,
267
- infer UniqueSpec
317
+ infer UniqueSpec,
318
+ infer Many
268
319
  >
269
320
  ? ScalarFieldState<
270
321
  CodecId,
@@ -272,9 +323,10 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
272
323
  Nullable,
273
324
  ColumnName,
274
325
  NamedConstraintSpec<Name>,
275
- UniqueSpec
326
+ UniqueSpec,
327
+ Many
276
328
  >
277
- : never);
329
+ : AnyScalarFieldState);
278
330
  }
279
331
 
280
332
  unique<const Name extends string | undefined = undefined>(
@@ -286,10 +338,19 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
286
338
  infer Nullable,
287
339
  infer ColumnName,
288
340
  infer IdSpec,
289
- NamedConstraintSpec | undefined
341
+ NamedConstraintSpec | undefined,
342
+ infer Many
290
343
  >
291
- ? ScalarFieldState<CodecId, TypeRef, Nullable, ColumnName, IdSpec, NamedConstraintSpec<Name>>
292
- : never
344
+ ? ScalarFieldState<
345
+ CodecId,
346
+ TypeRef,
347
+ Nullable,
348
+ ColumnName,
349
+ IdSpec,
350
+ NamedConstraintSpec<Name>,
351
+ Many
352
+ >
353
+ : AnyScalarFieldState
293
354
  > {
294
355
  return new ScalarFieldBuilder({
295
356
  ...this.state,
@@ -300,10 +361,19 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
300
361
  infer Nullable,
301
362
  infer ColumnName,
302
363
  infer IdSpec,
303
- NamedConstraintSpec | undefined
364
+ NamedConstraintSpec | undefined,
365
+ infer Many
304
366
  >
305
- ? ScalarFieldState<CodecId, TypeRef, Nullable, ColumnName, IdSpec, NamedConstraintSpec<Name>>
306
- : never);
367
+ ? ScalarFieldState<
368
+ CodecId,
369
+ TypeRef,
370
+ Nullable,
371
+ ColumnName,
372
+ IdSpec,
373
+ NamedConstraintSpec<Name>,
374
+ Many
375
+ >
376
+ : AnyScalarFieldState);
307
377
  }
308
378
 
309
379
  sql<const Spec extends FieldSqlSpecForState<State>>(
@@ -400,11 +470,14 @@ function namedTypeField<Handle extends EnumTypeHandle>(
400
470
  function namedTypeField(typeRef: NamedStorageTypeRef): ScalarFieldBuilder {
401
471
  if (isEnumTypeHandle(typeRef)) {
402
472
  return new EnumScalarFieldBuilder(
403
- {
473
+ blindCast<
474
+ ScalarFieldState<string, typeof typeRef, false, undefined>,
475
+ 'literal object lacks explicit many; cast to the full ScalarFieldState so optional() conditional resolves Many = false'
476
+ >({
404
477
  kind: 'scalar',
405
478
  typeRef,
406
479
  nullable: false,
407
- },
480
+ }),
408
481
  typeRef,
409
482
  );
410
483
  }
@@ -1487,7 +1560,7 @@ export type ContractInput<
1487
1560
  */
1488
1561
  readonly namespaces?: readonly string[];
1489
1562
  /**
1490
- * Target-supplied factory that materialises a `Namespace` concretion
1563
+ * Target-supplied factory that materialises a `SqlNamespaceBase` concretion
1491
1564
  * for a declared namespace coordinate. The SQL family layer is
1492
1565
  * target-agnostic and cannot import concretions like
1493
1566
  * `PostgresSchema` or `SqliteUnboundDatabase`; the factory is the
@@ -1499,14 +1572,8 @@ export type ContractInput<
1499
1572
  * `StorageTable.namespaceId` referenced by a model, and the
1500
1573
  * framework `UNBOUND_NAMESPACE_ID` sentinel (always present so the
1501
1574
  * late-bound slot stays available regardless of authoring choices).
1502
- *
1503
- * When omitted, the family layer falls back to its placeholder
1504
- * `SqlUnboundNamespace` singleton for the unbound slot and rejects
1505
- * any non-unbound coordinate — single-namespace contracts authored
1506
- * before targets ship their factory stay byte-stable; multi-namespace
1507
- * contracts must pass the factory through.
1508
1575
  */
1509
- readonly createNamespace?: (input: SqlNamespaceTablesInput) => Namespace;
1576
+ readonly createNamespace: (input: SqlNamespaceInput) => SqlNamespaceBase;
1510
1577
  readonly types?: Types;
1511
1578
  readonly models?: Models;
1512
1579
  readonly codecLookup?: CodecLookup;
@@ -727,6 +727,7 @@ function resolveModelNode(
727
727
  columnName,
728
728
  descriptor,
729
729
  nullable: fieldState.nullable,
730
+ ...(fieldState.many === true ? { many: true } : {}),
730
731
  ...(fieldState.default ? { default: fieldState.default } : {}),
731
732
  ...(fieldState.executionDefaults ? { executionDefaults: fieldState.executionDefaults } : {}),
732
733
  ...(enumHandle !== undefined ? { enumTypeHandle: enumHandle } : {}),
@@ -877,7 +878,7 @@ export function buildContractDefinition(definition: ContractInput): ContractDefi
877
878
  ? { storageTypes: collection.storageTypes }
878
879
  : {}),
879
880
  ...(definition.namespaces ? { namespaces: definition.namespaces } : {}),
880
- ...(definition.createNamespace ? { createNamespace: definition.createNamespace } : {}),
881
+ createNamespace: definition.createNamespace,
881
882
  ...(definition.enums && Object.keys(definition.enums).length > 0
882
883
  ? { enums: definition.enums }
883
884
  : {}),
@@ -21,10 +21,10 @@ import type { UnionToIntersection } from './authoring-type-utils';
21
21
  import type { AttributeStageIdFieldNames, FieldStateOf, ScalarFieldBuilder } from './contract-dsl';
22
22
  import type { EnumTypeHandle } from './enum-type';
23
23
 
24
- export type ExtractCodecTypesFromPack<P> = P extends { __codecTypes?: infer C }
25
- ? C extends Record<string, { output: unknown }>
26
- ? C
27
- : Record<string, never>
24
+ export type ExtractCodecTypesFromPack<P> = P extends {
25
+ __codecTypes?: infer C extends Record<string, { output: unknown }>;
26
+ }
27
+ ? C
28
28
  : Record<string, never>;
29
29
 
30
30
  export type MergeExtensionCodecTypes<Packs extends Record<string, unknown>> = UnionToIntersection<
@@ -279,6 +279,8 @@ type FieldNullableOf<FieldState> = FieldState extends {
279
279
  ? Nullable
280
280
  : boolean;
281
281
 
282
+ type FieldManyOf<FieldState> = FieldState extends { readonly many?: true } ? true : false;
283
+
282
284
  type FieldColumnOverrideOf<FieldState> = Present<
283
285
  FieldState extends { readonly columnName?: infer ColumnName } ? ColumnName : never
284
286
  >;
@@ -471,15 +473,17 @@ type StorageColumn<
471
473
  NativeType extends string,
472
474
  TypeRef extends string | undefined = undefined,
473
475
  TypeParams extends Record<string, unknown> | undefined = undefined,
476
+ Many extends boolean = false,
474
477
  > = {
475
478
  readonly nativeType: NativeType;
476
479
  readonly codecId: CodecId;
477
480
  readonly nullable: Nullable;
478
481
  readonly default?: ColumnDefault;
479
- } & (TypeRef extends string ? { readonly typeRef: TypeRef } : Record<string, never>) &
482
+ } & (TypeRef extends string ? { readonly typeRef: TypeRef } : Record<never, never>) &
480
483
  (TypeParams extends Record<string, unknown>
481
484
  ? { readonly typeParams: TypeParams }
482
- : Record<string, never>);
485
+ : Record<never, never>) &
486
+ (Many extends true ? { readonly many: true } : Record<never, never>);
483
487
 
484
488
  type ModelStorageColumn<
485
489
  Definition,
@@ -496,7 +500,8 @@ type ModelStorageColumn<
496
500
  ResolveFieldDescriptor<Definition, ModelFieldState<Definition, ModelName, FieldName>>
497
501
  >,
498
502
  ResolveFieldColumnTypeRef<Definition, ModelFieldState<Definition, ModelName, FieldName>>,
499
- ResolveFieldColumnTypeParams<Definition, ModelFieldState<Definition, ModelName, FieldName>>
503
+ ResolveFieldColumnTypeParams<Definition, ModelFieldState<Definition, ModelName, FieldName>>,
504
+ FieldManyOf<ModelFieldState<Definition, ModelName, FieldName>>
500
505
  >
501
506
  : never;
502
507
 
@@ -677,6 +682,8 @@ type BuiltStorage<Definition> = {
677
682
  };
678
683
  };
679
684
 
685
+ type StorageColumnManyOf<Col> = Col extends { readonly many: true } ? true : false;
686
+
680
687
  // The enum value union for an enum-typed field, or `never` for a non-enum
681
688
  // field. The field's `typeRef` carries the authored `EnumTypeHandle`, whose
682
689
  // `Values` tuple preserves the literal member values (text or numeric).
@@ -698,7 +705,9 @@ type CodecChannelType<
698
705
  > = ModelStorageColumn<Definition, ModelName, FieldName>['codecId'] extends infer Id extends
699
706
  keyof CodecTypesFromDefinition<Definition>
700
707
  ? CodecTypesFromDefinition<Definition>[Id] extends { readonly [K in Channel]: infer T }
701
- ? T
708
+ ? StorageColumnManyOf<ModelStorageColumn<Definition, ModelName, FieldName>> extends true
709
+ ? ReadonlyArray<T>
710
+ : T
702
711
  : unknown
703
712
  : unknown;
704
713
 
@@ -712,7 +721,9 @@ type FieldChannelType<
712
721
  > =
713
722
  | ([EnumValueUnion<ModelFieldState<Definition, ModelName, FieldName>>] extends [never]
714
723
  ? CodecChannelType<Definition, ModelName, FieldName, Channel>
715
- : EnumValueUnion<ModelFieldState<Definition, ModelName, FieldName>>)
724
+ : StorageColumnManyOf<ModelStorageColumn<Definition, ModelName, FieldName>> extends true
725
+ ? ReadonlyArray<EnumValueUnion<ModelFieldState<Definition, ModelName, FieldName>>>
726
+ : EnumValueUnion<ModelFieldState<Definition, ModelName, FieldName>>)
716
727
  | (FieldNullableOf<ModelFieldState<Definition, ModelName, FieldName>> extends true
717
728
  ? null
718
729
  : never);
@@ -735,6 +746,17 @@ type FieldChannelTypes<Definition, Channel extends 'output' | 'input'> = {
735
746
  };
736
747
  };
737
748
 
749
+ type StorageColumnChannelTypes<Definition, Channel extends 'output' | 'input'> = {
750
+ readonly [Ns in DefaultStorageNamespaceId<Definition>]: {
751
+ readonly [ModelName in ModelNames<Definition> as BuiltModelTableName<Definition, ModelName>]: {
752
+ readonly [FieldName in ModelFieldNames<Definition, ModelName> as BuiltModelColumnMappings<
753
+ Definition,
754
+ ModelName
755
+ >[FieldName]['column']]: FieldChannelType<Definition, ModelName, FieldName, Channel>;
756
+ };
757
+ };
758
+ };
759
+
738
760
  export type SqlContractResult<Definition> = ContractWithTypeMaps<
739
761
  Omit<Contract<BuiltStorage<Definition>>, 'domain'> & {
740
762
  readonly target: DefinitionTargetId<Definition>;
@@ -754,6 +776,8 @@ export type SqlContractResult<Definition> = ContractWithTypeMaps<
754
776
  CodecTypesFromDefinition<Definition>,
755
777
  Record<string, never>,
756
778
  FieldChannelTypes<Definition, 'output'>,
757
- FieldChannelTypes<Definition, 'input'>
779
+ FieldChannelTypes<Definition, 'input'>,
780
+ StorageColumnChannelTypes<Definition, 'output'>,
781
+ StorageColumnChannelTypes<Definition, 'input'>
758
782
  >
759
783
  >;