@prisma-next/sql-contract-psl 0.3.0-dev.55 → 0.3.0-dev.64

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/src/provider.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  import { readFile } from 'node:fs/promises';
2
+ import type { ContractConfig } from '@prisma-next/config/config-types';
2
3
  import type { TargetPackRef } from '@prisma-next/contract/framework-components';
3
- import type { ContractConfig } from '@prisma-next/core-control-plane/config-types';
4
4
  import { parsePslDocument } from '@prisma-next/psl-parser';
5
5
  import { ifDefined } from '@prisma-next/utils/defined';
6
6
  import { notOk } from '@prisma-next/utils/result';
7
7
  import { resolve } from 'pathe';
8
+ import { createBuiltinDefaultFunctionRegistry } from './default-function-registry';
8
9
  import { interpretPslDocumentToSqlContractIR } from './interpreter';
9
10
 
10
11
  export interface PrismaContractOptions {
@@ -56,6 +57,7 @@ export function prismaContract(
56
57
  document,
57
58
  ...ifDefined('target', options?.target),
58
59
  ...ifDefined('composedExtensionPacks', options?.composedExtensionPacks),
60
+ defaultFunctionRegistry: createBuiltinDefaultFunctionRegistry(),
59
61
  });
60
62
  },
61
63
  ...ifDefined('output', options?.output),
@@ -1,661 +0,0 @@
1
- import { defineContract } from "@prisma-next/sql-contract-ts/contract-builder";
2
- import { notOk, ok } from "@prisma-next/utils/result";
3
-
4
- //#region src/interpreter.ts
5
- const DEFAULT_POSTGRES_TARGET = {
6
- kind: "target",
7
- familyId: "sql",
8
- targetId: "postgres",
9
- id: "postgres",
10
- version: "0.0.1",
11
- capabilities: {}
12
- };
13
- const SCALAR_COLUMN_MAP = {
14
- String: {
15
- codecId: "pg/text@1",
16
- nativeType: "text"
17
- },
18
- Boolean: {
19
- codecId: "pg/bool@1",
20
- nativeType: "bool"
21
- },
22
- Int: {
23
- codecId: "pg/int4@1",
24
- nativeType: "int4"
25
- },
26
- BigInt: {
27
- codecId: "pg/int8@1",
28
- nativeType: "int8"
29
- },
30
- Float: {
31
- codecId: "pg/float8@1",
32
- nativeType: "float8"
33
- },
34
- Decimal: {
35
- codecId: "pg/numeric@1",
36
- nativeType: "numeric"
37
- },
38
- DateTime: {
39
- codecId: "pg/timestamptz@1",
40
- nativeType: "timestamptz"
41
- },
42
- Json: {
43
- codecId: "pg/jsonb@1",
44
- nativeType: "jsonb"
45
- },
46
- Bytes: {
47
- codecId: "pg/bytea@1",
48
- nativeType: "bytea"
49
- }
50
- };
51
- const REFERENTIAL_ACTION_MAP = {
52
- NoAction: "noAction",
53
- Restrict: "restrict",
54
- Cascade: "cascade",
55
- SetNull: "setNull",
56
- SetDefault: "setDefault",
57
- noAction: "noAction",
58
- restrict: "restrict",
59
- cascade: "cascade",
60
- setNull: "setNull",
61
- setDefault: "setDefault"
62
- };
63
- function lowerFirst(value) {
64
- if (value.length === 0) return value;
65
- return value[0]?.toLowerCase() + value.slice(1);
66
- }
67
- function getAttribute(attributes, name) {
68
- return attributes.find((attribute) => attribute.name === name);
69
- }
70
- function getNamedArgument(attribute, name) {
71
- const entry = attribute.args.find((arg) => arg.kind === "named" && arg.name === name);
72
- if (!entry || entry.kind !== "named") return;
73
- return entry.value;
74
- }
75
- function getPositionalArgument(attribute, index = 0) {
76
- const entry = attribute.args.filter((arg) => arg.kind === "positional")[index];
77
- if (!entry || entry.kind !== "positional") return;
78
- return entry.value;
79
- }
80
- function unquoteStringLiteral(value) {
81
- const trimmed = value.trim();
82
- const match = trimmed.match(/^(['"])(.*)\1$/);
83
- if (!match) return trimmed;
84
- return match[2] ?? "";
85
- }
86
- function parseQuotedStringLiteral(value) {
87
- const match = value.trim().match(/^(['"])(.*)\1$/);
88
- if (!match) return;
89
- return match[2] ?? "";
90
- }
91
- function parseFieldList(value) {
92
- const trimmed = value.trim();
93
- if (!trimmed.startsWith("[") || !trimmed.endsWith("]")) return;
94
- return trimmed.slice(1, -1).split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
95
- }
96
- function parseDefaultValueExpression(expression) {
97
- const trimmed = expression.trim();
98
- if (trimmed === "autoincrement()") return {
99
- kind: "function",
100
- expression: "autoincrement()"
101
- };
102
- if (trimmed === "now()") return {
103
- kind: "function",
104
- expression: "now()"
105
- };
106
- if (trimmed === "true" || trimmed === "false") return {
107
- kind: "literal",
108
- value: trimmed === "true"
109
- };
110
- const numericValue = Number(trimmed);
111
- if (!Number.isNaN(numericValue) && trimmed.length > 0 && !/^(['"]).*\1$/.test(trimmed)) return {
112
- kind: "literal",
113
- value: numericValue
114
- };
115
- if (/^(['"]).*\1$/.test(trimmed)) return {
116
- kind: "literal",
117
- value: unquoteStringLiteral(trimmed)
118
- };
119
- }
120
- function parseMapName(input) {
121
- if (!input.attribute) return input.defaultValue;
122
- const value = getPositionalArgument(input.attribute);
123
- if (!value) {
124
- input.diagnostics.push({
125
- code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
126
- message: `${input.entityLabel} @map requires a positional quoted string literal argument`,
127
- sourceId: input.sourceId,
128
- span: input.attribute.span
129
- });
130
- return input.defaultValue;
131
- }
132
- const parsed = parseQuotedStringLiteral(value);
133
- if (parsed === void 0) {
134
- input.diagnostics.push({
135
- code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
136
- message: `${input.entityLabel} @map requires a positional quoted string literal argument`,
137
- sourceId: input.sourceId,
138
- span: input.attribute.span
139
- });
140
- return input.defaultValue;
141
- }
142
- return parsed;
143
- }
144
- function parsePgvectorLength(input) {
145
- const namedLength = getNamedArgument(input.attribute, "length");
146
- const namedDim = getNamedArgument(input.attribute, "dim");
147
- const positional = getPositionalArgument(input.attribute);
148
- const raw = namedLength ?? namedDim ?? positional;
149
- if (!raw) {
150
- input.diagnostics.push({
151
- code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
152
- message: "@pgvector.column requires length/dim argument",
153
- sourceId: input.sourceId,
154
- span: input.attribute.span
155
- });
156
- return;
157
- }
158
- const parsed = Number(unquoteStringLiteral(raw));
159
- if (!Number.isInteger(parsed) || parsed < 1) {
160
- input.diagnostics.push({
161
- code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
162
- message: "@pgvector.column length/dim must be a positive integer",
163
- sourceId: input.sourceId,
164
- span: input.attribute.span
165
- });
166
- return;
167
- }
168
- return parsed;
169
- }
170
- function resolveColumnDescriptor(field, enumTypeDescriptors, namedTypeDescriptors) {
171
- if (field.typeRef && namedTypeDescriptors.has(field.typeRef)) return namedTypeDescriptors.get(field.typeRef);
172
- if (namedTypeDescriptors.has(field.typeName)) return namedTypeDescriptors.get(field.typeName);
173
- if (enumTypeDescriptors.has(field.typeName)) return enumTypeDescriptors.get(field.typeName);
174
- return SCALAR_COLUMN_MAP[field.typeName];
175
- }
176
- function collectResolvedFields(model, mapping, enumTypeDescriptors, namedTypeDescriptors, namedTypeBaseTypes, modelNames, composedExtensions, diagnostics, sourceId) {
177
- const resolvedFields = [];
178
- for (const field of model.fields) {
179
- if (field.list) {
180
- diagnostics.push({
181
- code: "PSL_UNSUPPORTED_FIELD_LIST",
182
- message: `Field "${model.name}.${field.name}" uses list types, which are not supported in SQL PSL provider v1`,
183
- sourceId,
184
- span: field.span
185
- });
186
- continue;
187
- }
188
- for (const attribute of field.attributes) {
189
- if (attribute.name === "id" || attribute.name === "unique" || attribute.name === "default" || attribute.name === "relation" || attribute.name === "map" || attribute.name === "pgvector.column") continue;
190
- if (attribute.name.startsWith("pgvector.") && !composedExtensions.has("pgvector")) {
191
- diagnostics.push({
192
- code: "PSL_EXTENSION_NAMESPACE_NOT_COMPOSED",
193
- message: `Attribute "@${attribute.name}" uses unrecognized namespace "pgvector". Add extension pack "pgvector" to extensionPacks in prisma-next.config.ts.`,
194
- sourceId,
195
- span: attribute.span
196
- });
197
- continue;
198
- }
199
- diagnostics.push({
200
- code: "PSL_UNSUPPORTED_FIELD_ATTRIBUTE",
201
- message: `Field "${model.name}.${field.name}" uses unsupported attribute "@${attribute.name}"`,
202
- sourceId,
203
- span: attribute.span
204
- });
205
- }
206
- if (getAttribute(field.attributes, "relation") && modelNames.has(field.typeName)) continue;
207
- let descriptor = resolveColumnDescriptor(field, enumTypeDescriptors, namedTypeDescriptors);
208
- const pgvectorColumnAttribute = getAttribute(field.attributes, "pgvector.column");
209
- if (pgvectorColumnAttribute) if (!composedExtensions.has("pgvector")) diagnostics.push({
210
- code: "PSL_EXTENSION_NAMESPACE_NOT_COMPOSED",
211
- message: "Attribute \"@pgvector.column\" uses unrecognized namespace \"pgvector\". Add extension pack \"pgvector\" to extensionPacks in prisma-next.config.ts.",
212
- sourceId,
213
- span: pgvectorColumnAttribute.span
214
- });
215
- else if (!(field.typeName === "Bytes" || namedTypeBaseTypes.get(field.typeRef ?? field.typeName) === "Bytes")) diagnostics.push({
216
- code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
217
- message: `Field "${model.name}.${field.name}" uses @pgvector.column on unsupported base type "${field.typeName}"`,
218
- sourceId,
219
- span: pgvectorColumnAttribute.span
220
- });
221
- else {
222
- const length = parsePgvectorLength({
223
- attribute: pgvectorColumnAttribute,
224
- diagnostics,
225
- sourceId
226
- });
227
- if (length !== void 0) descriptor = {
228
- codecId: "pg/vector@1",
229
- nativeType: `vector(${length})`,
230
- typeParams: { length }
231
- };
232
- }
233
- if (!descriptor) {
234
- diagnostics.push({
235
- code: "PSL_UNSUPPORTED_FIELD_TYPE",
236
- message: `Field "${model.name}.${field.name}" type "${field.typeName}" is not supported in SQL PSL provider v1`,
237
- sourceId,
238
- span: field.span
239
- });
240
- continue;
241
- }
242
- const defaultAttribute = getAttribute(field.attributes, "default");
243
- const defaultValueRaw = defaultAttribute ? getPositionalArgument(defaultAttribute) : void 0;
244
- const defaultValue = defaultValueRaw ? parseDefaultValueExpression(defaultValueRaw) : void 0;
245
- if (defaultAttribute && defaultValueRaw && !defaultValue) diagnostics.push({
246
- code: "PSL_INVALID_DEFAULT_VALUE",
247
- message: `Unsupported default value "${defaultValueRaw}"`,
248
- sourceId,
249
- span: defaultAttribute.span
250
- });
251
- const mappedColumnName = mapping.fieldColumns.get(field.name) ?? field.name;
252
- resolvedFields.push({
253
- field,
254
- columnName: mappedColumnName,
255
- descriptor,
256
- ...defaultValue ? { defaultValue } : {},
257
- isId: Boolean(getAttribute(field.attributes, "id")),
258
- isUnique: Boolean(getAttribute(field.attributes, "unique"))
259
- });
260
- }
261
- return resolvedFields;
262
- }
263
- function hasSameSpan(a, b) {
264
- return a.start.offset === b.start.offset && a.end.offset === b.end.offset && a.start.line === b.start.line && a.end.line === b.end.line;
265
- }
266
- function mapParserDiagnostics(document) {
267
- return document.diagnostics.map((diagnostic) => ({
268
- code: diagnostic.code,
269
- message: diagnostic.message,
270
- sourceId: diagnostic.sourceId,
271
- span: diagnostic.span
272
- }));
273
- }
274
- function normalizeReferentialAction(input) {
275
- const normalized = REFERENTIAL_ACTION_MAP[input.actionToken];
276
- if (normalized) return normalized;
277
- input.diagnostics.push({
278
- code: "PSL_UNSUPPORTED_REFERENTIAL_ACTION",
279
- message: `Relation field "${input.modelName}.${input.fieldName}" has unsupported ${input.actionName} action "${input.actionToken}"`,
280
- sourceId: input.sourceId,
281
- span: input.span
282
- });
283
- }
284
- function parseAttributeFieldList(input) {
285
- const raw = getNamedArgument(input.attribute, "fields") ?? getPositionalArgument(input.attribute);
286
- if (!raw) {
287
- input.diagnostics.push({
288
- code: input.code,
289
- message: `${input.messagePrefix} requires fields list argument`,
290
- sourceId: input.sourceId,
291
- span: input.attribute.span
292
- });
293
- return;
294
- }
295
- const fields = parseFieldList(raw);
296
- if (!fields || fields.length === 0) {
297
- input.diagnostics.push({
298
- code: input.code,
299
- message: `${input.messagePrefix} requires bracketed field list argument`,
300
- sourceId: input.sourceId,
301
- span: input.attribute.span
302
- });
303
- return;
304
- }
305
- return fields;
306
- }
307
- function mapFieldNamesToColumns(input) {
308
- const columns = [];
309
- for (const fieldName of input.fieldNames) {
310
- const columnName = input.mapping.fieldColumns.get(fieldName);
311
- if (!columnName) {
312
- input.diagnostics.push({
313
- code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
314
- message: `${input.contextLabel} references unknown field "${input.modelName}.${fieldName}"`,
315
- sourceId: input.sourceId,
316
- span: input.span
317
- });
318
- return;
319
- }
320
- columns.push(columnName);
321
- }
322
- return columns;
323
- }
324
- function buildModelMappings(models, diagnostics, sourceId) {
325
- const result = /* @__PURE__ */ new Map();
326
- for (const model of models) {
327
- const tableName = parseMapName({
328
- attribute: getAttribute(model.attributes, "map"),
329
- defaultValue: lowerFirst(model.name),
330
- sourceId,
331
- diagnostics,
332
- entityLabel: `Model "${model.name}"`,
333
- span: model.span
334
- });
335
- const fieldColumns = /* @__PURE__ */ new Map();
336
- for (const field of model.fields) {
337
- const columnName = parseMapName({
338
- attribute: getAttribute(field.attributes, "map"),
339
- defaultValue: field.name,
340
- sourceId,
341
- diagnostics,
342
- entityLabel: `Field "${model.name}.${field.name}"`,
343
- span: field.span
344
- });
345
- fieldColumns.set(field.name, columnName);
346
- }
347
- result.set(model.name, {
348
- model,
349
- tableName,
350
- fieldColumns
351
- });
352
- }
353
- return result;
354
- }
355
- function parseRelationAttribute(input) {
356
- for (const arg of input.attribute.args) {
357
- if (arg.kind === "positional") {
358
- input.diagnostics.push({
359
- code: "PSL_INVALID_RELATION_ATTRIBUTE",
360
- message: `Relation field "${input.modelName}.${input.fieldName}" must use named arguments`,
361
- sourceId: input.sourceId,
362
- span: arg.span
363
- });
364
- return;
365
- }
366
- if (arg.name !== "fields" && arg.name !== "references" && arg.name !== "onDelete" && arg.name !== "onUpdate") {
367
- input.diagnostics.push({
368
- code: "PSL_INVALID_RELATION_ATTRIBUTE",
369
- message: `Relation field "${input.modelName}.${input.fieldName}" has unsupported argument "${arg.name}"`,
370
- sourceId: input.sourceId,
371
- span: arg.span
372
- });
373
- return;
374
- }
375
- }
376
- const fieldsRaw = getNamedArgument(input.attribute, "fields");
377
- const referencesRaw = getNamedArgument(input.attribute, "references");
378
- if (!fieldsRaw || !referencesRaw) {
379
- input.diagnostics.push({
380
- code: "PSL_INVALID_RELATION_ATTRIBUTE",
381
- message: `Relation field "${input.modelName}.${input.fieldName}" requires fields and references arguments`,
382
- sourceId: input.sourceId,
383
- span: input.attribute.span
384
- });
385
- return;
386
- }
387
- const fields = parseFieldList(fieldsRaw);
388
- const references = parseFieldList(referencesRaw);
389
- if (!fields || !references || fields.length === 0 || references.length === 0) {
390
- input.diagnostics.push({
391
- code: "PSL_INVALID_RELATION_ATTRIBUTE",
392
- message: `Relation field "${input.modelName}.${input.fieldName}" requires bracketed fields and references lists`,
393
- sourceId: input.sourceId,
394
- span: input.attribute.span
395
- });
396
- return;
397
- }
398
- return {
399
- fields,
400
- references,
401
- ...getNamedArgument(input.attribute, "onDelete") ? { onDelete: unquoteStringLiteral(getNamedArgument(input.attribute, "onDelete") ?? "") } : {},
402
- ...getNamedArgument(input.attribute, "onUpdate") ? { onUpdate: unquoteStringLiteral(getNamedArgument(input.attribute, "onUpdate") ?? "") } : {}
403
- };
404
- }
405
- function interpretPslDocumentToSqlContractIR(input) {
406
- const diagnostics = mapParserDiagnostics(input.document);
407
- const modelNames = new Set(input.document.ast.models.map((model) => model.name));
408
- const sourceId = input.document.ast.sourceId;
409
- const composedExtensions = new Set(input.composedExtensionPacks ?? []);
410
- let builder = defineContract().target(input.target ?? DEFAULT_POSTGRES_TARGET);
411
- const enumTypeDescriptors = /* @__PURE__ */ new Map();
412
- const namedTypeDescriptors = /* @__PURE__ */ new Map();
413
- const namedTypeBaseTypes = /* @__PURE__ */ new Map();
414
- for (const enumDeclaration of input.document.ast.enums) {
415
- const nativeType = enumDeclaration.name.toLowerCase();
416
- const descriptor = {
417
- codecId: "pg/enum@1",
418
- nativeType,
419
- typeRef: enumDeclaration.name
420
- };
421
- enumTypeDescriptors.set(enumDeclaration.name, descriptor);
422
- builder = builder.storageType(enumDeclaration.name, {
423
- codecId: "pg/enum@1",
424
- nativeType,
425
- typeParams: { values: enumDeclaration.values.map((value) => value.name) }
426
- });
427
- }
428
- for (const declaration of input.document.ast.types?.declarations ?? []) {
429
- const baseDescriptor = enumTypeDescriptors.get(declaration.baseType) ?? SCALAR_COLUMN_MAP[declaration.baseType];
430
- if (!baseDescriptor) {
431
- diagnostics.push({
432
- code: "PSL_UNSUPPORTED_NAMED_TYPE_BASE",
433
- message: `Named type "${declaration.name}" references unsupported base type "${declaration.baseType}"`,
434
- sourceId,
435
- span: declaration.span
436
- });
437
- continue;
438
- }
439
- namedTypeBaseTypes.set(declaration.name, declaration.baseType);
440
- const pgvectorAttribute = getAttribute(declaration.attributes, "pgvector.column");
441
- const unsupportedNamedTypeAttribute = declaration.attributes.find((attribute) => attribute.name !== "pgvector.column");
442
- if (unsupportedNamedTypeAttribute) {
443
- diagnostics.push({
444
- code: "PSL_UNSUPPORTED_NAMED_TYPE_ATTRIBUTE",
445
- message: `Named type "${declaration.name}" uses unsupported attribute "${unsupportedNamedTypeAttribute.name}"`,
446
- sourceId,
447
- span: unsupportedNamedTypeAttribute.span
448
- });
449
- continue;
450
- }
451
- if (pgvectorAttribute) {
452
- if (!composedExtensions.has("pgvector")) {
453
- diagnostics.push({
454
- code: "PSL_EXTENSION_NAMESPACE_NOT_COMPOSED",
455
- message: "Attribute \"@pgvector.column\" uses unrecognized namespace \"pgvector\". Add extension pack \"pgvector\" to extensionPacks in prisma-next.config.ts.",
456
- sourceId,
457
- span: pgvectorAttribute.span
458
- });
459
- continue;
460
- }
461
- if (declaration.baseType !== "Bytes") {
462
- diagnostics.push({
463
- code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
464
- message: `Named type "${declaration.name}" uses @pgvector.column on unsupported base type "${declaration.baseType}"`,
465
- sourceId,
466
- span: pgvectorAttribute.span
467
- });
468
- continue;
469
- }
470
- const length = parsePgvectorLength({
471
- attribute: pgvectorAttribute,
472
- diagnostics,
473
- sourceId
474
- });
475
- if (length === void 0) continue;
476
- namedTypeDescriptors.set(declaration.name, {
477
- codecId: "pg/vector@1",
478
- nativeType: `vector(${length})`,
479
- typeRef: declaration.name
480
- });
481
- builder = builder.storageType(declaration.name, {
482
- codecId: "pg/vector@1",
483
- nativeType: `vector(${length})`,
484
- typeParams: { length }
485
- });
486
- continue;
487
- }
488
- const descriptor = {
489
- codecId: baseDescriptor.codecId,
490
- nativeType: baseDescriptor.nativeType,
491
- typeRef: declaration.name
492
- };
493
- namedTypeDescriptors.set(declaration.name, descriptor);
494
- builder = builder.storageType(declaration.name, {
495
- codecId: baseDescriptor.codecId,
496
- nativeType: baseDescriptor.nativeType,
497
- typeParams: {}
498
- });
499
- }
500
- const modelMappings = buildModelMappings(input.document.ast.models, diagnostics, sourceId);
501
- for (const model of input.document.ast.models) {
502
- const mapping = modelMappings.get(model.name);
503
- if (!mapping) continue;
504
- const tableName = mapping.tableName;
505
- const resolvedFields = collectResolvedFields(model, mapping, enumTypeDescriptors, namedTypeDescriptors, namedTypeBaseTypes, modelNames, composedExtensions, diagnostics, sourceId);
506
- const primaryKeyColumns = resolvedFields.filter((field) => field.isId).map((field) => field.columnName);
507
- if (primaryKeyColumns.length === 0) diagnostics.push({
508
- code: "PSL_MISSING_PRIMARY_KEY",
509
- message: `Model "${model.name}" must declare at least one @id field for SQL provider`,
510
- sourceId,
511
- span: model.span
512
- });
513
- const relationAttributes = model.fields.map((field) => ({
514
- field,
515
- relation: getAttribute(field.attributes, "relation")
516
- })).filter((entry) => Boolean(entry.relation));
517
- builder = builder.table(tableName, (tableBuilder) => {
518
- let table = tableBuilder;
519
- for (const resolvedField of resolvedFields) {
520
- const options = {
521
- type: resolvedField.descriptor,
522
- ...resolvedField.field.optional ? { nullable: true } : {},
523
- ...resolvedField.defaultValue ? { default: resolvedField.defaultValue } : {}
524
- };
525
- table = table.column(resolvedField.columnName, options);
526
- if (resolvedField.isUnique) table = table.unique([resolvedField.columnName]);
527
- }
528
- if (primaryKeyColumns.length > 0) table = table.primaryKey(primaryKeyColumns);
529
- for (const modelAttribute of model.attributes) {
530
- if (modelAttribute.name === "map") continue;
531
- if (modelAttribute.name === "unique" || modelAttribute.name === "index") {
532
- const fieldNames = parseAttributeFieldList({
533
- attribute: modelAttribute,
534
- sourceId,
535
- diagnostics,
536
- code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
537
- messagePrefix: `Model "${model.name}" @@${modelAttribute.name}`
538
- });
539
- if (!fieldNames) continue;
540
- const columnNames = mapFieldNamesToColumns({
541
- modelName: model.name,
542
- fieldNames,
543
- mapping,
544
- sourceId,
545
- diagnostics,
546
- span: modelAttribute.span,
547
- contextLabel: `Model "${model.name}" @@${modelAttribute.name}`
548
- });
549
- if (!columnNames) continue;
550
- if (modelAttribute.name === "unique") table = table.unique(columnNames);
551
- else table = table.index(columnNames);
552
- continue;
553
- }
554
- if (modelAttribute.name.startsWith("pgvector.") && !composedExtensions.has("pgvector")) {
555
- diagnostics.push({
556
- code: "PSL_EXTENSION_NAMESPACE_NOT_COMPOSED",
557
- message: `Attribute "@@${modelAttribute.name}" uses unrecognized namespace "pgvector". Add extension pack "pgvector" to extensionPacks in prisma-next.config.ts.`,
558
- sourceId,
559
- span: modelAttribute.span
560
- });
561
- continue;
562
- }
563
- diagnostics.push({
564
- code: "PSL_UNSUPPORTED_MODEL_ATTRIBUTE",
565
- message: `Model "${model.name}" uses unsupported attribute "@@${modelAttribute.name}"`,
566
- sourceId,
567
- span: modelAttribute.span
568
- });
569
- }
570
- for (const relationAttribute of relationAttributes) {
571
- if (!modelNames.has(relationAttribute.field.typeName)) {
572
- diagnostics.push({
573
- code: "PSL_INVALID_RELATION_TARGET",
574
- message: `Relation field "${model.name}.${relationAttribute.field.name}" references unknown model "${relationAttribute.field.typeName}"`,
575
- sourceId,
576
- span: relationAttribute.field.span
577
- });
578
- continue;
579
- }
580
- const parsedRelation = parseRelationAttribute({
581
- attribute: relationAttribute.relation,
582
- modelName: model.name,
583
- fieldName: relationAttribute.field.name,
584
- sourceId,
585
- diagnostics
586
- });
587
- if (!parsedRelation) continue;
588
- const targetMapping = modelMappings.get(relationAttribute.field.typeName);
589
- if (!targetMapping) {
590
- diagnostics.push({
591
- code: "PSL_INVALID_RELATION_TARGET",
592
- message: `Relation field "${model.name}.${relationAttribute.field.name}" references unknown model "${relationAttribute.field.typeName}"`,
593
- sourceId,
594
- span: relationAttribute.field.span
595
- });
596
- continue;
597
- }
598
- const localColumns = mapFieldNamesToColumns({
599
- modelName: model.name,
600
- fieldNames: parsedRelation.fields,
601
- mapping,
602
- sourceId,
603
- diagnostics,
604
- span: relationAttribute.relation.span,
605
- contextLabel: `Relation field "${model.name}.${relationAttribute.field.name}"`
606
- });
607
- if (!localColumns) continue;
608
- const referencedColumns = mapFieldNamesToColumns({
609
- modelName: targetMapping.model.name,
610
- fieldNames: parsedRelation.references,
611
- mapping: targetMapping,
612
- sourceId,
613
- diagnostics,
614
- span: relationAttribute.relation.span,
615
- contextLabel: `Relation field "${model.name}.${relationAttribute.field.name}"`
616
- });
617
- if (!referencedColumns) continue;
618
- const onDelete = parsedRelation.onDelete ? normalizeReferentialAction({
619
- modelName: model.name,
620
- fieldName: relationAttribute.field.name,
621
- actionName: "onDelete",
622
- actionToken: parsedRelation.onDelete,
623
- sourceId,
624
- span: relationAttribute.field.span,
625
- diagnostics
626
- }) : void 0;
627
- const onUpdate = parsedRelation.onUpdate ? normalizeReferentialAction({
628
- modelName: model.name,
629
- fieldName: relationAttribute.field.name,
630
- actionName: "onUpdate",
631
- actionToken: parsedRelation.onUpdate,
632
- sourceId,
633
- span: relationAttribute.field.span,
634
- diagnostics
635
- }) : void 0;
636
- table = table.foreignKey(localColumns, {
637
- table: targetMapping.tableName,
638
- columns: referencedColumns
639
- }, {
640
- ...onDelete ? { onDelete } : {},
641
- ...onUpdate ? { onUpdate } : {}
642
- });
643
- }
644
- return table;
645
- });
646
- builder = builder.model(model.name, tableName, (modelBuilder) => {
647
- let next = modelBuilder;
648
- for (const resolvedField of resolvedFields) next = next.field(resolvedField.field.name, resolvedField.columnName);
649
- return next;
650
- });
651
- }
652
- if (diagnostics.length > 0) return notOk({
653
- summary: "PSL to SQL Contract IR normalization failed",
654
- diagnostics: diagnostics.filter((diagnostic, index, allDiagnostics) => allDiagnostics.findIndex((candidate) => candidate.code === diagnostic.code && candidate.message === diagnostic.message && candidate.sourceId === diagnostic.sourceId && (candidate.span && diagnostic.span && hasSameSpan(candidate.span, diagnostic.span) || !candidate.span && !diagnostic.span)) === index)
655
- });
656
- return ok(builder.build());
657
- }
658
-
659
- //#endregion
660
- export { interpretPslDocumentToSqlContractIR as t };
661
- //# sourceMappingURL=interpreter-_6-Xk1_m.mjs.map