@prisma-next/sql-contract-ts 0.3.0-dev.15 → 0.3.0-dev.162
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 +209 -54
- 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 +769 -0
- package/dist/contract-builder.d.mts.map +1 -0
- package/dist/contract-builder.mjs +1288 -0
- package/dist/contract-builder.mjs.map +1 -0
- package/package.json +22 -19
- package/schemas/data-contract-sql-v1.json +235 -27
- package/src/authoring-helper-runtime.ts +139 -0
- package/src/authoring-type-utils.ts +168 -0
- package/src/build-contract.ts +463 -0
- package/src/composed-authoring-helpers.ts +256 -0
- package/src/config-types.ts +11 -0
- package/src/contract-builder.ts +232 -526
- package/src/contract-definition.ts +103 -0
- package/src/contract-dsl.ts +1492 -0
- package/src/contract-lowering.ts +703 -0
- package/src/contract-types.ts +534 -0
- package/src/contract-warnings.ts +242 -0
- package/src/exports/config-types.ts +2 -0
- package/src/exports/contract-builder.ts +23 -2
- 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/contract.ts +0 -533
- package/src/exports/contract.ts +0 -1
package/src/contract-builder.ts
CHANGED
|
@@ -1,561 +1,267 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ForeignKeyDefaultsState } from '@prisma-next/contract-authoring';
|
|
2
|
+
import type { CodecLookup } from '@prisma-next/framework-components/codec';
|
|
2
3
|
import type {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
} from '@prisma-next/contract
|
|
4
|
+
ExtensionPackRef,
|
|
5
|
+
FamilyPackRef,
|
|
6
|
+
TargetPackRef,
|
|
7
|
+
} from '@prisma-next/framework-components/components';
|
|
8
|
+
import type { StorageTypeInstance } from '@prisma-next/sql-contract/types';
|
|
9
|
+
import { buildSqlContractFromDefinition } from './build-contract';
|
|
8
10
|
import {
|
|
9
|
-
type
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
type
|
|
14
|
-
type
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
} from '
|
|
26
|
-
import {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
* **Difference from RuntimeContext**: This is a compile-time type for contract construction.
|
|
36
|
-
* `RuntimeContext` is a runtime object with populated registries for query execution.
|
|
37
|
-
*
|
|
38
|
-
* @template C - The `CodecTypes` generic parameter passed to `defineContract<CodecTypes>()`
|
|
39
|
-
*/
|
|
40
|
-
type ContractBuilderMappings<C extends Record<string, { output: unknown }>> = Omit<
|
|
41
|
-
SqlMappings,
|
|
42
|
-
'codecTypes' | 'operationTypes'
|
|
43
|
-
> & {
|
|
44
|
-
readonly codecTypes: C;
|
|
45
|
-
readonly operationTypes: Record<string, never>;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
type BuildStorageTable<
|
|
49
|
-
_TableName extends string,
|
|
50
|
-
Columns extends Record<string, ColumnBuilderState<string, boolean, string>>,
|
|
51
|
-
PK extends readonly string[] | undefined,
|
|
52
|
-
> = {
|
|
53
|
-
readonly columns: {
|
|
54
|
-
readonly [K in keyof Columns]: Columns[K] extends ColumnBuilderState<
|
|
55
|
-
string,
|
|
56
|
-
infer Null,
|
|
57
|
-
infer TType
|
|
58
|
-
>
|
|
59
|
-
? BuildStorageColumn<Null & boolean, TType>
|
|
60
|
-
: never;
|
|
11
|
+
type ComposedAuthoringHelpers,
|
|
12
|
+
createComposedAuthoringHelpers,
|
|
13
|
+
} from './composed-authoring-helpers';
|
|
14
|
+
import {
|
|
15
|
+
type ContractInput,
|
|
16
|
+
type ContractModelBuilder,
|
|
17
|
+
field,
|
|
18
|
+
isContractInput,
|
|
19
|
+
type ModelAttributesSpec,
|
|
20
|
+
model,
|
|
21
|
+
type RelationBuilder,
|
|
22
|
+
type RelationState,
|
|
23
|
+
rel,
|
|
24
|
+
type ScalarFieldBuilder,
|
|
25
|
+
type SqlStageSpec,
|
|
26
|
+
} from './contract-dsl';
|
|
27
|
+
import { buildContractDefinition } from './contract-lowering';
|
|
28
|
+
import type { SqlContractResult } from './contract-types';
|
|
29
|
+
|
|
30
|
+
export { buildSqlContractFromDefinition } from './build-contract';
|
|
31
|
+
|
|
32
|
+
type ModelLike = {
|
|
33
|
+
readonly stageOne: {
|
|
34
|
+
readonly modelName?: string;
|
|
35
|
+
readonly fields: Record<string, ScalarFieldBuilder>;
|
|
36
|
+
readonly relations: Record<string, RelationBuilder<RelationState>>;
|
|
61
37
|
};
|
|
62
|
-
readonly
|
|
63
|
-
readonly
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
: Record<string, never>);
|
|
38
|
+
readonly __attributes: ModelAttributesSpec | undefined;
|
|
39
|
+
readonly __sql: SqlStageSpec | undefined;
|
|
40
|
+
buildAttributesSpec(): ModelAttributesSpec | undefined;
|
|
41
|
+
buildSqlSpec(): SqlStageSpec | undefined;
|
|
42
|
+
};
|
|
68
43
|
|
|
69
|
-
type
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
44
|
+
type ContractDefinition<
|
|
45
|
+
Family extends FamilyPackRef<string>,
|
|
46
|
+
Target extends TargetPackRef<'sql', string>,
|
|
47
|
+
Types extends Record<string, StorageTypeInstance>,
|
|
48
|
+
Models extends Record<string, ModelLike>,
|
|
49
|
+
ExtensionPacks extends Record<string, ExtensionPackRef<'sql', string>> | undefined,
|
|
50
|
+
Capabilities extends Record<string, Record<string, boolean>> | undefined,
|
|
51
|
+
Naming extends ContractInput['naming'] | undefined,
|
|
52
|
+
StorageHash extends string | undefined,
|
|
53
|
+
ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined,
|
|
78
54
|
> = {
|
|
79
|
-
readonly
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
55
|
+
readonly family: Family;
|
|
56
|
+
readonly target: Target;
|
|
57
|
+
readonly extensionPacks?: ExtensionPacks;
|
|
58
|
+
readonly naming?: Naming;
|
|
59
|
+
readonly storageHash?: StorageHash;
|
|
60
|
+
readonly foreignKeyDefaults?: ForeignKeyDefaults;
|
|
61
|
+
readonly capabilities?: Capabilities;
|
|
62
|
+
readonly types?: Types;
|
|
63
|
+
readonly models?: Models;
|
|
64
|
+
readonly codecLookup?: CodecLookup;
|
|
86
65
|
};
|
|
87
66
|
|
|
88
|
-
type
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
>,
|
|
67
|
+
type ContractScaffold<
|
|
68
|
+
Family extends FamilyPackRef<string>,
|
|
69
|
+
Target extends TargetPackRef<'sql', string>,
|
|
70
|
+
ExtensionPacks extends Record<string, ExtensionPackRef<'sql', string>> | undefined,
|
|
71
|
+
Capabilities extends Record<string, Record<string, boolean>> | undefined,
|
|
72
|
+
Naming extends ContractInput['naming'] | undefined,
|
|
73
|
+
StorageHash extends string | undefined,
|
|
74
|
+
ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined,
|
|
97
75
|
> = {
|
|
98
|
-
readonly
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
76
|
+
readonly family: Family;
|
|
77
|
+
readonly target: Target;
|
|
78
|
+
readonly extensionPacks?: ExtensionPacks;
|
|
79
|
+
readonly naming?: Naming;
|
|
80
|
+
readonly storageHash?: StorageHash;
|
|
81
|
+
readonly foreignKeyDefaults?: ForeignKeyDefaults;
|
|
82
|
+
readonly capabilities?: Capabilities;
|
|
83
|
+
readonly codecLookup?: CodecLookup;
|
|
103
84
|
};
|
|
104
85
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
string,
|
|
116
|
-
TableBuilderState<
|
|
117
|
-
string,
|
|
118
|
-
Record<string, ColumnBuilderState<string, boolean, string>>,
|
|
119
|
-
readonly string[] | undefined
|
|
120
|
-
>
|
|
121
|
-
> = Record<never, never>,
|
|
122
|
-
Models extends Record<
|
|
123
|
-
string,
|
|
124
|
-
ModelBuilderState<string, string, Record<string, string>, Record<string, RelationDefinition>>
|
|
125
|
-
> = Record<never, never>,
|
|
126
|
-
CoreHash extends string | undefined = undefined,
|
|
127
|
-
ExtensionPacks extends Record<string, unknown> | undefined = undefined,
|
|
128
|
-
Capabilities extends Record<string, Record<string, boolean>> | undefined = undefined,
|
|
129
|
-
> extends ContractBuilder<Target, Tables, Models, CoreHash, ExtensionPacks, Capabilities> {
|
|
130
|
-
/**
|
|
131
|
-
* This method is responsible for normalizing the contract IR by setting default values
|
|
132
|
-
* for all required fields:
|
|
133
|
-
* - `nullable`: defaults to `false` if not provided
|
|
134
|
-
* - `uniques`: defaults to `[]` (empty array)
|
|
135
|
-
* - `indexes`: defaults to `[]` (empty array)
|
|
136
|
-
* - `foreignKeys`: defaults to `[]` (empty array)
|
|
137
|
-
* - `relations`: defaults to `{}` (empty object) for both model-level and contract-level
|
|
138
|
-
* - `nativeType`: required field set from column type descriptor when columns are defined
|
|
139
|
-
*
|
|
140
|
-
* The contract builder is the **only** place where normalization should occur.
|
|
141
|
-
* Validators, parsers, and emitters should assume the contract is already normalized.
|
|
142
|
-
*
|
|
143
|
-
* **Required**: Use column type descriptors (e.g., `int4Column`, `textColumn`) when defining columns.
|
|
144
|
-
* This ensures `nativeType` is set correctly at build time.
|
|
145
|
-
*
|
|
146
|
-
* @returns A normalized SqlContract with all required fields present
|
|
147
|
-
*/
|
|
148
|
-
build(): Target extends string
|
|
149
|
-
? SqlContract<
|
|
150
|
-
BuildStorage<Tables>,
|
|
151
|
-
BuildModels<Models>,
|
|
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>,
|
|
170
|
-
BuildModels<Models>,
|
|
171
|
-
BuildRelations<Models>,
|
|
172
|
-
ContractBuilderMappings<CodecTypes>
|
|
173
|
-
> & {
|
|
174
|
-
readonly schemaVersion: '1';
|
|
175
|
-
readonly target: Target;
|
|
176
|
-
readonly targetFamily: 'sql';
|
|
177
|
-
readonly coreHash: CoreHash extends string ? CoreHash : string;
|
|
178
|
-
} & (ExtensionPacks extends Record<string, unknown>
|
|
179
|
-
? { readonly extensionPacks: ExtensionPacks }
|
|
180
|
-
: Record<string, never>) &
|
|
181
|
-
(Capabilities extends Record<string, Record<string, boolean>>
|
|
182
|
-
? { readonly capabilities: Capabilities }
|
|
183
|
-
: Record<string, never>)
|
|
184
|
-
: never;
|
|
185
|
-
if (!this.state.target) {
|
|
186
|
-
throw new Error('target is required. Call .target() before .build()');
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
const target = this.state.target as Target & string;
|
|
190
|
-
|
|
191
|
-
const storageTables = {} as Partial<Mutable<BuildStorageTables<Tables>>>;
|
|
192
|
-
|
|
193
|
-
for (const tableName of Object.keys(this.state.tables) as Array<keyof Tables & string>) {
|
|
194
|
-
const tableState = this.state.tables[tableName];
|
|
195
|
-
if (!tableState) continue;
|
|
196
|
-
|
|
197
|
-
type TableKey = typeof tableName;
|
|
198
|
-
type ColumnDefs = ExtractColumns<Tables[TableKey]>;
|
|
199
|
-
type PrimaryKey = ExtractPrimaryKey<Tables[TableKey]>;
|
|
200
|
-
|
|
201
|
-
const columns = {} as Partial<{
|
|
202
|
-
[K in keyof ColumnDefs]: BuildStorageColumn<
|
|
203
|
-
ColumnDefs[K]['nullable'] & boolean,
|
|
204
|
-
ColumnDefs[K]['type']
|
|
205
|
-
>;
|
|
206
|
-
}>;
|
|
207
|
-
|
|
208
|
-
for (const columnName in tableState.columns) {
|
|
209
|
-
const columnState = tableState.columns[columnName];
|
|
210
|
-
if (!columnState) continue;
|
|
211
|
-
const codecId = columnState.type;
|
|
212
|
-
const nativeType = columnState.nativeType;
|
|
213
|
-
|
|
214
|
-
columns[columnName as keyof ColumnDefs] = {
|
|
215
|
-
nativeType,
|
|
216
|
-
codecId,
|
|
217
|
-
nullable: (columnState.nullable ?? false) as ColumnDefs[keyof ColumnDefs]['nullable'] &
|
|
218
|
-
boolean,
|
|
219
|
-
} as BuildStorageColumn<
|
|
220
|
-
ColumnDefs[keyof ColumnDefs]['nullable'] & boolean,
|
|
221
|
-
ColumnDefs[keyof ColumnDefs]['type']
|
|
222
|
-
>;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const table = {
|
|
226
|
-
columns: columns as {
|
|
227
|
-
[K in keyof ColumnDefs]: BuildStorageColumn<
|
|
228
|
-
ColumnDefs[K]['nullable'] & boolean,
|
|
229
|
-
ColumnDefs[K]['type']
|
|
230
|
-
>;
|
|
231
|
-
},
|
|
232
|
-
uniques: [],
|
|
233
|
-
indexes: [],
|
|
234
|
-
foreignKeys: [],
|
|
235
|
-
...(tableState.primaryKey
|
|
236
|
-
? {
|
|
237
|
-
primaryKey: {
|
|
238
|
-
columns: tableState.primaryKey,
|
|
239
|
-
},
|
|
240
|
-
}
|
|
241
|
-
: {}),
|
|
242
|
-
} as unknown as BuildStorageTable<TableKey & string, ColumnDefs, PrimaryKey>;
|
|
243
|
-
|
|
244
|
-
(storageTables as Mutable<BuildStorageTables<Tables>>)[tableName] = table;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
const storage = { tables: storageTables as BuildStorageTables<Tables> } as BuildStorage<Tables>;
|
|
248
|
-
|
|
249
|
-
// Build models - construct as partial first, then assert full type
|
|
250
|
-
const modelsPartial: Partial<BuildModels<Models>> = {};
|
|
251
|
-
|
|
252
|
-
// Iterate over models - TypeScript will see keys as string, but type assertion preserves literals
|
|
253
|
-
for (const modelName in this.state.models) {
|
|
254
|
-
const modelState = this.state.models[modelName];
|
|
255
|
-
if (!modelState) continue;
|
|
86
|
+
type ContractFactory<
|
|
87
|
+
Family extends FamilyPackRef<string>,
|
|
88
|
+
Target extends TargetPackRef<'sql', string>,
|
|
89
|
+
Types extends Record<string, StorageTypeInstance>,
|
|
90
|
+
Models extends Record<string, ModelLike>,
|
|
91
|
+
ExtensionPacks extends Record<string, ExtensionPackRef<'sql', string>> | undefined,
|
|
92
|
+
> = (helpers: ComposedAuthoringHelpers<Family, Target, ExtensionPacks>) => {
|
|
93
|
+
readonly types?: Types;
|
|
94
|
+
readonly models?: Models;
|
|
95
|
+
};
|
|
256
96
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
97
|
+
function validateTargetPackRef(
|
|
98
|
+
family: FamilyPackRef<string>,
|
|
99
|
+
target: TargetPackRef<'sql', string>,
|
|
100
|
+
): void {
|
|
101
|
+
if (family.familyId !== 'sql') {
|
|
102
|
+
throw new Error(
|
|
103
|
+
`defineContract only accepts SQL family packs. Received family "${family.familyId}".`,
|
|
104
|
+
);
|
|
105
|
+
}
|
|
262
106
|
|
|
263
|
-
|
|
264
|
-
|
|
107
|
+
if (target.familyId !== family.familyId) {
|
|
108
|
+
throw new Error(
|
|
109
|
+
`target pack "${target.id}" targets family "${target.familyId}" but contract family is "${family.familyId}".`,
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
265
113
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
}
|
|
274
|
-
}
|
|
114
|
+
function validateExtensionPackRefs(
|
|
115
|
+
target: TargetPackRef<'sql', string>,
|
|
116
|
+
extensionPacks?: Record<string, ExtensionPackRef<'sql', string>>,
|
|
117
|
+
): void {
|
|
118
|
+
if (!extensionPacks) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
275
121
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
fields: fields as Record<string, ModelField>,
|
|
282
|
-
relations: {},
|
|
283
|
-
};
|
|
122
|
+
for (const packRef of Object.values(extensionPacks)) {
|
|
123
|
+
if (packRef.kind !== 'extension') {
|
|
124
|
+
throw new Error(
|
|
125
|
+
`defineContract only accepts extension pack refs in extensionPacks. Received kind "${packRef.kind}".`,
|
|
126
|
+
);
|
|
284
127
|
}
|
|
285
128
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
for (const modelName in this.state.models) {
|
|
291
|
-
const modelState = this.state.models[modelName];
|
|
292
|
-
if (!modelState) continue;
|
|
293
|
-
|
|
294
|
-
const modelStateTyped = modelState as unknown as {
|
|
295
|
-
name: string;
|
|
296
|
-
table: string;
|
|
297
|
-
fields: Record<string, string>;
|
|
298
|
-
relations: Record<string, RelationDefinition>;
|
|
299
|
-
};
|
|
300
|
-
|
|
301
|
-
const tableName = modelStateTyped.table;
|
|
302
|
-
if (!tableName) continue;
|
|
303
|
-
|
|
304
|
-
// Only initialize relations object for this table if it has relations
|
|
305
|
-
if (modelStateTyped.relations && Object.keys(modelStateTyped.relations).length > 0) {
|
|
306
|
-
if (!relationsPartial[tableName]) {
|
|
307
|
-
relationsPartial[tableName] = {};
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
// Add relations from this model to the table's relations
|
|
311
|
-
const tableRelations = relationsPartial[tableName];
|
|
312
|
-
if (tableRelations) {
|
|
313
|
-
for (const relationName in modelStateTyped.relations) {
|
|
314
|
-
const relation = modelStateTyped.relations[relationName];
|
|
315
|
-
if (relation) {
|
|
316
|
-
tableRelations[relationName] = relation;
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
}
|
|
129
|
+
if (packRef.familyId !== target.familyId) {
|
|
130
|
+
throw new Error(
|
|
131
|
+
`extension pack "${packRef.id}" targets family "${packRef.familyId}" but contract target family is "${target.familyId}".`,
|
|
132
|
+
);
|
|
321
133
|
}
|
|
322
134
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
storage as SqlStorage,
|
|
328
|
-
);
|
|
329
|
-
|
|
330
|
-
const mappings = {
|
|
331
|
-
...baseMappings,
|
|
332
|
-
codecTypes: {} as CodecTypes,
|
|
333
|
-
operationTypes: {} as Record<string, never>,
|
|
334
|
-
} as ContractBuilderMappings<CodecTypes>;
|
|
335
|
-
|
|
336
|
-
const extensionNamespaces = this.state.extensionNamespaces ?? [];
|
|
337
|
-
const extensionPacks: Record<string, unknown> = { ...(this.state.extensionPacks || {}) };
|
|
338
|
-
for (const namespace of extensionNamespaces) {
|
|
339
|
-
if (!Object.hasOwn(extensionPacks, namespace)) {
|
|
340
|
-
extensionPacks[namespace] = {};
|
|
341
|
-
}
|
|
135
|
+
if (packRef.targetId && packRef.targetId !== target.targetId) {
|
|
136
|
+
throw new Error(
|
|
137
|
+
`extension pack "${packRef.id}" targets "${packRef.targetId}" but contract target is "${target.targetId}".`,
|
|
138
|
+
);
|
|
342
139
|
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
343
142
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
const contract = {
|
|
348
|
-
schemaVersion: '1' as const,
|
|
349
|
-
target,
|
|
350
|
-
targetFamily: 'sql' as const,
|
|
351
|
-
coreHash: this.state.coreHash || 'sha256:ts-builder-placeholder',
|
|
352
|
-
models,
|
|
353
|
-
relations: relationsPartial,
|
|
354
|
-
storage,
|
|
355
|
-
mappings,
|
|
356
|
-
extensionPacks,
|
|
357
|
-
capabilities: this.state.capabilities || {},
|
|
358
|
-
meta: {},
|
|
359
|
-
sources: {},
|
|
360
|
-
} as unknown as BuiltContract;
|
|
143
|
+
function buildContractFromDsl<Definition extends ContractInput>(
|
|
144
|
+
definition: Definition,
|
|
145
|
+
): SqlContractResult<Definition>;
|
|
361
146
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
Models,
|
|
368
|
-
CoreHash,
|
|
369
|
-
ExtensionPacks,
|
|
370
|
-
Capabilities
|
|
371
|
-
>['build']
|
|
372
|
-
>;
|
|
373
|
-
}
|
|
147
|
+
function buildContractFromDsl(
|
|
148
|
+
definition: ContractInput,
|
|
149
|
+
): ReturnType<typeof buildSqlContractFromDefinition> {
|
|
150
|
+
validateTargetPackRef(definition.family, definition.target);
|
|
151
|
+
validateExtensionPackRefs(definition.target, definition.extensionPacks);
|
|
374
152
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
T,
|
|
381
|
-
Tables,
|
|
382
|
-
Models,
|
|
383
|
-
CoreHash,
|
|
384
|
-
ExtensionPacks,
|
|
385
|
-
Capabilities
|
|
386
|
-
>({
|
|
387
|
-
...this.state,
|
|
388
|
-
target: packRef.targetId,
|
|
389
|
-
});
|
|
390
|
-
}
|
|
153
|
+
return buildSqlContractFromDefinition(
|
|
154
|
+
buildContractDefinition(definition),
|
|
155
|
+
definition.codecLookup,
|
|
156
|
+
);
|
|
157
|
+
}
|
|
391
158
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
159
|
+
export function defineContract<
|
|
160
|
+
const Family extends FamilyPackRef<string>,
|
|
161
|
+
const Target extends TargetPackRef<'sql', string>,
|
|
162
|
+
const Types extends Record<string, StorageTypeInstance> = Record<never, never>,
|
|
163
|
+
const Models extends Record<string, ModelLike> = Record<never, never>,
|
|
164
|
+
const ExtensionPacks extends
|
|
165
|
+
| Record<string, ExtensionPackRef<'sql', string>>
|
|
166
|
+
| undefined = undefined,
|
|
167
|
+
const Capabilities extends Record<string, Record<string, boolean>> | undefined = undefined,
|
|
168
|
+
const Naming extends ContractInput['naming'] | undefined = undefined,
|
|
169
|
+
const StorageHash extends string | undefined = undefined,
|
|
170
|
+
const ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined = undefined,
|
|
171
|
+
>(
|
|
172
|
+
definition: ContractDefinition<
|
|
173
|
+
Family,
|
|
396
174
|
Target,
|
|
397
|
-
|
|
175
|
+
Types,
|
|
398
176
|
Models,
|
|
399
|
-
CoreHash,
|
|
400
177
|
ExtensionPacks,
|
|
401
|
-
Capabilities
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
for (const packRef of Object.values(packs)) {
|
|
410
|
-
if (!packRef) continue;
|
|
411
|
-
|
|
412
|
-
if (packRef.kind !== 'extension') {
|
|
413
|
-
throw new Error(
|
|
414
|
-
`extensionPacks() only accepts extension pack refs. Received kind "${packRef.kind}".`,
|
|
415
|
-
);
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
if (packRef.familyId !== 'sql') {
|
|
419
|
-
throw new Error(
|
|
420
|
-
`extension pack "${packRef.id}" targets family "${packRef.familyId}" but this builder targets "sql".`,
|
|
421
|
-
);
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
if (packRef.targetId && packRef.targetId !== this.state.target) {
|
|
425
|
-
throw new Error(
|
|
426
|
-
`extension pack "${packRef.id}" targets "${packRef.targetId}" but builder target is "${this.state.target}".`,
|
|
427
|
-
);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
namespaces.add(packRef.id);
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
return new SqlContractBuilder<
|
|
434
|
-
CodecTypes,
|
|
435
|
-
Target,
|
|
436
|
-
Tables,
|
|
437
|
-
Models,
|
|
438
|
-
CoreHash,
|
|
439
|
-
ExtensionPacks,
|
|
440
|
-
Capabilities
|
|
441
|
-
>({
|
|
442
|
-
...this.state,
|
|
443
|
-
extensionNamespaces: [...namespaces],
|
|
444
|
-
});
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
override capabilities<C extends Record<string, Record<string, boolean>>>(
|
|
448
|
-
capabilities: C,
|
|
449
|
-
): SqlContractBuilder<CodecTypes, Target, Tables, Models, CoreHash, ExtensionPacks, C> {
|
|
450
|
-
return new SqlContractBuilder<CodecTypes, Target, Tables, Models, CoreHash, ExtensionPacks, C>({
|
|
451
|
-
...this.state,
|
|
452
|
-
capabilities,
|
|
453
|
-
});
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
override coreHash<H extends string>(
|
|
457
|
-
hash: H,
|
|
458
|
-
): SqlContractBuilder<CodecTypes, Target, Tables, Models, H, ExtensionPacks, Capabilities> {
|
|
459
|
-
return new SqlContractBuilder<
|
|
460
|
-
CodecTypes,
|
|
461
|
-
Target,
|
|
462
|
-
Tables,
|
|
463
|
-
Models,
|
|
464
|
-
H,
|
|
465
|
-
ExtensionPacks,
|
|
466
|
-
Capabilities
|
|
467
|
-
>({
|
|
468
|
-
...this.state,
|
|
469
|
-
coreHash: hash,
|
|
470
|
-
});
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
override table<
|
|
474
|
-
TableName extends string,
|
|
475
|
-
T extends TableBuilder<
|
|
476
|
-
TableName,
|
|
477
|
-
Record<string, ColumnBuilderState<string, boolean, string>>,
|
|
478
|
-
readonly string[] | undefined
|
|
479
|
-
>,
|
|
480
|
-
>(
|
|
481
|
-
name: TableName,
|
|
482
|
-
callback: (t: TableBuilder<TableName>) => T | undefined,
|
|
483
|
-
): SqlContractBuilder<
|
|
484
|
-
CodecTypes,
|
|
178
|
+
Capabilities,
|
|
179
|
+
Naming,
|
|
180
|
+
StorageHash,
|
|
181
|
+
ForeignKeyDefaults
|
|
182
|
+
>,
|
|
183
|
+
): SqlContractResult<
|
|
184
|
+
ContractDefinition<
|
|
185
|
+
Family,
|
|
485
186
|
Target,
|
|
486
|
-
|
|
187
|
+
Types,
|
|
487
188
|
Models,
|
|
488
|
-
CoreHash,
|
|
489
189
|
ExtensionPacks,
|
|
490
|
-
Capabilities
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
name: ModelName,
|
|
523
|
-
table: TableName,
|
|
524
|
-
callback: (
|
|
525
|
-
m: ModelBuilder<ModelName, TableName, Record<string, string>, Record<never, never>>,
|
|
526
|
-
) => M | undefined,
|
|
527
|
-
): SqlContractBuilder<
|
|
528
|
-
CodecTypes,
|
|
190
|
+
Capabilities,
|
|
191
|
+
Naming,
|
|
192
|
+
StorageHash,
|
|
193
|
+
ForeignKeyDefaults
|
|
194
|
+
>
|
|
195
|
+
>;
|
|
196
|
+
export function defineContract<
|
|
197
|
+
const Family extends FamilyPackRef<string>,
|
|
198
|
+
const Target extends TargetPackRef<'sql', string>,
|
|
199
|
+
const Types extends Record<string, StorageTypeInstance> = Record<never, never>,
|
|
200
|
+
const Models extends Record<string, ModelLike> = Record<never, never>,
|
|
201
|
+
const ExtensionPacks extends
|
|
202
|
+
| Record<string, ExtensionPackRef<'sql', string>>
|
|
203
|
+
| undefined = undefined,
|
|
204
|
+
const Capabilities extends Record<string, Record<string, boolean>> | undefined = undefined,
|
|
205
|
+
const Naming extends ContractInput['naming'] | undefined = undefined,
|
|
206
|
+
const StorageHash extends string | undefined = undefined,
|
|
207
|
+
const ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined = undefined,
|
|
208
|
+
>(
|
|
209
|
+
definition: ContractScaffold<
|
|
210
|
+
Family,
|
|
211
|
+
Target,
|
|
212
|
+
ExtensionPacks,
|
|
213
|
+
Capabilities,
|
|
214
|
+
Naming,
|
|
215
|
+
StorageHash,
|
|
216
|
+
ForeignKeyDefaults
|
|
217
|
+
>,
|
|
218
|
+
factory: ContractFactory<Family, Target, Types, Models, ExtensionPacks>,
|
|
219
|
+
): SqlContractResult<
|
|
220
|
+
ContractDefinition<
|
|
221
|
+
Family,
|
|
529
222
|
Target,
|
|
530
|
-
|
|
531
|
-
Models
|
|
532
|
-
CoreHash,
|
|
223
|
+
Types,
|
|
224
|
+
Models,
|
|
533
225
|
ExtensionPacks,
|
|
534
|
-
Capabilities
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
226
|
+
Capabilities,
|
|
227
|
+
Naming,
|
|
228
|
+
StorageHash,
|
|
229
|
+
ForeignKeyDefaults
|
|
230
|
+
>
|
|
231
|
+
>;
|
|
232
|
+
export function defineContract(
|
|
233
|
+
definition: ContractInput,
|
|
234
|
+
factory?: ContractFactory<
|
|
235
|
+
FamilyPackRef<string>,
|
|
236
|
+
TargetPackRef<'sql', string>,
|
|
237
|
+
Record<string, StorageTypeInstance>,
|
|
238
|
+
Record<string, ModelLike>,
|
|
239
|
+
Record<string, ExtensionPackRef<'sql', string>> | undefined
|
|
240
|
+
>,
|
|
241
|
+
): SqlContractResult<ContractInput> {
|
|
242
|
+
if (!isContractInput(definition)) {
|
|
243
|
+
throw new TypeError(
|
|
244
|
+
'defineContract expects a contract definition object. Define your contract with defineContract({ family, target, models, ... }).',
|
|
245
|
+
);
|
|
246
|
+
}
|
|
540
247
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
Target,
|
|
544
|
-
Tables,
|
|
545
|
-
Models & Record<ModelName, ReturnType<M['build']>>,
|
|
546
|
-
CoreHash,
|
|
547
|
-
ExtensionPacks,
|
|
548
|
-
Capabilities
|
|
549
|
-
>({
|
|
550
|
-
...this.state,
|
|
551
|
-
models: { ...this.state.models, [name]: modelState } as Models &
|
|
552
|
-
Record<ModelName, ReturnType<M['build']>>,
|
|
553
|
-
});
|
|
248
|
+
if (!factory) {
|
|
249
|
+
return buildContractFromDsl(definition);
|
|
554
250
|
}
|
|
555
|
-
}
|
|
556
251
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
252
|
+
const builtDefinition = {
|
|
253
|
+
...definition,
|
|
254
|
+
...factory(
|
|
255
|
+
createComposedAuthoringHelpers({
|
|
256
|
+
family: definition.family,
|
|
257
|
+
target: definition.target,
|
|
258
|
+
extensionPacks: definition.extensionPacks,
|
|
259
|
+
}),
|
|
260
|
+
),
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
return buildContractFromDsl(builtDefinition);
|
|
561
264
|
}
|
|
265
|
+
|
|
266
|
+
export { field, model, rel };
|
|
267
|
+
export type { ComposedAuthoringHelpers, ContractInput, ContractModelBuilder, ScalarFieldBuilder };
|