@prisma-next/sql-contract-psl 0.5.0-dev.8 → 0.5.0-dev.80
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 +9 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -3
- package/dist/{interpreter-iFCRN9nb.mjs → interpreter-C9MPo8FK.mjs} +358 -76
- package/dist/interpreter-C9MPo8FK.mjs.map +1 -0
- package/dist/provider.d.mts +2 -2
- package/dist/provider.d.mts.map +1 -1
- package/dist/provider.mjs +3 -6
- package/dist/provider.mjs.map +1 -1
- package/package.json +12 -11
- package/src/interpreter.ts +128 -28
- package/src/provider.ts +3 -5
- package/src/psl-attribute-parsing.ts +14 -5
- package/src/psl-authoring-arguments.ts +6 -0
- package/src/psl-column-resolution.ts +228 -37
- package/src/psl-field-resolution.ts +138 -17
- package/src/psl-relation-resolution.ts +3 -0
- package/dist/interpreter-iFCRN9nb.mjs.map +0 -1
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { instantiateAuthoringTypeConstructor, isAuthoringTypeConstructorDescriptor, validateAuthoringHelperArguments } from "@prisma-next/framework-components/authoring";
|
|
1
|
+
import { hasRegisteredFieldNamespace, instantiateAuthoringFieldPreset, instantiateAuthoringTypeConstructor, isAuthoringFieldPresetDescriptor, 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";
|
|
5
5
|
import { getPositionalArgument, parseQuotedStringLiteral } from "@prisma-next/psl-parser";
|
|
6
6
|
import { assertDefined, invariant } from "@prisma-next/utils/assertions";
|
|
7
|
-
|
|
8
7
|
//#region src/psl-attribute-parsing.ts
|
|
9
8
|
function lowerFirst(value) {
|
|
10
9
|
if (value.length === 0) return value;
|
|
@@ -149,7 +148,7 @@ function parseAttributeFieldList(input) {
|
|
|
149
148
|
if (!raw) {
|
|
150
149
|
input.diagnostics.push({
|
|
151
150
|
code: input.code,
|
|
152
|
-
message: `${input.
|
|
151
|
+
message: `${input.entityLabel} requires fields list argument`,
|
|
153
152
|
sourceId: input.sourceId,
|
|
154
153
|
span: input.attribute.span
|
|
155
154
|
});
|
|
@@ -159,7 +158,7 @@ function parseAttributeFieldList(input) {
|
|
|
159
158
|
if (!fields || fields.length === 0) {
|
|
160
159
|
input.diagnostics.push({
|
|
161
160
|
code: input.code,
|
|
162
|
-
message: `${input.
|
|
161
|
+
message: `${input.entityLabel} requires bracketed field list argument`,
|
|
163
162
|
sourceId: input.sourceId,
|
|
164
163
|
span: input.attribute.span
|
|
165
164
|
});
|
|
@@ -167,6 +166,13 @@ function parseAttributeFieldList(input) {
|
|
|
167
166
|
}
|
|
168
167
|
return fields;
|
|
169
168
|
}
|
|
169
|
+
function findDuplicateFieldName(fieldNames) {
|
|
170
|
+
const seen = /* @__PURE__ */ new Set();
|
|
171
|
+
for (const name of fieldNames) {
|
|
172
|
+
if (seen.has(name)) return name;
|
|
173
|
+
seen.add(name);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
170
176
|
function mapFieldNamesToColumns(input) {
|
|
171
177
|
const columns = [];
|
|
172
178
|
for (const fieldName of input.fieldNames) {
|
|
@@ -174,7 +180,7 @@ function mapFieldNamesToColumns(input) {
|
|
|
174
180
|
if (!columnName) {
|
|
175
181
|
input.diagnostics.push({
|
|
176
182
|
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
177
|
-
message: `${input.
|
|
183
|
+
message: `${input.entityLabel} references unknown field "${input.modelName}.${fieldName}"`,
|
|
178
184
|
sourceId: input.sourceId,
|
|
179
185
|
span: input.span
|
|
180
186
|
});
|
|
@@ -184,7 +190,6 @@ function mapFieldNamesToColumns(input) {
|
|
|
184
190
|
}
|
|
185
191
|
return columns;
|
|
186
192
|
}
|
|
187
|
-
|
|
188
193
|
//#endregion
|
|
189
194
|
//#region src/default-function-registry.ts
|
|
190
195
|
function resolveSpanPositionFromBase(base, text, offset) {
|
|
@@ -323,7 +328,6 @@ function lowerDefaultFunctionWithRegistry(input) {
|
|
|
323
328
|
}
|
|
324
329
|
};
|
|
325
330
|
}
|
|
326
|
-
|
|
327
331
|
//#endregion
|
|
328
332
|
//#region src/psl-authoring-arguments.ts
|
|
329
333
|
const INVALID_AUTHORING_ARGUMENT = Symbol("invalidAuthoringArgument");
|
|
@@ -401,10 +405,10 @@ function parseJsLikeLiteral(value) {
|
|
|
401
405
|
function parseNumber() {
|
|
402
406
|
const raw = value.slice(index).match(/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/)?.[0];
|
|
403
407
|
if (!raw) return INVALID_AUTHORING_ARGUMENT;
|
|
404
|
-
const parsed
|
|
405
|
-
if (!Number.isFinite(parsed
|
|
408
|
+
const parsed = Number(raw);
|
|
409
|
+
if (!Number.isFinite(parsed)) return INVALID_AUTHORING_ARGUMENT;
|
|
406
410
|
index += raw.length;
|
|
407
|
-
return parsed
|
|
411
|
+
return parsed;
|
|
408
412
|
}
|
|
409
413
|
function parseArray() {
|
|
410
414
|
if (value[index] !== "[") return INVALID_AUTHORING_ARGUMENT;
|
|
@@ -511,6 +515,12 @@ function parsePslObjectLiteral(value) {
|
|
|
511
515
|
function parsePslAuthoringArgumentValue(descriptor, rawValue) {
|
|
512
516
|
switch (descriptor.kind) {
|
|
513
517
|
case "string": return unquoteStringLiteral(rawValue);
|
|
518
|
+
case "boolean": {
|
|
519
|
+
const trimmed = rawValue.trim();
|
|
520
|
+
if (trimmed === "true") return true;
|
|
521
|
+
if (trimmed === "false") return false;
|
|
522
|
+
return INVALID_AUTHORING_ARGUMENT;
|
|
523
|
+
}
|
|
514
524
|
case "number": {
|
|
515
525
|
const parsed = Number(unquoteStringLiteral(rawValue));
|
|
516
526
|
return Number.isNaN(parsed) ? INVALID_AUTHORING_ARGUMENT : parsed;
|
|
@@ -562,7 +572,7 @@ function mapPslHelperArgs(input) {
|
|
|
562
572
|
mappedArgs[index] = value;
|
|
563
573
|
}
|
|
564
574
|
for (const argument of namedArgs) {
|
|
565
|
-
const descriptorIndex = input.descriptors.findIndex((descriptor
|
|
575
|
+
const descriptorIndex = input.descriptors.findIndex((descriptor) => descriptor.name === argument.name);
|
|
566
576
|
if (descriptorIndex < 0) return pushInvalidPslHelperArgument({
|
|
567
577
|
diagnostics: input.diagnostics,
|
|
568
578
|
sourceId: input.sourceId,
|
|
@@ -601,7 +611,6 @@ function mapPslHelperArgs(input) {
|
|
|
601
611
|
}
|
|
602
612
|
return mappedArgs;
|
|
603
613
|
}
|
|
604
|
-
|
|
605
614
|
//#endregion
|
|
606
615
|
//#region src/psl-column-resolution.ts
|
|
607
616
|
function toNamedTypeFieldDescriptor(typeRef, descriptor) {
|
|
@@ -620,33 +629,40 @@ function getAuthoringTypeConstructor(contributions, path) {
|
|
|
620
629
|
return isAuthoringTypeConstructorDescriptor(current) ? current : void 0;
|
|
621
630
|
}
|
|
622
631
|
/**
|
|
623
|
-
*
|
|
624
|
-
*
|
|
625
|
-
*
|
|
632
|
+
* Walks `authoringContributions.field` segment-by-segment and returns the field-preset descriptor at the resolved path, or `undefined` if no descriptor is registered.
|
|
633
|
+
*
|
|
634
|
+
* Symmetric with `getAuthoringTypeConstructor`. Field presets are strictly richer than type constructors — they can contribute `default` / `executionDefaults` / `id` / `unique` / `nullable` in addition to the `codecId` / `nativeType` / `typeParams` triple. PSL resolution tries field presets first, then falls back to type constructors on miss (see `resolveFieldTypeDescriptor`).
|
|
635
|
+
*/
|
|
636
|
+
function getAuthoringFieldPreset(contributions, path) {
|
|
637
|
+
let current = contributions?.field;
|
|
638
|
+
for (const segment of path) {
|
|
639
|
+
if (typeof current !== "object" || current === null || Array.isArray(current)) return;
|
|
640
|
+
current = current[segment];
|
|
641
|
+
}
|
|
642
|
+
return isAuthoringFieldPresetDescriptor(current) ? current : void 0;
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Returns the namespace prefix of `attributeName` if it references an unrecognized extension namespace, otherwise `undefined`. A namespace is considered recognized when it is:
|
|
626
646
|
*
|
|
627
647
|
* - `db` (native-type spec, always allowed),
|
|
628
648
|
* - the active family id (e.g. `sql`),
|
|
629
649
|
* - the active target id (e.g. `postgres`),
|
|
650
|
+
* - a registered field-preset namespace (e.g. `temporal`),
|
|
630
651
|
* - present in `composedExtensions`.
|
|
631
652
|
*
|
|
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).
|
|
653
|
+
* Family/target/field-preset namespaces are exempted so that e.g. `@sql.foo` surfaces as PSL_UNSUPPORTED_*_ATTRIBUTE (the attribute isn't defined) rather than PSL_EXTENSION_NAMESPACE_NOT_COMPOSED (the namespace is already composed).
|
|
635
654
|
*/
|
|
636
655
|
function checkUncomposedNamespace(attributeName, composedExtensions, context) {
|
|
637
656
|
const dotIndex = attributeName.indexOf(".");
|
|
638
657
|
if (dotIndex <= 0 || dotIndex === attributeName.length - 1) return;
|
|
639
658
|
const namespace = attributeName.slice(0, dotIndex);
|
|
640
|
-
if (namespace === "db" || namespace === context?.familyId || namespace === context?.targetId || composedExtensions.has(namespace)) return;
|
|
659
|
+
if (namespace === "db" || namespace === context?.familyId || namespace === context?.targetId || hasRegisteredFieldNamespace(context?.authoringContributions, namespace) || composedExtensions.has(namespace)) return;
|
|
641
660
|
return namespace;
|
|
642
661
|
}
|
|
643
662
|
/**
|
|
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.
|
|
663
|
+
* Pushes the canonical `PSL_EXTENSION_NAMESPACE_NOT_COMPOSED` diagnostic for a subject (attribute, model attribute, or type constructor) that references an extension namespace which is not composed in the current contract.
|
|
647
664
|
*
|
|
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.
|
|
665
|
+
* The `data` payload carries the missing namespace so machine consumers (agents, IDE extensions, CLI auto-fix) don't have to parse the prose.
|
|
650
666
|
*/
|
|
651
667
|
function reportUncomposedNamespace(input) {
|
|
652
668
|
input.diagnostics.push({
|
|
@@ -660,6 +676,21 @@ function reportUncomposedNamespace(input) {
|
|
|
660
676
|
}
|
|
661
677
|
});
|
|
662
678
|
}
|
|
679
|
+
/**
|
|
680
|
+
* Pushes the canonical `PSL_UNKNOWN_FIELD_PRESET` diagnostic when a typoed preset name is referenced inside a registered field-preset namespace. The `data` payload exposes the namespace and full helper path so machine consumers (agents, IDE extensions) don't have to parse the prose.
|
|
681
|
+
*/
|
|
682
|
+
function reportUnknownFieldPreset(input) {
|
|
683
|
+
input.diagnostics.push({
|
|
684
|
+
code: "PSL_UNKNOWN_FIELD_PRESET",
|
|
685
|
+
message: `${input.entityLabel} references unknown field preset "${input.helperPath}". Check the spelling against the available presets in the "${input.namespace}" namespace.`,
|
|
686
|
+
sourceId: input.sourceId,
|
|
687
|
+
span: input.span,
|
|
688
|
+
data: {
|
|
689
|
+
namespace: input.namespace,
|
|
690
|
+
helperPath: input.helperPath
|
|
691
|
+
}
|
|
692
|
+
});
|
|
693
|
+
}
|
|
663
694
|
function instantiatePslTypeConstructor(input) {
|
|
664
695
|
const helperPath = input.call.path.join(".");
|
|
665
696
|
const args = mapPslHelperArgs({
|
|
@@ -697,11 +728,15 @@ function pushUnsupportedTypeConstructorDiagnostic(input) {
|
|
|
697
728
|
function resolvePslTypeConstructorDescriptor(input) {
|
|
698
729
|
const descriptor = getAuthoringTypeConstructor(input.authoringContributions, input.call.path);
|
|
699
730
|
if (descriptor) return descriptor;
|
|
700
|
-
const
|
|
701
|
-
|
|
731
|
+
const uncomposedNamespace = checkUncomposedNamespace(input.call.path.join("."), input.composedExtensions, {
|
|
732
|
+
familyId: input.familyId,
|
|
733
|
+
targetId: input.targetId,
|
|
734
|
+
authoringContributions: input.authoringContributions
|
|
735
|
+
});
|
|
736
|
+
if (uncomposedNamespace) {
|
|
702
737
|
reportUncomposedNamespace({
|
|
703
738
|
subjectLabel: `Type constructor "${input.call.path.join(".")}"`,
|
|
704
|
-
namespace,
|
|
739
|
+
namespace: uncomposedNamespace,
|
|
705
740
|
sourceId: input.sourceId,
|
|
706
741
|
span: input.call.span,
|
|
707
742
|
diagnostics: input.diagnostics
|
|
@@ -716,10 +751,95 @@ function resolvePslTypeConstructorDescriptor(input) {
|
|
|
716
751
|
message: input.unsupportedMessage
|
|
717
752
|
});
|
|
718
753
|
}
|
|
754
|
+
/**
|
|
755
|
+
* Instantiates a field-preset call against its descriptor, coercing PSL AST arguments into the descriptor's typed argument shape and returning the preset's full set of contract contributions.
|
|
756
|
+
*
|
|
757
|
+
* Symmetric with `instantiatePslTypeConstructor` but richer: a field preset can contribute `default`, `executionDefaults`, `id`, `unique`, and `nullable` in addition to the storage-type triple. PSL → typed-args coercion happens here (via `mapPslHelperArgs`) so that `instantiateAuthoringFieldPreset` itself stays typed-input-only and TS keeps its zero-runtime-validation cost.
|
|
758
|
+
*/
|
|
759
|
+
function instantiatePslFieldPreset(input) {
|
|
760
|
+
const helperPath = input.call.path.join(".");
|
|
761
|
+
const args = mapPslHelperArgs({
|
|
762
|
+
args: input.call.args,
|
|
763
|
+
descriptors: input.descriptor.args ?? [],
|
|
764
|
+
helperLabel: `preset "${helperPath}"`,
|
|
765
|
+
span: input.call.span,
|
|
766
|
+
diagnostics: input.diagnostics,
|
|
767
|
+
sourceId: input.sourceId,
|
|
768
|
+
entityLabel: input.entityLabel
|
|
769
|
+
});
|
|
770
|
+
if (!args) return;
|
|
771
|
+
try {
|
|
772
|
+
validateAuthoringHelperArguments(helperPath, input.descriptor.args, args);
|
|
773
|
+
const instantiated = instantiateAuthoringFieldPreset(input.descriptor, args);
|
|
774
|
+
return {
|
|
775
|
+
descriptor: {
|
|
776
|
+
codecId: instantiated.descriptor.codecId,
|
|
777
|
+
nativeType: instantiated.descriptor.nativeType,
|
|
778
|
+
...instantiated.descriptor.typeParams !== void 0 ? { typeParams: instantiated.descriptor.typeParams } : {}
|
|
779
|
+
},
|
|
780
|
+
nullable: instantiated.nullable,
|
|
781
|
+
...instantiated.default !== void 0 ? { default: instantiated.default } : {},
|
|
782
|
+
...instantiated.executionDefaults !== void 0 ? { executionDefaults: instantiated.executionDefaults } : {},
|
|
783
|
+
id: instantiated.id,
|
|
784
|
+
unique: instantiated.unique
|
|
785
|
+
};
|
|
786
|
+
} catch (error) {
|
|
787
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
788
|
+
input.diagnostics.push({
|
|
789
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
790
|
+
message: `${input.entityLabel} preset "${helperPath}" ${message}`,
|
|
791
|
+
sourceId: input.sourceId,
|
|
792
|
+
span: input.call.span
|
|
793
|
+
});
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
719
797
|
function resolveFieldTypeDescriptor(input) {
|
|
720
798
|
if (input.field.typeConstructor) {
|
|
799
|
+
const presetDescriptor = getAuthoringFieldPreset(input.authoringContributions, input.field.typeConstructor.path);
|
|
800
|
+
if (presetDescriptor) {
|
|
801
|
+
const instantiated = instantiatePslFieldPreset({
|
|
802
|
+
call: input.field.typeConstructor,
|
|
803
|
+
descriptor: presetDescriptor,
|
|
804
|
+
diagnostics: input.diagnostics,
|
|
805
|
+
sourceId: input.sourceId,
|
|
806
|
+
entityLabel: input.entityLabel
|
|
807
|
+
});
|
|
808
|
+
if (!instantiated) return {
|
|
809
|
+
ok: false,
|
|
810
|
+
alreadyReported: true
|
|
811
|
+
};
|
|
812
|
+
const presetContributions = {
|
|
813
|
+
nullable: instantiated.nullable,
|
|
814
|
+
id: instantiated.id,
|
|
815
|
+
unique: instantiated.unique,
|
|
816
|
+
...instantiated.default !== void 0 ? { default: instantiated.default } : {},
|
|
817
|
+
...instantiated.executionDefaults !== void 0 ? { executionDefaults: instantiated.executionDefaults } : {}
|
|
818
|
+
};
|
|
819
|
+
return {
|
|
820
|
+
ok: true,
|
|
821
|
+
descriptor: instantiated.descriptor,
|
|
822
|
+
presetContributions
|
|
823
|
+
};
|
|
824
|
+
}
|
|
721
825
|
const helperPath = input.field.typeConstructor.path.join(".");
|
|
722
|
-
const
|
|
826
|
+
const namespacePrefix = input.field.typeConstructor.path.length > 1 ? input.field.typeConstructor.path[0] : void 0;
|
|
827
|
+
const typeDescriptor = getAuthoringTypeConstructor(input.authoringContributions, input.field.typeConstructor.path);
|
|
828
|
+
if (!typeDescriptor && namespacePrefix && hasRegisteredFieldNamespace(input.authoringContributions, namespacePrefix)) {
|
|
829
|
+
reportUnknownFieldPreset({
|
|
830
|
+
entityLabel: input.entityLabel,
|
|
831
|
+
namespace: namespacePrefix,
|
|
832
|
+
helperPath,
|
|
833
|
+
sourceId: input.sourceId,
|
|
834
|
+
span: input.field.typeConstructor.span,
|
|
835
|
+
diagnostics: input.diagnostics
|
|
836
|
+
});
|
|
837
|
+
return {
|
|
838
|
+
ok: false,
|
|
839
|
+
alreadyReported: true
|
|
840
|
+
};
|
|
841
|
+
}
|
|
842
|
+
const descriptor = typeDescriptor ?? resolvePslTypeConstructorDescriptor({
|
|
723
843
|
call: input.field.typeConstructor,
|
|
724
844
|
authoringContributions: input.authoringContributions,
|
|
725
845
|
composedExtensions: input.composedExtensions,
|
|
@@ -730,13 +850,13 @@ function resolveFieldTypeDescriptor(input) {
|
|
|
730
850
|
unsupportedCode: "PSL_UNSUPPORTED_FIELD_TYPE",
|
|
731
851
|
unsupportedMessage: `${input.entityLabel} type constructor "${helperPath}" is not supported in SQL PSL provider v1`
|
|
732
852
|
});
|
|
733
|
-
if (!descriptor
|
|
853
|
+
if (!descriptor) return {
|
|
734
854
|
ok: false,
|
|
735
855
|
alreadyReported: true
|
|
736
856
|
};
|
|
737
857
|
const instantiated = instantiatePslTypeConstructor({
|
|
738
858
|
call: input.field.typeConstructor,
|
|
739
|
-
descriptor
|
|
859
|
+
descriptor,
|
|
740
860
|
diagnostics: input.diagnostics,
|
|
741
861
|
sourceId: input.sourceId,
|
|
742
862
|
entityLabel: input.entityLabel
|
|
@@ -985,6 +1105,15 @@ function lowerDefaultForField(input) {
|
|
|
985
1105
|
});
|
|
986
1106
|
return {};
|
|
987
1107
|
}
|
|
1108
|
+
if (generatorDescriptor.applicableCodecIds === void 0) {
|
|
1109
|
+
input.diagnostics.push({
|
|
1110
|
+
code: "PSL_INVALID_DEFAULT_APPLICABILITY",
|
|
1111
|
+
message: `Default generator "${generatorDescriptor.id}" is not applicable to "@default(...)" lowering. Use the corresponding field preset (e.g. \`temporal.${generatorDescriptor.id === "timestampNow" ? "updatedAt" : generatorDescriptor.id}()\`) instead.`,
|
|
1112
|
+
sourceId: input.sourceId,
|
|
1113
|
+
span: expressionEntry.span
|
|
1114
|
+
});
|
|
1115
|
+
return {};
|
|
1116
|
+
}
|
|
988
1117
|
if (!generatorDescriptor.applicableCodecIds.includes(input.columnDescriptor.codecId)) {
|
|
989
1118
|
input.diagnostics.push({
|
|
990
1119
|
code: "PSL_INVALID_DEFAULT_APPLICABILITY",
|
|
@@ -994,7 +1123,7 @@ function lowerDefaultForField(input) {
|
|
|
994
1123
|
});
|
|
995
1124
|
return {};
|
|
996
1125
|
}
|
|
997
|
-
return {
|
|
1126
|
+
return { executionDefaults: { onCreate: lowered.value.generated } };
|
|
998
1127
|
}
|
|
999
1128
|
function resolveColumnDescriptor(field, enumTypeDescriptors, namedTypeDescriptors, scalarTypeDescriptors) {
|
|
1000
1129
|
if (field.typeRef && namedTypeDescriptors.has(field.typeRef)) return namedTypeDescriptors.get(field.typeRef);
|
|
@@ -1002,7 +1131,6 @@ function resolveColumnDescriptor(field, enumTypeDescriptors, namedTypeDescriptor
|
|
|
1002
1131
|
if (enumTypeDescriptors.has(field.typeName)) return enumTypeDescriptors.get(field.typeName);
|
|
1003
1132
|
return scalarTypeDescriptors.get(field.typeName);
|
|
1004
1133
|
}
|
|
1005
|
-
|
|
1006
1134
|
//#endregion
|
|
1007
1135
|
//#region src/psl-field-resolution.ts
|
|
1008
1136
|
const BUILTIN_FIELD_ATTRIBUTE_NAMES = new Set([
|
|
@@ -1012,12 +1140,21 @@ const BUILTIN_FIELD_ATTRIBUTE_NAMES = new Set([
|
|
|
1012
1140
|
"relation",
|
|
1013
1141
|
"map"
|
|
1014
1142
|
]);
|
|
1143
|
+
const REMOVED_ATTRIBUTE_RULES = new Map([["updatedAt", {
|
|
1144
|
+
hint: "Use `temporal.updatedAt()` as a field-preset call instead.",
|
|
1145
|
+
suppressWhen: (field) => field.typeConstructor?.path[0] === "temporal"
|
|
1146
|
+
}]]);
|
|
1147
|
+
{
|
|
1148
|
+
const overlap = [...REMOVED_ATTRIBUTE_RULES.keys()].filter((name) => BUILTIN_FIELD_ATTRIBUTE_NAMES.has(name));
|
|
1149
|
+
if (overlap.length > 0) throw new Error(`BUILTIN_FIELD_ATTRIBUTE_NAMES and REMOVED_ATTRIBUTE_RULES must not overlap. Names in both: ${overlap.join(", ")}`);
|
|
1150
|
+
}
|
|
1015
1151
|
function validateFieldAttributes(input) {
|
|
1016
1152
|
for (const attribute of input.field.attributes) {
|
|
1017
1153
|
if (BUILTIN_FIELD_ATTRIBUTE_NAMES.has(attribute.name)) continue;
|
|
1018
1154
|
const uncomposedNamespace = checkUncomposedNamespace(attribute.name, input.composedExtensions, {
|
|
1019
1155
|
familyId: input.familyId,
|
|
1020
|
-
targetId: input.targetId
|
|
1156
|
+
targetId: input.targetId,
|
|
1157
|
+
authoringContributions: input.authoringContributions
|
|
1021
1158
|
});
|
|
1022
1159
|
if (uncomposedNamespace) {
|
|
1023
1160
|
reportUncomposedNamespace({
|
|
@@ -1029,9 +1166,12 @@ function validateFieldAttributes(input) {
|
|
|
1029
1166
|
});
|
|
1030
1167
|
continue;
|
|
1031
1168
|
}
|
|
1169
|
+
const baseMessage = `Field "${input.model.name}.${input.field.name}" uses unsupported attribute "@${attribute.name}"`;
|
|
1170
|
+
const removedRule = REMOVED_ATTRIBUTE_RULES.get(attribute.name);
|
|
1171
|
+
const message = removedRule && !removedRule.suppressWhen(input.field) ? `${baseMessage}. ${removedRule.hint}` : baseMessage;
|
|
1032
1172
|
input.diagnostics.push({
|
|
1033
1173
|
code: "PSL_UNSUPPORTED_FIELD_ATTRIBUTE",
|
|
1034
|
-
message
|
|
1174
|
+
message,
|
|
1035
1175
|
sourceId: input.sourceId,
|
|
1036
1176
|
span: attribute.span
|
|
1037
1177
|
});
|
|
@@ -1065,21 +1205,25 @@ function collectResolvedFields(input) {
|
|
|
1065
1205
|
const { model, mapping, enumTypeDescriptors, namedTypeDescriptors, modelNames, compositeTypeNames, composedExtensions, authoringContributions, familyId, targetId, defaultFunctionRegistry, generatorDescriptorById, diagnostics, sourceId, scalarTypeDescriptors } = input;
|
|
1066
1206
|
const resolvedFields = [];
|
|
1067
1207
|
for (const field of model.fields) {
|
|
1068
|
-
|
|
1208
|
+
const isModelField = modelNames.has(field.typeName);
|
|
1209
|
+
if (field.list && isModelField) continue;
|
|
1069
1210
|
validateFieldAttributes({
|
|
1070
1211
|
model,
|
|
1071
1212
|
field,
|
|
1072
1213
|
composedExtensions,
|
|
1214
|
+
authoringContributions,
|
|
1073
1215
|
diagnostics,
|
|
1074
1216
|
sourceId,
|
|
1075
1217
|
familyId,
|
|
1076
1218
|
targetId
|
|
1077
1219
|
});
|
|
1078
|
-
|
|
1220
|
+
const relationAttribute = getAttribute(field.attributes, "relation");
|
|
1221
|
+
if (isModelField && relationAttribute) continue;
|
|
1079
1222
|
const isValueObjectField = compositeTypeNames.has(field.typeName);
|
|
1080
1223
|
const isListField = field.list;
|
|
1081
1224
|
let descriptor;
|
|
1082
1225
|
let scalarCodecId;
|
|
1226
|
+
let presetContributions;
|
|
1083
1227
|
const resolveInput = {
|
|
1084
1228
|
field,
|
|
1085
1229
|
enumTypeDescriptors,
|
|
@@ -1105,6 +1249,15 @@ function collectResolvedFields(input) {
|
|
|
1105
1249
|
});
|
|
1106
1250
|
continue;
|
|
1107
1251
|
}
|
|
1252
|
+
if (resolved.presetContributions) {
|
|
1253
|
+
diagnostics.push({
|
|
1254
|
+
code: "PSL_PRESET_NOT_LIST",
|
|
1255
|
+
message: `Field "${model.name}.${field.name}" uses a field-preset call as a list element type. Presets cannot be list elements; remove "[]" or use a scalar type.`,
|
|
1256
|
+
sourceId,
|
|
1257
|
+
span: field.span
|
|
1258
|
+
});
|
|
1259
|
+
continue;
|
|
1260
|
+
}
|
|
1108
1261
|
scalarCodecId = resolved.descriptor.codecId;
|
|
1109
1262
|
descriptor = scalarTypeDescriptors.get("Json");
|
|
1110
1263
|
} else {
|
|
@@ -1119,9 +1272,28 @@ function collectResolvedFields(input) {
|
|
|
1119
1272
|
continue;
|
|
1120
1273
|
}
|
|
1121
1274
|
descriptor = resolved.descriptor;
|
|
1275
|
+
presetContributions = resolved.presetContributions;
|
|
1122
1276
|
}
|
|
1123
1277
|
if (!descriptor) continue;
|
|
1278
|
+
if (presetContributions && field.optional) {
|
|
1279
|
+
diagnostics.push({
|
|
1280
|
+
code: "PSL_PRESET_NOT_OPTIONAL",
|
|
1281
|
+
message: `Field "${model.name}.${field.name}" uses a field-preset call and cannot be optional. Remove "?" or use a different field type.`,
|
|
1282
|
+
sourceId,
|
|
1283
|
+
span: field.span
|
|
1284
|
+
});
|
|
1285
|
+
continue;
|
|
1286
|
+
}
|
|
1124
1287
|
const defaultAttribute = getAttribute(field.attributes, "default");
|
|
1288
|
+
if (presetContributions && defaultAttribute) {
|
|
1289
|
+
diagnostics.push({
|
|
1290
|
+
code: "PSL_PRESET_AND_DEFAULT_CONFLICT",
|
|
1291
|
+
message: `Field "${model.name}.${field.name}" uses a field-preset call and cannot also declare @default(...). The preset already specifies the default value.`,
|
|
1292
|
+
sourceId,
|
|
1293
|
+
span: defaultAttribute.span
|
|
1294
|
+
});
|
|
1295
|
+
continue;
|
|
1296
|
+
}
|
|
1125
1297
|
const loweredDefault = defaultAttribute ? lowerDefaultForField({
|
|
1126
1298
|
modelName: model.name,
|
|
1127
1299
|
fieldName: field.name,
|
|
@@ -1132,8 +1304,9 @@ function collectResolvedFields(input) {
|
|
|
1132
1304
|
defaultFunctionRegistry,
|
|
1133
1305
|
diagnostics
|
|
1134
1306
|
}) : {};
|
|
1135
|
-
|
|
1136
|
-
|
|
1307
|
+
const loweredOnCreate = loweredDefault.executionDefaults?.onCreate;
|
|
1308
|
+
if (field.optional && loweredOnCreate) {
|
|
1309
|
+
const generatorDescription = loweredOnCreate.kind === "generator" ? `"${loweredOnCreate.id}"` : "for this field";
|
|
1137
1310
|
diagnostics.push({
|
|
1138
1311
|
code: "PSL_INVALID_DEFAULT_FUNCTION_ARGUMENT",
|
|
1139
1312
|
message: `Field "${model.name}.${field.name}" cannot be optional when using execution default ${generatorDescription}. Remove "?" or use a storage default.`,
|
|
@@ -1142,8 +1315,8 @@ function collectResolvedFields(input) {
|
|
|
1142
1315
|
});
|
|
1143
1316
|
continue;
|
|
1144
1317
|
}
|
|
1145
|
-
if (
|
|
1146
|
-
const generatedDescriptor = generatorDescriptorById.get(
|
|
1318
|
+
if (loweredOnCreate) {
|
|
1319
|
+
const generatedDescriptor = generatorDescriptorById.get(loweredOnCreate.id)?.resolveGeneratedColumnDescriptor?.({ generated: loweredOnCreate });
|
|
1147
1320
|
if (generatedDescriptor) descriptor = generatedDescriptor;
|
|
1148
1321
|
}
|
|
1149
1322
|
const mappedColumnName = mapping.fieldColumns.get(field.name) ?? field.name;
|
|
@@ -1153,14 +1326,35 @@ function collectResolvedFields(input) {
|
|
|
1153
1326
|
sourceId,
|
|
1154
1327
|
diagnostics
|
|
1155
1328
|
});
|
|
1329
|
+
let isIdField = Boolean(idAttribute);
|
|
1330
|
+
if (idAttribute && field.optional) {
|
|
1331
|
+
diagnostics.push({
|
|
1332
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
1333
|
+
message: `Field "${model.name}.${field.name}" @id cannot be optional; primary key columns must be NOT NULL`,
|
|
1334
|
+
sourceId,
|
|
1335
|
+
span: idAttribute.span
|
|
1336
|
+
});
|
|
1337
|
+
isIdField = false;
|
|
1338
|
+
}
|
|
1339
|
+
if (presetContributions && idAttribute && !presetContributions.id) {
|
|
1340
|
+
diagnostics.push({
|
|
1341
|
+
code: "PSL_PRESET_AND_ID_CONFLICT",
|
|
1342
|
+
message: `Field "${model.name}.${field.name}" uses a field-preset call and cannot also declare @id. Use a preset that contributes id semantics, or drop @id.`,
|
|
1343
|
+
sourceId,
|
|
1344
|
+
span: idAttribute.span
|
|
1345
|
+
});
|
|
1346
|
+
continue;
|
|
1347
|
+
}
|
|
1348
|
+
const fieldExecutionDefaults = presetContributions?.executionDefaults ?? loweredDefault.executionDefaults;
|
|
1349
|
+
const fieldDefaultValue = presetContributions?.default ?? loweredDefault.defaultValue;
|
|
1156
1350
|
resolvedFields.push({
|
|
1157
1351
|
field,
|
|
1158
1352
|
columnName: mappedColumnName,
|
|
1159
1353
|
descriptor,
|
|
1160
|
-
...ifDefined("defaultValue",
|
|
1161
|
-
...ifDefined("
|
|
1162
|
-
isId: Boolean(
|
|
1163
|
-
isUnique: Boolean(uniqueAttribute),
|
|
1354
|
+
...ifDefined("defaultValue", fieldDefaultValue),
|
|
1355
|
+
...ifDefined("executionDefaults", fieldExecutionDefaults),
|
|
1356
|
+
isId: isIdField || Boolean(presetContributions?.id),
|
|
1357
|
+
isUnique: Boolean(uniqueAttribute) || Boolean(presetContributions?.unique),
|
|
1164
1358
|
...ifDefined("idName", idName),
|
|
1165
1359
|
...ifDefined("uniqueName", uniqueName),
|
|
1166
1360
|
...ifDefined("many", isListField ? true : void 0),
|
|
@@ -1201,7 +1395,6 @@ function buildModelMappings(models, diagnostics, sourceId) {
|
|
|
1201
1395
|
}
|
|
1202
1396
|
return result;
|
|
1203
1397
|
}
|
|
1204
|
-
|
|
1205
1398
|
//#endregion
|
|
1206
1399
|
//#region src/psl-relation-resolution.ts
|
|
1207
1400
|
const REFERENTIAL_ACTION_MAP = {
|
|
@@ -1418,7 +1611,8 @@ function validateNavigationListFieldAttributes(input) {
|
|
|
1418
1611
|
if (attribute.name === "relation") continue;
|
|
1419
1612
|
const uncomposedNamespace = checkUncomposedNamespace(attribute.name, input.composedExtensions, {
|
|
1420
1613
|
familyId: input.familyId,
|
|
1421
|
-
targetId: input.targetId
|
|
1614
|
+
targetId: input.targetId,
|
|
1615
|
+
authoringContributions: input.authoringContributions
|
|
1422
1616
|
});
|
|
1423
1617
|
if (uncomposedNamespace) {
|
|
1424
1618
|
reportUncomposedNamespace({
|
|
@@ -1441,7 +1635,6 @@ function validateNavigationListFieldAttributes(input) {
|
|
|
1441
1635
|
}
|
|
1442
1636
|
return valid;
|
|
1443
1637
|
}
|
|
1444
|
-
|
|
1445
1638
|
//#endregion
|
|
1446
1639
|
//#region src/interpreter.ts
|
|
1447
1640
|
function buildComposedExtensionPackRefs(target, extensionIds, extensionPackRefs = []) {
|
|
@@ -1531,7 +1724,8 @@ function validateNamedTypeAttributes(input) {
|
|
|
1531
1724
|
if (input.allowDbNativeType && attribute.name.startsWith("db.")) continue;
|
|
1532
1725
|
const uncomposedNamespace = checkUncomposedNamespace(attribute.name, input.composedExtensions, {
|
|
1533
1726
|
familyId: input.familyId,
|
|
1534
|
-
targetId: input.targetId
|
|
1727
|
+
targetId: input.targetId,
|
|
1728
|
+
authoringContributions: input.authoringContributions
|
|
1535
1729
|
});
|
|
1536
1730
|
if (uncomposedNamespace) {
|
|
1537
1731
|
reportUncomposedNamespace({
|
|
@@ -1562,16 +1756,17 @@ function resolveNamedTypeDeclarations(input) {
|
|
|
1562
1756
|
const namedTypeDescriptors = /* @__PURE__ */ new Map();
|
|
1563
1757
|
for (const declaration of input.declarations) {
|
|
1564
1758
|
if (declaration.typeConstructor) {
|
|
1565
|
-
const { hasUnsupportedNamedTypeAttribute
|
|
1759
|
+
const { hasUnsupportedNamedTypeAttribute } = validateNamedTypeAttributes({
|
|
1566
1760
|
declaration,
|
|
1567
1761
|
sourceId: input.sourceId,
|
|
1568
1762
|
diagnostics: input.diagnostics,
|
|
1569
1763
|
composedExtensions: input.composedExtensions,
|
|
1764
|
+
authoringContributions: input.authoringContributions,
|
|
1570
1765
|
allowDbNativeType: false,
|
|
1571
1766
|
familyId: input.familyId,
|
|
1572
1767
|
targetId: input.targetId
|
|
1573
1768
|
});
|
|
1574
|
-
if (hasUnsupportedNamedTypeAttribute
|
|
1769
|
+
if (hasUnsupportedNamedTypeAttribute) continue;
|
|
1575
1770
|
const helperPath = declaration.typeConstructor.path.join(".");
|
|
1576
1771
|
const typeConstructor = resolvePslTypeConstructorDescriptor({
|
|
1577
1772
|
call: declaration.typeConstructor,
|
|
@@ -1626,13 +1821,14 @@ function resolveNamedTypeDeclarations(input) {
|
|
|
1626
1821
|
sourceId: input.sourceId,
|
|
1627
1822
|
diagnostics: input.diagnostics,
|
|
1628
1823
|
composedExtensions: input.composedExtensions,
|
|
1824
|
+
authoringContributions: input.authoringContributions,
|
|
1629
1825
|
allowDbNativeType: true,
|
|
1630
1826
|
familyId: input.familyId,
|
|
1631
1827
|
targetId: input.targetId
|
|
1632
1828
|
});
|
|
1633
1829
|
if (hasUnsupportedNamedTypeAttribute) continue;
|
|
1634
1830
|
if (dbNativeTypeAttribute) {
|
|
1635
|
-
const descriptor
|
|
1831
|
+
const descriptor = resolveDbNativeTypeAttribute({
|
|
1636
1832
|
attribute: dbNativeTypeAttribute,
|
|
1637
1833
|
baseType,
|
|
1638
1834
|
baseDescriptor,
|
|
@@ -1640,12 +1836,12 @@ function resolveNamedTypeDeclarations(input) {
|
|
|
1640
1836
|
sourceId: input.sourceId,
|
|
1641
1837
|
entityLabel: `Named type "${declaration.name}"`
|
|
1642
1838
|
});
|
|
1643
|
-
if (!descriptor
|
|
1644
|
-
namedTypeDescriptors.set(declaration.name, toNamedTypeFieldDescriptor(declaration.name, descriptor
|
|
1839
|
+
if (!descriptor) continue;
|
|
1840
|
+
namedTypeDescriptors.set(declaration.name, toNamedTypeFieldDescriptor(declaration.name, descriptor));
|
|
1645
1841
|
storageTypes[declaration.name] = {
|
|
1646
|
-
codecId: descriptor
|
|
1647
|
-
nativeType: descriptor
|
|
1648
|
-
typeParams: descriptor
|
|
1842
|
+
codecId: descriptor.codecId,
|
|
1843
|
+
nativeType: descriptor.nativeType,
|
|
1844
|
+
typeParams: descriptor.typeParams ?? {}
|
|
1649
1845
|
};
|
|
1650
1846
|
continue;
|
|
1651
1847
|
}
|
|
@@ -1682,16 +1878,20 @@ function buildModelNodeFromPsl(input) {
|
|
|
1682
1878
|
sourceId,
|
|
1683
1879
|
scalarTypeDescriptors: input.scalarTypeDescriptors
|
|
1684
1880
|
});
|
|
1685
|
-
const
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
if (primaryKeyColumns.length === 0 && !isVariantModel) diagnostics.push({
|
|
1690
|
-
code: "PSL_MISSING_PRIMARY_KEY",
|
|
1691
|
-
message: `Model "${model.name}" must declare at least one @id field for SQL provider`,
|
|
1881
|
+
const inlineIdFields = resolvedFields.filter((field) => field.isId);
|
|
1882
|
+
if (inlineIdFields.length > 1) diagnostics.push({
|
|
1883
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
1884
|
+
message: `Model "${model.name}" cannot declare inline @id on multiple fields; use model-level @@id([...]) for composite identity`,
|
|
1692
1885
|
sourceId,
|
|
1693
1886
|
span: model.span
|
|
1694
1887
|
});
|
|
1888
|
+
const singleInlineIdField = inlineIdFields.length === 1 ? inlineIdFields[0] : void 0;
|
|
1889
|
+
let primaryKey = singleInlineIdField ? {
|
|
1890
|
+
columns: [singleInlineIdField.columnName],
|
|
1891
|
+
...ifDefined("name", singleInlineIdField.idName)
|
|
1892
|
+
} : void 0;
|
|
1893
|
+
const hasInlinePrimaryKey = primaryKey !== void 0;
|
|
1894
|
+
let blockPrimaryKeyDeclared = false;
|
|
1695
1895
|
const resultBackrelationCandidates = [];
|
|
1696
1896
|
for (const field of model.fields) {
|
|
1697
1897
|
if (!field.list || !input.modelNames.has(field.typeName)) continue;
|
|
@@ -1700,6 +1900,7 @@ function buildModelNodeFromPsl(input) {
|
|
|
1700
1900
|
field,
|
|
1701
1901
|
sourceId,
|
|
1702
1902
|
composedExtensions: input.composedExtensions,
|
|
1903
|
+
authoringContributions: input.authoringContributions,
|
|
1703
1904
|
diagnostics,
|
|
1704
1905
|
familyId: input.familyId,
|
|
1705
1906
|
targetId: input.targetId
|
|
@@ -1757,15 +1958,98 @@ function buildModelNodeFromPsl(input) {
|
|
|
1757
1958
|
for (const modelAttribute of model.attributes) {
|
|
1758
1959
|
if (modelAttribute.name === "map") continue;
|
|
1759
1960
|
if (modelAttribute.name === "discriminator" || modelAttribute.name === "base") continue;
|
|
1961
|
+
const attributeLabel = `Model "${model.name}" @@${modelAttribute.name}`;
|
|
1962
|
+
if (modelAttribute.name === "id") {
|
|
1963
|
+
if (blockPrimaryKeyDeclared) {
|
|
1964
|
+
diagnostics.push({
|
|
1965
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
1966
|
+
message: `Model "${model.name}" declares @@id more than once`,
|
|
1967
|
+
sourceId,
|
|
1968
|
+
span: modelAttribute.span
|
|
1969
|
+
});
|
|
1970
|
+
continue;
|
|
1971
|
+
}
|
|
1972
|
+
if (hasInlinePrimaryKey) {
|
|
1973
|
+
diagnostics.push({
|
|
1974
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
1975
|
+
message: `Model "${model.name}" cannot declare both field-level @id and model-level @@id`,
|
|
1976
|
+
sourceId,
|
|
1977
|
+
span: modelAttribute.span
|
|
1978
|
+
});
|
|
1979
|
+
blockPrimaryKeyDeclared = true;
|
|
1980
|
+
continue;
|
|
1981
|
+
}
|
|
1982
|
+
const fieldNames = parseAttributeFieldList({
|
|
1983
|
+
attribute: modelAttribute,
|
|
1984
|
+
sourceId,
|
|
1985
|
+
diagnostics,
|
|
1986
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
1987
|
+
entityLabel: attributeLabel
|
|
1988
|
+
});
|
|
1989
|
+
if (!fieldNames) continue;
|
|
1990
|
+
const duplicateFieldName = findDuplicateFieldName(fieldNames);
|
|
1991
|
+
if (duplicateFieldName !== void 0) {
|
|
1992
|
+
diagnostics.push({
|
|
1993
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
1994
|
+
message: `${attributeLabel} list contains duplicate field "${duplicateFieldName}"`,
|
|
1995
|
+
sourceId,
|
|
1996
|
+
span: modelAttribute.span
|
|
1997
|
+
});
|
|
1998
|
+
continue;
|
|
1999
|
+
}
|
|
2000
|
+
const nullableFieldName = fieldNames.find((name) => model.fields.find((f) => f.name === name)?.optional === true);
|
|
2001
|
+
if (nullableFieldName !== void 0) {
|
|
2002
|
+
diagnostics.push({
|
|
2003
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
2004
|
+
message: `${attributeLabel} cannot include optional field "${nullableFieldName}"; primary key columns must be NOT NULL`,
|
|
2005
|
+
sourceId,
|
|
2006
|
+
span: modelAttribute.span
|
|
2007
|
+
});
|
|
2008
|
+
continue;
|
|
2009
|
+
}
|
|
2010
|
+
const columnNames = mapFieldNamesToColumns({
|
|
2011
|
+
modelName: model.name,
|
|
2012
|
+
fieldNames,
|
|
2013
|
+
mapping,
|
|
2014
|
+
sourceId,
|
|
2015
|
+
diagnostics,
|
|
2016
|
+
span: modelAttribute.span,
|
|
2017
|
+
entityLabel: attributeLabel
|
|
2018
|
+
});
|
|
2019
|
+
if (!columnNames) continue;
|
|
2020
|
+
primaryKey = {
|
|
2021
|
+
columns: columnNames,
|
|
2022
|
+
...ifDefined("name", parseConstraintMapArgument({
|
|
2023
|
+
attribute: modelAttribute,
|
|
2024
|
+
sourceId,
|
|
2025
|
+
diagnostics,
|
|
2026
|
+
entityLabel: attributeLabel,
|
|
2027
|
+
span: modelAttribute.span,
|
|
2028
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT"
|
|
2029
|
+
}))
|
|
2030
|
+
};
|
|
2031
|
+
blockPrimaryKeyDeclared = true;
|
|
2032
|
+
continue;
|
|
2033
|
+
}
|
|
1760
2034
|
if (modelAttribute.name === "unique" || modelAttribute.name === "index") {
|
|
1761
2035
|
const fieldNames = parseAttributeFieldList({
|
|
1762
2036
|
attribute: modelAttribute,
|
|
1763
2037
|
sourceId,
|
|
1764
2038
|
diagnostics,
|
|
1765
2039
|
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
1766
|
-
|
|
2040
|
+
entityLabel: attributeLabel
|
|
1767
2041
|
});
|
|
1768
2042
|
if (!fieldNames) continue;
|
|
2043
|
+
const duplicateFieldName = findDuplicateFieldName(fieldNames);
|
|
2044
|
+
if (duplicateFieldName !== void 0) {
|
|
2045
|
+
diagnostics.push({
|
|
2046
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
2047
|
+
message: `${attributeLabel} list contains duplicate field "${duplicateFieldName}"`,
|
|
2048
|
+
sourceId,
|
|
2049
|
+
span: modelAttribute.span
|
|
2050
|
+
});
|
|
2051
|
+
continue;
|
|
2052
|
+
}
|
|
1769
2053
|
const columnNames = mapFieldNamesToColumns({
|
|
1770
2054
|
modelName: model.name,
|
|
1771
2055
|
fieldNames,
|
|
@@ -1773,14 +2057,14 @@ function buildModelNodeFromPsl(input) {
|
|
|
1773
2057
|
sourceId,
|
|
1774
2058
|
diagnostics,
|
|
1775
2059
|
span: modelAttribute.span,
|
|
1776
|
-
|
|
2060
|
+
entityLabel: attributeLabel
|
|
1777
2061
|
});
|
|
1778
2062
|
if (!columnNames) continue;
|
|
1779
2063
|
const constraintName = parseConstraintMapArgument({
|
|
1780
2064
|
attribute: modelAttribute,
|
|
1781
2065
|
sourceId,
|
|
1782
2066
|
diagnostics,
|
|
1783
|
-
entityLabel:
|
|
2067
|
+
entityLabel: attributeLabel,
|
|
1784
2068
|
span: modelAttribute.span,
|
|
1785
2069
|
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT"
|
|
1786
2070
|
});
|
|
@@ -1796,7 +2080,8 @@ function buildModelNodeFromPsl(input) {
|
|
|
1796
2080
|
}
|
|
1797
2081
|
const uncomposedNamespace = checkUncomposedNamespace(modelAttribute.name, input.composedExtensions, {
|
|
1798
2082
|
familyId: input.familyId,
|
|
1799
|
-
targetId: input.targetId
|
|
2083
|
+
targetId: input.targetId,
|
|
2084
|
+
authoringContributions: input.authoringContributions
|
|
1800
2085
|
});
|
|
1801
2086
|
if (uncomposedNamespace) {
|
|
1802
2087
|
reportUncomposedNamespace({
|
|
@@ -1861,7 +2146,7 @@ function buildModelNodeFromPsl(input) {
|
|
|
1861
2146
|
sourceId,
|
|
1862
2147
|
diagnostics,
|
|
1863
2148
|
span: relationAttribute.relation.span,
|
|
1864
|
-
|
|
2149
|
+
entityLabel: `Relation field "${model.name}.${relationAttribute.field.name}"`
|
|
1865
2150
|
});
|
|
1866
2151
|
if (!localColumns) continue;
|
|
1867
2152
|
const referencedColumns = mapFieldNamesToColumns({
|
|
@@ -1871,7 +2156,7 @@ function buildModelNodeFromPsl(input) {
|
|
|
1871
2156
|
sourceId,
|
|
1872
2157
|
diagnostics,
|
|
1873
2158
|
span: relationAttribute.relation.span,
|
|
1874
|
-
|
|
2159
|
+
entityLabel: `Relation field "${model.name}.${relationAttribute.field.name}"`
|
|
1875
2160
|
});
|
|
1876
2161
|
if (!referencedColumns) continue;
|
|
1877
2162
|
if (localColumns.length !== referencedColumns.length) {
|
|
@@ -1933,12 +2218,9 @@ function buildModelNodeFromPsl(input) {
|
|
|
1933
2218
|
descriptor: resolvedField.descriptor,
|
|
1934
2219
|
nullable: resolvedField.field.optional,
|
|
1935
2220
|
...ifDefined("default", resolvedField.defaultValue),
|
|
1936
|
-
...ifDefined("
|
|
2221
|
+
...ifDefined("executionDefaults", resolvedField.executionDefaults)
|
|
1937
2222
|
})),
|
|
1938
|
-
...
|
|
1939
|
-
columns: primaryKeyColumns,
|
|
1940
|
-
...ifDefined("name", primaryKeyName)
|
|
1941
|
-
} } : {},
|
|
2223
|
+
...ifDefined("id", primaryKey),
|
|
1942
2224
|
...uniqueConstraints.length > 0 ? { uniques: uniqueConstraints } : {},
|
|
1943
2225
|
...indexNodes.length > 0 ? { indexes: indexNodes } : {},
|
|
1944
2226
|
...foreignKeyNodes.length > 0 ? { foreignKeys: foreignKeyNodes } : {}
|
|
@@ -2337,7 +2619,7 @@ function interpretPslDocumentToSqlContract(input) {
|
|
|
2337
2619
|
...Object.keys(valueObjects).length > 0 ? { valueObjects } : {}
|
|
2338
2620
|
});
|
|
2339
2621
|
}
|
|
2340
|
-
|
|
2341
2622
|
//#endregion
|
|
2342
2623
|
export { interpretPslDocumentToSqlContract as t };
|
|
2343
|
-
|
|
2624
|
+
|
|
2625
|
+
//# sourceMappingURL=interpreter-C9MPo8FK.mjs.map
|