@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 CHANGED
@@ -16,15 +16,15 @@ This package contains the SQL-specific TypeScript contract authoring surface for
16
16
 
17
17
  This package is part of the SQL family namespace (`packages/2-sql/2-authoring/contract-ts`) and provides:
18
18
  - SQL contract builder (`defineContract`) - TypeScript builder for creating SQL contracts programmatically
19
- - SQL contract validation (`validateContract`) - Structural and logical validation for SQL contracts
20
19
  - SQL contract JSON schema - JSON schema for validating contract structure
21
20
 
22
21
  ## Responsibilities
23
22
 
24
23
  - **SQL Contract Builder**: Provides the `defineContract()` builder API for creating SQL contracts programmatically with type safety, including pack-ref based `.target()` and `.extensionPacks()` helpers
25
- - **SQL Contract Validation**: Implements SQL-specific contract validation (`validateContractStructure`, `validateContractLogic`, `validateContract`) and normalization
24
+ - **Storage Type Authoring**: Supports `storage.types` declarations and `typeRef` columns via the SQL builder
26
25
  - **SQL Contract JSON Schema**: Provides JSON schema for validating contract structure in IDEs and tooling
27
26
  - **Composition Layer**: Composes the target-agnostic builder core from `@prisma-next/contract-authoring` with SQL-specific types and validation logic
27
+ - **Generated Defaults**: Supports client-generated defaults via `ColumnDefault.kind = 'generated'` in contract authoring
28
28
 
29
29
  ## Package Status
30
30
 
@@ -34,7 +34,6 @@ This package was created in Phase 1 and refactored in Phase 2. It now composes t
34
34
 
35
35
  - **Composes generic core**: Uses `@prisma-next/contract-authoring` for generic builder state management (`TableBuilder`, `ModelBuilder`, `ContractBuilder` base class)
36
36
  - **SQL-specific types**: Provides SQL-specific contract types (`SqlContract`, `SqlStorage`, `SqlMappings`) from `@prisma-next/sql-contract/types`
37
- - **SQL-specific validation**: Implements SQL-specific contract validation (`validateContractStructure`, `validateContractLogic`, `validateContract`) and normalization (`normalizeContract`)
38
37
  - **SQL-specific build()**: Implements SQL-specific `build()` method in `SqlContractBuilder` that constructs `SqlContract` instances with SQL-specific structure (uniques, indexes, foreignKeys arrays)
39
38
 
40
39
  This package is part of the package layering architecture:
@@ -44,7 +43,6 @@ This package is part of the package layering architecture:
44
43
  ## Exports
45
44
 
46
45
  - `./contract-builder` - Contract builder API (`defineContract`, `ColumnBuilder`)
47
- - `./contract` - Contract validation (`validateContract`, `computeMappings`)
48
46
  - `./schema-sql` - SQL contract JSON schema (`data-contract-sql-v1.json`)
49
47
 
50
48
  ## Usage
@@ -56,15 +54,17 @@ import { defineContract } from '@prisma-next/sql-contract-ts/contract-builder';
56
54
  import type { CodecTypes } from '@prisma-next/adapter-postgres/codec-types';
57
55
  import postgresPack from '@prisma-next/target-postgres/pack';
58
56
  import pgvector from '@prisma-next/extension-pgvector/pack';
59
- import { int4Column, textColumn } from '@prisma-next/adapter-postgres/column-types';
57
+ import { enumColumn, enumType, int4Column, textColumn } from '@prisma-next/adapter-postgres/column-types';
60
58
 
61
59
  const contract = defineContract<CodecTypes>()
62
60
  .target(postgresPack)
63
61
  .extensionPacks({ pgvector })
62
+ .storageType('Role', enumType('role', ['USER', 'ADMIN']))
64
63
  .table('user', (t) =>
65
64
  t
66
65
  .column('id', { type: int4Column, nullable: false })
67
66
  .column('email', { type: textColumn, nullable: false })
67
+ .column('role', { type: enumColumn('Role', 'role') })
68
68
  .primaryKey(['id'], 'user_pkey') // Named primary key
69
69
  .unique(['email'], 'user_email_unique') // Named unique constraint
70
70
  .index(['email'], 'user_email_idx'), // Named index
@@ -95,16 +95,13 @@ The table builder supports the following constraint methods:
95
95
 
96
96
  ### Validating Contracts
97
97
 
98
+ Contract JSON validation now lives in `@prisma-next/sql-contract/validate` (shared plane), while this package focuses on authoring/building contracts.
99
+
98
100
  ```typescript
99
- import { validateContract } from '@prisma-next/sql-contract-ts/contract';
100
- import type { SqlContract, SqlStorage } from '@prisma-next/sql-contract/types';
101
+ import { validateContract } from '@prisma-next/sql-contract/validate';
101
102
  import type { Contract } from './contract.d';
102
103
 
103
- // From JSON import
104
104
  const contract = validateContract<Contract>(contractJson);
105
-
106
- // Or with generic type (less type-safe)
107
- const contract = validateContract<SqlContract<SqlStorage>>(contractJson);
108
105
  ```
109
106
 
110
107
  ## Dependencies
@@ -0,0 +1,105 @@
1
+ import { BuildModels, BuildRelations, BuildStorageColumn, ColumnBuilderState, ContractBuilder, ContractBuilderState, ExtractColumns, ExtractPrimaryKey, ModelBuilder, ModelBuilderState, RelationDefinition, TableBuilder, TableBuilderState } from "@prisma-next/contract-authoring";
2
+ import { ExtensionPackRef, TargetPackRef } from "@prisma-next/contract/framework-components";
3
+ import { SqlContract, SqlMappings, StorageTypeInstance } from "@prisma-next/sql-contract/types";
4
+
5
+ //#region src/contract-builder.d.ts
6
+
7
+ /**
8
+ * Type-level mappings structure for contracts built via `defineContract()`.
9
+ *
10
+ * Compile-time type helper (not a runtime object) that ensures mappings match what the builder
11
+ * produces. `codecTypes` uses the generic `CodecTypes` parameter; `operationTypes` is always
12
+ * empty since operations are added via extensions at runtime.
13
+ *
14
+ * **Difference from ExecutionContext**: This is a compile-time type for contract construction.
15
+ * `ExecutionContext` is a runtime object with populated registries for query execution.
16
+ *
17
+ * @template C - The `CodecTypes` generic parameter passed to `defineContract<CodecTypes>()`
18
+ */
19
+ type ContractBuilderMappings<C extends Record<string, {
20
+ output: unknown;
21
+ }>> = Omit<SqlMappings, 'codecTypes' | 'operationTypes'> & {
22
+ readonly codecTypes: C;
23
+ readonly operationTypes: Record<string, never>;
24
+ };
25
+ type BuildStorageTable<_TableName extends string, Columns extends Record<string, ColumnBuilderState<string, boolean, string>>, PK extends readonly string[] | undefined> = {
26
+ readonly columns: { readonly [K in keyof Columns]: Columns[K] extends ColumnBuilderState<string, infer Null, infer TType> ? BuildStorageColumn<Null & boolean, TType> : never };
27
+ readonly uniques: ReadonlyArray<{
28
+ readonly columns: readonly string[];
29
+ readonly name?: string;
30
+ }>;
31
+ readonly indexes: ReadonlyArray<{
32
+ readonly columns: readonly string[];
33
+ readonly name?: string;
34
+ }>;
35
+ readonly foreignKeys: ReadonlyArray<{
36
+ readonly columns: readonly string[];
37
+ readonly references: {
38
+ readonly table: string;
39
+ readonly columns: readonly string[];
40
+ };
41
+ readonly name?: string;
42
+ }>;
43
+ } & (PK extends readonly string[] ? {
44
+ readonly primaryKey: {
45
+ readonly columns: PK;
46
+ readonly name?: string;
47
+ };
48
+ } : Record<string, never>);
49
+ type BuildStorage<Tables extends Record<string, TableBuilderState<string, Record<string, ColumnBuilderState<string, boolean, string>>, readonly string[] | undefined>>, Types extends Record<string, StorageTypeInstance>> = {
50
+ readonly tables: { readonly [K in keyof Tables]: BuildStorageTable<K & string, ExtractColumns<Tables[K]>, ExtractPrimaryKey<Tables[K]>> };
51
+ readonly types: Types;
52
+ };
53
+ interface ColumnBuilder<Name extends string, Nullable extends boolean, Type extends string> {
54
+ nullable<Value extends boolean>(value?: Value): ColumnBuilder<Name, Value, Type>;
55
+ type<Id extends string>(id: Id): ColumnBuilder<Name, Nullable, Id>;
56
+ build(): ColumnBuilderState<Name, Nullable, Type>;
57
+ }
58
+ declare class SqlContractBuilder<CodecTypes extends Record<string, {
59
+ output: unknown;
60
+ }> = Record<string, never>, Target extends string | undefined = undefined, Tables extends Record<string, TableBuilderState<string, Record<string, ColumnBuilderState<string, boolean, string>>, readonly string[] | undefined>> = Record<never, never>, Models extends Record<string, ModelBuilderState<string, string, Record<string, string>, Record<string, RelationDefinition>>> = Record<never, never>, Types extends Record<string, StorageTypeInstance> = Record<never, never>, StorageHash extends string | undefined = undefined, ExtensionPacks extends Record<string, unknown> | undefined = undefined, Capabilities extends Record<string, Record<string, boolean>> | undefined = undefined> extends ContractBuilder<Target, Tables, Models, StorageHash, ExtensionPacks, Capabilities> {
61
+ protected readonly state: ContractBuilderState<Target, Tables, Models, StorageHash, ExtensionPacks, Capabilities> & {
62
+ readonly storageTypes?: Types;
63
+ };
64
+ /**
65
+ * This method is responsible for normalizing the contract IR by setting default values
66
+ * for all required fields:
67
+ * - `nullable`: defaults to `false` if not provided
68
+ * - `uniques`: defaults to `[]` (empty array)
69
+ * - `indexes`: defaults to `[]` (empty array)
70
+ * - `foreignKeys`: defaults to `[]` (empty array)
71
+ * - `relations`: defaults to `{}` (empty object) for both model-level and contract-level
72
+ * - `nativeType`: required field set from column type descriptor when columns are defined
73
+ *
74
+ * The contract builder is the **only** place where normalization should occur.
75
+ * Validators, parsers, and emitters should assume the contract is already normalized.
76
+ *
77
+ * **Required**: Use column type descriptors (e.g., `int4Column`, `textColumn`) when defining columns.
78
+ * This ensures `nativeType` is set correctly at build time.
79
+ *
80
+ * @returns A normalized SqlContract with all required fields present
81
+ */
82
+ build(): Target extends string ? SqlContract<BuildStorage<Tables, Types>, BuildModels<Models>, BuildRelations<Models>, ContractBuilderMappings<CodecTypes>> & {
83
+ readonly schemaVersion: '1';
84
+ readonly target: Target;
85
+ readonly targetFamily: 'sql';
86
+ readonly storageHash: StorageHash extends string ? StorageHash : string;
87
+ } & (ExtensionPacks extends Record<string, unknown> ? {
88
+ readonly extensionPacks: ExtensionPacks;
89
+ } : Record<string, never>) & (Capabilities extends Record<string, Record<string, boolean>> ? {
90
+ readonly capabilities: Capabilities;
91
+ } : Record<string, never>) : never;
92
+ target<T extends string>(packRef: TargetPackRef<'sql', T>): SqlContractBuilder<CodecTypes, T, Tables, Models, Types, StorageHash, ExtensionPacks, Capabilities>;
93
+ extensionPacks(packs: Record<string, ExtensionPackRef<'sql', string>>): SqlContractBuilder<CodecTypes, Target, Tables, Models, Types, StorageHash, ExtensionPacks, Capabilities>;
94
+ capabilities<C extends Record<string, Record<string, boolean>>>(capabilities: C): SqlContractBuilder<CodecTypes, Target, Tables, Models, Types, StorageHash, ExtensionPacks, C>;
95
+ storageHash<H extends string>(hash: H): SqlContractBuilder<CodecTypes, Target, Tables, Models, Types, H, ExtensionPacks, Capabilities>;
96
+ table<TableName extends string, T extends TableBuilder<TableName, Record<string, ColumnBuilderState<string, boolean, string>>, readonly string[] | undefined>>(name: TableName, callback: (t: TableBuilder<TableName>) => T | undefined): SqlContractBuilder<CodecTypes, Target, Tables & Record<TableName, ReturnType<T['build']>>, Models, Types, StorageHash, ExtensionPacks, Capabilities>;
97
+ model<ModelName extends string, TableName extends string, M extends ModelBuilder<ModelName, TableName, Record<string, string>, Record<string, RelationDefinition>>>(name: ModelName, table: TableName, callback: (m: ModelBuilder<ModelName, TableName, Record<string, string>, Record<never, never>>) => M | undefined): SqlContractBuilder<CodecTypes, Target, Tables, Models & Record<ModelName, ReturnType<M['build']>>, Types, StorageHash, ExtensionPacks, Capabilities>;
98
+ storageType<Name extends string, Type extends StorageTypeInstance>(name: Name, typeInstance: Type): SqlContractBuilder<CodecTypes, Target, Tables, Models, Types & Record<Name, Type>, StorageHash, ExtensionPacks, Capabilities>;
99
+ }
100
+ declare function defineContract<CodecTypes extends Record<string, {
101
+ output: unknown;
102
+ }> = Record<string, never>>(): SqlContractBuilder<CodecTypes>;
103
+ //#endregion
104
+ export { type ColumnBuilder, defineContract };
105
+ //# sourceMappingURL=contract-builder.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract-builder.d.mts","names":[],"sources":["../src/contract-builder.ts"],"sourcesContent":[],"mappings":"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"}
@@ -0,0 +1,344 @@
1
+ import { ContractBuilder, ModelBuilder, TableBuilder, createTable } from "@prisma-next/contract-authoring";
2
+ import { ifDefined } from "@prisma-next/utils/defined";
3
+ import { ColumnDefaultSchema } from "@prisma-next/sql-contract/validators";
4
+ import { type } from "arktype";
5
+
6
+ //#region src/contract.ts
7
+ /**
8
+ * Structural validation schema for SqlContract using Arktype.
9
+ * This validates the shape and types of the contract structure.
10
+ */
11
+ const StorageColumnSchema = type.declare().type({
12
+ nativeType: "string",
13
+ codecId: "string",
14
+ nullable: "boolean",
15
+ "typeParams?": "Record<string, unknown>",
16
+ "typeRef?": "string",
17
+ "default?": ColumnDefaultSchema
18
+ });
19
+ const StorageTypeInstanceSchema = type.declare().type({
20
+ codecId: "string",
21
+ nativeType: "string",
22
+ typeParams: "Record<string, unknown>"
23
+ });
24
+ const PrimaryKeySchema = type.declare().type({
25
+ columns: type.string.array().readonly(),
26
+ "name?": "string"
27
+ });
28
+ const UniqueConstraintSchema = type.declare().type({
29
+ columns: type.string.array().readonly(),
30
+ "name?": "string"
31
+ });
32
+ const IndexSchema = type.declare().type({
33
+ columns: type.string.array().readonly(),
34
+ "name?": "string"
35
+ });
36
+ const ForeignKeyReferencesSchema = type.declare().type({
37
+ table: "string",
38
+ columns: type.string.array().readonly()
39
+ });
40
+ const ForeignKeySchema = type.declare().type({
41
+ columns: type.string.array().readonly(),
42
+ references: ForeignKeyReferencesSchema,
43
+ "name?": "string"
44
+ });
45
+ const StorageTableSchema = type.declare().type({
46
+ columns: type({ "[string]": StorageColumnSchema }),
47
+ "primaryKey?": PrimaryKeySchema,
48
+ uniques: UniqueConstraintSchema.array().readonly(),
49
+ indexes: IndexSchema.array().readonly(),
50
+ foreignKeys: ForeignKeySchema.array().readonly()
51
+ });
52
+ const StorageSchema = type.declare().type({
53
+ tables: type({ "[string]": StorageTableSchema }),
54
+ "types?": type({ "[string]": StorageTypeInstanceSchema })
55
+ });
56
+ const ModelFieldSchema = type.declare().type({ column: "string" });
57
+ const ModelStorageSchema = type.declare().type({ table: "string" });
58
+ const ModelSchema = type.declare().type({
59
+ storage: ModelStorageSchema,
60
+ fields: type({ "[string]": ModelFieldSchema }),
61
+ relations: type({ "[string]": "unknown" })
62
+ });
63
+ const ExecutionMutationDefaultValueSchema = type({
64
+ kind: "'generator'",
65
+ id: "'ulid' | 'nanoid' | 'uuidv7' | 'uuidv4' | 'cuid2' | 'ksuid'",
66
+ "params?": "Record<string, unknown>"
67
+ });
68
+ const ExecutionSchema = type({ mutations: { defaults: type({
69
+ ref: {
70
+ table: "string",
71
+ column: "string"
72
+ },
73
+ "onCreate?": ExecutionMutationDefaultValueSchema,
74
+ "onUpdate?": ExecutionMutationDefaultValueSchema
75
+ }).array().readonly() } });
76
+ /**
77
+ * Complete SqlContract schema for structural validation.
78
+ * This validates the entire contract structure at once.
79
+ */
80
+ const SqlContractSchema = type({
81
+ "schemaVersion?": "'1'",
82
+ target: "string",
83
+ targetFamily: "'sql'",
84
+ storageHash: "string",
85
+ "executionHash?": "string",
86
+ "profileHash?": "string",
87
+ "capabilities?": "Record<string, Record<string, boolean>>",
88
+ "extensionPacks?": "Record<string, unknown>",
89
+ "meta?": "Record<string, unknown>",
90
+ "sources?": "Record<string, unknown>",
91
+ models: type({ "[string]": ModelSchema }),
92
+ storage: StorageSchema,
93
+ "execution?": ExecutionSchema
94
+ });
95
+ /**
96
+ * Computes mapping dictionaries from models and storage structures.
97
+ * Assumes valid input - validation happens separately in validateContractLogic().
98
+ *
99
+ * @param models - Models object from contract
100
+ * @param storage - Storage object from contract
101
+ * @param existingMappings - Existing mappings from contract input (optional)
102
+ * @returns Computed mappings dictionary
103
+ */
104
+ function computeMappings(models, _storage, existingMappings) {
105
+ const modelToTable = {};
106
+ const tableToModel = {};
107
+ const fieldToColumn = {};
108
+ const columnToField = {};
109
+ for (const [modelName, model] of Object.entries(models)) {
110
+ const tableName = model.storage.table;
111
+ modelToTable[modelName] = tableName;
112
+ tableToModel[tableName] = modelName;
113
+ const modelFieldToColumn = {};
114
+ for (const [fieldName, field] of Object.entries(model.fields)) {
115
+ const columnName = field.column;
116
+ modelFieldToColumn[fieldName] = columnName;
117
+ if (!columnToField[tableName]) columnToField[tableName] = {};
118
+ columnToField[tableName][columnName] = fieldName;
119
+ }
120
+ fieldToColumn[modelName] = modelFieldToColumn;
121
+ }
122
+ return {
123
+ modelToTable: existingMappings?.modelToTable ?? modelToTable,
124
+ tableToModel: existingMappings?.tableToModel ?? tableToModel,
125
+ fieldToColumn: existingMappings?.fieldToColumn ?? fieldToColumn,
126
+ columnToField: existingMappings?.columnToField ?? columnToField,
127
+ codecTypes: existingMappings?.codecTypes ?? {},
128
+ operationTypes: existingMappings?.operationTypes ?? {}
129
+ };
130
+ }
131
+
132
+ //#endregion
133
+ //#region src/contract-builder.ts
134
+ var SqlContractBuilder = class SqlContractBuilder extends ContractBuilder {
135
+ /**
136
+ * This method is responsible for normalizing the contract IR by setting default values
137
+ * for all required fields:
138
+ * - `nullable`: defaults to `false` if not provided
139
+ * - `uniques`: defaults to `[]` (empty array)
140
+ * - `indexes`: defaults to `[]` (empty array)
141
+ * - `foreignKeys`: defaults to `[]` (empty array)
142
+ * - `relations`: defaults to `{}` (empty object) for both model-level and contract-level
143
+ * - `nativeType`: required field set from column type descriptor when columns are defined
144
+ *
145
+ * The contract builder is the **only** place where normalization should occur.
146
+ * Validators, parsers, and emitters should assume the contract is already normalized.
147
+ *
148
+ * **Required**: Use column type descriptors (e.g., `int4Column`, `textColumn`) when defining columns.
149
+ * This ensures `nativeType` is set correctly at build time.
150
+ *
151
+ * @returns A normalized SqlContract with all required fields present
152
+ */
153
+ build() {
154
+ if (!this.state.target) throw new Error("target is required. Call .target() before .build()");
155
+ const target = this.state.target;
156
+ const storageTables = {};
157
+ const executionDefaults = [];
158
+ for (const tableName of Object.keys(this.state.tables)) {
159
+ const tableState = this.state.tables[tableName];
160
+ if (!tableState) continue;
161
+ const columns = {};
162
+ for (const columnName in tableState.columns) {
163
+ const columnState = tableState.columns[columnName];
164
+ if (!columnState) continue;
165
+ const codecId = columnState.type;
166
+ const nativeType = columnState.nativeType;
167
+ const typeRef = columnState.typeRef;
168
+ columns[columnName] = {
169
+ nativeType,
170
+ codecId,
171
+ nullable: columnState.nullable ?? false,
172
+ ...ifDefined("typeParams", columnState.typeParams),
173
+ ...ifDefined("default", columnState.default),
174
+ ...ifDefined("typeRef", typeRef)
175
+ };
176
+ if ("executionDefault" in columnState && columnState.executionDefault) executionDefaults.push({
177
+ ref: {
178
+ table: tableName,
179
+ column: columnName
180
+ },
181
+ onCreate: columnState.executionDefault
182
+ });
183
+ }
184
+ storageTables[tableName] = {
185
+ columns,
186
+ uniques: (tableState.uniques ?? []).map((u) => ({
187
+ columns: u.columns,
188
+ ...u.name ? { name: u.name } : {}
189
+ })),
190
+ indexes: (tableState.indexes ?? []).map((i) => ({
191
+ columns: i.columns,
192
+ ...i.name ? { name: i.name } : {}
193
+ })),
194
+ foreignKeys: (tableState.foreignKeys ?? []).map((fk) => ({
195
+ columns: fk.columns,
196
+ references: fk.references,
197
+ ...fk.name ? { name: fk.name } : {}
198
+ })),
199
+ ...tableState.primaryKey ? { primaryKey: {
200
+ columns: tableState.primaryKey,
201
+ ...tableState.primaryKeyName ? { name: tableState.primaryKeyName } : {}
202
+ } } : {}
203
+ };
204
+ }
205
+ const storage = {
206
+ tables: storageTables,
207
+ types: this.state.storageTypes ?? {}
208
+ };
209
+ const execution = executionDefaults.length > 0 ? { mutations: { defaults: executionDefaults.sort((a, b) => {
210
+ const tableCompare = a.ref.table.localeCompare(b.ref.table);
211
+ if (tableCompare !== 0) return tableCompare;
212
+ return a.ref.column.localeCompare(b.ref.column);
213
+ }) } } : void 0;
214
+ const modelsPartial = {};
215
+ for (const modelName in this.state.models) {
216
+ const modelState = this.state.models[modelName];
217
+ if (!modelState) continue;
218
+ const modelStateTyped = modelState;
219
+ const fields = {};
220
+ for (const fieldName in modelStateTyped.fields) {
221
+ const columnName = modelStateTyped.fields[fieldName];
222
+ if (columnName) fields[fieldName] = { column: columnName };
223
+ }
224
+ modelsPartial[modelName] = {
225
+ storage: { table: modelStateTyped.table },
226
+ fields,
227
+ relations: {}
228
+ };
229
+ }
230
+ const relationsPartial = {};
231
+ for (const modelName in this.state.models) {
232
+ const modelState = this.state.models[modelName];
233
+ if (!modelState) continue;
234
+ const modelStateTyped = modelState;
235
+ const tableName = modelStateTyped.table;
236
+ if (!tableName) continue;
237
+ if (modelStateTyped.relations && Object.keys(modelStateTyped.relations).length > 0) {
238
+ if (!relationsPartial[tableName]) relationsPartial[tableName] = {};
239
+ const tableRelations = relationsPartial[tableName];
240
+ if (tableRelations) for (const relationName in modelStateTyped.relations) {
241
+ const relation = modelStateTyped.relations[relationName];
242
+ if (relation) tableRelations[relationName] = relation;
243
+ }
244
+ }
245
+ }
246
+ const models = modelsPartial;
247
+ const mappings = {
248
+ ...computeMappings(models, storage),
249
+ codecTypes: {},
250
+ operationTypes: {}
251
+ };
252
+ const extensionNamespaces = this.state.extensionNamespaces ?? [];
253
+ const extensionPacks = { ...this.state.extensionPacks || {} };
254
+ for (const namespace of extensionNamespaces) if (!Object.hasOwn(extensionPacks, namespace)) extensionPacks[namespace] = {};
255
+ return {
256
+ schemaVersion: "1",
257
+ target,
258
+ targetFamily: "sql",
259
+ storageHash: this.state.storageHash || "sha256:ts-builder-placeholder",
260
+ models,
261
+ relations: relationsPartial,
262
+ storage,
263
+ mappings,
264
+ ...execution ? { execution } : {},
265
+ extensionPacks,
266
+ capabilities: this.state.capabilities || {},
267
+ meta: {},
268
+ sources: {}
269
+ };
270
+ }
271
+ target(packRef) {
272
+ return new SqlContractBuilder({
273
+ ...this.state,
274
+ target: packRef.targetId
275
+ });
276
+ }
277
+ extensionPacks(packs) {
278
+ if (!this.state.target) throw new Error("extensionPacks() requires target() to be called first");
279
+ const namespaces = new Set(this.state.extensionNamespaces ?? []);
280
+ for (const packRef of Object.values(packs)) {
281
+ if (!packRef) continue;
282
+ if (packRef.kind !== "extension") throw new Error(`extensionPacks() only accepts extension pack refs. Received kind "${packRef.kind}".`);
283
+ if (packRef.familyId !== "sql") throw new Error(`extension pack "${packRef.id}" targets family "${packRef.familyId}" but this builder targets "sql".`);
284
+ if (packRef.targetId && packRef.targetId !== this.state.target) throw new Error(`extension pack "${packRef.id}" targets "${packRef.targetId}" but builder target is "${this.state.target}".`);
285
+ namespaces.add(packRef.id);
286
+ }
287
+ return new SqlContractBuilder({
288
+ ...this.state,
289
+ extensionNamespaces: [...namespaces]
290
+ });
291
+ }
292
+ capabilities(capabilities) {
293
+ return new SqlContractBuilder({
294
+ ...this.state,
295
+ capabilities
296
+ });
297
+ }
298
+ storageHash(hash) {
299
+ return new SqlContractBuilder({
300
+ ...this.state,
301
+ storageHash: hash
302
+ });
303
+ }
304
+ table(name, callback) {
305
+ const tableBuilder = createTable(name);
306
+ const result = callback(tableBuilder);
307
+ const tableState = (result instanceof TableBuilder ? result : tableBuilder).build();
308
+ return new SqlContractBuilder({
309
+ ...this.state,
310
+ tables: {
311
+ ...this.state.tables,
312
+ [name]: tableState
313
+ }
314
+ });
315
+ }
316
+ model(name, table, callback) {
317
+ const modelBuilder = new ModelBuilder(name, table);
318
+ const result = callback(modelBuilder);
319
+ const modelState = (result instanceof ModelBuilder ? result : modelBuilder).build();
320
+ return new SqlContractBuilder({
321
+ ...this.state,
322
+ models: {
323
+ ...this.state.models,
324
+ [name]: modelState
325
+ }
326
+ });
327
+ }
328
+ storageType(name, typeInstance) {
329
+ return new SqlContractBuilder({
330
+ ...this.state,
331
+ storageTypes: {
332
+ ...this.state.storageTypes ?? {},
333
+ [name]: typeInstance
334
+ }
335
+ });
336
+ }
337
+ };
338
+ function defineContract() {
339
+ return new SqlContractBuilder();
340
+ }
341
+
342
+ //#endregion
343
+ export { defineContract };
344
+ //# sourceMappingURL=contract-builder.mjs.map