@prisma-next/sql-contract-ts 0.5.0-dev.9 → 0.6.0-dev.1
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 +6 -3
- package/dist/config-types.d.mts.map +1 -1
- package/dist/config-types.mjs +1 -2
- package/dist/config-types.mjs.map +1 -1
- package/dist/contract-builder.d.mts +257 -223
- package/dist/contract-builder.d.mts.map +1 -1
- package/dist/contract-builder.mjs +83 -101
- package/dist/contract-builder.mjs.map +1 -1
- package/package.json +14 -13
- package/src/authoring-type-utils.ts +15 -13
- package/src/build-contract.ts +47 -25
- package/src/composed-authoring-helpers.ts +49 -55
- package/src/contract-definition.ts +9 -9
- package/src/contract-dsl.ts +83 -58
- package/src/contract-lowering.ts +6 -5
- package/src/contract-types.ts +33 -0
package/package.json
CHANGED
|
@@ -1,28 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/sql-contract-ts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0-dev.1",
|
|
4
|
+
"license": "Apache-2.0",
|
|
4
5
|
"type": "module",
|
|
5
6
|
"sideEffects": false,
|
|
6
7
|
"description": "SQL-specific TypeScript contract authoring surface for Prisma Next",
|
|
7
8
|
"dependencies": {
|
|
8
|
-
"arktype": "^2.1.
|
|
9
|
+
"arktype": "^2.1.29",
|
|
9
10
|
"pathe": "^2.0.3",
|
|
10
11
|
"ts-toolbelt": "^9.6.0",
|
|
11
|
-
"@prisma-next/
|
|
12
|
-
"@prisma-next/
|
|
13
|
-
"@prisma-next/contract-authoring": "0.
|
|
14
|
-
"@prisma-next/
|
|
15
|
-
"@prisma-next/sql-contract": "0.
|
|
16
|
-
"@prisma-next/
|
|
12
|
+
"@prisma-next/contract": "0.6.0-dev.1",
|
|
13
|
+
"@prisma-next/config": "0.6.0-dev.1",
|
|
14
|
+
"@prisma-next/contract-authoring": "0.6.0-dev.1",
|
|
15
|
+
"@prisma-next/framework-components": "0.6.0-dev.1",
|
|
16
|
+
"@prisma-next/sql-contract": "0.6.0-dev.1",
|
|
17
|
+
"@prisma-next/utils": "0.6.0-dev.1"
|
|
17
18
|
},
|
|
18
19
|
"devDependencies": {
|
|
19
|
-
"@types/pg": "8.
|
|
20
|
-
"pg": "8.
|
|
21
|
-
"tsdown": "0.
|
|
20
|
+
"@types/pg": "8.20.0",
|
|
21
|
+
"pg": "8.20.0",
|
|
22
|
+
"tsdown": "0.22.0",
|
|
22
23
|
"typescript": "5.9.3",
|
|
23
|
-
"vitest": "4.
|
|
24
|
-
"@prisma-next/tsconfig": "0.0.0",
|
|
24
|
+
"vitest": "4.1.5",
|
|
25
25
|
"@prisma-next/test-utils": "0.0.1",
|
|
26
|
+
"@prisma-next/tsconfig": "0.0.0",
|
|
26
27
|
"@prisma-next/tsdown": "0.0.0"
|
|
27
28
|
},
|
|
28
29
|
"files": [
|
|
@@ -38,19 +38,21 @@ export type ArgTypeFromDescriptor<Arg extends AuthoringArgumentDescriptor> = Arg
|
|
|
38
38
|
readonly kind: 'string';
|
|
39
39
|
}
|
|
40
40
|
? string
|
|
41
|
-
: Arg extends { readonly kind: '
|
|
42
|
-
?
|
|
43
|
-
: Arg extends { readonly kind: '
|
|
44
|
-
?
|
|
45
|
-
: Arg extends {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
41
|
+
: Arg extends { readonly kind: 'boolean' }
|
|
42
|
+
? boolean
|
|
43
|
+
: Arg extends { readonly kind: 'number' }
|
|
44
|
+
? number
|
|
45
|
+
: Arg extends { readonly kind: 'stringArray' }
|
|
46
|
+
? readonly string[]
|
|
47
|
+
: Arg extends {
|
|
48
|
+
readonly kind: 'object';
|
|
49
|
+
readonly properties: infer Properties extends Record<
|
|
50
|
+
string,
|
|
51
|
+
AuthoringArgumentDescriptor
|
|
52
|
+
>;
|
|
53
|
+
}
|
|
54
|
+
? ObjectArgumentType<Properties>
|
|
55
|
+
: never;
|
|
54
56
|
|
|
55
57
|
export type TupleFromArgumentDescriptors<Args extends readonly AuthoringArgumentDescriptor[]> = {
|
|
56
58
|
readonly [K in keyof Args]: Args[K] extends AuthoringArgumentDescriptor
|
package/src/build-contract.ts
CHANGED
|
@@ -13,11 +13,16 @@ import {
|
|
|
13
13
|
type ContractValueObject,
|
|
14
14
|
coreHash,
|
|
15
15
|
type ExecutionMutationDefault,
|
|
16
|
-
type ExecutionMutationDefaultValue,
|
|
17
16
|
type JsonValue,
|
|
18
17
|
type StorageHashBase,
|
|
19
18
|
} from '@prisma-next/contract/types';
|
|
20
19
|
import type { CodecLookup } from '@prisma-next/framework-components/codec';
|
|
20
|
+
import { validateIndexTypes } from '@prisma-next/sql-contract/index-type-validation';
|
|
21
|
+
import {
|
|
22
|
+
createIndexTypeRegistry,
|
|
23
|
+
type IndexTypeMap,
|
|
24
|
+
type IndexTypeRegistration,
|
|
25
|
+
} from '@prisma-next/sql-contract/index-types';
|
|
21
26
|
import {
|
|
22
27
|
applyFkDefaults,
|
|
23
28
|
type SqlStorage,
|
|
@@ -64,11 +69,37 @@ function encodeColumnDefault(
|
|
|
64
69
|
};
|
|
65
70
|
}
|
|
66
71
|
|
|
67
|
-
function assertStorageSemantics(
|
|
68
|
-
|
|
72
|
+
function assertStorageSemantics(
|
|
73
|
+
definition: ContractDefinition,
|
|
74
|
+
contract: Contract<SqlStorage>,
|
|
75
|
+
): void {
|
|
76
|
+
const semanticErrors = validateStorageSemantics(contract.storage);
|
|
69
77
|
if (semanticErrors.length > 0) {
|
|
70
78
|
throw new Error(`Contract semantic validation failed: ${semanticErrors.join('; ')}`);
|
|
71
79
|
}
|
|
80
|
+
|
|
81
|
+
const indexTypeRegistry = createIndexTypeRegistry();
|
|
82
|
+
const packsToRegister: ReadonlyArray<{ readonly id?: string; readonly indexTypes?: unknown }> = [
|
|
83
|
+
definition.target,
|
|
84
|
+
...Object.values(definition.extensionPacks ?? {}),
|
|
85
|
+
];
|
|
86
|
+
for (const pack of packsToRegister) {
|
|
87
|
+
const registration = pack.indexTypes;
|
|
88
|
+
if (registration === undefined) continue;
|
|
89
|
+
if (
|
|
90
|
+
typeof registration !== 'object' ||
|
|
91
|
+
registration === null ||
|
|
92
|
+
!Array.isArray((registration as { entries?: unknown }).entries)
|
|
93
|
+
) {
|
|
94
|
+
throw new Error(
|
|
95
|
+
`Pack "${pack.id ?? '<unknown>'}" declares "indexTypes" but its value is not an IndexTypeRegistration (expected an object with an "entries" array; got ${typeof registration}).`,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
for (const entry of (registration as IndexTypeRegistration<IndexTypeMap>).entries) {
|
|
99
|
+
indexTypeRegistry.register(entry);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
validateIndexTypes(contract, indexTypeRegistry);
|
|
72
103
|
}
|
|
73
104
|
|
|
74
105
|
function assertKnownTargetModel(
|
|
@@ -198,15 +229,19 @@ export function buildSqlContractFromDefinition(
|
|
|
198
229
|
const domainFieldRefs: Record<string, DomainFieldRef> = {};
|
|
199
230
|
|
|
200
231
|
for (const field of semanticModel.fields) {
|
|
201
|
-
|
|
232
|
+
const executionDefaultPhases =
|
|
233
|
+
field.executionDefaults?.onCreate || field.executionDefaults?.onUpdate
|
|
234
|
+
? field.executionDefaults
|
|
235
|
+
: undefined;
|
|
236
|
+
if (executionDefaultPhases) {
|
|
202
237
|
if (field.default !== undefined) {
|
|
203
238
|
throw new Error(
|
|
204
|
-
`Field "${semanticModel.modelName}.${field.fieldName}" cannot define both default and
|
|
239
|
+
`Field "${semanticModel.modelName}.${field.fieldName}" cannot define both default and executionDefaults.`,
|
|
205
240
|
);
|
|
206
241
|
}
|
|
207
242
|
if (field.nullable) {
|
|
208
243
|
throw new Error(
|
|
209
|
-
`Field "${semanticModel.modelName}.${field.fieldName}" cannot be nullable when
|
|
244
|
+
`Field "${semanticModel.modelName}.${field.fieldName}" cannot be nullable when executionDefaults are present.`,
|
|
210
245
|
);
|
|
211
246
|
}
|
|
212
247
|
}
|
|
@@ -227,28 +262,15 @@ export function buildSqlContractFromDefinition(
|
|
|
227
262
|
domainFieldRefs[field.fieldName] = { kind: 'scalar', many: true };
|
|
228
263
|
}
|
|
229
264
|
|
|
230
|
-
if (
|
|
265
|
+
if (executionDefaultPhases) {
|
|
231
266
|
executionDefaults.push({
|
|
232
267
|
ref: { table: tableName, column: field.columnName },
|
|
233
|
-
onCreate
|
|
268
|
+
...ifDefined('onCreate', executionDefaultPhases.onCreate),
|
|
269
|
+
...ifDefined('onUpdate', executionDefaultPhases.onUpdate),
|
|
234
270
|
});
|
|
235
271
|
}
|
|
236
272
|
}
|
|
237
273
|
|
|
238
|
-
if (semanticModel.id) {
|
|
239
|
-
const fieldsByColumnName = new Map(
|
|
240
|
-
semanticModel.fields.map((field) => [field.columnName, field]),
|
|
241
|
-
);
|
|
242
|
-
for (const columnName of semanticModel.id.columns) {
|
|
243
|
-
const field = fieldsByColumnName.get(columnName);
|
|
244
|
-
if (field?.nullable) {
|
|
245
|
-
throw new Error(
|
|
246
|
-
`Model "${semanticModel.modelName}" uses nullable field "${field.fieldName}" in its identity.`,
|
|
247
|
-
);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
274
|
const foreignKeys = (semanticModel.foreignKeys ?? []).map((fk) => {
|
|
253
275
|
const targetModel = assertKnownTargetModel(
|
|
254
276
|
modelsByName,
|
|
@@ -287,8 +309,8 @@ export function buildSqlContractFromDefinition(
|
|
|
287
309
|
indexes: (semanticModel.indexes ?? []).map((i) => ({
|
|
288
310
|
columns: i.columns,
|
|
289
311
|
...ifDefined('name', i.name),
|
|
290
|
-
...ifDefined('
|
|
291
|
-
...ifDefined('
|
|
312
|
+
...ifDefined('type', i.type),
|
|
313
|
+
...ifDefined('options', i.options),
|
|
292
314
|
})),
|
|
293
315
|
foreignKeys,
|
|
294
316
|
...(semanticModel.id
|
|
@@ -457,7 +479,7 @@ export function buildSqlContractFromDefinition(
|
|
|
457
479
|
meta: {},
|
|
458
480
|
};
|
|
459
481
|
|
|
460
|
-
assertStorageSemantics(contract
|
|
482
|
+
assertStorageSemantics(definition, contract);
|
|
461
483
|
|
|
462
484
|
return contract;
|
|
463
485
|
}
|
|
@@ -5,8 +5,10 @@ import type {
|
|
|
5
5
|
AuthoringTypeNamespace,
|
|
6
6
|
} from '@prisma-next/framework-components/authoring';
|
|
7
7
|
import {
|
|
8
|
+
assertNoCrossRegistryCollisions,
|
|
8
9
|
isAuthoringFieldPresetDescriptor,
|
|
9
10
|
isAuthoringTypeConstructorDescriptor,
|
|
11
|
+
mergeAuthoringNamespaces,
|
|
10
12
|
} from '@prisma-next/framework-components/authoring';
|
|
11
13
|
import type {
|
|
12
14
|
ExtensionPackRef,
|
|
@@ -24,7 +26,14 @@ import type {
|
|
|
24
26
|
TupleFromArgumentDescriptors,
|
|
25
27
|
UnionToIntersection,
|
|
26
28
|
} from './authoring-type-utils';
|
|
29
|
+
import type {
|
|
30
|
+
AnyRelationBuilder,
|
|
31
|
+
ContractModelBuilder,
|
|
32
|
+
IndexTypeMap,
|
|
33
|
+
ScalarFieldBuilder,
|
|
34
|
+
} from './contract-dsl';
|
|
27
35
|
import { buildFieldPreset, field, model, rel } from './contract-dsl';
|
|
36
|
+
import type { MergeExtensionIndexTypes } from './contract-types';
|
|
28
37
|
|
|
29
38
|
type ExtractTypeNamespaceFromPack<Pack> = Pack extends {
|
|
30
39
|
readonly authoring?: { readonly type?: infer Namespace extends AuthoringTypeNamespace };
|
|
@@ -91,6 +100,33 @@ type TypeHelpersFromNamespace<Namespace> = {
|
|
|
91
100
|
|
|
92
101
|
type CoreFieldHelpers = Pick<typeof field, 'column' | 'generated' | 'namedType'>;
|
|
93
102
|
|
|
103
|
+
type MergeAllPackIndexTypes<Family, Target, ExtensionPacks> = MergeExtensionIndexTypes<
|
|
104
|
+
{ readonly __family: Family; readonly __target: Target } & (ExtensionPacks extends Record<
|
|
105
|
+
string,
|
|
106
|
+
unknown
|
|
107
|
+
>
|
|
108
|
+
? ExtensionPacks
|
|
109
|
+
: Record<never, never>)
|
|
110
|
+
>;
|
|
111
|
+
|
|
112
|
+
type PackAwareModel<IndexTypes extends IndexTypeMap> = {
|
|
113
|
+
<
|
|
114
|
+
const ModelName extends string,
|
|
115
|
+
Fields extends Record<string, ScalarFieldBuilder>,
|
|
116
|
+
Relations extends Record<string, AnyRelationBuilder> = Record<never, never>,
|
|
117
|
+
>(
|
|
118
|
+
modelName: ModelName,
|
|
119
|
+
input: { readonly fields: Fields; readonly relations?: Relations },
|
|
120
|
+
): ContractModelBuilder<ModelName, Fields, Relations, undefined, undefined, IndexTypes>;
|
|
121
|
+
<
|
|
122
|
+
Fields extends Record<string, ScalarFieldBuilder>,
|
|
123
|
+
Relations extends Record<string, AnyRelationBuilder> = Record<never, never>,
|
|
124
|
+
>(input: {
|
|
125
|
+
readonly fields: Fields;
|
|
126
|
+
readonly relations?: Relations;
|
|
127
|
+
}): ContractModelBuilder<undefined, Fields, Relations, undefined, undefined, IndexTypes>;
|
|
128
|
+
};
|
|
129
|
+
|
|
94
130
|
export type ComposedAuthoringHelpers<
|
|
95
131
|
Family extends FamilyPackRef<string>,
|
|
96
132
|
Target extends TargetPackRef<'sql', string>,
|
|
@@ -102,7 +138,7 @@ export type ComposedAuthoringHelpers<
|
|
|
102
138
|
ExtractFieldNamespaceFromPack<Target> &
|
|
103
139
|
MergeExtensionFieldNamespaces<ExtensionPacks>
|
|
104
140
|
>;
|
|
105
|
-
readonly model:
|
|
141
|
+
readonly model: PackAwareModel<MergeAllPackIndexTypes<Family, Target, ExtensionPacks>>;
|
|
106
142
|
readonly rel: typeof rel;
|
|
107
143
|
readonly type: TypeHelpersFromNamespace<
|
|
108
144
|
ExtractTypeNamespaceFromPack<Family> &
|
|
@@ -121,54 +157,6 @@ function extractFieldNamespace<Pack>(pack: Pack): ExtractFieldNamespaceFromPack<
|
|
|
121
157
|
{}) as ExtractFieldNamespaceFromPack<Pack>;
|
|
122
158
|
}
|
|
123
159
|
|
|
124
|
-
function mergeHelperNamespaces(
|
|
125
|
-
target: Record<string, unknown>,
|
|
126
|
-
source: Record<string, unknown>,
|
|
127
|
-
path: readonly string[],
|
|
128
|
-
leafGuard: (value: unknown) => boolean,
|
|
129
|
-
label: string,
|
|
130
|
-
): void {
|
|
131
|
-
const assertSafePath = (currentPath: readonly string[]) => {
|
|
132
|
-
const blockedSegment = currentPath.find(
|
|
133
|
-
(segment) => segment === '__proto__' || segment === 'constructor' || segment === 'prototype',
|
|
134
|
-
);
|
|
135
|
-
if (blockedSegment) {
|
|
136
|
-
throw new Error(
|
|
137
|
-
`Invalid authoring ${label} helper "${currentPath.join('.')}". Helper path segments must not use "${blockedSegment}".`,
|
|
138
|
-
);
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
for (const [key, sourceValue] of Object.entries(source)) {
|
|
143
|
-
const currentPath = [...path, key];
|
|
144
|
-
assertSafePath(currentPath);
|
|
145
|
-
const hasExistingValue = Object.hasOwn(target, key);
|
|
146
|
-
const existingValue = hasExistingValue ? target[key] : undefined;
|
|
147
|
-
|
|
148
|
-
if (!hasExistingValue) {
|
|
149
|
-
target[key] = sourceValue;
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const existingIsLeaf = leafGuard(existingValue);
|
|
154
|
-
const sourceIsLeaf = leafGuard(sourceValue);
|
|
155
|
-
|
|
156
|
-
if (existingIsLeaf || sourceIsLeaf) {
|
|
157
|
-
throw new Error(
|
|
158
|
-
`Duplicate authoring ${label} helper "${currentPath.join('.')}". Helper names must be unique across composed packs.`,
|
|
159
|
-
);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
mergeHelperNamespaces(
|
|
163
|
-
existingValue as Record<string, unknown>,
|
|
164
|
-
sourceValue as Record<string, unknown>,
|
|
165
|
-
currentPath,
|
|
166
|
-
leafGuard,
|
|
167
|
-
label,
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
160
|
type AuthoringComponent = {
|
|
173
161
|
readonly authoring?: { readonly type?: unknown; readonly field?: unknown };
|
|
174
162
|
};
|
|
@@ -178,7 +166,7 @@ function composeTypeNamespace(components: readonly AuthoringComponent[]): Author
|
|
|
178
166
|
for (const component of components) {
|
|
179
167
|
const ns = extractTypeNamespace(component);
|
|
180
168
|
if (Object.keys(ns).length > 0) {
|
|
181
|
-
|
|
169
|
+
mergeAuthoringNamespaces(merged, ns, [], isAuthoringTypeConstructorDescriptor, 'type');
|
|
182
170
|
}
|
|
183
171
|
}
|
|
184
172
|
return merged as AuthoringTypeNamespace;
|
|
@@ -189,17 +177,17 @@ function composeFieldNamespace(components: readonly AuthoringComponent[]): Autho
|
|
|
189
177
|
for (const component of components) {
|
|
190
178
|
const ns = extractFieldNamespace(component);
|
|
191
179
|
if (Object.keys(ns).length > 0) {
|
|
192
|
-
|
|
180
|
+
mergeAuthoringNamespaces(merged, ns, [], isAuthoringFieldPresetDescriptor, 'field');
|
|
193
181
|
}
|
|
194
182
|
}
|
|
195
183
|
return merged as AuthoringFieldNamespace;
|
|
196
184
|
}
|
|
197
185
|
|
|
198
186
|
function createComposedFieldHelpers(
|
|
199
|
-
|
|
187
|
+
fieldNamespace: AuthoringFieldNamespace,
|
|
200
188
|
): CoreFieldHelpers & Record<string, unknown> {
|
|
201
189
|
const helperNamespace = createFieldHelpersFromNamespace(
|
|
202
|
-
|
|
190
|
+
fieldNamespace,
|
|
203
191
|
({ helperPath, descriptor }) =>
|
|
204
192
|
createFieldPresetHelper({
|
|
205
193
|
helperPath,
|
|
@@ -247,10 +235,16 @@ export function createComposedAuthoringHelpers<
|
|
|
247
235
|
...extensionValues,
|
|
248
236
|
];
|
|
249
237
|
|
|
238
|
+
const typeNamespace = composeTypeNamespace(components);
|
|
239
|
+
const fieldNamespace = composeFieldNamespace(components);
|
|
240
|
+
// Mirrors the call in `assembleAuthoringContributions`: PSL composes via
|
|
241
|
+
// `createControlStack`, the TS DSL composes here. Both seams need the guard.
|
|
242
|
+
assertNoCrossRegistryCollisions(typeNamespace, fieldNamespace);
|
|
243
|
+
|
|
250
244
|
return {
|
|
251
|
-
field: createComposedFieldHelpers(
|
|
245
|
+
field: createComposedFieldHelpers(fieldNamespace),
|
|
252
246
|
model,
|
|
253
247
|
rel,
|
|
254
|
-
type: createTypeHelpersFromNamespace(
|
|
248
|
+
type: createTypeHelpersFromNamespace(typeNamespace),
|
|
255
249
|
} as ComposedAuthoringHelpers<Family, Target, ExtensionPacks>;
|
|
256
250
|
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import type { ColumnDefault,
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
ForeignKeyDefaultsState,
|
|
5
|
-
} from '@prisma-next/contract-authoring';
|
|
1
|
+
import type { ColumnDefault, ExecutionMutationDefaultPhases } from '@prisma-next/contract/types';
|
|
2
|
+
import type { ForeignKeyDefaultsState } from '@prisma-next/contract-authoring';
|
|
3
|
+
import type { ColumnTypeDescriptor } from '@prisma-next/framework-components/codec';
|
|
6
4
|
import type { ExtensionPackRef, TargetPackRef } from '@prisma-next/framework-components/components';
|
|
7
5
|
import type { ReferentialAction, StorageTypeInstance } from '@prisma-next/sql-contract/types';
|
|
8
6
|
|
|
7
|
+
export type { ExecutionMutationDefaultPhases };
|
|
8
|
+
|
|
9
9
|
export interface FieldNode {
|
|
10
10
|
readonly fieldName: string;
|
|
11
11
|
readonly columnName: string;
|
|
12
12
|
readonly descriptor: ColumnTypeDescriptor;
|
|
13
13
|
readonly nullable: boolean;
|
|
14
14
|
readonly default?: ColumnDefault;
|
|
15
|
-
readonly
|
|
15
|
+
readonly executionDefaults?: ExecutionMutationDefaultPhases;
|
|
16
16
|
readonly many?: boolean;
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -29,8 +29,8 @@ export interface UniqueConstraintNode {
|
|
|
29
29
|
export interface IndexNode {
|
|
30
30
|
readonly columns: readonly string[];
|
|
31
31
|
readonly name?: string;
|
|
32
|
-
readonly
|
|
33
|
-
readonly
|
|
32
|
+
readonly type?: string;
|
|
33
|
+
readonly options?: Record<string, unknown>;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
export interface ForeignKeyNode {
|
|
@@ -71,7 +71,7 @@ export interface ValueObjectFieldNode {
|
|
|
71
71
|
readonly valueObjectName: string;
|
|
72
72
|
readonly nullable: boolean;
|
|
73
73
|
readonly default?: ColumnDefault;
|
|
74
|
-
readonly
|
|
74
|
+
readonly executionDefaults?: ExecutionMutationDefaultPhases;
|
|
75
75
|
readonly many?: boolean;
|
|
76
76
|
}
|
|
77
77
|
|