@prisma-next/sql-contract-ts 0.9.0 → 0.10.0
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/dist/contract-builder.d.mts +123 -11
- package/dist/contract-builder.d.mts.map +1 -1
- package/dist/contract-builder.mjs +155 -18
- package/dist/contract-builder.mjs.map +1 -1
- package/package.json +10 -10
- package/src/build-contract.ts +138 -12
- package/src/composed-authoring-helpers.ts +2 -1
- package/src/contract-builder.ts +145 -4
- package/src/contract-definition.ts +40 -0
- package/src/contract-dsl.ts +53 -0
- package/src/contract-lowering.ts +5 -0
- package/src/contract-types.ts +51 -6
package/src/contract-dsl.ts
CHANGED
|
@@ -14,8 +14,10 @@ import type {
|
|
|
14
14
|
FamilyPackRef,
|
|
15
15
|
TargetPackRef,
|
|
16
16
|
} from '@prisma-next/framework-components/components';
|
|
17
|
+
import type { Namespace } from '@prisma-next/framework-components/ir';
|
|
17
18
|
import type {
|
|
18
19
|
PostgresEnumStorageEntry,
|
|
20
|
+
SqlNamespaceTablesInput,
|
|
19
21
|
StorageTypeInstance,
|
|
20
22
|
} from '@prisma-next/sql-contract/types';
|
|
21
23
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
@@ -998,6 +1000,7 @@ export class ContractModelBuilder<
|
|
|
998
1000
|
constructor(
|
|
999
1001
|
readonly stageOne: {
|
|
1000
1002
|
readonly modelName?: ModelName;
|
|
1003
|
+
readonly namespace?: string;
|
|
1001
1004
|
readonly fields: Fields;
|
|
1002
1005
|
readonly relations: Relations;
|
|
1003
1006
|
},
|
|
@@ -1215,6 +1218,51 @@ export type ContractInput<
|
|
|
1215
1218
|
readonly storageHash?: string;
|
|
1216
1219
|
readonly foreignKeyDefaults?: ForeignKeyDefaultsState;
|
|
1217
1220
|
readonly capabilities?: Capabilities;
|
|
1221
|
+
/**
|
|
1222
|
+
* Declared namespace coordinates the contract recognises. Per-model
|
|
1223
|
+
* `namespace` references must reference an entry in this list (or the
|
|
1224
|
+
* Postgres-specific late-binding keyword `unbound`). Reserved values:
|
|
1225
|
+
*
|
|
1226
|
+
* - `__unbound__` — IR sentinel for the late-binding slot.
|
|
1227
|
+
* - `__unspecified__` — parser-synthesised AST bucket for top-level
|
|
1228
|
+
* declarations (not a real namespace).
|
|
1229
|
+
* - `unbound` — Postgres-specific reserved keyword (the PSL surface
|
|
1230
|
+
* uses `namespace unbound { … }` to opt into late binding).
|
|
1231
|
+
*
|
|
1232
|
+
* SQLite contracts must declare an empty list (or omit the field) —
|
|
1233
|
+
* SQLite has no schema concept and emits unqualified DDL.
|
|
1234
|
+
*
|
|
1235
|
+
* Populates `SqlStorage.namespaces` together with the
|
|
1236
|
+
* {@link ContractInput.createNamespace} factory: each declared name
|
|
1237
|
+
* (plus the framework-reserved `UNBOUND_NAMESPACE_ID` sentinel) is
|
|
1238
|
+
* resolved through `createNamespace` and stored as the matching slot
|
|
1239
|
+
* value. Models reference declared namespaces via their per-model
|
|
1240
|
+
* `namespace` coordinate; entries that go unreferenced still occupy a
|
|
1241
|
+
* slot so contracts that pre-declare schemas surface them on the live
|
|
1242
|
+
* storage walk.
|
|
1243
|
+
*/
|
|
1244
|
+
readonly namespaces?: readonly string[];
|
|
1245
|
+
/**
|
|
1246
|
+
* Target-supplied factory that materialises a `Namespace` concretion
|
|
1247
|
+
* for a declared namespace coordinate. The SQL family layer is
|
|
1248
|
+
* target-agnostic and cannot import concretions like
|
|
1249
|
+
* `PostgresSchema` or `SqliteUnboundDatabase`; the factory is the
|
|
1250
|
+
* seam by which target packs hand the family the right runtime
|
|
1251
|
+
* representation.
|
|
1252
|
+
*
|
|
1253
|
+
* Called once per distinct namespace id discovered in the contract:
|
|
1254
|
+
* each entry of {@link ContractInput.namespaces}, every
|
|
1255
|
+
* `StorageTable.namespaceId` referenced by a model, and the
|
|
1256
|
+
* framework `UNBOUND_NAMESPACE_ID` sentinel (always present so the
|
|
1257
|
+
* late-bound slot stays available regardless of authoring choices).
|
|
1258
|
+
*
|
|
1259
|
+
* When omitted, the family layer falls back to its placeholder
|
|
1260
|
+
* `SqlUnboundNamespace` singleton for the unbound slot and rejects
|
|
1261
|
+
* any non-unbound coordinate — single-namespace contracts authored
|
|
1262
|
+
* before targets ship their factory stay byte-stable; multi-namespace
|
|
1263
|
+
* contracts must pass the factory through.
|
|
1264
|
+
*/
|
|
1265
|
+
readonly createNamespace?: (input: SqlNamespaceTablesInput) => Namespace;
|
|
1218
1266
|
readonly types?: Types;
|
|
1219
1267
|
readonly models?: Models;
|
|
1220
1268
|
readonly codecLookup?: CodecLookup;
|
|
@@ -1229,6 +1277,7 @@ export function model<
|
|
|
1229
1277
|
input: {
|
|
1230
1278
|
readonly fields: Fields;
|
|
1231
1279
|
readonly relations?: Relations;
|
|
1280
|
+
readonly namespace?: string;
|
|
1232
1281
|
},
|
|
1233
1282
|
): ContractModelBuilder<ModelName, Fields, Relations>;
|
|
1234
1283
|
|
|
@@ -1238,6 +1287,7 @@ export function model<
|
|
|
1238
1287
|
>(input: {
|
|
1239
1288
|
readonly fields: Fields;
|
|
1240
1289
|
readonly relations?: Relations;
|
|
1290
|
+
readonly namespace?: string;
|
|
1241
1291
|
}): ContractModelBuilder<undefined, Fields, Relations>;
|
|
1242
1292
|
|
|
1243
1293
|
export function model<
|
|
@@ -1250,10 +1300,12 @@ export function model<
|
|
|
1250
1300
|
| {
|
|
1251
1301
|
readonly fields: Fields;
|
|
1252
1302
|
readonly relations?: Relations;
|
|
1303
|
+
readonly namespace?: string;
|
|
1253
1304
|
},
|
|
1254
1305
|
maybeInput?: {
|
|
1255
1306
|
readonly fields: Fields;
|
|
1256
1307
|
readonly relations?: Relations;
|
|
1308
|
+
readonly namespace?: string;
|
|
1257
1309
|
},
|
|
1258
1310
|
): ContractModelBuilder<ModelName | undefined, Fields, Relations> {
|
|
1259
1311
|
const input = typeof modelNameOrInput === 'string' ? maybeInput : modelNameOrInput;
|
|
@@ -1264,6 +1316,7 @@ export function model<
|
|
|
1264
1316
|
|
|
1265
1317
|
return new ContractModelBuilder({
|
|
1266
1318
|
...(typeof modelNameOrInput === 'string' ? { modelName: modelNameOrInput } : {}),
|
|
1319
|
+
...(input.namespace !== undefined ? { namespace: input.namespace } : {}),
|
|
1267
1320
|
fields: input.fields,
|
|
1268
1321
|
relations: (input.relations ?? {}) as Relations,
|
|
1269
1322
|
});
|
package/src/contract-lowering.ts
CHANGED
|
@@ -47,6 +47,7 @@ type RuntimeModel = ContractModelBuilder<
|
|
|
47
47
|
type RuntimeModelSpec = {
|
|
48
48
|
readonly modelName: string;
|
|
49
49
|
readonly tableName: string;
|
|
50
|
+
readonly namespace: string | undefined;
|
|
50
51
|
readonly fieldBuilders: Record<string, ScalarFieldBuilder>;
|
|
51
52
|
readonly fieldToColumn: Record<string, string>;
|
|
52
53
|
readonly relations: Record<string, RelationBuilder<RelationState>>;
|
|
@@ -595,6 +596,7 @@ function resolveModelNode(
|
|
|
595
596
|
return {
|
|
596
597
|
modelName: spec.modelName,
|
|
597
598
|
tableName: spec.tableName,
|
|
599
|
+
...(spec.namespace !== undefined ? { namespaceId: spec.namespace } : {}),
|
|
598
600
|
fields,
|
|
599
601
|
...(idConstraint
|
|
600
602
|
? {
|
|
@@ -668,6 +670,7 @@ function collectRuntimeModelSpecs(definition: ContractInput): RuntimeCollection
|
|
|
668
670
|
modelSpecs.set(modelName, {
|
|
669
671
|
modelName,
|
|
670
672
|
tableName,
|
|
673
|
+
namespace: modelDefinition.stageOne.namespace,
|
|
671
674
|
fieldBuilders,
|
|
672
675
|
fieldToColumn,
|
|
673
676
|
relations: modelDefinition.stageOne.relations,
|
|
@@ -711,6 +714,8 @@ export function buildContractDefinition(definition: ContractInput): ContractDefi
|
|
|
711
714
|
...(Object.keys(collection.storageTypes).length > 0
|
|
712
715
|
? { storageTypes: collection.storageTypes }
|
|
713
716
|
: {}),
|
|
717
|
+
...(definition.namespaces ? { namespaces: definition.namespaces } : {}),
|
|
718
|
+
...(definition.createNamespace ? { createNamespace: definition.createNamespace } : {}),
|
|
714
719
|
models,
|
|
715
720
|
};
|
|
716
721
|
}
|
package/src/contract-types.ts
CHANGED
|
@@ -5,7 +5,6 @@ import type {
|
|
|
5
5
|
StorageHashBase,
|
|
6
6
|
} from '@prisma-next/contract/types';
|
|
7
7
|
import type { ExtensionPackRef, TargetPackRef } from '@prisma-next/framework-components/components';
|
|
8
|
-
import type { Namespace } from '@prisma-next/framework-components/ir';
|
|
9
8
|
import type { IndexTypeRegistration } from '@prisma-next/sql-contract/index-types';
|
|
10
9
|
import type {
|
|
11
10
|
ContractWithTypeMaps,
|
|
@@ -107,6 +106,16 @@ type DefinitionModels<Definition> = Definition extends {
|
|
|
107
106
|
: Record<never, never>
|
|
108
107
|
: Record<never, never>;
|
|
109
108
|
|
|
109
|
+
type DefinitionNamespaces<Definition> = Definition extends {
|
|
110
|
+
readonly namespaces?: infer Names extends readonly string[];
|
|
111
|
+
}
|
|
112
|
+
? string[] extends Names
|
|
113
|
+
? never
|
|
114
|
+
: readonly string[] extends Names
|
|
115
|
+
? never
|
|
116
|
+
: Names[number]
|
|
117
|
+
: never;
|
|
118
|
+
|
|
110
119
|
type DefinitionTypes<Definition> = Definition extends {
|
|
111
120
|
readonly types?: unknown;
|
|
112
121
|
}
|
|
@@ -499,8 +508,16 @@ type BuiltStorageTables<Definition> = {
|
|
|
499
508
|
}>;
|
|
500
509
|
readonly indexes: ReadonlyArray<Index>;
|
|
501
510
|
readonly foreignKeys: ReadonlyArray<{
|
|
502
|
-
readonly
|
|
503
|
-
|
|
511
|
+
readonly source: {
|
|
512
|
+
readonly namespaceId: string;
|
|
513
|
+
readonly tableName: string;
|
|
514
|
+
readonly columns: readonly string[];
|
|
515
|
+
};
|
|
516
|
+
readonly target: {
|
|
517
|
+
readonly namespaceId: string;
|
|
518
|
+
readonly tableName: string;
|
|
519
|
+
readonly columns: readonly string[];
|
|
520
|
+
};
|
|
504
521
|
readonly name?: string;
|
|
505
522
|
readonly onDelete?: ReferentialAction;
|
|
506
523
|
readonly onUpdate?: ReferentialAction;
|
|
@@ -521,11 +538,39 @@ type BuiltStorageTables<Definition> = {
|
|
|
521
538
|
: Record<string, never>);
|
|
522
539
|
};
|
|
523
540
|
|
|
541
|
+
type BuiltStorageTypes<Definition> = {
|
|
542
|
+
readonly [K in keyof DefinitionTypes<Definition> as DefinitionTypes<Definition>[K] extends PostgresEnumStorageEntry
|
|
543
|
+
? never
|
|
544
|
+
: K]: DefinitionTypes<Definition>[K];
|
|
545
|
+
};
|
|
546
|
+
|
|
524
547
|
type BuiltStorage<Definition> = {
|
|
525
548
|
readonly storageHash: StorageHashBase<string>;
|
|
526
|
-
readonly
|
|
527
|
-
|
|
528
|
-
|
|
549
|
+
readonly types: BuiltStorageTypes<Definition>;
|
|
550
|
+
// SQL contracts always carry a literal `__unbound__` namespace whose tables
|
|
551
|
+
// slot is narrowed to the actual built table shape so downstream DSL
|
|
552
|
+
// surfaces (TableProxyContract, Ref, SelectBuilder) keep literal-keyed
|
|
553
|
+
// access without an optional-narrowing dance. The shape is described
|
|
554
|
+
// inline (rather than intersecting with `SqlStorage['namespaces']`) so
|
|
555
|
+
// its `Readonly<Record<string, Namespace>>` index signature doesn't
|
|
556
|
+
// collapse `keyof tables` to `string`. The literal object is still
|
|
557
|
+
// structurally assignable to `SqlStorage['namespaces']` because every
|
|
558
|
+
// value satisfies the framework `Namespace` interface.
|
|
559
|
+
readonly namespaces: {
|
|
560
|
+
readonly __unbound__: {
|
|
561
|
+
readonly id: '__unbound__';
|
|
562
|
+
readonly kind?: string;
|
|
563
|
+
readonly tables: BuiltStorageTables<Definition>;
|
|
564
|
+
readonly types?: Readonly<Record<string, PostgresEnumStorageEntry>>;
|
|
565
|
+
};
|
|
566
|
+
} & {
|
|
567
|
+
readonly [Ns in Exclude<DefinitionNamespaces<Definition>, '__unbound__'>]: {
|
|
568
|
+
readonly id: Ns;
|
|
569
|
+
readonly kind?: string;
|
|
570
|
+
readonly tables: Record<never, never>;
|
|
571
|
+
readonly types?: Readonly<Record<string, PostgresEnumStorageEntry>>;
|
|
572
|
+
};
|
|
573
|
+
};
|
|
529
574
|
};
|
|
530
575
|
|
|
531
576
|
type FieldOutputType<
|