@prisma-next/sql-contract-ts 0.3.0-dev.9 → 0.3.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.
- package/LICENSE +201 -0
- package/README.md +78 -13
- package/dist/config-types.d.mts +8 -0
- package/dist/config-types.d.mts.map +1 -0
- package/dist/config-types.mjs +14 -0
- package/dist/config-types.mjs.map +1 -0
- package/dist/contract-builder.d.mts +97 -0
- package/dist/contract-builder.d.mts.map +1 -0
- package/dist/contract-builder.mjs +379 -0
- package/dist/contract-builder.mjs.map +1 -0
- package/package.json +24 -22
- package/schemas/data-contract-sql-v1.json +168 -8
- package/src/config-types.ts +11 -0
- package/src/contract-builder.ts +447 -93
- package/src/contract.ts +115 -105
- package/src/exports/config-types.ts +2 -0
- package/dist/chunk-SEOX3AAQ.js +0 -309
- package/dist/chunk-SEOX3AAQ.js.map +0 -1
- package/dist/contract-builder.d.ts +0 -87
- package/dist/contract-builder.d.ts.map +0 -1
- package/dist/contract.d.ts +0 -50
- package/dist/contract.d.ts.map +0 -1
- package/dist/exports/contract-builder.d.ts +0 -3
- package/dist/exports/contract-builder.d.ts.map +0 -1
- package/dist/exports/contract-builder.js +0 -216
- package/dist/exports/contract-builder.js.map +0 -1
- package/dist/exports/contract.d.ts +0 -2
- package/dist/exports/contract.d.ts.map +0 -1
- package/dist/exports/contract.js +0 -9
- package/dist/exports/contract.js.map +0 -1
- package/src/exports/contract.ts +0 -1
package/src/contract-builder.ts
CHANGED
|
@@ -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,41 +21,137 @@ 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
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
31
|
+
import {
|
|
32
|
+
applyFkDefaults,
|
|
33
|
+
type ContractWithTypeMaps,
|
|
34
|
+
type Index,
|
|
35
|
+
type ModelDefinition,
|
|
36
|
+
type ModelField,
|
|
37
|
+
type ReferentialAction,
|
|
38
|
+
type SqlContract,
|
|
39
|
+
type SqlMappings,
|
|
40
|
+
type SqlStorage,
|
|
41
|
+
type StorageTypeInstance,
|
|
42
|
+
type TypeMaps,
|
|
25
43
|
} from '@prisma-next/sql-contract/types';
|
|
44
|
+
import { ifDefined } from '@prisma-next/utils/defined';
|
|
26
45
|
import { computeMappings } from './contract';
|
|
27
46
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
readonly
|
|
45
|
-
readonly
|
|
47
|
+
type ColumnDefaultForCodec<
|
|
48
|
+
CodecTypes extends Record<string, { output: unknown }>,
|
|
49
|
+
CodecId extends string,
|
|
50
|
+
> =
|
|
51
|
+
| {
|
|
52
|
+
readonly kind: 'literal';
|
|
53
|
+
readonly value: CodecId extends keyof CodecTypes ? CodecTypes[CodecId]['output'] : unknown;
|
|
54
|
+
}
|
|
55
|
+
| { readonly kind: 'function'; readonly expression: string };
|
|
56
|
+
|
|
57
|
+
type SqlNullableColumnOptions<
|
|
58
|
+
Descriptor extends ColumnTypeDescriptor,
|
|
59
|
+
CodecTypes extends Record<string, { output: unknown }>,
|
|
60
|
+
> = {
|
|
61
|
+
readonly type: Descriptor;
|
|
62
|
+
readonly nullable: true;
|
|
63
|
+
readonly typeParams?: Record<string, unknown>;
|
|
64
|
+
readonly default?: ColumnDefaultForCodec<CodecTypes, Descriptor['codecId']>;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
type SqlNonNullableColumnOptions<
|
|
68
|
+
Descriptor extends ColumnTypeDescriptor,
|
|
69
|
+
CodecTypes extends Record<string, { output: unknown }>,
|
|
70
|
+
> = {
|
|
71
|
+
readonly type: Descriptor;
|
|
72
|
+
readonly nullable?: false;
|
|
73
|
+
readonly typeParams?: Record<string, unknown>;
|
|
74
|
+
readonly default?: ColumnDefaultForCodec<CodecTypes, Descriptor['codecId']>;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
type SqlGeneratedColumnOptions<
|
|
78
|
+
Descriptor extends ColumnTypeDescriptor,
|
|
79
|
+
CodecTypes extends Record<string, { output: unknown }>,
|
|
80
|
+
> = Omit<SqlNonNullableColumnOptions<Descriptor, CodecTypes>, 'default' | 'nullable'> & {
|
|
81
|
+
readonly nullable?: false;
|
|
82
|
+
readonly generated: ExecutionMutationDefaultValue;
|
|
46
83
|
};
|
|
47
84
|
|
|
85
|
+
type SqlColumnOptions<
|
|
86
|
+
Descriptor extends ColumnTypeDescriptor,
|
|
87
|
+
CodecTypes extends Record<string, { output: unknown }>,
|
|
88
|
+
> =
|
|
89
|
+
| SqlNullableColumnOptions<Descriptor, CodecTypes>
|
|
90
|
+
| SqlNonNullableColumnOptions<Descriptor, CodecTypes>;
|
|
91
|
+
|
|
92
|
+
export interface SqlTableBuilder<
|
|
93
|
+
Name extends string,
|
|
94
|
+
CodecTypes extends Record<string, { output: unknown }>,
|
|
95
|
+
Columns extends Record<string, ColumnBuilderState<string, boolean, string>> = Record<
|
|
96
|
+
never,
|
|
97
|
+
ColumnBuilderState<string, boolean, string>
|
|
98
|
+
>,
|
|
99
|
+
PrimaryKey extends readonly string[] | undefined = undefined,
|
|
100
|
+
> extends Omit<TableBuilder<Name, Columns, PrimaryKey>, 'column' | 'generated'> {
|
|
101
|
+
column<ColName extends string, Descriptor extends ColumnTypeDescriptor>(
|
|
102
|
+
name: ColName,
|
|
103
|
+
options: SqlNullableColumnOptions<Descriptor, CodecTypes>,
|
|
104
|
+
): TableBuilder<
|
|
105
|
+
Name,
|
|
106
|
+
Columns & Record<ColName, ColumnBuilderState<ColName, true, Descriptor['codecId']>>,
|
|
107
|
+
PrimaryKey
|
|
108
|
+
>;
|
|
109
|
+
column<ColName extends string, Descriptor extends ColumnTypeDescriptor>(
|
|
110
|
+
name: ColName,
|
|
111
|
+
options: SqlNonNullableColumnOptions<Descriptor, CodecTypes>,
|
|
112
|
+
): TableBuilder<
|
|
113
|
+
Name,
|
|
114
|
+
Columns & Record<ColName, ColumnBuilderState<ColName, false, Descriptor['codecId']>>,
|
|
115
|
+
PrimaryKey
|
|
116
|
+
>;
|
|
117
|
+
column<ColName extends string, Descriptor extends ColumnTypeDescriptor>(
|
|
118
|
+
name: ColName,
|
|
119
|
+
options: SqlColumnOptions<Descriptor, CodecTypes>,
|
|
120
|
+
): TableBuilder<
|
|
121
|
+
Name,
|
|
122
|
+
Columns & Record<ColName, ColumnBuilderState<ColName, boolean, Descriptor['codecId']>>,
|
|
123
|
+
PrimaryKey
|
|
124
|
+
>;
|
|
125
|
+
generated<ColName extends string, Descriptor extends ColumnTypeDescriptor>(
|
|
126
|
+
name: ColName,
|
|
127
|
+
options: SqlGeneratedColumnOptions<Descriptor, CodecTypes>,
|
|
128
|
+
): TableBuilder<
|
|
129
|
+
Name,
|
|
130
|
+
Columns & Record<ColName, ColumnBuilderState<ColName, false, Descriptor['codecId']>>,
|
|
131
|
+
PrimaryKey
|
|
132
|
+
>;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
type ContractBuilderMappings = SqlMappings;
|
|
136
|
+
|
|
137
|
+
type ExtractCodecTypesFromPack<P> = P extends { __codecTypes?: infer C }
|
|
138
|
+
? C extends Record<string, { output: unknown }>
|
|
139
|
+
? C
|
|
140
|
+
: Record<string, never>
|
|
141
|
+
: Record<string, never>;
|
|
142
|
+
|
|
143
|
+
type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (
|
|
144
|
+
k: infer I,
|
|
145
|
+
) => void
|
|
146
|
+
? I
|
|
147
|
+
: never;
|
|
148
|
+
|
|
149
|
+
type MergeExtensionCodecTypes<Packs extends Record<string, unknown>> = UnionToIntersection<
|
|
150
|
+
{
|
|
151
|
+
[K in keyof Packs]: ExtractCodecTypesFromPack<Packs[K]>;
|
|
152
|
+
}[keyof Packs]
|
|
153
|
+
>;
|
|
154
|
+
|
|
48
155
|
type BuildStorageTable<
|
|
49
156
|
_TableName extends string,
|
|
50
157
|
Columns extends Record<string, ColumnBuilderState<string, boolean, string>>,
|
|
@@ -59,11 +166,19 @@ type BuildStorageTable<
|
|
|
59
166
|
? BuildStorageColumn<Null & boolean, TType>
|
|
60
167
|
: never;
|
|
61
168
|
};
|
|
62
|
-
readonly uniques: ReadonlyArray<
|
|
63
|
-
readonly indexes: ReadonlyArray<
|
|
64
|
-
readonly foreignKeys: ReadonlyArray<
|
|
169
|
+
readonly uniques: ReadonlyArray<{ readonly columns: readonly string[]; readonly name?: string }>;
|
|
170
|
+
readonly indexes: ReadonlyArray<Index>;
|
|
171
|
+
readonly foreignKeys: ReadonlyArray<{
|
|
172
|
+
readonly columns: readonly string[];
|
|
173
|
+
readonly references: { readonly table: string; readonly columns: readonly string[] };
|
|
174
|
+
readonly name?: string;
|
|
175
|
+
readonly onDelete?: ReferentialAction;
|
|
176
|
+
readonly onUpdate?: ReferentialAction;
|
|
177
|
+
readonly constraint: boolean;
|
|
178
|
+
readonly index: boolean;
|
|
179
|
+
}>;
|
|
65
180
|
} & (PK extends readonly string[]
|
|
66
|
-
? { readonly primaryKey: { readonly columns: PK } }
|
|
181
|
+
? { readonly primaryKey: { readonly columns: PK; readonly name?: string } }
|
|
67
182
|
: Record<string, never>);
|
|
68
183
|
|
|
69
184
|
type BuildStorage<
|
|
@@ -75,6 +190,7 @@ type BuildStorage<
|
|
|
75
190
|
readonly string[] | undefined
|
|
76
191
|
>
|
|
77
192
|
>,
|
|
193
|
+
Types extends Record<string, StorageTypeInstance>,
|
|
78
194
|
> = {
|
|
79
195
|
readonly tables: {
|
|
80
196
|
readonly [K in keyof Tables]: BuildStorageTable<
|
|
@@ -83,6 +199,7 @@ type BuildStorage<
|
|
|
83
199
|
ExtractPrimaryKey<Tables[K]>
|
|
84
200
|
>;
|
|
85
201
|
};
|
|
202
|
+
readonly types: Types;
|
|
86
203
|
};
|
|
87
204
|
|
|
88
205
|
type BuildStorageTables<
|
|
@@ -108,6 +225,52 @@ export interface ColumnBuilder<Name extends string, Nullable extends boolean, Ty
|
|
|
108
225
|
build(): ColumnBuilderState<Name, Nullable, Type>;
|
|
109
226
|
}
|
|
110
227
|
|
|
228
|
+
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
229
|
+
if (typeof value !== 'object' || value === null) return false;
|
|
230
|
+
const proto = Object.getPrototypeOf(value);
|
|
231
|
+
return proto === Object.prototype || proto === null;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function isJsonValue(value: unknown): value is ColumnDefaultLiteralValue {
|
|
235
|
+
if (value === null) return true;
|
|
236
|
+
const valueType = typeof value;
|
|
237
|
+
if (valueType === 'string' || valueType === 'number' || valueType === 'boolean') return true;
|
|
238
|
+
if (Array.isArray(value)) {
|
|
239
|
+
return value.every((item) => isJsonValue(item));
|
|
240
|
+
}
|
|
241
|
+
if (isPlainObject(value)) {
|
|
242
|
+
return Object.values(value).every((item) => isJsonValue(item));
|
|
243
|
+
}
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function encodeDefaultLiteralValue(
|
|
248
|
+
value: ColumnDefaultLiteralInputValue,
|
|
249
|
+
): ColumnDefaultLiteralValue {
|
|
250
|
+
if (typeof value === 'bigint') {
|
|
251
|
+
return { $type: 'bigint', value: value.toString() };
|
|
252
|
+
}
|
|
253
|
+
if (value instanceof Date) {
|
|
254
|
+
return value.toISOString();
|
|
255
|
+
}
|
|
256
|
+
if (isJsonValue(value)) {
|
|
257
|
+
if (isPlainObject(value) && '$type' in value) {
|
|
258
|
+
return { $type: 'raw', value } satisfies TaggedRaw;
|
|
259
|
+
}
|
|
260
|
+
return value;
|
|
261
|
+
}
|
|
262
|
+
throw new Error(
|
|
263
|
+
'Unsupported column default literal value: expected JSON-safe value, bigint, or Date.',
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function encodeColumnDefault(defaultInput: ColumnDefault): ColumnDefault {
|
|
268
|
+
if (defaultInput.kind === 'function') {
|
|
269
|
+
return { kind: 'function', expression: defaultInput.expression };
|
|
270
|
+
}
|
|
271
|
+
return { kind: 'literal', value: encodeDefaultLiteralValue(defaultInput.value) };
|
|
272
|
+
}
|
|
273
|
+
|
|
111
274
|
class SqlContractBuilder<
|
|
112
275
|
CodecTypes extends Record<string, { output: unknown }> = Record<string, never>,
|
|
113
276
|
Target extends string | undefined = undefined,
|
|
@@ -123,10 +286,21 @@ class SqlContractBuilder<
|
|
|
123
286
|
string,
|
|
124
287
|
ModelBuilderState<string, string, Record<string, string>, Record<string, RelationDefinition>>
|
|
125
288
|
> = Record<never, never>,
|
|
126
|
-
|
|
289
|
+
Types extends Record<string, StorageTypeInstance> = Record<never, never>,
|
|
290
|
+
StorageHash extends string | undefined = undefined,
|
|
127
291
|
ExtensionPacks extends Record<string, unknown> | undefined = undefined,
|
|
128
292
|
Capabilities extends Record<string, Record<string, boolean>> | undefined = undefined,
|
|
129
|
-
> extends ContractBuilder<Target, Tables, Models,
|
|
293
|
+
> extends ContractBuilder<Target, Tables, Models, StorageHash, ExtensionPacks, Capabilities> {
|
|
294
|
+
protected declare readonly state: ContractBuilderState<
|
|
295
|
+
Target,
|
|
296
|
+
Tables,
|
|
297
|
+
Models,
|
|
298
|
+
StorageHash,
|
|
299
|
+
ExtensionPacks,
|
|
300
|
+
Capabilities
|
|
301
|
+
> & {
|
|
302
|
+
readonly storageTypes?: Types;
|
|
303
|
+
};
|
|
130
304
|
/**
|
|
131
305
|
* This method is responsible for normalizing the contract IR by setting default values
|
|
132
306
|
* for all required fields:
|
|
@@ -146,41 +320,46 @@ class SqlContractBuilder<
|
|
|
146
320
|
* @returns A normalized SqlContract with all required fields present
|
|
147
321
|
*/
|
|
148
322
|
build(): Target extends string
|
|
149
|
-
?
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
BuildRelations<Models>,
|
|
153
|
-
ContractBuilderMappings<CodecTypes>
|
|
154
|
-
> & {
|
|
155
|
-
readonly schemaVersion: '1';
|
|
156
|
-
readonly target: Target;
|
|
157
|
-
readonly targetFamily: 'sql';
|
|
158
|
-
readonly coreHash: CoreHash extends string ? CoreHash : string;
|
|
159
|
-
} & (ExtensionPacks extends Record<string, unknown>
|
|
160
|
-
? { readonly extensionPacks: ExtensionPacks }
|
|
161
|
-
: Record<string, never>) &
|
|
162
|
-
(Capabilities extends Record<string, Record<string, boolean>>
|
|
163
|
-
? { readonly capabilities: Capabilities }
|
|
164
|
-
: Record<string, never>)
|
|
165
|
-
: never {
|
|
166
|
-
// Type helper to ensure literal types are preserved in return type
|
|
167
|
-
type BuiltContract = Target extends string
|
|
168
|
-
? SqlContract<
|
|
169
|
-
BuildStorage<Tables>,
|
|
323
|
+
? ContractWithTypeMaps<
|
|
324
|
+
SqlContract<
|
|
325
|
+
BuildStorage<Tables, Types>,
|
|
170
326
|
BuildModels<Models>,
|
|
171
327
|
BuildRelations<Models>,
|
|
172
|
-
ContractBuilderMappings
|
|
328
|
+
ContractBuilderMappings
|
|
173
329
|
> & {
|
|
174
330
|
readonly schemaVersion: '1';
|
|
175
331
|
readonly target: Target;
|
|
176
332
|
readonly targetFamily: 'sql';
|
|
177
|
-
readonly
|
|
333
|
+
readonly storageHash: StorageHash extends string ? StorageHash : string;
|
|
178
334
|
} & (ExtensionPacks extends Record<string, unknown>
|
|
179
335
|
? { readonly extensionPacks: ExtensionPacks }
|
|
180
336
|
: Record<string, never>) &
|
|
181
337
|
(Capabilities extends Record<string, Record<string, boolean>>
|
|
182
338
|
? { readonly capabilities: Capabilities }
|
|
183
|
-
: Record<string, never>)
|
|
339
|
+
: Record<string, never>),
|
|
340
|
+
TypeMaps<CodecTypes, Record<string, never>>
|
|
341
|
+
>
|
|
342
|
+
: never {
|
|
343
|
+
type BuiltContract = Target extends string
|
|
344
|
+
? ContractWithTypeMaps<
|
|
345
|
+
SqlContract<
|
|
346
|
+
BuildStorage<Tables, Types>,
|
|
347
|
+
BuildModels<Models>,
|
|
348
|
+
BuildRelations<Models>,
|
|
349
|
+
ContractBuilderMappings
|
|
350
|
+
> & {
|
|
351
|
+
readonly schemaVersion: '1';
|
|
352
|
+
readonly target: Target;
|
|
353
|
+
readonly targetFamily: 'sql';
|
|
354
|
+
readonly storageHash: StorageHash extends string ? StorageHash : string;
|
|
355
|
+
} & (ExtensionPacks extends Record<string, unknown>
|
|
356
|
+
? { readonly extensionPacks: ExtensionPacks }
|
|
357
|
+
: Record<string, never>) &
|
|
358
|
+
(Capabilities extends Record<string, Record<string, boolean>>
|
|
359
|
+
? { readonly capabilities: Capabilities }
|
|
360
|
+
: Record<string, never>),
|
|
361
|
+
TypeMaps<CodecTypes, Record<string, never>>
|
|
362
|
+
>
|
|
184
363
|
: never;
|
|
185
364
|
if (!this.state.target) {
|
|
186
365
|
throw new Error('target is required. Call .target() before .build()');
|
|
@@ -189,6 +368,7 @@ class SqlContractBuilder<
|
|
|
189
368
|
const target = this.state.target as Target & string;
|
|
190
369
|
|
|
191
370
|
const storageTables = {} as Partial<Mutable<BuildStorageTables<Tables>>>;
|
|
371
|
+
const executionDefaults: ExecutionMutationDefault[] = [];
|
|
192
372
|
|
|
193
373
|
for (const tableName of Object.keys(this.state.tables) as Array<keyof Tables & string>) {
|
|
194
374
|
const tableState = this.state.tables[tableName];
|
|
@@ -210,18 +390,58 @@ class SqlContractBuilder<
|
|
|
210
390
|
if (!columnState) continue;
|
|
211
391
|
const codecId = columnState.type;
|
|
212
392
|
const nativeType = columnState.nativeType;
|
|
393
|
+
const typeRef = columnState.typeRef;
|
|
394
|
+
|
|
395
|
+
const encodedDefault =
|
|
396
|
+
columnState.default !== undefined
|
|
397
|
+
? encodeColumnDefault(columnState.default as ColumnDefault)
|
|
398
|
+
: undefined;
|
|
213
399
|
|
|
214
400
|
columns[columnName as keyof ColumnDefs] = {
|
|
215
401
|
nativeType,
|
|
216
402
|
codecId,
|
|
217
403
|
nullable: (columnState.nullable ?? false) as ColumnDefs[keyof ColumnDefs]['nullable'] &
|
|
218
404
|
boolean,
|
|
405
|
+
...ifDefined('typeParams', columnState.typeParams),
|
|
406
|
+
...ifDefined('default', encodedDefault),
|
|
407
|
+
...ifDefined('typeRef', typeRef),
|
|
219
408
|
} as BuildStorageColumn<
|
|
220
409
|
ColumnDefs[keyof ColumnDefs]['nullable'] & boolean,
|
|
221
410
|
ColumnDefs[keyof ColumnDefs]['type']
|
|
222
411
|
>;
|
|
412
|
+
|
|
413
|
+
if ('executionDefault' in columnState && columnState.executionDefault) {
|
|
414
|
+
executionDefaults.push({
|
|
415
|
+
ref: { table: tableName, column: columnName },
|
|
416
|
+
onCreate: columnState.executionDefault,
|
|
417
|
+
});
|
|
418
|
+
}
|
|
223
419
|
}
|
|
224
420
|
|
|
421
|
+
// Build uniques from table state
|
|
422
|
+
const uniques = (tableState.uniques ?? []).map((u) => ({
|
|
423
|
+
columns: u.columns,
|
|
424
|
+
...(u.name ? { name: u.name } : {}),
|
|
425
|
+
}));
|
|
426
|
+
|
|
427
|
+
// Build indexes from table state
|
|
428
|
+
const indexes = (tableState.indexes ?? []).map((i) => ({
|
|
429
|
+
columns: i.columns,
|
|
430
|
+
...(i.name ? { name: i.name } : {}),
|
|
431
|
+
...(i.using ? { using: i.using } : {}),
|
|
432
|
+
...(i.config ? { config: i.config } : {}),
|
|
433
|
+
}));
|
|
434
|
+
|
|
435
|
+
// Build foreign keys from table state, materializing defaults
|
|
436
|
+
const foreignKeys = (tableState.foreignKeys ?? []).map((fk) => ({
|
|
437
|
+
columns: fk.columns,
|
|
438
|
+
references: fk.references,
|
|
439
|
+
...applyFkDefaults(fk, this.state.foreignKeyDefaults),
|
|
440
|
+
...(fk.name ? { name: fk.name } : {}),
|
|
441
|
+
...(fk.onDelete !== undefined ? { onDelete: fk.onDelete } : {}),
|
|
442
|
+
...(fk.onUpdate !== undefined ? { onUpdate: fk.onUpdate } : {}),
|
|
443
|
+
}));
|
|
444
|
+
|
|
225
445
|
const table = {
|
|
226
446
|
columns: columns as {
|
|
227
447
|
[K in keyof ColumnDefs]: BuildStorageColumn<
|
|
@@ -229,13 +449,14 @@ class SqlContractBuilder<
|
|
|
229
449
|
ColumnDefs[K]['type']
|
|
230
450
|
>;
|
|
231
451
|
},
|
|
232
|
-
uniques
|
|
233
|
-
indexes
|
|
234
|
-
foreignKeys
|
|
452
|
+
uniques,
|
|
453
|
+
indexes,
|
|
454
|
+
foreignKeys,
|
|
235
455
|
...(tableState.primaryKey
|
|
236
456
|
? {
|
|
237
457
|
primaryKey: {
|
|
238
458
|
columns: tableState.primaryKey,
|
|
459
|
+
...(tableState.primaryKeyName ? { name: tableState.primaryKeyName } : {}),
|
|
239
460
|
},
|
|
240
461
|
}
|
|
241
462
|
: {}),
|
|
@@ -244,7 +465,26 @@ class SqlContractBuilder<
|
|
|
244
465
|
(storageTables as Mutable<BuildStorageTables<Tables>>)[tableName] = table;
|
|
245
466
|
}
|
|
246
467
|
|
|
247
|
-
const
|
|
468
|
+
const storageTypes = (this.state.storageTypes ?? {}) as Types;
|
|
469
|
+
const storage: BuildStorage<Tables, Types> = {
|
|
470
|
+
tables: storageTables as BuildStorageTables<Tables>,
|
|
471
|
+
types: storageTypes,
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
const execution =
|
|
475
|
+
executionDefaults.length > 0
|
|
476
|
+
? {
|
|
477
|
+
mutations: {
|
|
478
|
+
defaults: executionDefaults.sort((a, b) => {
|
|
479
|
+
const tableCompare = a.ref.table.localeCompare(b.ref.table);
|
|
480
|
+
if (tableCompare !== 0) {
|
|
481
|
+
return tableCompare;
|
|
482
|
+
}
|
|
483
|
+
return a.ref.column.localeCompare(b.ref.column);
|
|
484
|
+
}),
|
|
485
|
+
},
|
|
486
|
+
}
|
|
487
|
+
: undefined;
|
|
248
488
|
|
|
249
489
|
// Build models - construct as partial first, then assert full type
|
|
250
490
|
const modelsPartial: Partial<BuildModels<Models>> = {};
|
|
@@ -327,11 +567,7 @@ class SqlContractBuilder<
|
|
|
327
567
|
storage as SqlStorage,
|
|
328
568
|
);
|
|
329
569
|
|
|
330
|
-
const mappings =
|
|
331
|
-
...baseMappings,
|
|
332
|
-
codecTypes: {} as CodecTypes,
|
|
333
|
-
operationTypes: {} as Record<string, never>,
|
|
334
|
-
} as ContractBuilderMappings<CodecTypes>;
|
|
570
|
+
const mappings = baseMappings as ContractBuilderMappings;
|
|
335
571
|
|
|
336
572
|
const extensionNamespaces = this.state.extensionNamespaces ?? [];
|
|
337
573
|
const extensionPacks: Record<string, unknown> = { ...(this.state.extensionPacks || {}) };
|
|
@@ -348,11 +584,12 @@ class SqlContractBuilder<
|
|
|
348
584
|
schemaVersion: '1' as const,
|
|
349
585
|
target,
|
|
350
586
|
targetFamily: 'sql' as const,
|
|
351
|
-
|
|
587
|
+
storageHash: this.state.storageHash || 'sha256:ts-builder-placeholder',
|
|
352
588
|
models,
|
|
353
589
|
relations: relationsPartial,
|
|
354
590
|
storage,
|
|
355
591
|
mappings,
|
|
592
|
+
...(execution ? { execution } : {}),
|
|
356
593
|
extensionPacks,
|
|
357
594
|
capabilities: this.state.capabilities || {},
|
|
358
595
|
meta: {},
|
|
@@ -365,38 +602,68 @@ class SqlContractBuilder<
|
|
|
365
602
|
Target,
|
|
366
603
|
Tables,
|
|
367
604
|
Models,
|
|
368
|
-
|
|
605
|
+
Types,
|
|
606
|
+
StorageHash,
|
|
369
607
|
ExtensionPacks,
|
|
370
608
|
Capabilities
|
|
371
609
|
>['build']
|
|
372
610
|
>;
|
|
373
611
|
}
|
|
374
612
|
|
|
375
|
-
override target<
|
|
376
|
-
|
|
377
|
-
|
|
613
|
+
override target<
|
|
614
|
+
T extends string,
|
|
615
|
+
TPack extends TargetPackRef<string, T> = TargetPackRef<string, T>,
|
|
616
|
+
>(
|
|
617
|
+
packRef: TPack & TargetPackRef<string, T>,
|
|
618
|
+
): SqlContractBuilder<
|
|
619
|
+
ExtractCodecTypesFromPack<TPack> extends Record<string, never>
|
|
620
|
+
? CodecTypes
|
|
621
|
+
: ExtractCodecTypesFromPack<TPack>,
|
|
622
|
+
T,
|
|
623
|
+
Tables,
|
|
624
|
+
Models,
|
|
625
|
+
Types,
|
|
626
|
+
StorageHash,
|
|
627
|
+
ExtensionPacks,
|
|
628
|
+
Capabilities
|
|
629
|
+
> {
|
|
378
630
|
return new SqlContractBuilder<
|
|
379
|
-
|
|
631
|
+
ExtractCodecTypesFromPack<TPack> extends Record<string, never>
|
|
632
|
+
? CodecTypes
|
|
633
|
+
: ExtractCodecTypesFromPack<TPack>,
|
|
380
634
|
T,
|
|
381
635
|
Tables,
|
|
382
636
|
Models,
|
|
383
|
-
|
|
637
|
+
Types,
|
|
638
|
+
StorageHash,
|
|
384
639
|
ExtensionPacks,
|
|
385
640
|
Capabilities
|
|
386
641
|
>({
|
|
387
642
|
...this.state,
|
|
388
643
|
target: packRef.targetId,
|
|
389
|
-
})
|
|
644
|
+
}) as SqlContractBuilder<
|
|
645
|
+
ExtractCodecTypesFromPack<TPack> extends Record<string, never>
|
|
646
|
+
? CodecTypes
|
|
647
|
+
: ExtractCodecTypesFromPack<TPack>,
|
|
648
|
+
T,
|
|
649
|
+
Tables,
|
|
650
|
+
Models,
|
|
651
|
+
Types,
|
|
652
|
+
StorageHash,
|
|
653
|
+
ExtensionPacks,
|
|
654
|
+
Capabilities
|
|
655
|
+
>;
|
|
390
656
|
}
|
|
391
657
|
|
|
392
|
-
extensionPacks(
|
|
393
|
-
packs:
|
|
658
|
+
extensionPacks<const Packs extends Record<string, ExtensionPackRef<'sql', string>>>(
|
|
659
|
+
packs: Packs,
|
|
394
660
|
): SqlContractBuilder<
|
|
395
|
-
CodecTypes
|
|
661
|
+
CodecTypes & MergeExtensionCodecTypes<Packs>,
|
|
396
662
|
Target,
|
|
397
663
|
Tables,
|
|
398
664
|
Models,
|
|
399
|
-
|
|
665
|
+
Types,
|
|
666
|
+
StorageHash,
|
|
400
667
|
ExtensionPacks,
|
|
401
668
|
Capabilities
|
|
402
669
|
> {
|
|
@@ -406,24 +673,24 @@ class SqlContractBuilder<
|
|
|
406
673
|
|
|
407
674
|
const namespaces = new Set(this.state.extensionNamespaces ?? []);
|
|
408
675
|
|
|
409
|
-
for (const packRef of Object.values(packs)) {
|
|
676
|
+
for (const packRef of Object.values(packs) as ExtensionPackRef<'sql', string>[]) {
|
|
410
677
|
if (!packRef) continue;
|
|
411
678
|
|
|
412
679
|
if (packRef.kind !== 'extension') {
|
|
413
680
|
throw new Error(
|
|
414
|
-
`extensionPacks() only accepts extension pack refs. Received kind
|
|
681
|
+
`extensionPacks() only accepts extension pack refs. Received kind "${packRef.kind}".`,
|
|
415
682
|
);
|
|
416
683
|
}
|
|
417
684
|
|
|
418
685
|
if (packRef.familyId !== 'sql') {
|
|
419
686
|
throw new Error(
|
|
420
|
-
`extension pack
|
|
687
|
+
`extension pack "${packRef.id}" targets family "${packRef.familyId}" but this builder targets "sql".`,
|
|
421
688
|
);
|
|
422
689
|
}
|
|
423
690
|
|
|
424
691
|
if (packRef.targetId && packRef.targetId !== this.state.target) {
|
|
425
692
|
throw new Error(
|
|
426
|
-
`extension pack
|
|
693
|
+
`extension pack "${packRef.id}" targets "${packRef.targetId}" but builder target is "${this.state.target}".`,
|
|
427
694
|
);
|
|
428
695
|
}
|
|
429
696
|
|
|
@@ -431,11 +698,12 @@ class SqlContractBuilder<
|
|
|
431
698
|
}
|
|
432
699
|
|
|
433
700
|
return new SqlContractBuilder<
|
|
434
|
-
CodecTypes
|
|
701
|
+
CodecTypes & MergeExtensionCodecTypes<Packs>,
|
|
435
702
|
Target,
|
|
436
703
|
Tables,
|
|
437
704
|
Models,
|
|
438
|
-
|
|
705
|
+
Types,
|
|
706
|
+
StorageHash,
|
|
439
707
|
ExtensionPacks,
|
|
440
708
|
Capabilities
|
|
441
709
|
>({
|
|
@@ -446,27 +714,46 @@ class SqlContractBuilder<
|
|
|
446
714
|
|
|
447
715
|
override capabilities<C extends Record<string, Record<string, boolean>>>(
|
|
448
716
|
capabilities: C,
|
|
449
|
-
): SqlContractBuilder<CodecTypes, Target, Tables, Models,
|
|
450
|
-
return new SqlContractBuilder<
|
|
717
|
+
): SqlContractBuilder<CodecTypes, Target, Tables, Models, Types, StorageHash, ExtensionPacks, C> {
|
|
718
|
+
return new SqlContractBuilder<
|
|
719
|
+
CodecTypes,
|
|
720
|
+
Target,
|
|
721
|
+
Tables,
|
|
722
|
+
Models,
|
|
723
|
+
Types,
|
|
724
|
+
StorageHash,
|
|
725
|
+
ExtensionPacks,
|
|
726
|
+
C
|
|
727
|
+
>({
|
|
451
728
|
...this.state,
|
|
452
729
|
capabilities,
|
|
453
730
|
});
|
|
454
731
|
}
|
|
455
732
|
|
|
456
|
-
override
|
|
733
|
+
override storageHash<H extends string>(
|
|
457
734
|
hash: H,
|
|
458
|
-
): SqlContractBuilder<
|
|
735
|
+
): SqlContractBuilder<
|
|
736
|
+
CodecTypes,
|
|
737
|
+
Target,
|
|
738
|
+
Tables,
|
|
739
|
+
Models,
|
|
740
|
+
Types,
|
|
741
|
+
H,
|
|
742
|
+
ExtensionPacks,
|
|
743
|
+
Capabilities
|
|
744
|
+
> {
|
|
459
745
|
return new SqlContractBuilder<
|
|
460
746
|
CodecTypes,
|
|
461
747
|
Target,
|
|
462
748
|
Tables,
|
|
463
749
|
Models,
|
|
750
|
+
Types,
|
|
464
751
|
H,
|
|
465
752
|
ExtensionPacks,
|
|
466
753
|
Capabilities
|
|
467
754
|
>({
|
|
468
755
|
...this.state,
|
|
469
|
-
|
|
756
|
+
storageHash: hash,
|
|
470
757
|
});
|
|
471
758
|
}
|
|
472
759
|
|
|
@@ -485,12 +772,18 @@ class SqlContractBuilder<
|
|
|
485
772
|
Target,
|
|
486
773
|
Tables & Record<TableName, ReturnType<T['build']>>,
|
|
487
774
|
Models,
|
|
488
|
-
|
|
775
|
+
Types,
|
|
776
|
+
StorageHash,
|
|
489
777
|
ExtensionPacks,
|
|
490
778
|
Capabilities
|
|
491
779
|
> {
|
|
492
|
-
const tableBuilder =
|
|
493
|
-
const result = callback(
|
|
780
|
+
const tableBuilder = createTable(name);
|
|
781
|
+
const result = callback(
|
|
782
|
+
tableBuilder as unknown as SqlTableBuilder<
|
|
783
|
+
TableName,
|
|
784
|
+
CodecTypes
|
|
785
|
+
> as unknown as TableBuilder<TableName>,
|
|
786
|
+
);
|
|
494
787
|
const finalBuilder = result instanceof TableBuilder ? result : tableBuilder;
|
|
495
788
|
const tableState = finalBuilder.build();
|
|
496
789
|
|
|
@@ -499,7 +792,8 @@ class SqlContractBuilder<
|
|
|
499
792
|
Target,
|
|
500
793
|
Tables & Record<TableName, ReturnType<T['build']>>,
|
|
501
794
|
Models,
|
|
502
|
-
|
|
795
|
+
Types,
|
|
796
|
+
StorageHash,
|
|
503
797
|
ExtensionPacks,
|
|
504
798
|
Capabilities
|
|
505
799
|
>({
|
|
@@ -522,14 +816,15 @@ class SqlContractBuilder<
|
|
|
522
816
|
name: ModelName,
|
|
523
817
|
table: TableName,
|
|
524
818
|
callback: (
|
|
525
|
-
m: ModelBuilder<ModelName, TableName, Record<
|
|
819
|
+
m: ModelBuilder<ModelName, TableName, Record<never, never>, Record<never, never>>,
|
|
526
820
|
) => M | undefined,
|
|
527
821
|
): SqlContractBuilder<
|
|
528
822
|
CodecTypes,
|
|
529
823
|
Target,
|
|
530
824
|
Tables,
|
|
531
825
|
Models & Record<ModelName, ReturnType<M['build']>>,
|
|
532
|
-
|
|
826
|
+
Types,
|
|
827
|
+
StorageHash,
|
|
533
828
|
ExtensionPacks,
|
|
534
829
|
Capabilities
|
|
535
830
|
> {
|
|
@@ -543,7 +838,8 @@ class SqlContractBuilder<
|
|
|
543
838
|
Target,
|
|
544
839
|
Tables,
|
|
545
840
|
Models & Record<ModelName, ReturnType<M['build']>>,
|
|
546
|
-
|
|
841
|
+
Types,
|
|
842
|
+
StorageHash,
|
|
547
843
|
ExtensionPacks,
|
|
548
844
|
Capabilities
|
|
549
845
|
>({
|
|
@@ -552,6 +848,64 @@ class SqlContractBuilder<
|
|
|
552
848
|
Record<ModelName, ReturnType<M['build']>>,
|
|
553
849
|
});
|
|
554
850
|
}
|
|
851
|
+
|
|
852
|
+
override foreignKeyDefaults(
|
|
853
|
+
config: ForeignKeyDefaultsState,
|
|
854
|
+
): SqlContractBuilder<
|
|
855
|
+
CodecTypes,
|
|
856
|
+
Target,
|
|
857
|
+
Tables,
|
|
858
|
+
Models,
|
|
859
|
+
Types,
|
|
860
|
+
StorageHash,
|
|
861
|
+
ExtensionPacks,
|
|
862
|
+
Capabilities
|
|
863
|
+
> {
|
|
864
|
+
return new SqlContractBuilder<
|
|
865
|
+
CodecTypes,
|
|
866
|
+
Target,
|
|
867
|
+
Tables,
|
|
868
|
+
Models,
|
|
869
|
+
Types,
|
|
870
|
+
StorageHash,
|
|
871
|
+
ExtensionPacks,
|
|
872
|
+
Capabilities
|
|
873
|
+
>({
|
|
874
|
+
...this.state,
|
|
875
|
+
foreignKeyDefaults: config,
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
storageType<Name extends string, Type extends StorageTypeInstance>(
|
|
880
|
+
name: Name,
|
|
881
|
+
typeInstance: Type,
|
|
882
|
+
): SqlContractBuilder<
|
|
883
|
+
CodecTypes,
|
|
884
|
+
Target,
|
|
885
|
+
Tables,
|
|
886
|
+
Models,
|
|
887
|
+
Types & Record<Name, Type>,
|
|
888
|
+
StorageHash,
|
|
889
|
+
ExtensionPacks,
|
|
890
|
+
Capabilities
|
|
891
|
+
> {
|
|
892
|
+
return new SqlContractBuilder<
|
|
893
|
+
CodecTypes,
|
|
894
|
+
Target,
|
|
895
|
+
Tables,
|
|
896
|
+
Models,
|
|
897
|
+
Types & Record<Name, Type>,
|
|
898
|
+
StorageHash,
|
|
899
|
+
ExtensionPacks,
|
|
900
|
+
Capabilities
|
|
901
|
+
>({
|
|
902
|
+
...this.state,
|
|
903
|
+
storageTypes: {
|
|
904
|
+
...(this.state.storageTypes ?? {}),
|
|
905
|
+
[name]: typeInstance,
|
|
906
|
+
},
|
|
907
|
+
});
|
|
908
|
+
}
|
|
555
909
|
}
|
|
556
910
|
|
|
557
911
|
export function defineContract<
|