@prisma-next/sql-contract-psl 0.3.0-dev.147 → 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/README.md +5 -5
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{interpreter-qjtea3zY.mjs → interpreter-iFCRN9nb.mjs} +712 -195
- package/dist/interpreter-iFCRN9nb.mjs.map +1 -0
- package/dist/provider.mjs +1 -1
- package/package.json +9 -9
- package/src/interpreter.ts +259 -149
- package/src/psl-authoring-arguments.ts +454 -0
- package/src/psl-column-resolution.ts +233 -37
- package/src/psl-field-resolution.ts +162 -139
- package/src/psl-relation-resolution.ts +13 -4
- package/dist/interpreter-qjtea3zY.mjs.map +0 -1
|
@@ -4,8 +4,17 @@ import type {
|
|
|
4
4
|
AuthoringContributions,
|
|
5
5
|
AuthoringTypeConstructorDescriptor,
|
|
6
6
|
} from '@prisma-next/framework-components/authoring';
|
|
7
|
-
import {
|
|
8
|
-
|
|
7
|
+
import {
|
|
8
|
+
instantiateAuthoringTypeConstructor,
|
|
9
|
+
isAuthoringTypeConstructorDescriptor,
|
|
10
|
+
validateAuthoringHelperArguments,
|
|
11
|
+
} from '@prisma-next/framework-components/authoring';
|
|
12
|
+
import type {
|
|
13
|
+
PslAttribute,
|
|
14
|
+
PslField,
|
|
15
|
+
PslSpan,
|
|
16
|
+
PslTypeConstructorCall,
|
|
17
|
+
} from '@prisma-next/psl-parser';
|
|
9
18
|
import type {
|
|
10
19
|
ControlMutationDefaultRegistry,
|
|
11
20
|
MutationDefaultGeneratorDescriptor,
|
|
@@ -15,8 +24,6 @@ import {
|
|
|
15
24
|
parseDefaultFunctionCall,
|
|
16
25
|
} from './default-function-registry';
|
|
17
26
|
import {
|
|
18
|
-
getNamedArgument,
|
|
19
|
-
getPositionalArgument,
|
|
20
27
|
getPositionalArgumentEntry,
|
|
21
28
|
getPositionalArguments,
|
|
22
29
|
parseOptionalNumericArguments,
|
|
@@ -24,6 +31,7 @@ import {
|
|
|
24
31
|
pushInvalidAttributeArgument,
|
|
25
32
|
unquoteStringLiteral,
|
|
26
33
|
} from './psl-attribute-parsing';
|
|
34
|
+
import { mapPslHelperArgs } from './psl-authoring-arguments';
|
|
27
35
|
|
|
28
36
|
export type ColumnDescriptor = {
|
|
29
37
|
readonly codecId: string;
|
|
@@ -59,6 +67,225 @@ export function getAuthoringTypeConstructor(
|
|
|
59
67
|
return isAuthoringTypeConstructorDescriptor(current) ? current : undefined;
|
|
60
68
|
}
|
|
61
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Returns the namespace prefix of `attributeName` if it references an
|
|
72
|
+
* unrecognized extension namespace, otherwise `undefined`. A namespace is
|
|
73
|
+
* considered recognized when it is:
|
|
74
|
+
*
|
|
75
|
+
* - `db` (native-type spec, always allowed),
|
|
76
|
+
* - the active family id (e.g. `sql`),
|
|
77
|
+
* - the active target id (e.g. `postgres`),
|
|
78
|
+
* - present in `composedExtensions`.
|
|
79
|
+
*
|
|
80
|
+
* Family/target namespaces are exempted so that e.g. `@sql.foo` surfaces as
|
|
81
|
+
* PSL_UNSUPPORTED_*_ATTRIBUTE (the attribute isn't defined) rather than
|
|
82
|
+
* PSL_EXTENSION_NAMESPACE_NOT_COMPOSED (the namespace is already composed).
|
|
83
|
+
*/
|
|
84
|
+
export function checkUncomposedNamespace(
|
|
85
|
+
attributeName: string,
|
|
86
|
+
composedExtensions: ReadonlySet<string>,
|
|
87
|
+
context?: { readonly familyId?: string; readonly targetId?: string },
|
|
88
|
+
): string | undefined {
|
|
89
|
+
const dotIndex = attributeName.indexOf('.');
|
|
90
|
+
if (dotIndex <= 0 || dotIndex === attributeName.length - 1) {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
const namespace = attributeName.slice(0, dotIndex);
|
|
94
|
+
if (
|
|
95
|
+
namespace === 'db' ||
|
|
96
|
+
namespace === context?.familyId ||
|
|
97
|
+
namespace === context?.targetId ||
|
|
98
|
+
composedExtensions.has(namespace)
|
|
99
|
+
) {
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
return namespace;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Pushes the canonical `PSL_EXTENSION_NAMESPACE_NOT_COMPOSED` diagnostic for a
|
|
107
|
+
* subject (attribute, model attribute, or type constructor) that references an
|
|
108
|
+
* extension namespace which is not composed in the current contract.
|
|
109
|
+
*
|
|
110
|
+
* The `data` payload carries the missing namespace so machine consumers
|
|
111
|
+
* (agents, IDE extensions, CLI auto-fix) don't have to parse the prose.
|
|
112
|
+
*/
|
|
113
|
+
export function reportUncomposedNamespace(input: {
|
|
114
|
+
readonly subjectLabel: string;
|
|
115
|
+
readonly namespace: string;
|
|
116
|
+
readonly sourceId: string;
|
|
117
|
+
readonly span: PslSpan;
|
|
118
|
+
readonly diagnostics: ContractSourceDiagnostic[];
|
|
119
|
+
}): void {
|
|
120
|
+
input.diagnostics.push({
|
|
121
|
+
code: 'PSL_EXTENSION_NAMESPACE_NOT_COMPOSED',
|
|
122
|
+
message: `${input.subjectLabel} uses unrecognized namespace "${input.namespace}". Add extension pack "${input.namespace}" to extensionPacks in prisma-next.config.ts.`,
|
|
123
|
+
sourceId: input.sourceId,
|
|
124
|
+
span: input.span,
|
|
125
|
+
data: { namespace: input.namespace, suggestedPack: input.namespace },
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function instantiatePslTypeConstructor(input: {
|
|
130
|
+
readonly call: PslTypeConstructorCall;
|
|
131
|
+
readonly descriptor: AuthoringTypeConstructorDescriptor;
|
|
132
|
+
readonly diagnostics: ContractSourceDiagnostic[];
|
|
133
|
+
readonly sourceId: string;
|
|
134
|
+
readonly entityLabel: string;
|
|
135
|
+
}):
|
|
136
|
+
| {
|
|
137
|
+
readonly codecId: string;
|
|
138
|
+
readonly nativeType: string;
|
|
139
|
+
readonly typeParams?: Record<string, unknown>;
|
|
140
|
+
}
|
|
141
|
+
| undefined {
|
|
142
|
+
const helperPath = input.call.path.join('.');
|
|
143
|
+
const args = mapPslHelperArgs({
|
|
144
|
+
args: input.call.args,
|
|
145
|
+
descriptors: input.descriptor.args ?? [],
|
|
146
|
+
helperLabel: `constructor "${helperPath}"`,
|
|
147
|
+
span: input.call.span,
|
|
148
|
+
diagnostics: input.diagnostics,
|
|
149
|
+
sourceId: input.sourceId,
|
|
150
|
+
entityLabel: input.entityLabel,
|
|
151
|
+
});
|
|
152
|
+
if (!args) {
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
validateAuthoringHelperArguments(helperPath, input.descriptor.args, args);
|
|
158
|
+
return instantiateAuthoringTypeConstructor(input.descriptor, args);
|
|
159
|
+
} catch (error) {
|
|
160
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
161
|
+
input.diagnostics.push({
|
|
162
|
+
code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',
|
|
163
|
+
message: `${input.entityLabel} constructor "${helperPath}" ${message}`,
|
|
164
|
+
sourceId: input.sourceId,
|
|
165
|
+
span: input.call.span,
|
|
166
|
+
});
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function pushUnsupportedTypeConstructorDiagnostic(input: {
|
|
172
|
+
readonly diagnostics: ContractSourceDiagnostic[];
|
|
173
|
+
readonly sourceId: string;
|
|
174
|
+
readonly span: PslSpan;
|
|
175
|
+
readonly code: 'PSL_UNSUPPORTED_FIELD_TYPE' | 'PSL_UNSUPPORTED_NAMED_TYPE_CONSTRUCTOR';
|
|
176
|
+
readonly message: string;
|
|
177
|
+
}): undefined {
|
|
178
|
+
input.diagnostics.push({
|
|
179
|
+
code: input.code,
|
|
180
|
+
message: input.message,
|
|
181
|
+
sourceId: input.sourceId,
|
|
182
|
+
span: input.span,
|
|
183
|
+
});
|
|
184
|
+
return undefined;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export function resolvePslTypeConstructorDescriptor(input: {
|
|
188
|
+
readonly call: PslTypeConstructorCall;
|
|
189
|
+
readonly authoringContributions: AuthoringContributions | undefined;
|
|
190
|
+
readonly composedExtensions: ReadonlySet<string>;
|
|
191
|
+
readonly familyId: string;
|
|
192
|
+
readonly targetId: string;
|
|
193
|
+
readonly diagnostics: ContractSourceDiagnostic[];
|
|
194
|
+
readonly sourceId: string;
|
|
195
|
+
readonly unsupportedCode: 'PSL_UNSUPPORTED_FIELD_TYPE' | 'PSL_UNSUPPORTED_NAMED_TYPE_CONSTRUCTOR';
|
|
196
|
+
readonly unsupportedMessage: string;
|
|
197
|
+
}): AuthoringTypeConstructorDescriptor | undefined {
|
|
198
|
+
const descriptor = getAuthoringTypeConstructor(input.authoringContributions, input.call.path);
|
|
199
|
+
if (descriptor) {
|
|
200
|
+
return descriptor;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const namespace = input.call.path.length > 1 ? input.call.path[0] : undefined;
|
|
204
|
+
if (
|
|
205
|
+
namespace &&
|
|
206
|
+
namespace !== 'db' &&
|
|
207
|
+
namespace !== input.familyId &&
|
|
208
|
+
namespace !== input.targetId &&
|
|
209
|
+
!input.composedExtensions.has(namespace)
|
|
210
|
+
) {
|
|
211
|
+
reportUncomposedNamespace({
|
|
212
|
+
subjectLabel: `Type constructor "${input.call.path.join('.')}"`,
|
|
213
|
+
namespace,
|
|
214
|
+
sourceId: input.sourceId,
|
|
215
|
+
span: input.call.span,
|
|
216
|
+
diagnostics: input.diagnostics,
|
|
217
|
+
});
|
|
218
|
+
return undefined;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return pushUnsupportedTypeConstructorDiagnostic({
|
|
222
|
+
diagnostics: input.diagnostics,
|
|
223
|
+
sourceId: input.sourceId,
|
|
224
|
+
span: input.call.span,
|
|
225
|
+
code: input.unsupportedCode,
|
|
226
|
+
message: input.unsupportedMessage,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export type ResolveFieldTypeResult =
|
|
231
|
+
| { readonly ok: true; readonly descriptor: ColumnDescriptor }
|
|
232
|
+
| { readonly ok: false; readonly alreadyReported: boolean };
|
|
233
|
+
|
|
234
|
+
export function resolveFieldTypeDescriptor(input: {
|
|
235
|
+
readonly field: PslField;
|
|
236
|
+
readonly enumTypeDescriptors: ReadonlyMap<string, ColumnDescriptor>;
|
|
237
|
+
readonly namedTypeDescriptors: ReadonlyMap<string, ColumnDescriptor>;
|
|
238
|
+
readonly scalarTypeDescriptors: ReadonlyMap<string, ColumnDescriptor>;
|
|
239
|
+
readonly authoringContributions: AuthoringContributions | undefined;
|
|
240
|
+
readonly composedExtensions: ReadonlySet<string>;
|
|
241
|
+
readonly familyId: string;
|
|
242
|
+
readonly targetId: string;
|
|
243
|
+
readonly diagnostics: ContractSourceDiagnostic[];
|
|
244
|
+
readonly sourceId: string;
|
|
245
|
+
readonly entityLabel: string;
|
|
246
|
+
}): ResolveFieldTypeResult {
|
|
247
|
+
if (input.field.typeConstructor) {
|
|
248
|
+
const helperPath = input.field.typeConstructor.path.join('.');
|
|
249
|
+
const descriptor = resolvePslTypeConstructorDescriptor({
|
|
250
|
+
call: input.field.typeConstructor,
|
|
251
|
+
authoringContributions: input.authoringContributions,
|
|
252
|
+
composedExtensions: input.composedExtensions,
|
|
253
|
+
familyId: input.familyId,
|
|
254
|
+
targetId: input.targetId,
|
|
255
|
+
diagnostics: input.diagnostics,
|
|
256
|
+
sourceId: input.sourceId,
|
|
257
|
+
unsupportedCode: 'PSL_UNSUPPORTED_FIELD_TYPE',
|
|
258
|
+
unsupportedMessage: `${input.entityLabel} type constructor "${helperPath}" is not supported in SQL PSL provider v1`,
|
|
259
|
+
});
|
|
260
|
+
if (!descriptor) {
|
|
261
|
+
return { ok: false, alreadyReported: true };
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const instantiated = instantiatePslTypeConstructor({
|
|
265
|
+
call: input.field.typeConstructor,
|
|
266
|
+
descriptor,
|
|
267
|
+
diagnostics: input.diagnostics,
|
|
268
|
+
sourceId: input.sourceId,
|
|
269
|
+
entityLabel: input.entityLabel,
|
|
270
|
+
});
|
|
271
|
+
if (!instantiated) {
|
|
272
|
+
return { ok: false, alreadyReported: true };
|
|
273
|
+
}
|
|
274
|
+
return { ok: true, descriptor: instantiated };
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const descriptor = resolveColumnDescriptor(
|
|
278
|
+
input.field,
|
|
279
|
+
input.enumTypeDescriptors,
|
|
280
|
+
input.namedTypeDescriptors,
|
|
281
|
+
input.scalarTypeDescriptors,
|
|
282
|
+
);
|
|
283
|
+
if (!descriptor) {
|
|
284
|
+
return { ok: false, alreadyReported: false };
|
|
285
|
+
}
|
|
286
|
+
return { ok: true, descriptor };
|
|
287
|
+
}
|
|
288
|
+
|
|
62
289
|
/**
|
|
63
290
|
* Declarative specification for @db.* native type attributes.
|
|
64
291
|
*
|
|
@@ -242,37 +469,6 @@ export function resolveDbNativeTypeAttribute(input: {
|
|
|
242
469
|
}
|
|
243
470
|
}
|
|
244
471
|
|
|
245
|
-
export function parsePgvectorLength(input: {
|
|
246
|
-
readonly attribute: PslAttribute;
|
|
247
|
-
readonly diagnostics: ContractSourceDiagnostic[];
|
|
248
|
-
readonly sourceId: string;
|
|
249
|
-
}): number | undefined {
|
|
250
|
-
const namedLength = getNamedArgument(input.attribute, 'length');
|
|
251
|
-
const namedDim = getNamedArgument(input.attribute, 'dim');
|
|
252
|
-
const positional = getPositionalArgument(input.attribute);
|
|
253
|
-
const raw = namedLength ?? namedDim ?? positional;
|
|
254
|
-
if (!raw) {
|
|
255
|
-
input.diagnostics.push({
|
|
256
|
-
code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',
|
|
257
|
-
message: '@pgvector.column requires length/dim argument',
|
|
258
|
-
sourceId: input.sourceId,
|
|
259
|
-
span: input.attribute.span,
|
|
260
|
-
});
|
|
261
|
-
return undefined;
|
|
262
|
-
}
|
|
263
|
-
const parsed = Number(unquoteStringLiteral(raw));
|
|
264
|
-
if (!Number.isInteger(parsed) || parsed < 1) {
|
|
265
|
-
input.diagnostics.push({
|
|
266
|
-
code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',
|
|
267
|
-
message: '@pgvector.column length/dim must be a positive integer',
|
|
268
|
-
sourceId: input.sourceId,
|
|
269
|
-
span: input.attribute.span,
|
|
270
|
-
});
|
|
271
|
-
return undefined;
|
|
272
|
-
}
|
|
273
|
-
return parsed;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
472
|
export function parseDefaultLiteralValue(expression: string): ColumnDefault | undefined {
|
|
277
473
|
const trimmed = expression.trim();
|
|
278
474
|
if (trimmed === 'true' || trimmed === 'false') {
|
|
@@ -387,8 +583,8 @@ export function lowerDefaultForField(input: {
|
|
|
387
583
|
|
|
388
584
|
export function resolveColumnDescriptor(
|
|
389
585
|
field: PslField,
|
|
390
|
-
enumTypeDescriptors:
|
|
391
|
-
namedTypeDescriptors:
|
|
586
|
+
enumTypeDescriptors: ReadonlyMap<string, ColumnDescriptor>,
|
|
587
|
+
namedTypeDescriptors: ReadonlyMap<string, ColumnDescriptor>,
|
|
392
588
|
scalarTypeDescriptors: ReadonlyMap<string, ColumnDescriptor>,
|
|
393
589
|
): ColumnDescriptor | undefined {
|
|
394
590
|
if (field.typeRef && namedTypeDescriptors.has(field.typeRef)) {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { ContractSourceDiagnostic } from '@prisma-next/config/config-types';
|
|
2
2
|
import type { ColumnDefault, ExecutionMutationDefaultValue } from '@prisma-next/contract/types';
|
|
3
3
|
import type { AuthoringContributions } from '@prisma-next/framework-components/authoring';
|
|
4
|
-
import {
|
|
5
|
-
import type { PslField, PslModel } from '@prisma-next/psl-parser';
|
|
4
|
+
import type { PslAttribute, PslField, PslModel } from '@prisma-next/psl-parser';
|
|
6
5
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
7
6
|
import type {
|
|
8
7
|
ControlMutationDefaultRegistry,
|
|
@@ -16,10 +15,10 @@ import {
|
|
|
16
15
|
} from './psl-attribute-parsing';
|
|
17
16
|
import type { ColumnDescriptor } from './psl-column-resolution';
|
|
18
17
|
import {
|
|
19
|
-
|
|
18
|
+
checkUncomposedNamespace,
|
|
20
19
|
lowerDefaultForField,
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
reportUncomposedNamespace,
|
|
21
|
+
resolveFieldTypeDescriptor,
|
|
23
22
|
} from './psl-column-resolution';
|
|
24
23
|
|
|
25
24
|
export type ResolvedField = {
|
|
@@ -43,61 +42,137 @@ export type ModelNameMapping = {
|
|
|
43
42
|
readonly fieldColumns: Map<string, string>;
|
|
44
43
|
};
|
|
45
44
|
|
|
46
|
-
export
|
|
47
|
-
model: PslModel
|
|
48
|
-
mapping: ModelNameMapping
|
|
49
|
-
enumTypeDescriptors: Map<string, ColumnDescriptor
|
|
50
|
-
namedTypeDescriptors: Map<string, ColumnDescriptor
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const pgvectorVectorConstructor = getAuthoringTypeConstructor(authoringContributions, [
|
|
64
|
-
'pgvector',
|
|
65
|
-
'vector',
|
|
66
|
-
]);
|
|
45
|
+
export interface CollectResolvedFieldsInput {
|
|
46
|
+
readonly model: PslModel;
|
|
47
|
+
readonly mapping: ModelNameMapping;
|
|
48
|
+
readonly enumTypeDescriptors: Map<string, ColumnDescriptor>;
|
|
49
|
+
readonly namedTypeDescriptors: Map<string, ColumnDescriptor>;
|
|
50
|
+
readonly modelNames: Set<string>;
|
|
51
|
+
readonly compositeTypeNames: ReadonlySet<string>;
|
|
52
|
+
readonly composedExtensions: Set<string>;
|
|
53
|
+
readonly authoringContributions: AuthoringContributions | undefined;
|
|
54
|
+
readonly familyId: string;
|
|
55
|
+
readonly targetId: string;
|
|
56
|
+
readonly defaultFunctionRegistry: ControlMutationDefaultRegistry;
|
|
57
|
+
readonly generatorDescriptorById: ReadonlyMap<string, MutationDefaultGeneratorDescriptor>;
|
|
58
|
+
readonly diagnostics: ContractSourceDiagnostic[];
|
|
59
|
+
readonly sourceId: string;
|
|
60
|
+
readonly scalarTypeDescriptors: ReadonlyMap<string, ColumnDescriptor>;
|
|
61
|
+
}
|
|
67
62
|
|
|
68
|
-
|
|
69
|
-
|
|
63
|
+
const BUILTIN_FIELD_ATTRIBUTE_NAMES: ReadonlySet<string> = new Set([
|
|
64
|
+
'id',
|
|
65
|
+
'unique',
|
|
66
|
+
'default',
|
|
67
|
+
'relation',
|
|
68
|
+
'map',
|
|
69
|
+
]);
|
|
70
|
+
|
|
71
|
+
function validateFieldAttributes(input: {
|
|
72
|
+
readonly model: PslModel;
|
|
73
|
+
readonly field: PslField;
|
|
74
|
+
readonly composedExtensions: ReadonlySet<string>;
|
|
75
|
+
readonly diagnostics: ContractSourceDiagnostic[];
|
|
76
|
+
readonly sourceId: string;
|
|
77
|
+
readonly familyId: string;
|
|
78
|
+
readonly targetId: string;
|
|
79
|
+
}): void {
|
|
80
|
+
for (const attribute of input.field.attributes) {
|
|
81
|
+
if (BUILTIN_FIELD_ATTRIBUTE_NAMES.has(attribute.name)) {
|
|
70
82
|
continue;
|
|
71
83
|
}
|
|
72
84
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
attribute.name
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
continue;
|
|
83
|
-
}
|
|
84
|
-
if (attribute.name.startsWith('pgvector.') && !composedExtensions.has('pgvector')) {
|
|
85
|
-
diagnostics.push({
|
|
86
|
-
code: 'PSL_EXTENSION_NAMESPACE_NOT_COMPOSED',
|
|
87
|
-
message: `Attribute "@${attribute.name}" uses unrecognized namespace "pgvector". Add extension pack "pgvector" to extensionPacks in prisma-next.config.ts.`,
|
|
88
|
-
sourceId,
|
|
89
|
-
span: attribute.span,
|
|
90
|
-
});
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
diagnostics.push({
|
|
94
|
-
code: 'PSL_UNSUPPORTED_FIELD_ATTRIBUTE',
|
|
95
|
-
message: `Field "${model.name}.${field.name}" uses unsupported attribute "@${attribute.name}"`,
|
|
96
|
-
sourceId,
|
|
85
|
+
const uncomposedNamespace = checkUncomposedNamespace(attribute.name, input.composedExtensions, {
|
|
86
|
+
familyId: input.familyId,
|
|
87
|
+
targetId: input.targetId,
|
|
88
|
+
});
|
|
89
|
+
if (uncomposedNamespace) {
|
|
90
|
+
reportUncomposedNamespace({
|
|
91
|
+
subjectLabel: `Attribute "@${attribute.name}"`,
|
|
92
|
+
namespace: uncomposedNamespace,
|
|
93
|
+
sourceId: input.sourceId,
|
|
97
94
|
span: attribute.span,
|
|
95
|
+
diagnostics: input.diagnostics,
|
|
98
96
|
});
|
|
97
|
+
continue;
|
|
99
98
|
}
|
|
100
99
|
|
|
100
|
+
input.diagnostics.push({
|
|
101
|
+
code: 'PSL_UNSUPPORTED_FIELD_ATTRIBUTE',
|
|
102
|
+
message: `Field "${input.model.name}.${input.field.name}" uses unsupported attribute "@${attribute.name}"`,
|
|
103
|
+
sourceId: input.sourceId,
|
|
104
|
+
span: attribute.span,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function extractFieldConstraintNames(input: {
|
|
110
|
+
readonly model: PslModel;
|
|
111
|
+
readonly field: PslField;
|
|
112
|
+
readonly sourceId: string;
|
|
113
|
+
readonly diagnostics: ContractSourceDiagnostic[];
|
|
114
|
+
}): {
|
|
115
|
+
readonly idAttribute: PslAttribute | undefined;
|
|
116
|
+
readonly uniqueAttribute: PslAttribute | undefined;
|
|
117
|
+
readonly idName: string | undefined;
|
|
118
|
+
readonly uniqueName: string | undefined;
|
|
119
|
+
} {
|
|
120
|
+
const idAttribute = getAttribute(input.field.attributes, 'id');
|
|
121
|
+
const uniqueAttribute = getAttribute(input.field.attributes, 'unique');
|
|
122
|
+
const idName = parseConstraintMapArgument({
|
|
123
|
+
attribute: idAttribute,
|
|
124
|
+
sourceId: input.sourceId,
|
|
125
|
+
diagnostics: input.diagnostics,
|
|
126
|
+
entityLabel: `Field "${input.model.name}.${input.field.name}" @id`,
|
|
127
|
+
span: input.field.span,
|
|
128
|
+
code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',
|
|
129
|
+
});
|
|
130
|
+
const uniqueName = parseConstraintMapArgument({
|
|
131
|
+
attribute: uniqueAttribute,
|
|
132
|
+
sourceId: input.sourceId,
|
|
133
|
+
diagnostics: input.diagnostics,
|
|
134
|
+
entityLabel: `Field "${input.model.name}.${input.field.name}" @unique`,
|
|
135
|
+
span: input.field.span,
|
|
136
|
+
code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',
|
|
137
|
+
});
|
|
138
|
+
return { idAttribute, uniqueAttribute, idName, uniqueName };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function collectResolvedFields(input: CollectResolvedFieldsInput): ResolvedField[] {
|
|
142
|
+
const {
|
|
143
|
+
model,
|
|
144
|
+
mapping,
|
|
145
|
+
enumTypeDescriptors,
|
|
146
|
+
namedTypeDescriptors,
|
|
147
|
+
modelNames,
|
|
148
|
+
compositeTypeNames,
|
|
149
|
+
composedExtensions,
|
|
150
|
+
authoringContributions,
|
|
151
|
+
familyId,
|
|
152
|
+
targetId,
|
|
153
|
+
defaultFunctionRegistry,
|
|
154
|
+
generatorDescriptorById,
|
|
155
|
+
diagnostics,
|
|
156
|
+
sourceId,
|
|
157
|
+
scalarTypeDescriptors,
|
|
158
|
+
} = input;
|
|
159
|
+
const resolvedFields: ResolvedField[] = [];
|
|
160
|
+
|
|
161
|
+
for (const field of model.fields) {
|
|
162
|
+
if (field.list && modelNames.has(field.typeName)) {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
validateFieldAttributes({
|
|
167
|
+
model,
|
|
168
|
+
field,
|
|
169
|
+
composedExtensions,
|
|
170
|
+
diagnostics,
|
|
171
|
+
sourceId,
|
|
172
|
+
familyId,
|
|
173
|
+
targetId,
|
|
174
|
+
});
|
|
175
|
+
|
|
101
176
|
const relationAttribute = getAttribute(field.attributes, 'relation');
|
|
102
177
|
if (relationAttribute && modelNames.has(field.typeName)) {
|
|
103
178
|
continue;
|
|
@@ -106,96 +181,56 @@ export function collectResolvedFields(
|
|
|
106
181
|
const isValueObjectField = compositeTypeNames.has(field.typeName);
|
|
107
182
|
const isListField = field.list;
|
|
108
183
|
|
|
109
|
-
const pgvectorOnJsonField = getAttribute(field.attributes, 'pgvector.column');
|
|
110
|
-
if (pgvectorOnJsonField && (isValueObjectField || isListField)) {
|
|
111
|
-
diagnostics.push({
|
|
112
|
-
code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',
|
|
113
|
-
message: `Field "${model.name}.${field.name}" uses @pgvector.column on a JSON-backed field (${isValueObjectField ? 'value object' : 'list'}). @pgvector.column is only supported on scalar Bytes fields.`,
|
|
114
|
-
sourceId,
|
|
115
|
-
span: pgvectorOnJsonField.span,
|
|
116
|
-
});
|
|
117
|
-
continue;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
184
|
let descriptor: ColumnDescriptor | undefined;
|
|
121
185
|
let scalarCodecId: string | undefined;
|
|
186
|
+
const resolveInput = {
|
|
187
|
+
field,
|
|
188
|
+
enumTypeDescriptors,
|
|
189
|
+
namedTypeDescriptors,
|
|
190
|
+
scalarTypeDescriptors,
|
|
191
|
+
authoringContributions,
|
|
192
|
+
composedExtensions,
|
|
193
|
+
familyId,
|
|
194
|
+
targetId,
|
|
195
|
+
diagnostics,
|
|
196
|
+
sourceId,
|
|
197
|
+
entityLabel: `Field "${model.name}.${field.name}"`,
|
|
198
|
+
};
|
|
122
199
|
|
|
123
200
|
if (isValueObjectField) {
|
|
124
201
|
descriptor = scalarTypeDescriptors.get('Json');
|
|
125
202
|
} else if (isListField) {
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
sourceId,
|
|
137
|
-
span: field.span,
|
|
138
|
-
});
|
|
203
|
+
const resolved = resolveFieldTypeDescriptor(resolveInput);
|
|
204
|
+
if (!resolved.ok) {
|
|
205
|
+
if (!resolved.alreadyReported) {
|
|
206
|
+
diagnostics.push({
|
|
207
|
+
code: 'PSL_UNSUPPORTED_FIELD_TYPE',
|
|
208
|
+
message: `Field "${model.name}.${field.name}" type "${field.typeName}" is not supported in SQL PSL provider v1`,
|
|
209
|
+
sourceId,
|
|
210
|
+
span: field.span,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
139
213
|
continue;
|
|
140
214
|
}
|
|
141
|
-
scalarCodecId =
|
|
215
|
+
scalarCodecId = resolved.descriptor.codecId;
|
|
142
216
|
descriptor = scalarTypeDescriptors.get('Json');
|
|
143
217
|
} else {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
namedTypeDescriptors,
|
|
148
|
-
scalarTypeDescriptors,
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
const pgvectorColumnAttribute = getAttribute(field.attributes, 'pgvector.column');
|
|
152
|
-
if (pgvectorColumnAttribute) {
|
|
153
|
-
if (!composedExtensions.has('pgvector')) {
|
|
218
|
+
const resolved = resolveFieldTypeDescriptor(resolveInput);
|
|
219
|
+
if (!resolved.ok) {
|
|
220
|
+
if (!resolved.alreadyReported) {
|
|
154
221
|
diagnostics.push({
|
|
155
|
-
code: '
|
|
156
|
-
message:
|
|
157
|
-
'Attribute "@pgvector.column" uses unrecognized namespace "pgvector". Add extension pack "pgvector" to extensionPacks in prisma-next.config.ts.',
|
|
222
|
+
code: 'PSL_UNSUPPORTED_FIELD_TYPE',
|
|
223
|
+
message: `Field "${model.name}.${field.name}" type "${field.typeName}" is not supported in SQL PSL provider v1`,
|
|
158
224
|
sourceId,
|
|
159
|
-
span:
|
|
225
|
+
span: field.span,
|
|
160
226
|
});
|
|
161
|
-
} else {
|
|
162
|
-
const isBytesBase =
|
|
163
|
-
field.typeName === 'Bytes' ||
|
|
164
|
-
namedTypeBaseTypes.get(field.typeRef ?? field.typeName) === 'Bytes';
|
|
165
|
-
if (!isBytesBase) {
|
|
166
|
-
diagnostics.push({
|
|
167
|
-
code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',
|
|
168
|
-
message: `Field "${model.name}.${field.name}" uses @pgvector.column on unsupported base type "${field.typeName}"`,
|
|
169
|
-
sourceId,
|
|
170
|
-
span: pgvectorColumnAttribute.span,
|
|
171
|
-
});
|
|
172
|
-
} else {
|
|
173
|
-
const length = parsePgvectorLength({
|
|
174
|
-
attribute: pgvectorColumnAttribute,
|
|
175
|
-
diagnostics,
|
|
176
|
-
sourceId,
|
|
177
|
-
});
|
|
178
|
-
if (length !== undefined) {
|
|
179
|
-
descriptor = pgvectorVectorConstructor
|
|
180
|
-
? instantiateAuthoringTypeConstructor(pgvectorVectorConstructor, [length])
|
|
181
|
-
: {
|
|
182
|
-
codecId: 'pg/vector@1',
|
|
183
|
-
nativeType: 'vector',
|
|
184
|
-
typeParams: { length },
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
227
|
}
|
|
228
|
+
continue;
|
|
189
229
|
}
|
|
230
|
+
descriptor = resolved.descriptor;
|
|
190
231
|
}
|
|
191
232
|
|
|
192
233
|
if (!descriptor) {
|
|
193
|
-
diagnostics.push({
|
|
194
|
-
code: 'PSL_UNSUPPORTED_FIELD_TYPE',
|
|
195
|
-
message: `Field "${model.name}.${field.name}" type "${field.typeName}" is not supported in SQL PSL provider v1`,
|
|
196
|
-
sourceId,
|
|
197
|
-
span: field.span,
|
|
198
|
-
});
|
|
199
234
|
continue;
|
|
200
235
|
}
|
|
201
236
|
|
|
@@ -235,23 +270,11 @@ export function collectResolvedFields(
|
|
|
235
270
|
}
|
|
236
271
|
}
|
|
237
272
|
const mappedColumnName = mapping.fieldColumns.get(field.name) ?? field.name;
|
|
238
|
-
const idAttribute =
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
attribute: idAttribute,
|
|
242
|
-
sourceId,
|
|
243
|
-
diagnostics,
|
|
244
|
-
entityLabel: `Field "${model.name}.${field.name}" @id`,
|
|
245
|
-
span: field.span,
|
|
246
|
-
code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',
|
|
247
|
-
});
|
|
248
|
-
const uniqueName = parseConstraintMapArgument({
|
|
249
|
-
attribute: uniqueAttribute,
|
|
273
|
+
const { idAttribute, uniqueAttribute, idName, uniqueName } = extractFieldConstraintNames({
|
|
274
|
+
model,
|
|
275
|
+
field,
|
|
250
276
|
sourceId,
|
|
251
277
|
diagnostics,
|
|
252
|
-
entityLabel: `Field "${model.name}.${field.name}" @unique`,
|
|
253
|
-
span: field.span,
|
|
254
|
-
code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',
|
|
255
278
|
});
|
|
256
279
|
|
|
257
280
|
resolvedFields.push({
|