@prisma-next/sql-contract-psl 0.3.0-dev.147 → 0.3.0-dev.163
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 +11 -11
- 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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { instantiateAuthoringTypeConstructor, isAuthoringTypeConstructorDescriptor } from "@prisma-next/framework-components/authoring";
|
|
1
|
+
import { instantiateAuthoringTypeConstructor, isAuthoringTypeConstructorDescriptor, validateAuthoringHelperArguments } from "@prisma-next/framework-components/authoring";
|
|
2
2
|
import { buildSqlContractFromDefinition } from "@prisma-next/sql-contract-ts/contract-builder";
|
|
3
3
|
import { ifDefined } from "@prisma-next/utils/defined";
|
|
4
4
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
@@ -324,6 +324,284 @@ function lowerDefaultFunctionWithRegistry(input) {
|
|
|
324
324
|
};
|
|
325
325
|
}
|
|
326
326
|
|
|
327
|
+
//#endregion
|
|
328
|
+
//#region src/psl-authoring-arguments.ts
|
|
329
|
+
const INVALID_AUTHORING_ARGUMENT = Symbol("invalidAuthoringArgument");
|
|
330
|
+
function isIdentifierStartCharacter(character) {
|
|
331
|
+
return character !== void 0 && /[A-Za-z_$]/.test(character);
|
|
332
|
+
}
|
|
333
|
+
function isIdentifierCharacter(character) {
|
|
334
|
+
return character !== void 0 && /[A-Za-z0-9_$]/.test(character);
|
|
335
|
+
}
|
|
336
|
+
function parseJsLikeLiteral(value) {
|
|
337
|
+
let index = 0;
|
|
338
|
+
function skipWhitespace() {
|
|
339
|
+
while (/\s/.test(value[index] ?? "")) index += 1;
|
|
340
|
+
}
|
|
341
|
+
function parseIdentifier() {
|
|
342
|
+
const first = value[index];
|
|
343
|
+
if (!isIdentifierStartCharacter(first)) return INVALID_AUTHORING_ARGUMENT;
|
|
344
|
+
let end = index + 1;
|
|
345
|
+
while (isIdentifierCharacter(value[end])) end += 1;
|
|
346
|
+
const identifier = value.slice(index, end);
|
|
347
|
+
index = end;
|
|
348
|
+
return identifier;
|
|
349
|
+
}
|
|
350
|
+
function parseString() {
|
|
351
|
+
const quote = value[index];
|
|
352
|
+
if (quote !== "\"" && quote !== "'") return INVALID_AUTHORING_ARGUMENT;
|
|
353
|
+
index += 1;
|
|
354
|
+
let result = "";
|
|
355
|
+
while (index < value.length) {
|
|
356
|
+
const character = value[index];
|
|
357
|
+
index += 1;
|
|
358
|
+
if (character === void 0) return INVALID_AUTHORING_ARGUMENT;
|
|
359
|
+
if (character === quote) return result;
|
|
360
|
+
if (character !== "\\") {
|
|
361
|
+
result += character;
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
const escaped = value[index];
|
|
365
|
+
index += 1;
|
|
366
|
+
if (escaped === void 0) return INVALID_AUTHORING_ARGUMENT;
|
|
367
|
+
switch (escaped) {
|
|
368
|
+
case "'":
|
|
369
|
+
case "\"":
|
|
370
|
+
case "\\":
|
|
371
|
+
case "/":
|
|
372
|
+
result += escaped;
|
|
373
|
+
break;
|
|
374
|
+
case "b":
|
|
375
|
+
result += "\b";
|
|
376
|
+
break;
|
|
377
|
+
case "f":
|
|
378
|
+
result += "\f";
|
|
379
|
+
break;
|
|
380
|
+
case "n":
|
|
381
|
+
result += "\n";
|
|
382
|
+
break;
|
|
383
|
+
case "r":
|
|
384
|
+
result += "\r";
|
|
385
|
+
break;
|
|
386
|
+
case "t":
|
|
387
|
+
result += " ";
|
|
388
|
+
break;
|
|
389
|
+
case "u": {
|
|
390
|
+
const hex = value.slice(index, index + 4);
|
|
391
|
+
if (!/^[0-9A-Fa-f]{4}$/.test(hex)) return INVALID_AUTHORING_ARGUMENT;
|
|
392
|
+
result += String.fromCharCode(Number.parseInt(hex, 16));
|
|
393
|
+
index += 4;
|
|
394
|
+
break;
|
|
395
|
+
}
|
|
396
|
+
default: return INVALID_AUTHORING_ARGUMENT;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
return INVALID_AUTHORING_ARGUMENT;
|
|
400
|
+
}
|
|
401
|
+
function parseNumber() {
|
|
402
|
+
const raw = value.slice(index).match(/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/)?.[0];
|
|
403
|
+
if (!raw) return INVALID_AUTHORING_ARGUMENT;
|
|
404
|
+
const parsed$1 = Number(raw);
|
|
405
|
+
if (!Number.isFinite(parsed$1)) return INVALID_AUTHORING_ARGUMENT;
|
|
406
|
+
index += raw.length;
|
|
407
|
+
return parsed$1;
|
|
408
|
+
}
|
|
409
|
+
function parseArray() {
|
|
410
|
+
if (value[index] !== "[") return INVALID_AUTHORING_ARGUMENT;
|
|
411
|
+
index += 1;
|
|
412
|
+
const result = [];
|
|
413
|
+
skipWhitespace();
|
|
414
|
+
if (value[index] === "]") {
|
|
415
|
+
index += 1;
|
|
416
|
+
return result;
|
|
417
|
+
}
|
|
418
|
+
while (index < value.length) {
|
|
419
|
+
const entry = parseValue();
|
|
420
|
+
if (entry === INVALID_AUTHORING_ARGUMENT) return INVALID_AUTHORING_ARGUMENT;
|
|
421
|
+
result.push(entry);
|
|
422
|
+
skipWhitespace();
|
|
423
|
+
if (value[index] === ",") {
|
|
424
|
+
index += 1;
|
|
425
|
+
skipWhitespace();
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
if (value[index] === "]") {
|
|
429
|
+
index += 1;
|
|
430
|
+
return result;
|
|
431
|
+
}
|
|
432
|
+
return INVALID_AUTHORING_ARGUMENT;
|
|
433
|
+
}
|
|
434
|
+
return INVALID_AUTHORING_ARGUMENT;
|
|
435
|
+
}
|
|
436
|
+
function parseObject() {
|
|
437
|
+
if (value[index] !== "{") return INVALID_AUTHORING_ARGUMENT;
|
|
438
|
+
index += 1;
|
|
439
|
+
const result = {};
|
|
440
|
+
skipWhitespace();
|
|
441
|
+
if (value[index] === "}") {
|
|
442
|
+
index += 1;
|
|
443
|
+
return result;
|
|
444
|
+
}
|
|
445
|
+
while (index < value.length) {
|
|
446
|
+
skipWhitespace();
|
|
447
|
+
const key = value[index] === "\"" || value[index] === "'" ? parseString() : parseIdentifier();
|
|
448
|
+
if (key === INVALID_AUTHORING_ARGUMENT) return INVALID_AUTHORING_ARGUMENT;
|
|
449
|
+
skipWhitespace();
|
|
450
|
+
if (value[index] !== ":") return INVALID_AUTHORING_ARGUMENT;
|
|
451
|
+
index += 1;
|
|
452
|
+
const entry = parseValue();
|
|
453
|
+
if (entry === INVALID_AUTHORING_ARGUMENT) return INVALID_AUTHORING_ARGUMENT;
|
|
454
|
+
result[key] = entry;
|
|
455
|
+
skipWhitespace();
|
|
456
|
+
if (value[index] === ",") {
|
|
457
|
+
index += 1;
|
|
458
|
+
skipWhitespace();
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
if (value[index] === "}") {
|
|
462
|
+
index += 1;
|
|
463
|
+
return result;
|
|
464
|
+
}
|
|
465
|
+
return INVALID_AUTHORING_ARGUMENT;
|
|
466
|
+
}
|
|
467
|
+
return INVALID_AUTHORING_ARGUMENT;
|
|
468
|
+
}
|
|
469
|
+
function parseValue() {
|
|
470
|
+
skipWhitespace();
|
|
471
|
+
const character = value[index];
|
|
472
|
+
if (character === "{") return parseObject();
|
|
473
|
+
if (character === "[") return parseArray();
|
|
474
|
+
if (character === "\"" || character === "'") return parseString();
|
|
475
|
+
if (character === "-" || /\d/.test(character ?? "")) return parseNumber();
|
|
476
|
+
const identifier = parseIdentifier();
|
|
477
|
+
if (identifier === INVALID_AUTHORING_ARGUMENT) return INVALID_AUTHORING_ARGUMENT;
|
|
478
|
+
if (identifier === "true") return true;
|
|
479
|
+
if (identifier === "false") return false;
|
|
480
|
+
if (identifier === "null") return null;
|
|
481
|
+
return INVALID_AUTHORING_ARGUMENT;
|
|
482
|
+
}
|
|
483
|
+
skipWhitespace();
|
|
484
|
+
const parsed = parseValue();
|
|
485
|
+
if (parsed === INVALID_AUTHORING_ARGUMENT) return parsed;
|
|
486
|
+
skipWhitespace();
|
|
487
|
+
return index === value.length ? parsed : INVALID_AUTHORING_ARGUMENT;
|
|
488
|
+
}
|
|
489
|
+
function parseStringArrayLiteral(value) {
|
|
490
|
+
const parsed = parseJsLikeLiteral(value);
|
|
491
|
+
if (parsed === INVALID_AUTHORING_ARGUMENT || !Array.isArray(parsed)) return INVALID_AUTHORING_ARGUMENT;
|
|
492
|
+
if (!parsed.every((item) => typeof item === "string")) return INVALID_AUTHORING_ARGUMENT;
|
|
493
|
+
return parsed;
|
|
494
|
+
}
|
|
495
|
+
function isPlainObject(value) {
|
|
496
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
497
|
+
}
|
|
498
|
+
function parsePslObjectLiteral(value) {
|
|
499
|
+
const trimmed = value.trim();
|
|
500
|
+
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) return INVALID_AUTHORING_ARGUMENT;
|
|
501
|
+
let parsed;
|
|
502
|
+
try {
|
|
503
|
+
parsed = JSON.parse(trimmed);
|
|
504
|
+
} catch {
|
|
505
|
+
parsed = parseJsLikeLiteral(trimmed);
|
|
506
|
+
if (parsed === INVALID_AUTHORING_ARGUMENT) return INVALID_AUTHORING_ARGUMENT;
|
|
507
|
+
}
|
|
508
|
+
if (!isPlainObject(parsed)) return INVALID_AUTHORING_ARGUMENT;
|
|
509
|
+
return parsed;
|
|
510
|
+
}
|
|
511
|
+
function parsePslAuthoringArgumentValue(descriptor, rawValue) {
|
|
512
|
+
switch (descriptor.kind) {
|
|
513
|
+
case "string": return unquoteStringLiteral(rawValue);
|
|
514
|
+
case "number": {
|
|
515
|
+
const parsed = Number(unquoteStringLiteral(rawValue));
|
|
516
|
+
return Number.isNaN(parsed) ? INVALID_AUTHORING_ARGUMENT : parsed;
|
|
517
|
+
}
|
|
518
|
+
case "stringArray": return parseStringArrayLiteral(rawValue);
|
|
519
|
+
case "object": return parsePslObjectLiteral(rawValue);
|
|
520
|
+
default: return INVALID_AUTHORING_ARGUMENT;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
function pushInvalidPslHelperArgument(input) {
|
|
524
|
+
input.diagnostics.push({
|
|
525
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
526
|
+
message: `${input.entityLabel} ${input.helperLabel} ${input.message}`,
|
|
527
|
+
sourceId: input.sourceId,
|
|
528
|
+
span: input.span
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
function mapPslHelperArgs(input) {
|
|
532
|
+
const mappedArgs = input.descriptors.map(() => void 0);
|
|
533
|
+
const positionalArgs = input.args.filter((arg) => arg.kind === "positional");
|
|
534
|
+
const namedArgs = input.args.filter((arg) => arg.kind === "named");
|
|
535
|
+
if (positionalArgs.length > input.descriptors.length) return pushInvalidPslHelperArgument({
|
|
536
|
+
diagnostics: input.diagnostics,
|
|
537
|
+
sourceId: input.sourceId,
|
|
538
|
+
span: input.span,
|
|
539
|
+
entityLabel: input.entityLabel,
|
|
540
|
+
helperLabel: input.helperLabel,
|
|
541
|
+
message: `accepts at most ${input.descriptors.length} argument(s), received ${positionalArgs.length}.`
|
|
542
|
+
});
|
|
543
|
+
for (const [index, argument] of positionalArgs.entries()) {
|
|
544
|
+
const descriptor = input.descriptors[index];
|
|
545
|
+
if (!descriptor) return pushInvalidPslHelperArgument({
|
|
546
|
+
diagnostics: input.diagnostics,
|
|
547
|
+
sourceId: input.sourceId,
|
|
548
|
+
span: argument.span,
|
|
549
|
+
entityLabel: input.entityLabel,
|
|
550
|
+
helperLabel: input.helperLabel,
|
|
551
|
+
message: `does not define positional argument #${index + 1}.`
|
|
552
|
+
});
|
|
553
|
+
const value = parsePslAuthoringArgumentValue(descriptor, argument.value);
|
|
554
|
+
if (value === INVALID_AUTHORING_ARGUMENT) return pushInvalidPslHelperArgument({
|
|
555
|
+
diagnostics: input.diagnostics,
|
|
556
|
+
sourceId: input.sourceId,
|
|
557
|
+
span: argument.span,
|
|
558
|
+
entityLabel: input.entityLabel,
|
|
559
|
+
helperLabel: input.helperLabel,
|
|
560
|
+
message: `cannot parse argument #${index + 1} for descriptor kind "${descriptor.kind}".`
|
|
561
|
+
});
|
|
562
|
+
mappedArgs[index] = value;
|
|
563
|
+
}
|
|
564
|
+
for (const argument of namedArgs) {
|
|
565
|
+
const descriptorIndex = input.descriptors.findIndex((descriptor$1) => descriptor$1.name === argument.name);
|
|
566
|
+
if (descriptorIndex < 0) return pushInvalidPslHelperArgument({
|
|
567
|
+
diagnostics: input.diagnostics,
|
|
568
|
+
sourceId: input.sourceId,
|
|
569
|
+
span: argument.span,
|
|
570
|
+
entityLabel: input.entityLabel,
|
|
571
|
+
helperLabel: input.helperLabel,
|
|
572
|
+
message: `received unknown named argument "${argument.name}".`
|
|
573
|
+
});
|
|
574
|
+
if (mappedArgs[descriptorIndex] !== void 0) return pushInvalidPslHelperArgument({
|
|
575
|
+
diagnostics: input.diagnostics,
|
|
576
|
+
sourceId: input.sourceId,
|
|
577
|
+
span: argument.span,
|
|
578
|
+
entityLabel: input.entityLabel,
|
|
579
|
+
helperLabel: input.helperLabel,
|
|
580
|
+
message: `received duplicate value for argument "${argument.name}".`
|
|
581
|
+
});
|
|
582
|
+
const descriptor = input.descriptors[descriptorIndex];
|
|
583
|
+
if (!descriptor) return pushInvalidPslHelperArgument({
|
|
584
|
+
diagnostics: input.diagnostics,
|
|
585
|
+
sourceId: input.sourceId,
|
|
586
|
+
span: argument.span,
|
|
587
|
+
entityLabel: input.entityLabel,
|
|
588
|
+
helperLabel: input.helperLabel,
|
|
589
|
+
message: `does not define named argument "${argument.name}".`
|
|
590
|
+
});
|
|
591
|
+
const value = parsePslAuthoringArgumentValue(descriptor, argument.value);
|
|
592
|
+
if (value === INVALID_AUTHORING_ARGUMENT) return pushInvalidPslHelperArgument({
|
|
593
|
+
diagnostics: input.diagnostics,
|
|
594
|
+
sourceId: input.sourceId,
|
|
595
|
+
span: argument.span,
|
|
596
|
+
entityLabel: input.entityLabel,
|
|
597
|
+
helperLabel: input.helperLabel,
|
|
598
|
+
message: `cannot parse named argument "${argument.name}" for descriptor kind "${descriptor.kind}".`
|
|
599
|
+
});
|
|
600
|
+
mappedArgs[descriptorIndex] = value;
|
|
601
|
+
}
|
|
602
|
+
return mappedArgs;
|
|
603
|
+
}
|
|
604
|
+
|
|
327
605
|
//#endregion
|
|
328
606
|
//#region src/psl-column-resolution.ts
|
|
329
607
|
function toNamedTypeFieldDescriptor(typeRef, descriptor) {
|
|
@@ -341,6 +619,147 @@ function getAuthoringTypeConstructor(contributions, path) {
|
|
|
341
619
|
}
|
|
342
620
|
return isAuthoringTypeConstructorDescriptor(current) ? current : void 0;
|
|
343
621
|
}
|
|
622
|
+
/**
|
|
623
|
+
* Returns the namespace prefix of `attributeName` if it references an
|
|
624
|
+
* unrecognized extension namespace, otherwise `undefined`. A namespace is
|
|
625
|
+
* considered recognized when it is:
|
|
626
|
+
*
|
|
627
|
+
* - `db` (native-type spec, always allowed),
|
|
628
|
+
* - the active family id (e.g. `sql`),
|
|
629
|
+
* - the active target id (e.g. `postgres`),
|
|
630
|
+
* - present in `composedExtensions`.
|
|
631
|
+
*
|
|
632
|
+
* Family/target namespaces are exempted so that e.g. `@sql.foo` surfaces as
|
|
633
|
+
* PSL_UNSUPPORTED_*_ATTRIBUTE (the attribute isn't defined) rather than
|
|
634
|
+
* PSL_EXTENSION_NAMESPACE_NOT_COMPOSED (the namespace is already composed).
|
|
635
|
+
*/
|
|
636
|
+
function checkUncomposedNamespace(attributeName, composedExtensions, context) {
|
|
637
|
+
const dotIndex = attributeName.indexOf(".");
|
|
638
|
+
if (dotIndex <= 0 || dotIndex === attributeName.length - 1) return;
|
|
639
|
+
const namespace = attributeName.slice(0, dotIndex);
|
|
640
|
+
if (namespace === "db" || namespace === context?.familyId || namespace === context?.targetId || composedExtensions.has(namespace)) return;
|
|
641
|
+
return namespace;
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Pushes the canonical `PSL_EXTENSION_NAMESPACE_NOT_COMPOSED` diagnostic for a
|
|
645
|
+
* subject (attribute, model attribute, or type constructor) that references an
|
|
646
|
+
* extension namespace which is not composed in the current contract.
|
|
647
|
+
*
|
|
648
|
+
* The `data` payload carries the missing namespace so machine consumers
|
|
649
|
+
* (agents, IDE extensions, CLI auto-fix) don't have to parse the prose.
|
|
650
|
+
*/
|
|
651
|
+
function reportUncomposedNamespace(input) {
|
|
652
|
+
input.diagnostics.push({
|
|
653
|
+
code: "PSL_EXTENSION_NAMESPACE_NOT_COMPOSED",
|
|
654
|
+
message: `${input.subjectLabel} uses unrecognized namespace "${input.namespace}". Add extension pack "${input.namespace}" to extensionPacks in prisma-next.config.ts.`,
|
|
655
|
+
sourceId: input.sourceId,
|
|
656
|
+
span: input.span,
|
|
657
|
+
data: {
|
|
658
|
+
namespace: input.namespace,
|
|
659
|
+
suggestedPack: input.namespace
|
|
660
|
+
}
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
function instantiatePslTypeConstructor(input) {
|
|
664
|
+
const helperPath = input.call.path.join(".");
|
|
665
|
+
const args = mapPslHelperArgs({
|
|
666
|
+
args: input.call.args,
|
|
667
|
+
descriptors: input.descriptor.args ?? [],
|
|
668
|
+
helperLabel: `constructor "${helperPath}"`,
|
|
669
|
+
span: input.call.span,
|
|
670
|
+
diagnostics: input.diagnostics,
|
|
671
|
+
sourceId: input.sourceId,
|
|
672
|
+
entityLabel: input.entityLabel
|
|
673
|
+
});
|
|
674
|
+
if (!args) return;
|
|
675
|
+
try {
|
|
676
|
+
validateAuthoringHelperArguments(helperPath, input.descriptor.args, args);
|
|
677
|
+
return instantiateAuthoringTypeConstructor(input.descriptor, args);
|
|
678
|
+
} catch (error) {
|
|
679
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
680
|
+
input.diagnostics.push({
|
|
681
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
682
|
+
message: `${input.entityLabel} constructor "${helperPath}" ${message}`,
|
|
683
|
+
sourceId: input.sourceId,
|
|
684
|
+
span: input.call.span
|
|
685
|
+
});
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
function pushUnsupportedTypeConstructorDiagnostic(input) {
|
|
690
|
+
input.diagnostics.push({
|
|
691
|
+
code: input.code,
|
|
692
|
+
message: input.message,
|
|
693
|
+
sourceId: input.sourceId,
|
|
694
|
+
span: input.span
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
function resolvePslTypeConstructorDescriptor(input) {
|
|
698
|
+
const descriptor = getAuthoringTypeConstructor(input.authoringContributions, input.call.path);
|
|
699
|
+
if (descriptor) return descriptor;
|
|
700
|
+
const namespace = input.call.path.length > 1 ? input.call.path[0] : void 0;
|
|
701
|
+
if (namespace && namespace !== "db" && namespace !== input.familyId && namespace !== input.targetId && !input.composedExtensions.has(namespace)) {
|
|
702
|
+
reportUncomposedNamespace({
|
|
703
|
+
subjectLabel: `Type constructor "${input.call.path.join(".")}"`,
|
|
704
|
+
namespace,
|
|
705
|
+
sourceId: input.sourceId,
|
|
706
|
+
span: input.call.span,
|
|
707
|
+
diagnostics: input.diagnostics
|
|
708
|
+
});
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
return pushUnsupportedTypeConstructorDiagnostic({
|
|
712
|
+
diagnostics: input.diagnostics,
|
|
713
|
+
sourceId: input.sourceId,
|
|
714
|
+
span: input.call.span,
|
|
715
|
+
code: input.unsupportedCode,
|
|
716
|
+
message: input.unsupportedMessage
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
function resolveFieldTypeDescriptor(input) {
|
|
720
|
+
if (input.field.typeConstructor) {
|
|
721
|
+
const helperPath = input.field.typeConstructor.path.join(".");
|
|
722
|
+
const descriptor$1 = resolvePslTypeConstructorDescriptor({
|
|
723
|
+
call: input.field.typeConstructor,
|
|
724
|
+
authoringContributions: input.authoringContributions,
|
|
725
|
+
composedExtensions: input.composedExtensions,
|
|
726
|
+
familyId: input.familyId,
|
|
727
|
+
targetId: input.targetId,
|
|
728
|
+
diagnostics: input.diagnostics,
|
|
729
|
+
sourceId: input.sourceId,
|
|
730
|
+
unsupportedCode: "PSL_UNSUPPORTED_FIELD_TYPE",
|
|
731
|
+
unsupportedMessage: `${input.entityLabel} type constructor "${helperPath}" is not supported in SQL PSL provider v1`
|
|
732
|
+
});
|
|
733
|
+
if (!descriptor$1) return {
|
|
734
|
+
ok: false,
|
|
735
|
+
alreadyReported: true
|
|
736
|
+
};
|
|
737
|
+
const instantiated = instantiatePslTypeConstructor({
|
|
738
|
+
call: input.field.typeConstructor,
|
|
739
|
+
descriptor: descriptor$1,
|
|
740
|
+
diagnostics: input.diagnostics,
|
|
741
|
+
sourceId: input.sourceId,
|
|
742
|
+
entityLabel: input.entityLabel
|
|
743
|
+
});
|
|
744
|
+
if (!instantiated) return {
|
|
745
|
+
ok: false,
|
|
746
|
+
alreadyReported: true
|
|
747
|
+
};
|
|
748
|
+
return {
|
|
749
|
+
ok: true,
|
|
750
|
+
descriptor: instantiated
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
const descriptor = resolveColumnDescriptor(input.field, input.enumTypeDescriptors, input.namedTypeDescriptors, input.scalarTypeDescriptors);
|
|
754
|
+
if (!descriptor) return {
|
|
755
|
+
ok: false,
|
|
756
|
+
alreadyReported: false
|
|
757
|
+
};
|
|
758
|
+
return {
|
|
759
|
+
ok: true,
|
|
760
|
+
descriptor
|
|
761
|
+
};
|
|
762
|
+
}
|
|
344
763
|
const NATIVE_TYPE_SPECS = {
|
|
345
764
|
"db.VarChar": {
|
|
346
765
|
args: "optionalLength",
|
|
@@ -492,32 +911,6 @@ function resolveDbNativeTypeAttribute(input) {
|
|
|
492
911
|
}
|
|
493
912
|
}
|
|
494
913
|
}
|
|
495
|
-
function parsePgvectorLength(input) {
|
|
496
|
-
const namedLength = getNamedArgument(input.attribute, "length");
|
|
497
|
-
const namedDim = getNamedArgument(input.attribute, "dim");
|
|
498
|
-
const positional = getPositionalArgument(input.attribute);
|
|
499
|
-
const raw = namedLength ?? namedDim ?? positional;
|
|
500
|
-
if (!raw) {
|
|
501
|
-
input.diagnostics.push({
|
|
502
|
-
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
503
|
-
message: "@pgvector.column requires length/dim argument",
|
|
504
|
-
sourceId: input.sourceId,
|
|
505
|
-
span: input.attribute.span
|
|
506
|
-
});
|
|
507
|
-
return;
|
|
508
|
-
}
|
|
509
|
-
const parsed = Number(unquoteStringLiteral(raw));
|
|
510
|
-
if (!Number.isInteger(parsed) || parsed < 1) {
|
|
511
|
-
input.diagnostics.push({
|
|
512
|
-
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
513
|
-
message: "@pgvector.column length/dim must be a positive integer",
|
|
514
|
-
sourceId: input.sourceId,
|
|
515
|
-
span: input.attribute.span
|
|
516
|
-
});
|
|
517
|
-
return;
|
|
518
|
-
}
|
|
519
|
-
return parsed;
|
|
520
|
-
}
|
|
521
914
|
function parseDefaultLiteralValue(expression) {
|
|
522
915
|
const trimmed = expression.trim();
|
|
523
916
|
if (trimmed === "true" || trimmed === "false") return {
|
|
@@ -612,49 +1005,99 @@ function resolveColumnDescriptor(field, enumTypeDescriptors, namedTypeDescriptor
|
|
|
612
1005
|
|
|
613
1006
|
//#endregion
|
|
614
1007
|
//#region src/psl-field-resolution.ts
|
|
615
|
-
|
|
1008
|
+
const BUILTIN_FIELD_ATTRIBUTE_NAMES = new Set([
|
|
1009
|
+
"id",
|
|
1010
|
+
"unique",
|
|
1011
|
+
"default",
|
|
1012
|
+
"relation",
|
|
1013
|
+
"map"
|
|
1014
|
+
]);
|
|
1015
|
+
function validateFieldAttributes(input) {
|
|
1016
|
+
for (const attribute of input.field.attributes) {
|
|
1017
|
+
if (BUILTIN_FIELD_ATTRIBUTE_NAMES.has(attribute.name)) continue;
|
|
1018
|
+
const uncomposedNamespace = checkUncomposedNamespace(attribute.name, input.composedExtensions, {
|
|
1019
|
+
familyId: input.familyId,
|
|
1020
|
+
targetId: input.targetId
|
|
1021
|
+
});
|
|
1022
|
+
if (uncomposedNamespace) {
|
|
1023
|
+
reportUncomposedNamespace({
|
|
1024
|
+
subjectLabel: `Attribute "@${attribute.name}"`,
|
|
1025
|
+
namespace: uncomposedNamespace,
|
|
1026
|
+
sourceId: input.sourceId,
|
|
1027
|
+
span: attribute.span,
|
|
1028
|
+
diagnostics: input.diagnostics
|
|
1029
|
+
});
|
|
1030
|
+
continue;
|
|
1031
|
+
}
|
|
1032
|
+
input.diagnostics.push({
|
|
1033
|
+
code: "PSL_UNSUPPORTED_FIELD_ATTRIBUTE",
|
|
1034
|
+
message: `Field "${input.model.name}.${input.field.name}" uses unsupported attribute "@${attribute.name}"`,
|
|
1035
|
+
sourceId: input.sourceId,
|
|
1036
|
+
span: attribute.span
|
|
1037
|
+
});
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
function extractFieldConstraintNames(input) {
|
|
1041
|
+
const idAttribute = getAttribute(input.field.attributes, "id");
|
|
1042
|
+
const uniqueAttribute = getAttribute(input.field.attributes, "unique");
|
|
1043
|
+
return {
|
|
1044
|
+
idAttribute,
|
|
1045
|
+
uniqueAttribute,
|
|
1046
|
+
idName: parseConstraintMapArgument({
|
|
1047
|
+
attribute: idAttribute,
|
|
1048
|
+
sourceId: input.sourceId,
|
|
1049
|
+
diagnostics: input.diagnostics,
|
|
1050
|
+
entityLabel: `Field "${input.model.name}.${input.field.name}" @id`,
|
|
1051
|
+
span: input.field.span,
|
|
1052
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT"
|
|
1053
|
+
}),
|
|
1054
|
+
uniqueName: parseConstraintMapArgument({
|
|
1055
|
+
attribute: uniqueAttribute,
|
|
1056
|
+
sourceId: input.sourceId,
|
|
1057
|
+
diagnostics: input.diagnostics,
|
|
1058
|
+
entityLabel: `Field "${input.model.name}.${input.field.name}" @unique`,
|
|
1059
|
+
span: input.field.span,
|
|
1060
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT"
|
|
1061
|
+
})
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
function collectResolvedFields(input) {
|
|
1065
|
+
const { model, mapping, enumTypeDescriptors, namedTypeDescriptors, modelNames, compositeTypeNames, composedExtensions, authoringContributions, familyId, targetId, defaultFunctionRegistry, generatorDescriptorById, diagnostics, sourceId, scalarTypeDescriptors } = input;
|
|
616
1066
|
const resolvedFields = [];
|
|
617
|
-
const pgvectorVectorConstructor = getAuthoringTypeConstructor(authoringContributions, ["pgvector", "vector"]);
|
|
618
1067
|
for (const field of model.fields) {
|
|
619
1068
|
if (field.list && modelNames.has(field.typeName)) continue;
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
continue;
|
|
630
|
-
}
|
|
631
|
-
diagnostics.push({
|
|
632
|
-
code: "PSL_UNSUPPORTED_FIELD_ATTRIBUTE",
|
|
633
|
-
message: `Field "${model.name}.${field.name}" uses unsupported attribute "@${attribute.name}"`,
|
|
634
|
-
sourceId,
|
|
635
|
-
span: attribute.span
|
|
636
|
-
});
|
|
637
|
-
}
|
|
1069
|
+
validateFieldAttributes({
|
|
1070
|
+
model,
|
|
1071
|
+
field,
|
|
1072
|
+
composedExtensions,
|
|
1073
|
+
diagnostics,
|
|
1074
|
+
sourceId,
|
|
1075
|
+
familyId,
|
|
1076
|
+
targetId
|
|
1077
|
+
});
|
|
638
1078
|
if (getAttribute(field.attributes, "relation") && modelNames.has(field.typeName)) continue;
|
|
639
1079
|
const isValueObjectField = compositeTypeNames.has(field.typeName);
|
|
640
1080
|
const isListField = field.list;
|
|
641
|
-
const pgvectorOnJsonField = getAttribute(field.attributes, "pgvector.column");
|
|
642
|
-
if (pgvectorOnJsonField && (isValueObjectField || isListField)) {
|
|
643
|
-
diagnostics.push({
|
|
644
|
-
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
645
|
-
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.`,
|
|
646
|
-
sourceId,
|
|
647
|
-
span: pgvectorOnJsonField.span
|
|
648
|
-
});
|
|
649
|
-
continue;
|
|
650
|
-
}
|
|
651
1081
|
let descriptor;
|
|
652
1082
|
let scalarCodecId;
|
|
1083
|
+
const resolveInput = {
|
|
1084
|
+
field,
|
|
1085
|
+
enumTypeDescriptors,
|
|
1086
|
+
namedTypeDescriptors,
|
|
1087
|
+
scalarTypeDescriptors,
|
|
1088
|
+
authoringContributions,
|
|
1089
|
+
composedExtensions,
|
|
1090
|
+
familyId,
|
|
1091
|
+
targetId,
|
|
1092
|
+
diagnostics,
|
|
1093
|
+
sourceId,
|
|
1094
|
+
entityLabel: `Field "${model.name}.${field.name}"`
|
|
1095
|
+
};
|
|
653
1096
|
if (isValueObjectField) descriptor = scalarTypeDescriptors.get("Json");
|
|
654
1097
|
else if (isListField) {
|
|
655
|
-
const
|
|
656
|
-
if (!
|
|
657
|
-
diagnostics.push({
|
|
1098
|
+
const resolved = resolveFieldTypeDescriptor(resolveInput);
|
|
1099
|
+
if (!resolved.ok) {
|
|
1100
|
+
if (!resolved.alreadyReported) diagnostics.push({
|
|
658
1101
|
code: "PSL_UNSUPPORTED_FIELD_TYPE",
|
|
659
1102
|
message: `Field "${model.name}.${field.name}" type "${field.typeName}" is not supported in SQL PSL provider v1`,
|
|
660
1103
|
sourceId,
|
|
@@ -662,45 +1105,22 @@ function collectResolvedFields(model, mapping, enumTypeDescriptors, namedTypeDes
|
|
|
662
1105
|
});
|
|
663
1106
|
continue;
|
|
664
1107
|
}
|
|
665
|
-
scalarCodecId =
|
|
1108
|
+
scalarCodecId = resolved.descriptor.codecId;
|
|
666
1109
|
descriptor = scalarTypeDescriptors.get("Json");
|
|
667
1110
|
} else {
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
});
|
|
676
|
-
else if (!(field.typeName === "Bytes" || namedTypeBaseTypes.get(field.typeRef ?? field.typeName) === "Bytes")) diagnostics.push({
|
|
677
|
-
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
678
|
-
message: `Field "${model.name}.${field.name}" uses @pgvector.column on unsupported base type "${field.typeName}"`,
|
|
679
|
-
sourceId,
|
|
680
|
-
span: pgvectorColumnAttribute.span
|
|
681
|
-
});
|
|
682
|
-
else {
|
|
683
|
-
const length = parsePgvectorLength({
|
|
684
|
-
attribute: pgvectorColumnAttribute,
|
|
685
|
-
diagnostics,
|
|
686
|
-
sourceId
|
|
1111
|
+
const resolved = resolveFieldTypeDescriptor(resolveInput);
|
|
1112
|
+
if (!resolved.ok) {
|
|
1113
|
+
if (!resolved.alreadyReported) diagnostics.push({
|
|
1114
|
+
code: "PSL_UNSUPPORTED_FIELD_TYPE",
|
|
1115
|
+
message: `Field "${model.name}.${field.name}" type "${field.typeName}" is not supported in SQL PSL provider v1`,
|
|
1116
|
+
sourceId,
|
|
1117
|
+
span: field.span
|
|
687
1118
|
});
|
|
688
|
-
|
|
689
|
-
codecId: "pg/vector@1",
|
|
690
|
-
nativeType: "vector",
|
|
691
|
-
typeParams: { length }
|
|
692
|
-
};
|
|
1119
|
+
continue;
|
|
693
1120
|
}
|
|
1121
|
+
descriptor = resolved.descriptor;
|
|
694
1122
|
}
|
|
695
|
-
if (!descriptor)
|
|
696
|
-
diagnostics.push({
|
|
697
|
-
code: "PSL_UNSUPPORTED_FIELD_TYPE",
|
|
698
|
-
message: `Field "${model.name}.${field.name}" type "${field.typeName}" is not supported in SQL PSL provider v1`,
|
|
699
|
-
sourceId,
|
|
700
|
-
span: field.span
|
|
701
|
-
});
|
|
702
|
-
continue;
|
|
703
|
-
}
|
|
1123
|
+
if (!descriptor) continue;
|
|
704
1124
|
const defaultAttribute = getAttribute(field.attributes, "default");
|
|
705
1125
|
const loweredDefault = defaultAttribute ? lowerDefaultForField({
|
|
706
1126
|
modelName: model.name,
|
|
@@ -727,23 +1147,11 @@ function collectResolvedFields(model, mapping, enumTypeDescriptors, namedTypeDes
|
|
|
727
1147
|
if (generatedDescriptor) descriptor = generatedDescriptor;
|
|
728
1148
|
}
|
|
729
1149
|
const mappedColumnName = mapping.fieldColumns.get(field.name) ?? field.name;
|
|
730
|
-
const idAttribute =
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
attribute: idAttribute,
|
|
734
|
-
sourceId,
|
|
735
|
-
diagnostics,
|
|
736
|
-
entityLabel: `Field "${model.name}.${field.name}" @id`,
|
|
737
|
-
span: field.span,
|
|
738
|
-
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT"
|
|
739
|
-
});
|
|
740
|
-
const uniqueName = parseConstraintMapArgument({
|
|
741
|
-
attribute: uniqueAttribute,
|
|
1150
|
+
const { idAttribute, uniqueAttribute, idName, uniqueName } = extractFieldConstraintNames({
|
|
1151
|
+
model,
|
|
1152
|
+
field,
|
|
742
1153
|
sourceId,
|
|
743
|
-
diagnostics
|
|
744
|
-
entityLabel: `Field "${model.name}.${field.name}" @unique`,
|
|
745
|
-
span: field.span,
|
|
746
|
-
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT"
|
|
1154
|
+
diagnostics
|
|
747
1155
|
});
|
|
748
1156
|
resolvedFields.push({
|
|
749
1157
|
field,
|
|
@@ -1008,12 +1416,17 @@ function validateNavigationListFieldAttributes(input) {
|
|
|
1008
1416
|
let valid = true;
|
|
1009
1417
|
for (const attribute of input.field.attributes) {
|
|
1010
1418
|
if (attribute.name === "relation") continue;
|
|
1011
|
-
|
|
1012
|
-
input.
|
|
1013
|
-
|
|
1014
|
-
|
|
1419
|
+
const uncomposedNamespace = checkUncomposedNamespace(attribute.name, input.composedExtensions, {
|
|
1420
|
+
familyId: input.familyId,
|
|
1421
|
+
targetId: input.targetId
|
|
1422
|
+
});
|
|
1423
|
+
if (uncomposedNamespace) {
|
|
1424
|
+
reportUncomposedNamespace({
|
|
1425
|
+
subjectLabel: `Attribute "@${attribute.name}"`,
|
|
1426
|
+
namespace: uncomposedNamespace,
|
|
1015
1427
|
sourceId: input.sourceId,
|
|
1016
|
-
span: attribute.span
|
|
1428
|
+
span: attribute.span,
|
|
1429
|
+
diagnostics: input.diagnostics
|
|
1017
1430
|
});
|
|
1018
1431
|
valid = false;
|
|
1019
1432
|
continue;
|
|
@@ -1042,8 +1455,18 @@ function buildComposedExtensionPackRefs(target, extensionIds, extensionPackRefs
|
|
|
1042
1455
|
version: "0.0.1"
|
|
1043
1456
|
}]));
|
|
1044
1457
|
}
|
|
1045
|
-
function
|
|
1046
|
-
|
|
1458
|
+
function diagnosticDedupKey(diagnostic) {
|
|
1459
|
+
const span = diagnostic.span;
|
|
1460
|
+
const spanKey = span ? `${span.start.offset}:${span.end.offset}:${span.start.line}:${span.end.line}` : "";
|
|
1461
|
+
return `${diagnostic.code}\u0000${diagnostic.sourceId}\u0000${spanKey}\u0000${diagnostic.message}`;
|
|
1462
|
+
}
|
|
1463
|
+
function dedupeDiagnostics(diagnostics) {
|
|
1464
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1465
|
+
for (const diagnostic of diagnostics) {
|
|
1466
|
+
const key = diagnosticDedupKey(diagnostic);
|
|
1467
|
+
if (!seen.has(key)) seen.set(key, diagnostic);
|
|
1468
|
+
}
|
|
1469
|
+
return [...seen.values()];
|
|
1047
1470
|
}
|
|
1048
1471
|
function compareStrings(left, right) {
|
|
1049
1472
|
if (left < right) return -1;
|
|
@@ -1092,85 +1515,126 @@ function processEnumDeclarations(input) {
|
|
|
1092
1515
|
enumTypeDescriptors
|
|
1093
1516
|
};
|
|
1094
1517
|
}
|
|
1518
|
+
function validateNamedTypeAttributes(input) {
|
|
1519
|
+
const [dbNativeTypeAttribute, ...extraDbNativeTypeAttributes] = input.allowDbNativeType ? input.declaration.attributes.filter((attribute) => attribute.name.startsWith("db.")) : [];
|
|
1520
|
+
let hasUnsupportedNamedTypeAttribute = false;
|
|
1521
|
+
for (const extra of extraDbNativeTypeAttributes) {
|
|
1522
|
+
input.diagnostics.push({
|
|
1523
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
1524
|
+
message: `Named type "${input.declaration.name}" can declare at most one @db.* attribute`,
|
|
1525
|
+
sourceId: input.sourceId,
|
|
1526
|
+
span: extra.span
|
|
1527
|
+
});
|
|
1528
|
+
hasUnsupportedNamedTypeAttribute = true;
|
|
1529
|
+
}
|
|
1530
|
+
for (const attribute of input.declaration.attributes) {
|
|
1531
|
+
if (input.allowDbNativeType && attribute.name.startsWith("db.")) continue;
|
|
1532
|
+
const uncomposedNamespace = checkUncomposedNamespace(attribute.name, input.composedExtensions, {
|
|
1533
|
+
familyId: input.familyId,
|
|
1534
|
+
targetId: input.targetId
|
|
1535
|
+
});
|
|
1536
|
+
if (uncomposedNamespace) {
|
|
1537
|
+
reportUncomposedNamespace({
|
|
1538
|
+
subjectLabel: `Attribute "@${attribute.name}"`,
|
|
1539
|
+
namespace: uncomposedNamespace,
|
|
1540
|
+
sourceId: input.sourceId,
|
|
1541
|
+
span: attribute.span,
|
|
1542
|
+
diagnostics: input.diagnostics
|
|
1543
|
+
});
|
|
1544
|
+
hasUnsupportedNamedTypeAttribute = true;
|
|
1545
|
+
continue;
|
|
1546
|
+
}
|
|
1547
|
+
input.diagnostics.push({
|
|
1548
|
+
code: "PSL_UNSUPPORTED_NAMED_TYPE_ATTRIBUTE",
|
|
1549
|
+
message: `Named type "${input.declaration.name}" uses unsupported attribute "${attribute.name}"`,
|
|
1550
|
+
sourceId: input.sourceId,
|
|
1551
|
+
span: attribute.span
|
|
1552
|
+
});
|
|
1553
|
+
hasUnsupportedNamedTypeAttribute = true;
|
|
1554
|
+
}
|
|
1555
|
+
return {
|
|
1556
|
+
dbNativeTypeAttribute,
|
|
1557
|
+
hasUnsupportedNamedTypeAttribute
|
|
1558
|
+
};
|
|
1559
|
+
}
|
|
1095
1560
|
function resolveNamedTypeDeclarations(input) {
|
|
1096
1561
|
const storageTypes = {};
|
|
1097
1562
|
const namedTypeDescriptors = /* @__PURE__ */ new Map();
|
|
1098
|
-
const namedTypeBaseTypes = /* @__PURE__ */ new Map();
|
|
1099
1563
|
for (const declaration of input.declarations) {
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
code: "PSL_UNSUPPORTED_NAMED_TYPE_BASE",
|
|
1104
|
-
message: `Named type "${declaration.name}" references unsupported base type "${declaration.baseType}"`,
|
|
1564
|
+
if (declaration.typeConstructor) {
|
|
1565
|
+
const { hasUnsupportedNamedTypeAttribute: hasUnsupportedNamedTypeAttribute$1 } = validateNamedTypeAttributes({
|
|
1566
|
+
declaration,
|
|
1105
1567
|
sourceId: input.sourceId,
|
|
1106
|
-
|
|
1568
|
+
diagnostics: input.diagnostics,
|
|
1569
|
+
composedExtensions: input.composedExtensions,
|
|
1570
|
+
allowDbNativeType: false,
|
|
1571
|
+
familyId: input.familyId,
|
|
1572
|
+
targetId: input.targetId
|
|
1107
1573
|
});
|
|
1108
|
-
continue;
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1574
|
+
if (hasUnsupportedNamedTypeAttribute$1) continue;
|
|
1575
|
+
const helperPath = declaration.typeConstructor.path.join(".");
|
|
1576
|
+
const typeConstructor = resolvePslTypeConstructorDescriptor({
|
|
1577
|
+
call: declaration.typeConstructor,
|
|
1578
|
+
authoringContributions: input.authoringContributions,
|
|
1579
|
+
composedExtensions: input.composedExtensions,
|
|
1580
|
+
familyId: input.familyId,
|
|
1581
|
+
targetId: input.targetId,
|
|
1582
|
+
diagnostics: input.diagnostics,
|
|
1583
|
+
sourceId: input.sourceId,
|
|
1584
|
+
unsupportedCode: "PSL_UNSUPPORTED_NAMED_TYPE_CONSTRUCTOR",
|
|
1585
|
+
unsupportedMessage: `Named type "${declaration.name}" references unsupported constructor "${helperPath}"`
|
|
1586
|
+
});
|
|
1587
|
+
if (!typeConstructor) continue;
|
|
1588
|
+
const storageType = instantiatePslTypeConstructor({
|
|
1589
|
+
call: declaration.typeConstructor,
|
|
1590
|
+
descriptor: typeConstructor,
|
|
1591
|
+
diagnostics: input.diagnostics,
|
|
1118
1592
|
sourceId: input.sourceId,
|
|
1119
|
-
|
|
1593
|
+
entityLabel: `Named type "${declaration.name}"`
|
|
1120
1594
|
});
|
|
1595
|
+
if (!storageType) continue;
|
|
1596
|
+
namedTypeDescriptors.set(declaration.name, toNamedTypeFieldDescriptor(declaration.name, storageType));
|
|
1597
|
+
storageTypes[declaration.name] = {
|
|
1598
|
+
codecId: storageType.codecId,
|
|
1599
|
+
nativeType: storageType.nativeType,
|
|
1600
|
+
typeParams: storageType.typeParams ?? {}
|
|
1601
|
+
};
|
|
1121
1602
|
continue;
|
|
1122
1603
|
}
|
|
1123
|
-
if (
|
|
1604
|
+
if (declaration.baseType === void 0) {
|
|
1124
1605
|
input.diagnostics.push({
|
|
1125
|
-
code: "
|
|
1126
|
-
message: `Named type "${declaration.name}"
|
|
1606
|
+
code: "PSL_UNSUPPORTED_NAMED_TYPE_BASE",
|
|
1607
|
+
message: `Named type "${declaration.name}" must declare a base type or constructor`,
|
|
1127
1608
|
sourceId: input.sourceId,
|
|
1128
|
-
span:
|
|
1609
|
+
span: declaration.span
|
|
1129
1610
|
});
|
|
1130
1611
|
continue;
|
|
1131
1612
|
}
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
continue;
|
|
1141
|
-
}
|
|
1142
|
-
if (declaration.baseType !== "Bytes") {
|
|
1143
|
-
input.diagnostics.push({
|
|
1144
|
-
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
1145
|
-
message: `Named type "${declaration.name}" uses @pgvector.column on unsupported base type "${declaration.baseType}"`,
|
|
1146
|
-
sourceId: input.sourceId,
|
|
1147
|
-
span: pgvectorAttribute.span
|
|
1148
|
-
});
|
|
1149
|
-
continue;
|
|
1150
|
-
}
|
|
1151
|
-
const length = parsePgvectorLength({
|
|
1152
|
-
attribute: pgvectorAttribute,
|
|
1153
|
-
diagnostics: input.diagnostics,
|
|
1154
|
-
sourceId: input.sourceId
|
|
1613
|
+
const { baseType } = declaration;
|
|
1614
|
+
const baseDescriptor = input.enumTypeDescriptors.get(baseType) ?? input.scalarTypeDescriptors.get(baseType);
|
|
1615
|
+
if (!baseDescriptor) {
|
|
1616
|
+
input.diagnostics.push({
|
|
1617
|
+
code: "PSL_UNSUPPORTED_NAMED_TYPE_BASE",
|
|
1618
|
+
message: `Named type "${declaration.name}" references unsupported base type "${baseType}"`,
|
|
1619
|
+
sourceId: input.sourceId,
|
|
1620
|
+
span: declaration.span
|
|
1155
1621
|
});
|
|
1156
|
-
if (length === void 0) continue;
|
|
1157
|
-
const pgvectorStorageType = input.pgvectorVectorConstructor ? instantiateAuthoringTypeConstructor(input.pgvectorVectorConstructor, [length]) : {
|
|
1158
|
-
codecId: "pg/vector@1",
|
|
1159
|
-
nativeType: "vector",
|
|
1160
|
-
typeParams: { length }
|
|
1161
|
-
};
|
|
1162
|
-
namedTypeDescriptors.set(declaration.name, toNamedTypeFieldDescriptor(declaration.name, pgvectorStorageType));
|
|
1163
|
-
storageTypes[declaration.name] = {
|
|
1164
|
-
codecId: pgvectorStorageType.codecId,
|
|
1165
|
-
nativeType: pgvectorStorageType.nativeType,
|
|
1166
|
-
typeParams: pgvectorStorageType.typeParams ?? { length }
|
|
1167
|
-
};
|
|
1168
1622
|
continue;
|
|
1169
1623
|
}
|
|
1624
|
+
const { dbNativeTypeAttribute, hasUnsupportedNamedTypeAttribute } = validateNamedTypeAttributes({
|
|
1625
|
+
declaration,
|
|
1626
|
+
sourceId: input.sourceId,
|
|
1627
|
+
diagnostics: input.diagnostics,
|
|
1628
|
+
composedExtensions: input.composedExtensions,
|
|
1629
|
+
allowDbNativeType: true,
|
|
1630
|
+
familyId: input.familyId,
|
|
1631
|
+
targetId: input.targetId
|
|
1632
|
+
});
|
|
1633
|
+
if (hasUnsupportedNamedTypeAttribute) continue;
|
|
1170
1634
|
if (dbNativeTypeAttribute) {
|
|
1171
1635
|
const descriptor$1 = resolveDbNativeTypeAttribute({
|
|
1172
1636
|
attribute: dbNativeTypeAttribute,
|
|
1173
|
-
baseType
|
|
1637
|
+
baseType,
|
|
1174
1638
|
baseDescriptor,
|
|
1175
1639
|
diagnostics: input.diagnostics,
|
|
1176
1640
|
sourceId: input.sourceId,
|
|
@@ -1195,14 +1659,29 @@ function resolveNamedTypeDeclarations(input) {
|
|
|
1195
1659
|
}
|
|
1196
1660
|
return {
|
|
1197
1661
|
storageTypes,
|
|
1198
|
-
namedTypeDescriptors
|
|
1199
|
-
namedTypeBaseTypes
|
|
1662
|
+
namedTypeDescriptors
|
|
1200
1663
|
};
|
|
1201
1664
|
}
|
|
1202
1665
|
function buildModelNodeFromPsl(input) {
|
|
1203
1666
|
const { model, mapping, sourceId, diagnostics } = input;
|
|
1204
1667
|
const tableName = mapping.tableName;
|
|
1205
|
-
const resolvedFields = collectResolvedFields(
|
|
1668
|
+
const resolvedFields = collectResolvedFields({
|
|
1669
|
+
model,
|
|
1670
|
+
mapping,
|
|
1671
|
+
enumTypeDescriptors: input.enumTypeDescriptors,
|
|
1672
|
+
namedTypeDescriptors: input.namedTypeDescriptors,
|
|
1673
|
+
modelNames: input.modelNames,
|
|
1674
|
+
compositeTypeNames: input.compositeTypeNames,
|
|
1675
|
+
composedExtensions: input.composedExtensions,
|
|
1676
|
+
authoringContributions: input.authoringContributions,
|
|
1677
|
+
familyId: input.familyId,
|
|
1678
|
+
targetId: input.targetId,
|
|
1679
|
+
defaultFunctionRegistry: input.defaultFunctionRegistry,
|
|
1680
|
+
generatorDescriptorById: input.generatorDescriptorById,
|
|
1681
|
+
diagnostics,
|
|
1682
|
+
sourceId,
|
|
1683
|
+
scalarTypeDescriptors: input.scalarTypeDescriptors
|
|
1684
|
+
});
|
|
1206
1685
|
const primaryKeyFields = resolvedFields.filter((field) => field.isId);
|
|
1207
1686
|
const primaryKeyColumns = primaryKeyFields.map((field) => field.columnName);
|
|
1208
1687
|
const primaryKeyName = primaryKeyFields.length === 1 ? primaryKeyFields[0]?.idName : void 0;
|
|
@@ -1221,7 +1700,9 @@ function buildModelNodeFromPsl(input) {
|
|
|
1221
1700
|
field,
|
|
1222
1701
|
sourceId,
|
|
1223
1702
|
composedExtensions: input.composedExtensions,
|
|
1224
|
-
diagnostics
|
|
1703
|
+
diagnostics,
|
|
1704
|
+
familyId: input.familyId,
|
|
1705
|
+
targetId: input.targetId
|
|
1225
1706
|
});
|
|
1226
1707
|
const relationAttribute = getAttribute(field.attributes, "relation");
|
|
1227
1708
|
let relationName;
|
|
@@ -1313,12 +1794,17 @@ function buildModelNodeFromPsl(input) {
|
|
|
1313
1794
|
});
|
|
1314
1795
|
continue;
|
|
1315
1796
|
}
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1797
|
+
const uncomposedNamespace = checkUncomposedNamespace(modelAttribute.name, input.composedExtensions, {
|
|
1798
|
+
familyId: input.familyId,
|
|
1799
|
+
targetId: input.targetId
|
|
1800
|
+
});
|
|
1801
|
+
if (uncomposedNamespace) {
|
|
1802
|
+
reportUncomposedNamespace({
|
|
1803
|
+
subjectLabel: `Attribute "@@${modelAttribute.name}"`,
|
|
1804
|
+
namespace: uncomposedNamespace,
|
|
1320
1805
|
sourceId,
|
|
1321
|
-
span: modelAttribute.span
|
|
1806
|
+
span: modelAttribute.span,
|
|
1807
|
+
diagnostics
|
|
1322
1808
|
});
|
|
1323
1809
|
continue;
|
|
1324
1810
|
}
|
|
@@ -1462,7 +1948,8 @@ function buildModelNodeFromPsl(input) {
|
|
|
1462
1948
|
resolvedFields
|
|
1463
1949
|
};
|
|
1464
1950
|
}
|
|
1465
|
-
function buildValueObjects(
|
|
1951
|
+
function buildValueObjects(input) {
|
|
1952
|
+
const { compositeTypes, enumTypeDescriptors, namedTypeDescriptors, scalarTypeDescriptors, composedExtensions, familyId, targetId, authoringContributions, diagnostics, sourceId } = input;
|
|
1466
1953
|
const valueObjects = {};
|
|
1467
1954
|
const compositeTypeNames = new Set(compositeTypes.map((ct) => ct.name));
|
|
1468
1955
|
for (const compositeType of compositeTypes) {
|
|
@@ -1482,9 +1969,21 @@ function buildValueObjects(compositeTypes, enumTypeDescriptors, namedTypeDescrip
|
|
|
1482
1969
|
} : result;
|
|
1483
1970
|
continue;
|
|
1484
1971
|
}
|
|
1485
|
-
const
|
|
1486
|
-
|
|
1487
|
-
|
|
1972
|
+
const resolved = resolveFieldTypeDescriptor({
|
|
1973
|
+
field,
|
|
1974
|
+
enumTypeDescriptors,
|
|
1975
|
+
namedTypeDescriptors,
|
|
1976
|
+
scalarTypeDescriptors,
|
|
1977
|
+
authoringContributions,
|
|
1978
|
+
composedExtensions,
|
|
1979
|
+
familyId,
|
|
1980
|
+
targetId,
|
|
1981
|
+
diagnostics,
|
|
1982
|
+
sourceId,
|
|
1983
|
+
entityLabel: `Field "${compositeType.name}.${field.name}"`
|
|
1984
|
+
});
|
|
1985
|
+
if (!resolved.ok) {
|
|
1986
|
+
if (!resolved.alreadyReported) diagnostics.push({
|
|
1488
1987
|
code: "PSL_UNSUPPORTED_FIELD_TYPE",
|
|
1489
1988
|
message: `Field "${compositeType.name}.${field.name}" type "${field.typeName}" is not supported`,
|
|
1490
1989
|
sourceId,
|
|
@@ -1492,13 +1991,17 @@ function buildValueObjects(compositeTypes, enumTypeDescriptors, namedTypeDescrip
|
|
|
1492
1991
|
});
|
|
1493
1992
|
continue;
|
|
1494
1993
|
}
|
|
1495
|
-
|
|
1994
|
+
const scalarField = {
|
|
1496
1995
|
nullable: field.optional,
|
|
1497
1996
|
type: {
|
|
1498
1997
|
kind: "scalar",
|
|
1499
|
-
codecId: descriptor.codecId
|
|
1998
|
+
codecId: resolved.descriptor.codecId
|
|
1500
1999
|
}
|
|
1501
2000
|
};
|
|
2001
|
+
fields[field.name] = field.list ? {
|
|
2002
|
+
...scalarField,
|
|
2003
|
+
many: true
|
|
2004
|
+
} : scalarField;
|
|
1502
2005
|
}
|
|
1503
2006
|
valueObjects[compositeType.name] = { fields };
|
|
1504
2007
|
}
|
|
@@ -1744,7 +2247,9 @@ function interpretPslDocumentToSqlContract(input) {
|
|
|
1744
2247
|
enumTypeDescriptors: enumResult.enumTypeDescriptors,
|
|
1745
2248
|
scalarTypeDescriptors: input.scalarTypeDescriptors,
|
|
1746
2249
|
composedExtensions,
|
|
1747
|
-
|
|
2250
|
+
familyId: input.target.familyId,
|
|
2251
|
+
targetId: input.target.targetId,
|
|
2252
|
+
authoringContributions: input.authoringContributions,
|
|
1748
2253
|
diagnostics
|
|
1749
2254
|
});
|
|
1750
2255
|
const storageTypes = {
|
|
@@ -1767,8 +2272,9 @@ function interpretPslDocumentToSqlContract(input) {
|
|
|
1767
2272
|
compositeTypeNames,
|
|
1768
2273
|
enumTypeDescriptors: enumResult.enumTypeDescriptors,
|
|
1769
2274
|
namedTypeDescriptors: namedTypeResult.namedTypeDescriptors,
|
|
1770
|
-
namedTypeBaseTypes: namedTypeResult.namedTypeBaseTypes,
|
|
1771
2275
|
composedExtensions,
|
|
2276
|
+
familyId: input.target.familyId,
|
|
2277
|
+
targetId: input.target.targetId,
|
|
1772
2278
|
authoringContributions: input.authoringContributions,
|
|
1773
2279
|
defaultFunctionRegistry,
|
|
1774
2280
|
generatorDescriptorById,
|
|
@@ -1790,9 +2296,21 @@ function interpretPslDocumentToSqlContract(input) {
|
|
|
1790
2296
|
sourceId
|
|
1791
2297
|
});
|
|
1792
2298
|
const { discriminatorDeclarations, baseDeclarations } = collectPolymorphismDeclarations(models, sourceId, diagnostics);
|
|
2299
|
+
const valueObjects = buildValueObjects({
|
|
2300
|
+
compositeTypes,
|
|
2301
|
+
enumTypeDescriptors: enumResult.enumTypeDescriptors,
|
|
2302
|
+
namedTypeDescriptors: namedTypeResult.namedTypeDescriptors,
|
|
2303
|
+
scalarTypeDescriptors: input.scalarTypeDescriptors,
|
|
2304
|
+
composedExtensions,
|
|
2305
|
+
familyId: input.target.familyId,
|
|
2306
|
+
targetId: input.target.targetId,
|
|
2307
|
+
authoringContributions: input.authoringContributions,
|
|
2308
|
+
diagnostics,
|
|
2309
|
+
sourceId
|
|
2310
|
+
});
|
|
1793
2311
|
if (diagnostics.length > 0) return notOk({
|
|
1794
2312
|
summary: "PSL to SQL contract interpretation failed",
|
|
1795
|
-
diagnostics: diagnostics
|
|
2313
|
+
diagnostics: dedupeDiagnostics(diagnostics)
|
|
1796
2314
|
});
|
|
1797
2315
|
const contract = buildSqlContractFromDefinition({
|
|
1798
2316
|
target: input.target,
|
|
@@ -1803,7 +2321,6 @@ function interpretPslDocumentToSqlContract(input) {
|
|
|
1803
2321
|
...modelRelations.has(model.modelName) ? { relations: [...modelRelations.get(model.modelName) ?? []].sort((left, right) => compareStrings(left.fieldName, right.fieldName)) } : {}
|
|
1804
2322
|
}))
|
|
1805
2323
|
});
|
|
1806
|
-
const valueObjects = buildValueObjects(compositeTypes, enumResult.enumTypeDescriptors, namedTypeResult.namedTypeDescriptors, input.scalarTypeDescriptors, diagnostics, sourceId);
|
|
1807
2324
|
let patchedModels = patchModelDomainFields(contract.models, modelResolvedFields);
|
|
1808
2325
|
const polyDiagnostics = [];
|
|
1809
2326
|
patchedModels = resolvePolymorphism(patchedModels, discriminatorDeclarations, baseDeclarations, modelNames, modelMappings, sourceId, polyDiagnostics);
|
|
@@ -1823,4 +2340,4 @@ function interpretPslDocumentToSqlContract(input) {
|
|
|
1823
2340
|
|
|
1824
2341
|
//#endregion
|
|
1825
2342
|
export { interpretPslDocumentToSqlContract as t };
|
|
1826
|
-
//# sourceMappingURL=interpreter-
|
|
2343
|
+
//# sourceMappingURL=interpreter-iFCRN9nb.mjs.map
|