@prisma-next/sql-contract-ts 0.14.0-dev.9 → 0.14.0-dev.90

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.
@@ -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';
@@ -37,20 +40,22 @@ type NamedConstraintNameSpec<Name extends string = string> = {
37
40
  };
38
41
 
39
42
  export type ScalarFieldState<
40
- CodecId extends string = string,
43
+ Descriptor extends ColumnTypeDescriptor = ColumnTypeDescriptor,
41
44
  TypeRef extends NamedStorageTypeRef | undefined = undefined,
42
45
  Nullable extends boolean = boolean,
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
- readonly descriptor?: (ColumnTypeDescriptor & { readonly codecId: CodecId }) | undefined;
52
+ readonly descriptor?: Descriptor | undefined;
49
53
  readonly typeRef?: TypeRef | undefined;
50
54
  readonly nullable: Nullable;
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 }
@@ -58,24 +63,26 @@ export type ScalarFieldState<
58
63
 
59
64
  type AnyScalarFieldState = {
60
65
  readonly kind: 'scalar';
61
- readonly descriptor?: (ColumnTypeDescriptor & { readonly codecId: string }) | undefined;
66
+ readonly descriptor?: ColumnTypeDescriptor | undefined;
62
67
  readonly typeRef?: NamedStorageTypeRef | undefined;
63
68
  readonly nullable: boolean;
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
  };
70
76
 
71
77
  type HasNamedConstraintId<State extends AnyScalarFieldState> =
72
78
  State extends ScalarFieldState<
73
- string,
79
+ ColumnTypeDescriptor,
74
80
  NamedStorageTypeRef | undefined,
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
@@ -84,12 +91,13 @@ type HasNamedConstraintId<State extends AnyScalarFieldState> =
84
91
 
85
92
  type HasNamedConstraintUnique<State extends AnyScalarFieldState> =
86
93
  State extends ScalarFieldState<
87
- string,
94
+ ColumnTypeDescriptor,
88
95
  NamedStorageTypeRef | undefined,
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
@@ -110,15 +118,16 @@ type ApplyFieldSqlSpec<
110
118
  Spec extends FieldSqlSpecForState<State>,
111
119
  > =
112
120
  State extends ScalarFieldState<
113
- infer CodecId,
121
+ infer Descriptor,
114
122
  infer TypeRef,
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
- CodecId,
130
+ Descriptor,
122
131
  TypeRef,
123
132
  Nullable,
124
133
  Spec extends { readonly column: infer NextColumn extends string } ? NextColumn : ColumnName,
@@ -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;
@@ -148,7 +158,6 @@ function toColumnDefault(value: ColumnDefaultLiteralInputValue | ColumnDefault):
148
158
  return { kind: 'literal', value };
149
159
  }
150
160
 
151
- // Chaining methods use `as unknown as <ConditionalType>` because TypeScript cannot narrow generic conditional return types through object spread. The runtime values are correct — the casts bridge the gap between the spread result and the compile-time conditional type that encodes the state transition.
152
161
  export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFieldState> {
153
162
  declare readonly __state: State;
154
163
 
@@ -166,58 +175,106 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
166
175
 
167
176
  optional(): ScalarFieldBuilder<
168
177
  State extends ScalarFieldState<
169
- infer CodecId,
178
+ infer Descriptor,
170
179
  infer TypeRef,
171
180
  boolean,
172
181
  infer ColumnName,
173
182
  infer IdSpec,
174
- infer UniqueSpec
183
+ infer UniqueSpec,
184
+ infer Many
175
185
  >
176
- ? ScalarFieldState<CodecId, TypeRef, true, ColumnName, IdSpec, UniqueSpec>
177
- : never
186
+ ? ScalarFieldState<Descriptor, TypeRef, true, ColumnName, IdSpec, UniqueSpec, Many>
187
+ : AnyScalarFieldState
178
188
  > {
179
- return new ScalarFieldBuilder({
180
- ...this.state,
181
- nullable: true,
182
- } as unknown as State extends ScalarFieldState<
183
- infer CodecId,
184
- infer TypeRef,
185
- boolean,
186
- infer ColumnName,
187
- infer IdSpec,
188
- infer UniqueSpec
189
- >
190
- ? ScalarFieldState<CodecId, TypeRef, true, ColumnName, IdSpec, UniqueSpec>
191
- : never);
189
+ return new ScalarFieldBuilder(
190
+ blindCast<
191
+ State extends ScalarFieldState<
192
+ infer Descriptor,
193
+ infer TypeRef,
194
+ boolean,
195
+ infer ColumnName,
196
+ infer IdSpec,
197
+ infer UniqueSpec,
198
+ infer Many
199
+ >
200
+ ? ScalarFieldState<Descriptor, TypeRef, true, ColumnName, IdSpec, UniqueSpec, Many>
201
+ : AnyScalarFieldState,
202
+ 'object spread does not narrow the generic State conditional; runtime shape is correct'
203
+ >({
204
+ ...this.state,
205
+ nullable: true,
206
+ }),
207
+ );
192
208
  }
193
209
 
194
210
  column<ColumnName extends string>(
195
211
  name: ColumnName,
196
212
  ): ScalarFieldBuilder<
197
213
  State extends ScalarFieldState<
198
- infer CodecId,
214
+ infer Descriptor,
199
215
  infer TypeRef,
200
216
  infer Nullable,
201
217
  string | undefined,
202
218
  infer IdSpec,
203
- infer UniqueSpec
219
+ infer UniqueSpec,
220
+ infer Many
204
221
  >
205
- ? ScalarFieldState<CodecId, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec>
206
- : never
222
+ ? ScalarFieldState<Descriptor, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec, Many>
223
+ : AnyScalarFieldState
207
224
  > {
208
- return new ScalarFieldBuilder({
209
- ...this.state,
210
- columnName: name,
211
- } as unknown as State extends ScalarFieldState<
212
- infer CodecId,
225
+ return new ScalarFieldBuilder(
226
+ blindCast<
227
+ State extends ScalarFieldState<
228
+ infer Descriptor,
229
+ infer TypeRef,
230
+ infer Nullable,
231
+ string | undefined,
232
+ infer IdSpec,
233
+ infer UniqueSpec,
234
+ infer Many
235
+ >
236
+ ? ScalarFieldState<Descriptor, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec, Many>
237
+ : AnyScalarFieldState,
238
+ 'object spread does not narrow the generic State conditional; runtime shape is correct'
239
+ >({
240
+ ...this.state,
241
+ columnName: name,
242
+ }),
243
+ );
244
+ }
245
+
246
+ many(): ScalarFieldBuilder<
247
+ State extends ScalarFieldState<
248
+ infer Descriptor,
213
249
  infer TypeRef,
214
250
  infer Nullable,
215
- string | undefined,
251
+ infer ColumnName,
216
252
  infer IdSpec,
217
- infer UniqueSpec
253
+ infer UniqueSpec,
254
+ boolean
218
255
  >
219
- ? ScalarFieldState<CodecId, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec>
220
- : never);
256
+ ? ScalarFieldState<Descriptor, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec, true>
257
+ : AnyScalarFieldState
258
+ > {
259
+ return new ScalarFieldBuilder(
260
+ blindCast<
261
+ State extends ScalarFieldState<
262
+ infer Descriptor,
263
+ infer TypeRef,
264
+ infer Nullable,
265
+ infer ColumnName,
266
+ infer IdSpec,
267
+ infer UniqueSpec,
268
+ boolean
269
+ >
270
+ ? ScalarFieldState<Descriptor, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec, true>
271
+ : AnyScalarFieldState,
272
+ 'object spread does not narrow the generic State conditional; runtime shape is correct'
273
+ >({
274
+ ...this.state,
275
+ many: true,
276
+ }),
277
+ );
221
278
  }
222
279
 
223
280
  default(value: ColumnDefaultLiteralInputValue | ColumnDefault): ScalarFieldBuilder<State> {
@@ -238,72 +295,104 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
238
295
  options?: NamedConstraintSpec<Name>,
239
296
  ): ScalarFieldBuilder<
240
297
  State extends ScalarFieldState<
241
- infer CodecId,
298
+ infer Descriptor,
242
299
  infer TypeRef,
243
300
  infer Nullable,
244
301
  infer ColumnName,
245
302
  NamedConstraintSpec | undefined,
246
- infer UniqueSpec
303
+ infer UniqueSpec,
304
+ infer Many
247
305
  >
248
306
  ? ScalarFieldState<
249
- CodecId,
307
+ Descriptor,
250
308
  TypeRef,
251
309
  Nullable,
252
310
  ColumnName,
253
311
  NamedConstraintSpec<Name>,
254
- UniqueSpec
312
+ UniqueSpec,
313
+ Many
255
314
  >
256
- : never
315
+ : AnyScalarFieldState
257
316
  > {
258
- return new ScalarFieldBuilder({
259
- ...this.state,
260
- id: options?.name ? { name: options.name } : {},
261
- } as unknown as State extends ScalarFieldState<
262
- infer CodecId,
263
- infer TypeRef,
264
- infer Nullable,
265
- infer ColumnName,
266
- NamedConstraintSpec | undefined,
267
- infer UniqueSpec
268
- >
269
- ? ScalarFieldState<
270
- CodecId,
271
- TypeRef,
272
- Nullable,
273
- ColumnName,
274
- NamedConstraintSpec<Name>,
275
- UniqueSpec
317
+ return new ScalarFieldBuilder(
318
+ blindCast<
319
+ State extends ScalarFieldState<
320
+ infer Descriptor,
321
+ infer TypeRef,
322
+ infer Nullable,
323
+ infer ColumnName,
324
+ NamedConstraintSpec | undefined,
325
+ infer UniqueSpec,
326
+ infer Many
276
327
  >
277
- : never);
328
+ ? ScalarFieldState<
329
+ Descriptor,
330
+ TypeRef,
331
+ Nullable,
332
+ ColumnName,
333
+ NamedConstraintSpec<Name>,
334
+ UniqueSpec,
335
+ Many
336
+ >
337
+ : AnyScalarFieldState,
338
+ 'object spread does not narrow the generic State conditional; runtime shape is correct'
339
+ >({
340
+ ...this.state,
341
+ id: options?.name ? { name: options.name } : {},
342
+ }),
343
+ );
278
344
  }
279
345
 
280
346
  unique<const Name extends string | undefined = undefined>(
281
347
  options?: NamedConstraintSpec<Name>,
282
348
  ): ScalarFieldBuilder<
283
349
  State extends ScalarFieldState<
284
- infer CodecId,
350
+ infer Descriptor,
285
351
  infer TypeRef,
286
352
  infer Nullable,
287
353
  infer ColumnName,
288
354
  infer IdSpec,
289
- NamedConstraintSpec | undefined
355
+ NamedConstraintSpec | undefined,
356
+ infer Many
290
357
  >
291
- ? ScalarFieldState<CodecId, TypeRef, Nullable, ColumnName, IdSpec, NamedConstraintSpec<Name>>
292
- : never
358
+ ? ScalarFieldState<
359
+ Descriptor,
360
+ TypeRef,
361
+ Nullable,
362
+ ColumnName,
363
+ IdSpec,
364
+ NamedConstraintSpec<Name>,
365
+ Many
366
+ >
367
+ : AnyScalarFieldState
293
368
  > {
294
- return new ScalarFieldBuilder({
295
- ...this.state,
296
- unique: options?.name ? { name: options.name } : {},
297
- } as unknown as State extends ScalarFieldState<
298
- infer CodecId,
299
- infer TypeRef,
300
- infer Nullable,
301
- infer ColumnName,
302
- infer IdSpec,
303
- NamedConstraintSpec | undefined
304
- >
305
- ? ScalarFieldState<CodecId, TypeRef, Nullable, ColumnName, IdSpec, NamedConstraintSpec<Name>>
306
- : never);
369
+ return new ScalarFieldBuilder(
370
+ blindCast<
371
+ State extends ScalarFieldState<
372
+ infer Descriptor,
373
+ infer TypeRef,
374
+ infer Nullable,
375
+ infer ColumnName,
376
+ infer IdSpec,
377
+ NamedConstraintSpec | undefined,
378
+ infer Many
379
+ >
380
+ ? ScalarFieldState<
381
+ Descriptor,
382
+ TypeRef,
383
+ Nullable,
384
+ ColumnName,
385
+ IdSpec,
386
+ NamedConstraintSpec<Name>,
387
+ Many
388
+ >
389
+ : AnyScalarFieldState,
390
+ 'object spread does not narrow the generic State conditional; runtime shape is correct'
391
+ >({
392
+ ...this.state,
393
+ unique: options?.name ? { name: options.name } : {},
394
+ }),
395
+ );
307
396
  }
308
397
 
309
398
  sql<const Spec extends FieldSqlSpecForState<State>>(
@@ -321,12 +410,17 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
321
410
  );
322
411
  }
323
412
 
324
- return new ScalarFieldBuilder({
325
- ...this.state,
326
- ...(spec.column ? { columnName: spec.column } : {}),
327
- ...(idSpec ? { id: { name: idSpec.name } } : {}),
328
- ...(uniqueSpec ? { unique: { name: uniqueSpec.name } } : {}),
329
- } as unknown as ApplyFieldSqlSpec<State, Spec>);
413
+ return new ScalarFieldBuilder(
414
+ blindCast<
415
+ ApplyFieldSqlSpec<State, Spec>,
416
+ 'conditional object spread does not narrow ApplyFieldSqlSpec; runtime shape is correct'
417
+ >({
418
+ ...this.state,
419
+ ...(spec.column ? { columnName: spec.column } : {}),
420
+ ...(idSpec ? { id: { name: idSpec.name } } : {}),
421
+ ...(uniqueSpec ? { unique: { name: uniqueSpec.name } } : {}),
422
+ }),
423
+ );
330
424
  }
331
425
 
332
426
  build(): State {
@@ -336,7 +430,12 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
336
430
 
337
431
  export class EnumScalarFieldBuilder<
338
432
  Handle extends EnumTypeHandle,
339
- State extends AnyScalarFieldState = ScalarFieldState<Handle['codecId'], Handle, false, undefined>,
433
+ State extends AnyScalarFieldState = ScalarFieldState<
434
+ ColumnTypeDescriptor,
435
+ Handle,
436
+ false,
437
+ undefined
438
+ >,
340
439
  > extends ScalarFieldBuilder<State> {
341
440
  readonly #handle: Handle;
342
441
 
@@ -366,7 +465,7 @@ export class EnumScalarFieldBuilder<
366
465
 
367
466
  function columnField<Descriptor extends ColumnTypeDescriptor>(
368
467
  descriptor: Descriptor,
369
- ): ScalarFieldBuilder<ScalarFieldState<Descriptor['codecId'], undefined, false, undefined>> {
468
+ ): ScalarFieldBuilder<ScalarFieldState<Descriptor, undefined, false, undefined>> {
370
469
  return new ScalarFieldBuilder({
371
470
  kind: 'scalar',
372
471
  descriptor,
@@ -376,7 +475,7 @@ function columnField<Descriptor extends ColumnTypeDescriptor>(
376
475
 
377
476
  function generatedField<Descriptor extends ColumnTypeDescriptor>(
378
477
  spec: GeneratedFieldSpec & { readonly type: Descriptor },
379
- ): ScalarFieldBuilder<ScalarFieldState<Descriptor['codecId'], undefined, false, undefined>> {
478
+ ): ScalarFieldBuilder<ScalarFieldState<Descriptor, undefined, false, undefined>> {
380
479
  return new ScalarFieldBuilder({
381
480
  kind: 'scalar',
382
481
  descriptor: {
@@ -390,21 +489,26 @@ function generatedField<Descriptor extends ColumnTypeDescriptor>(
390
489
 
391
490
  function namedTypeField<TypeRef extends string>(
392
491
  typeRef: TypeRef,
393
- ): ScalarFieldBuilder<ScalarFieldState<string, TypeRef, false, undefined>>;
492
+ ): ScalarFieldBuilder<ScalarFieldState<ColumnTypeDescriptor, TypeRef, false, undefined>>;
394
493
  function namedTypeField<TypeRef extends StorageTypeInstance>(
395
494
  typeRef: TypeRef,
396
- ): ScalarFieldBuilder<ScalarFieldState<TypeRef['codecId'], TypeRef, false, undefined>>;
495
+ ): ScalarFieldBuilder<
496
+ ScalarFieldState<ColumnTypeDescriptor<TypeRef['codecId']>, TypeRef, false, undefined>
497
+ >;
397
498
  function namedTypeField<Handle extends EnumTypeHandle>(
398
499
  typeRef: Handle,
399
500
  ): EnumScalarFieldBuilder<Handle>;
400
501
  function namedTypeField(typeRef: NamedStorageTypeRef): ScalarFieldBuilder {
401
502
  if (isEnumTypeHandle(typeRef)) {
402
503
  return new EnumScalarFieldBuilder(
403
- {
504
+ blindCast<
505
+ ScalarFieldState<ColumnTypeDescriptor, typeof typeRef, false, undefined>,
506
+ 'literal object lacks explicit many; cast to the full ScalarFieldState so optional() conditional resolves Many = false'
507
+ >({
404
508
  kind: 'scalar',
405
509
  typeRef,
406
510
  nullable: false,
407
- },
511
+ }),
408
512
  typeRef,
409
513
  );
410
514
  }
@@ -1487,7 +1591,7 @@ export type ContractInput<
1487
1591
  */
1488
1592
  readonly namespaces?: readonly string[];
1489
1593
  /**
1490
- * Target-supplied factory that materialises a `Namespace` concretion
1594
+ * Target-supplied factory that materialises a `SqlNamespaceBase` concretion
1491
1595
  * for a declared namespace coordinate. The SQL family layer is
1492
1596
  * target-agnostic and cannot import concretions like
1493
1597
  * `PostgresSchema` or `SqliteUnboundDatabase`; the factory is the
@@ -1499,14 +1603,8 @@ export type ContractInput<
1499
1603
  * `StorageTable.namespaceId` referenced by a model, and the
1500
1604
  * framework `UNBOUND_NAMESPACE_ID` sentinel (always present so the
1501
1605
  * 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
1606
  */
1509
- readonly createNamespace?: (input: SqlNamespaceTablesInput) => Namespace;
1607
+ readonly createNamespace: (input: SqlNamespaceInput) => SqlNamespaceBase;
1510
1608
  readonly types?: Types;
1511
1609
  readonly models?: Models;
1512
1610
  readonly codecLookup?: CodecLookup;
@@ -1516,6 +1614,15 @@ export type ContractInput<
1516
1614
  * default namespace. Fields reference the enum via `field.namedType(handle)`.
1517
1615
  */
1518
1616
  readonly enums?: Record<string, import('./enum-type').EnumTypeHandle>;
1617
+ /**
1618
+ * Author-declared pack-entity handles, lowered by the pack that registered
1619
+ * each handle's `entityKind` (through the SQL-family batch lowering hook)
1620
+ * into namespace-scoped entry attachments at build time. Generic on
1621
+ * purpose — neither this type nor the walk names a specific kind; a handle
1622
+ * whose kind no composed pack registers is a build error. This is the only
1623
+ * public channel for attaching pack entities.
1624
+ */
1625
+ readonly entities?: readonly import('@prisma-next/sql-contract/entity-handle-lowering-hook').PackEntityHandle[];
1519
1626
  };
1520
1627
 
1521
1628
  export function model<
@@ -1637,7 +1744,7 @@ type CrossSpaceHandle = {
1637
1744
  readonly stageOne: { readonly namespace?: string };
1638
1745
  };
1639
1746
 
1640
- function isCrossSpaceHandle(value: unknown): value is CrossSpaceHandle {
1747
+ export function isCrossSpaceHandle(value: unknown): value is CrossSpaceHandle {
1641
1748
  if (typeof value !== 'object' || value === null) {
1642
1749
  return false;
1643
1750
  }