@prisma-next/sql-contract-psl 0.5.0-dev.7 → 0.5.0-dev.71
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-C9EP3HJr.mjs} +352 -76
- package/dist/interpreter-C9EP3HJr.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 +14 -13
- package/src/interpreter.ts +128 -28
- package/src/provider.ts +3 -5
- package/src/psl-attribute-parsing.ts +14 -5
- 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;
|
|
@@ -562,7 +566,7 @@ function mapPslHelperArgs(input) {
|
|
|
562
566
|
mappedArgs[index] = value;
|
|
563
567
|
}
|
|
564
568
|
for (const argument of namedArgs) {
|
|
565
|
-
const descriptorIndex = input.descriptors.findIndex((descriptor
|
|
569
|
+
const descriptorIndex = input.descriptors.findIndex((descriptor) => descriptor.name === argument.name);
|
|
566
570
|
if (descriptorIndex < 0) return pushInvalidPslHelperArgument({
|
|
567
571
|
diagnostics: input.diagnostics,
|
|
568
572
|
sourceId: input.sourceId,
|
|
@@ -601,7 +605,6 @@ function mapPslHelperArgs(input) {
|
|
|
601
605
|
}
|
|
602
606
|
return mappedArgs;
|
|
603
607
|
}
|
|
604
|
-
|
|
605
608
|
//#endregion
|
|
606
609
|
//#region src/psl-column-resolution.ts
|
|
607
610
|
function toNamedTypeFieldDescriptor(typeRef, descriptor) {
|
|
@@ -620,33 +623,40 @@ function getAuthoringTypeConstructor(contributions, path) {
|
|
|
620
623
|
return isAuthoringTypeConstructorDescriptor(current) ? current : void 0;
|
|
621
624
|
}
|
|
622
625
|
/**
|
|
623
|
-
*
|
|
624
|
-
*
|
|
625
|
-
*
|
|
626
|
+
* Walks `authoringContributions.field` segment-by-segment and returns the field-preset descriptor at the resolved path, or `undefined` if no descriptor is registered.
|
|
627
|
+
*
|
|
628
|
+
* 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`).
|
|
629
|
+
*/
|
|
630
|
+
function getAuthoringFieldPreset(contributions, path) {
|
|
631
|
+
let current = contributions?.field;
|
|
632
|
+
for (const segment of path) {
|
|
633
|
+
if (typeof current !== "object" || current === null || Array.isArray(current)) return;
|
|
634
|
+
current = current[segment];
|
|
635
|
+
}
|
|
636
|
+
return isAuthoringFieldPresetDescriptor(current) ? current : void 0;
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* Returns the namespace prefix of `attributeName` if it references an unrecognized extension namespace, otherwise `undefined`. A namespace is considered recognized when it is:
|
|
626
640
|
*
|
|
627
641
|
* - `db` (native-type spec, always allowed),
|
|
628
642
|
* - the active family id (e.g. `sql`),
|
|
629
643
|
* - the active target id (e.g. `postgres`),
|
|
644
|
+
* - a registered field-preset namespace (e.g. `temporal`),
|
|
630
645
|
* - present in `composedExtensions`.
|
|
631
646
|
*
|
|
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).
|
|
647
|
+
* 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
648
|
*/
|
|
636
649
|
function checkUncomposedNamespace(attributeName, composedExtensions, context) {
|
|
637
650
|
const dotIndex = attributeName.indexOf(".");
|
|
638
651
|
if (dotIndex <= 0 || dotIndex === attributeName.length - 1) return;
|
|
639
652
|
const namespace = attributeName.slice(0, dotIndex);
|
|
640
|
-
if (namespace === "db" || namespace === context?.familyId || namespace === context?.targetId || composedExtensions.has(namespace)) return;
|
|
653
|
+
if (namespace === "db" || namespace === context?.familyId || namespace === context?.targetId || hasRegisteredFieldNamespace(context?.authoringContributions, namespace) || composedExtensions.has(namespace)) return;
|
|
641
654
|
return namespace;
|
|
642
655
|
}
|
|
643
656
|
/**
|
|
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.
|
|
657
|
+
* 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
658
|
*
|
|
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.
|
|
659
|
+
* The `data` payload carries the missing namespace so machine consumers (agents, IDE extensions, CLI auto-fix) don't have to parse the prose.
|
|
650
660
|
*/
|
|
651
661
|
function reportUncomposedNamespace(input) {
|
|
652
662
|
input.diagnostics.push({
|
|
@@ -660,6 +670,21 @@ function reportUncomposedNamespace(input) {
|
|
|
660
670
|
}
|
|
661
671
|
});
|
|
662
672
|
}
|
|
673
|
+
/**
|
|
674
|
+
* 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.
|
|
675
|
+
*/
|
|
676
|
+
function reportUnknownFieldPreset(input) {
|
|
677
|
+
input.diagnostics.push({
|
|
678
|
+
code: "PSL_UNKNOWN_FIELD_PRESET",
|
|
679
|
+
message: `${input.entityLabel} references unknown field preset "${input.helperPath}". Check the spelling against the available presets in the "${input.namespace}" namespace.`,
|
|
680
|
+
sourceId: input.sourceId,
|
|
681
|
+
span: input.span,
|
|
682
|
+
data: {
|
|
683
|
+
namespace: input.namespace,
|
|
684
|
+
helperPath: input.helperPath
|
|
685
|
+
}
|
|
686
|
+
});
|
|
687
|
+
}
|
|
663
688
|
function instantiatePslTypeConstructor(input) {
|
|
664
689
|
const helperPath = input.call.path.join(".");
|
|
665
690
|
const args = mapPslHelperArgs({
|
|
@@ -697,11 +722,15 @@ function pushUnsupportedTypeConstructorDiagnostic(input) {
|
|
|
697
722
|
function resolvePslTypeConstructorDescriptor(input) {
|
|
698
723
|
const descriptor = getAuthoringTypeConstructor(input.authoringContributions, input.call.path);
|
|
699
724
|
if (descriptor) return descriptor;
|
|
700
|
-
const
|
|
701
|
-
|
|
725
|
+
const uncomposedNamespace = checkUncomposedNamespace(input.call.path.join("."), input.composedExtensions, {
|
|
726
|
+
familyId: input.familyId,
|
|
727
|
+
targetId: input.targetId,
|
|
728
|
+
authoringContributions: input.authoringContributions
|
|
729
|
+
});
|
|
730
|
+
if (uncomposedNamespace) {
|
|
702
731
|
reportUncomposedNamespace({
|
|
703
732
|
subjectLabel: `Type constructor "${input.call.path.join(".")}"`,
|
|
704
|
-
namespace,
|
|
733
|
+
namespace: uncomposedNamespace,
|
|
705
734
|
sourceId: input.sourceId,
|
|
706
735
|
span: input.call.span,
|
|
707
736
|
diagnostics: input.diagnostics
|
|
@@ -716,10 +745,95 @@ function resolvePslTypeConstructorDescriptor(input) {
|
|
|
716
745
|
message: input.unsupportedMessage
|
|
717
746
|
});
|
|
718
747
|
}
|
|
748
|
+
/**
|
|
749
|
+
* 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.
|
|
750
|
+
*
|
|
751
|
+
* 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.
|
|
752
|
+
*/
|
|
753
|
+
function instantiatePslFieldPreset(input) {
|
|
754
|
+
const helperPath = input.call.path.join(".");
|
|
755
|
+
const args = mapPslHelperArgs({
|
|
756
|
+
args: input.call.args,
|
|
757
|
+
descriptors: input.descriptor.args ?? [],
|
|
758
|
+
helperLabel: `preset "${helperPath}"`,
|
|
759
|
+
span: input.call.span,
|
|
760
|
+
diagnostics: input.diagnostics,
|
|
761
|
+
sourceId: input.sourceId,
|
|
762
|
+
entityLabel: input.entityLabel
|
|
763
|
+
});
|
|
764
|
+
if (!args) return;
|
|
765
|
+
try {
|
|
766
|
+
validateAuthoringHelperArguments(helperPath, input.descriptor.args, args);
|
|
767
|
+
const instantiated = instantiateAuthoringFieldPreset(input.descriptor, args);
|
|
768
|
+
return {
|
|
769
|
+
descriptor: {
|
|
770
|
+
codecId: instantiated.descriptor.codecId,
|
|
771
|
+
nativeType: instantiated.descriptor.nativeType,
|
|
772
|
+
...instantiated.descriptor.typeParams !== void 0 ? { typeParams: instantiated.descriptor.typeParams } : {}
|
|
773
|
+
},
|
|
774
|
+
nullable: instantiated.nullable,
|
|
775
|
+
...instantiated.default !== void 0 ? { default: instantiated.default } : {},
|
|
776
|
+
...instantiated.executionDefaults !== void 0 ? { executionDefaults: instantiated.executionDefaults } : {},
|
|
777
|
+
id: instantiated.id,
|
|
778
|
+
unique: instantiated.unique
|
|
779
|
+
};
|
|
780
|
+
} catch (error) {
|
|
781
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
782
|
+
input.diagnostics.push({
|
|
783
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
784
|
+
message: `${input.entityLabel} preset "${helperPath}" ${message}`,
|
|
785
|
+
sourceId: input.sourceId,
|
|
786
|
+
span: input.call.span
|
|
787
|
+
});
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
719
791
|
function resolveFieldTypeDescriptor(input) {
|
|
720
792
|
if (input.field.typeConstructor) {
|
|
793
|
+
const presetDescriptor = getAuthoringFieldPreset(input.authoringContributions, input.field.typeConstructor.path);
|
|
794
|
+
if (presetDescriptor) {
|
|
795
|
+
const instantiated = instantiatePslFieldPreset({
|
|
796
|
+
call: input.field.typeConstructor,
|
|
797
|
+
descriptor: presetDescriptor,
|
|
798
|
+
diagnostics: input.diagnostics,
|
|
799
|
+
sourceId: input.sourceId,
|
|
800
|
+
entityLabel: input.entityLabel
|
|
801
|
+
});
|
|
802
|
+
if (!instantiated) return {
|
|
803
|
+
ok: false,
|
|
804
|
+
alreadyReported: true
|
|
805
|
+
};
|
|
806
|
+
const presetContributions = {
|
|
807
|
+
nullable: instantiated.nullable,
|
|
808
|
+
id: instantiated.id,
|
|
809
|
+
unique: instantiated.unique,
|
|
810
|
+
...instantiated.default !== void 0 ? { default: instantiated.default } : {},
|
|
811
|
+
...instantiated.executionDefaults !== void 0 ? { executionDefaults: instantiated.executionDefaults } : {}
|
|
812
|
+
};
|
|
813
|
+
return {
|
|
814
|
+
ok: true,
|
|
815
|
+
descriptor: instantiated.descriptor,
|
|
816
|
+
presetContributions
|
|
817
|
+
};
|
|
818
|
+
}
|
|
721
819
|
const helperPath = input.field.typeConstructor.path.join(".");
|
|
722
|
-
const
|
|
820
|
+
const namespacePrefix = input.field.typeConstructor.path.length > 1 ? input.field.typeConstructor.path[0] : void 0;
|
|
821
|
+
const typeDescriptor = getAuthoringTypeConstructor(input.authoringContributions, input.field.typeConstructor.path);
|
|
822
|
+
if (!typeDescriptor && namespacePrefix && hasRegisteredFieldNamespace(input.authoringContributions, namespacePrefix)) {
|
|
823
|
+
reportUnknownFieldPreset({
|
|
824
|
+
entityLabel: input.entityLabel,
|
|
825
|
+
namespace: namespacePrefix,
|
|
826
|
+
helperPath,
|
|
827
|
+
sourceId: input.sourceId,
|
|
828
|
+
span: input.field.typeConstructor.span,
|
|
829
|
+
diagnostics: input.diagnostics
|
|
830
|
+
});
|
|
831
|
+
return {
|
|
832
|
+
ok: false,
|
|
833
|
+
alreadyReported: true
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
const descriptor = typeDescriptor ?? resolvePslTypeConstructorDescriptor({
|
|
723
837
|
call: input.field.typeConstructor,
|
|
724
838
|
authoringContributions: input.authoringContributions,
|
|
725
839
|
composedExtensions: input.composedExtensions,
|
|
@@ -730,13 +844,13 @@ function resolveFieldTypeDescriptor(input) {
|
|
|
730
844
|
unsupportedCode: "PSL_UNSUPPORTED_FIELD_TYPE",
|
|
731
845
|
unsupportedMessage: `${input.entityLabel} type constructor "${helperPath}" is not supported in SQL PSL provider v1`
|
|
732
846
|
});
|
|
733
|
-
if (!descriptor
|
|
847
|
+
if (!descriptor) return {
|
|
734
848
|
ok: false,
|
|
735
849
|
alreadyReported: true
|
|
736
850
|
};
|
|
737
851
|
const instantiated = instantiatePslTypeConstructor({
|
|
738
852
|
call: input.field.typeConstructor,
|
|
739
|
-
descriptor
|
|
853
|
+
descriptor,
|
|
740
854
|
diagnostics: input.diagnostics,
|
|
741
855
|
sourceId: input.sourceId,
|
|
742
856
|
entityLabel: input.entityLabel
|
|
@@ -985,6 +1099,15 @@ function lowerDefaultForField(input) {
|
|
|
985
1099
|
});
|
|
986
1100
|
return {};
|
|
987
1101
|
}
|
|
1102
|
+
if (generatorDescriptor.applicableCodecIds === void 0) {
|
|
1103
|
+
input.diagnostics.push({
|
|
1104
|
+
code: "PSL_INVALID_DEFAULT_APPLICABILITY",
|
|
1105
|
+
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.`,
|
|
1106
|
+
sourceId: input.sourceId,
|
|
1107
|
+
span: expressionEntry.span
|
|
1108
|
+
});
|
|
1109
|
+
return {};
|
|
1110
|
+
}
|
|
988
1111
|
if (!generatorDescriptor.applicableCodecIds.includes(input.columnDescriptor.codecId)) {
|
|
989
1112
|
input.diagnostics.push({
|
|
990
1113
|
code: "PSL_INVALID_DEFAULT_APPLICABILITY",
|
|
@@ -994,7 +1117,7 @@ function lowerDefaultForField(input) {
|
|
|
994
1117
|
});
|
|
995
1118
|
return {};
|
|
996
1119
|
}
|
|
997
|
-
return {
|
|
1120
|
+
return { executionDefaults: { onCreate: lowered.value.generated } };
|
|
998
1121
|
}
|
|
999
1122
|
function resolveColumnDescriptor(field, enumTypeDescriptors, namedTypeDescriptors, scalarTypeDescriptors) {
|
|
1000
1123
|
if (field.typeRef && namedTypeDescriptors.has(field.typeRef)) return namedTypeDescriptors.get(field.typeRef);
|
|
@@ -1002,7 +1125,6 @@ function resolveColumnDescriptor(field, enumTypeDescriptors, namedTypeDescriptor
|
|
|
1002
1125
|
if (enumTypeDescriptors.has(field.typeName)) return enumTypeDescriptors.get(field.typeName);
|
|
1003
1126
|
return scalarTypeDescriptors.get(field.typeName);
|
|
1004
1127
|
}
|
|
1005
|
-
|
|
1006
1128
|
//#endregion
|
|
1007
1129
|
//#region src/psl-field-resolution.ts
|
|
1008
1130
|
const BUILTIN_FIELD_ATTRIBUTE_NAMES = new Set([
|
|
@@ -1012,12 +1134,21 @@ const BUILTIN_FIELD_ATTRIBUTE_NAMES = new Set([
|
|
|
1012
1134
|
"relation",
|
|
1013
1135
|
"map"
|
|
1014
1136
|
]);
|
|
1137
|
+
const REMOVED_ATTRIBUTE_RULES = new Map([["updatedAt", {
|
|
1138
|
+
hint: "Use `temporal.updatedAt()` as a field-preset call instead.",
|
|
1139
|
+
suppressWhen: (field) => field.typeConstructor?.path[0] === "temporal"
|
|
1140
|
+
}]]);
|
|
1141
|
+
{
|
|
1142
|
+
const overlap = [...REMOVED_ATTRIBUTE_RULES.keys()].filter((name) => BUILTIN_FIELD_ATTRIBUTE_NAMES.has(name));
|
|
1143
|
+
if (overlap.length > 0) throw new Error(`BUILTIN_FIELD_ATTRIBUTE_NAMES and REMOVED_ATTRIBUTE_RULES must not overlap. Names in both: ${overlap.join(", ")}`);
|
|
1144
|
+
}
|
|
1015
1145
|
function validateFieldAttributes(input) {
|
|
1016
1146
|
for (const attribute of input.field.attributes) {
|
|
1017
1147
|
if (BUILTIN_FIELD_ATTRIBUTE_NAMES.has(attribute.name)) continue;
|
|
1018
1148
|
const uncomposedNamespace = checkUncomposedNamespace(attribute.name, input.composedExtensions, {
|
|
1019
1149
|
familyId: input.familyId,
|
|
1020
|
-
targetId: input.targetId
|
|
1150
|
+
targetId: input.targetId,
|
|
1151
|
+
authoringContributions: input.authoringContributions
|
|
1021
1152
|
});
|
|
1022
1153
|
if (uncomposedNamespace) {
|
|
1023
1154
|
reportUncomposedNamespace({
|
|
@@ -1029,9 +1160,12 @@ function validateFieldAttributes(input) {
|
|
|
1029
1160
|
});
|
|
1030
1161
|
continue;
|
|
1031
1162
|
}
|
|
1163
|
+
const baseMessage = `Field "${input.model.name}.${input.field.name}" uses unsupported attribute "@${attribute.name}"`;
|
|
1164
|
+
const removedRule = REMOVED_ATTRIBUTE_RULES.get(attribute.name);
|
|
1165
|
+
const message = removedRule && !removedRule.suppressWhen(input.field) ? `${baseMessage}. ${removedRule.hint}` : baseMessage;
|
|
1032
1166
|
input.diagnostics.push({
|
|
1033
1167
|
code: "PSL_UNSUPPORTED_FIELD_ATTRIBUTE",
|
|
1034
|
-
message
|
|
1168
|
+
message,
|
|
1035
1169
|
sourceId: input.sourceId,
|
|
1036
1170
|
span: attribute.span
|
|
1037
1171
|
});
|
|
@@ -1065,21 +1199,25 @@ function collectResolvedFields(input) {
|
|
|
1065
1199
|
const { model, mapping, enumTypeDescriptors, namedTypeDescriptors, modelNames, compositeTypeNames, composedExtensions, authoringContributions, familyId, targetId, defaultFunctionRegistry, generatorDescriptorById, diagnostics, sourceId, scalarTypeDescriptors } = input;
|
|
1066
1200
|
const resolvedFields = [];
|
|
1067
1201
|
for (const field of model.fields) {
|
|
1068
|
-
|
|
1202
|
+
const isModelField = modelNames.has(field.typeName);
|
|
1203
|
+
if (field.list && isModelField) continue;
|
|
1069
1204
|
validateFieldAttributes({
|
|
1070
1205
|
model,
|
|
1071
1206
|
field,
|
|
1072
1207
|
composedExtensions,
|
|
1208
|
+
authoringContributions,
|
|
1073
1209
|
diagnostics,
|
|
1074
1210
|
sourceId,
|
|
1075
1211
|
familyId,
|
|
1076
1212
|
targetId
|
|
1077
1213
|
});
|
|
1078
|
-
|
|
1214
|
+
const relationAttribute = getAttribute(field.attributes, "relation");
|
|
1215
|
+
if (isModelField && relationAttribute) continue;
|
|
1079
1216
|
const isValueObjectField = compositeTypeNames.has(field.typeName);
|
|
1080
1217
|
const isListField = field.list;
|
|
1081
1218
|
let descriptor;
|
|
1082
1219
|
let scalarCodecId;
|
|
1220
|
+
let presetContributions;
|
|
1083
1221
|
const resolveInput = {
|
|
1084
1222
|
field,
|
|
1085
1223
|
enumTypeDescriptors,
|
|
@@ -1105,6 +1243,15 @@ function collectResolvedFields(input) {
|
|
|
1105
1243
|
});
|
|
1106
1244
|
continue;
|
|
1107
1245
|
}
|
|
1246
|
+
if (resolved.presetContributions) {
|
|
1247
|
+
diagnostics.push({
|
|
1248
|
+
code: "PSL_PRESET_NOT_LIST",
|
|
1249
|
+
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.`,
|
|
1250
|
+
sourceId,
|
|
1251
|
+
span: field.span
|
|
1252
|
+
});
|
|
1253
|
+
continue;
|
|
1254
|
+
}
|
|
1108
1255
|
scalarCodecId = resolved.descriptor.codecId;
|
|
1109
1256
|
descriptor = scalarTypeDescriptors.get("Json");
|
|
1110
1257
|
} else {
|
|
@@ -1119,9 +1266,28 @@ function collectResolvedFields(input) {
|
|
|
1119
1266
|
continue;
|
|
1120
1267
|
}
|
|
1121
1268
|
descriptor = resolved.descriptor;
|
|
1269
|
+
presetContributions = resolved.presetContributions;
|
|
1122
1270
|
}
|
|
1123
1271
|
if (!descriptor) continue;
|
|
1272
|
+
if (presetContributions && field.optional) {
|
|
1273
|
+
diagnostics.push({
|
|
1274
|
+
code: "PSL_PRESET_NOT_OPTIONAL",
|
|
1275
|
+
message: `Field "${model.name}.${field.name}" uses a field-preset call and cannot be optional. Remove "?" or use a different field type.`,
|
|
1276
|
+
sourceId,
|
|
1277
|
+
span: field.span
|
|
1278
|
+
});
|
|
1279
|
+
continue;
|
|
1280
|
+
}
|
|
1124
1281
|
const defaultAttribute = getAttribute(field.attributes, "default");
|
|
1282
|
+
if (presetContributions && defaultAttribute) {
|
|
1283
|
+
diagnostics.push({
|
|
1284
|
+
code: "PSL_PRESET_AND_DEFAULT_CONFLICT",
|
|
1285
|
+
message: `Field "${model.name}.${field.name}" uses a field-preset call and cannot also declare @default(...). The preset already specifies the default value.`,
|
|
1286
|
+
sourceId,
|
|
1287
|
+
span: defaultAttribute.span
|
|
1288
|
+
});
|
|
1289
|
+
continue;
|
|
1290
|
+
}
|
|
1125
1291
|
const loweredDefault = defaultAttribute ? lowerDefaultForField({
|
|
1126
1292
|
modelName: model.name,
|
|
1127
1293
|
fieldName: field.name,
|
|
@@ -1132,8 +1298,9 @@ function collectResolvedFields(input) {
|
|
|
1132
1298
|
defaultFunctionRegistry,
|
|
1133
1299
|
diagnostics
|
|
1134
1300
|
}) : {};
|
|
1135
|
-
|
|
1136
|
-
|
|
1301
|
+
const loweredOnCreate = loweredDefault.executionDefaults?.onCreate;
|
|
1302
|
+
if (field.optional && loweredOnCreate) {
|
|
1303
|
+
const generatorDescription = loweredOnCreate.kind === "generator" ? `"${loweredOnCreate.id}"` : "for this field";
|
|
1137
1304
|
diagnostics.push({
|
|
1138
1305
|
code: "PSL_INVALID_DEFAULT_FUNCTION_ARGUMENT",
|
|
1139
1306
|
message: `Field "${model.name}.${field.name}" cannot be optional when using execution default ${generatorDescription}. Remove "?" or use a storage default.`,
|
|
@@ -1142,8 +1309,8 @@ function collectResolvedFields(input) {
|
|
|
1142
1309
|
});
|
|
1143
1310
|
continue;
|
|
1144
1311
|
}
|
|
1145
|
-
if (
|
|
1146
|
-
const generatedDescriptor = generatorDescriptorById.get(
|
|
1312
|
+
if (loweredOnCreate) {
|
|
1313
|
+
const generatedDescriptor = generatorDescriptorById.get(loweredOnCreate.id)?.resolveGeneratedColumnDescriptor?.({ generated: loweredOnCreate });
|
|
1147
1314
|
if (generatedDescriptor) descriptor = generatedDescriptor;
|
|
1148
1315
|
}
|
|
1149
1316
|
const mappedColumnName = mapping.fieldColumns.get(field.name) ?? field.name;
|
|
@@ -1153,14 +1320,35 @@ function collectResolvedFields(input) {
|
|
|
1153
1320
|
sourceId,
|
|
1154
1321
|
diagnostics
|
|
1155
1322
|
});
|
|
1323
|
+
let isIdField = Boolean(idAttribute);
|
|
1324
|
+
if (idAttribute && field.optional) {
|
|
1325
|
+
diagnostics.push({
|
|
1326
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
1327
|
+
message: `Field "${model.name}.${field.name}" @id cannot be optional; primary key columns must be NOT NULL`,
|
|
1328
|
+
sourceId,
|
|
1329
|
+
span: idAttribute.span
|
|
1330
|
+
});
|
|
1331
|
+
isIdField = false;
|
|
1332
|
+
}
|
|
1333
|
+
if (presetContributions && idAttribute && !presetContributions.id) {
|
|
1334
|
+
diagnostics.push({
|
|
1335
|
+
code: "PSL_PRESET_AND_ID_CONFLICT",
|
|
1336
|
+
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.`,
|
|
1337
|
+
sourceId,
|
|
1338
|
+
span: idAttribute.span
|
|
1339
|
+
});
|
|
1340
|
+
continue;
|
|
1341
|
+
}
|
|
1342
|
+
const fieldExecutionDefaults = presetContributions?.executionDefaults ?? loweredDefault.executionDefaults;
|
|
1343
|
+
const fieldDefaultValue = presetContributions?.default ?? loweredDefault.defaultValue;
|
|
1156
1344
|
resolvedFields.push({
|
|
1157
1345
|
field,
|
|
1158
1346
|
columnName: mappedColumnName,
|
|
1159
1347
|
descriptor,
|
|
1160
|
-
...ifDefined("defaultValue",
|
|
1161
|
-
...ifDefined("
|
|
1162
|
-
isId: Boolean(
|
|
1163
|
-
isUnique: Boolean(uniqueAttribute),
|
|
1348
|
+
...ifDefined("defaultValue", fieldDefaultValue),
|
|
1349
|
+
...ifDefined("executionDefaults", fieldExecutionDefaults),
|
|
1350
|
+
isId: isIdField || Boolean(presetContributions?.id),
|
|
1351
|
+
isUnique: Boolean(uniqueAttribute) || Boolean(presetContributions?.unique),
|
|
1164
1352
|
...ifDefined("idName", idName),
|
|
1165
1353
|
...ifDefined("uniqueName", uniqueName),
|
|
1166
1354
|
...ifDefined("many", isListField ? true : void 0),
|
|
@@ -1201,7 +1389,6 @@ function buildModelMappings(models, diagnostics, sourceId) {
|
|
|
1201
1389
|
}
|
|
1202
1390
|
return result;
|
|
1203
1391
|
}
|
|
1204
|
-
|
|
1205
1392
|
//#endregion
|
|
1206
1393
|
//#region src/psl-relation-resolution.ts
|
|
1207
1394
|
const REFERENTIAL_ACTION_MAP = {
|
|
@@ -1418,7 +1605,8 @@ function validateNavigationListFieldAttributes(input) {
|
|
|
1418
1605
|
if (attribute.name === "relation") continue;
|
|
1419
1606
|
const uncomposedNamespace = checkUncomposedNamespace(attribute.name, input.composedExtensions, {
|
|
1420
1607
|
familyId: input.familyId,
|
|
1421
|
-
targetId: input.targetId
|
|
1608
|
+
targetId: input.targetId,
|
|
1609
|
+
authoringContributions: input.authoringContributions
|
|
1422
1610
|
});
|
|
1423
1611
|
if (uncomposedNamespace) {
|
|
1424
1612
|
reportUncomposedNamespace({
|
|
@@ -1441,7 +1629,6 @@ function validateNavigationListFieldAttributes(input) {
|
|
|
1441
1629
|
}
|
|
1442
1630
|
return valid;
|
|
1443
1631
|
}
|
|
1444
|
-
|
|
1445
1632
|
//#endregion
|
|
1446
1633
|
//#region src/interpreter.ts
|
|
1447
1634
|
function buildComposedExtensionPackRefs(target, extensionIds, extensionPackRefs = []) {
|
|
@@ -1531,7 +1718,8 @@ function validateNamedTypeAttributes(input) {
|
|
|
1531
1718
|
if (input.allowDbNativeType && attribute.name.startsWith("db.")) continue;
|
|
1532
1719
|
const uncomposedNamespace = checkUncomposedNamespace(attribute.name, input.composedExtensions, {
|
|
1533
1720
|
familyId: input.familyId,
|
|
1534
|
-
targetId: input.targetId
|
|
1721
|
+
targetId: input.targetId,
|
|
1722
|
+
authoringContributions: input.authoringContributions
|
|
1535
1723
|
});
|
|
1536
1724
|
if (uncomposedNamespace) {
|
|
1537
1725
|
reportUncomposedNamespace({
|
|
@@ -1562,16 +1750,17 @@ function resolveNamedTypeDeclarations(input) {
|
|
|
1562
1750
|
const namedTypeDescriptors = /* @__PURE__ */ new Map();
|
|
1563
1751
|
for (const declaration of input.declarations) {
|
|
1564
1752
|
if (declaration.typeConstructor) {
|
|
1565
|
-
const { hasUnsupportedNamedTypeAttribute
|
|
1753
|
+
const { hasUnsupportedNamedTypeAttribute } = validateNamedTypeAttributes({
|
|
1566
1754
|
declaration,
|
|
1567
1755
|
sourceId: input.sourceId,
|
|
1568
1756
|
diagnostics: input.diagnostics,
|
|
1569
1757
|
composedExtensions: input.composedExtensions,
|
|
1758
|
+
authoringContributions: input.authoringContributions,
|
|
1570
1759
|
allowDbNativeType: false,
|
|
1571
1760
|
familyId: input.familyId,
|
|
1572
1761
|
targetId: input.targetId
|
|
1573
1762
|
});
|
|
1574
|
-
if (hasUnsupportedNamedTypeAttribute
|
|
1763
|
+
if (hasUnsupportedNamedTypeAttribute) continue;
|
|
1575
1764
|
const helperPath = declaration.typeConstructor.path.join(".");
|
|
1576
1765
|
const typeConstructor = resolvePslTypeConstructorDescriptor({
|
|
1577
1766
|
call: declaration.typeConstructor,
|
|
@@ -1626,13 +1815,14 @@ function resolveNamedTypeDeclarations(input) {
|
|
|
1626
1815
|
sourceId: input.sourceId,
|
|
1627
1816
|
diagnostics: input.diagnostics,
|
|
1628
1817
|
composedExtensions: input.composedExtensions,
|
|
1818
|
+
authoringContributions: input.authoringContributions,
|
|
1629
1819
|
allowDbNativeType: true,
|
|
1630
1820
|
familyId: input.familyId,
|
|
1631
1821
|
targetId: input.targetId
|
|
1632
1822
|
});
|
|
1633
1823
|
if (hasUnsupportedNamedTypeAttribute) continue;
|
|
1634
1824
|
if (dbNativeTypeAttribute) {
|
|
1635
|
-
const descriptor
|
|
1825
|
+
const descriptor = resolveDbNativeTypeAttribute({
|
|
1636
1826
|
attribute: dbNativeTypeAttribute,
|
|
1637
1827
|
baseType,
|
|
1638
1828
|
baseDescriptor,
|
|
@@ -1640,12 +1830,12 @@ function resolveNamedTypeDeclarations(input) {
|
|
|
1640
1830
|
sourceId: input.sourceId,
|
|
1641
1831
|
entityLabel: `Named type "${declaration.name}"`
|
|
1642
1832
|
});
|
|
1643
|
-
if (!descriptor
|
|
1644
|
-
namedTypeDescriptors.set(declaration.name, toNamedTypeFieldDescriptor(declaration.name, descriptor
|
|
1833
|
+
if (!descriptor) continue;
|
|
1834
|
+
namedTypeDescriptors.set(declaration.name, toNamedTypeFieldDescriptor(declaration.name, descriptor));
|
|
1645
1835
|
storageTypes[declaration.name] = {
|
|
1646
|
-
codecId: descriptor
|
|
1647
|
-
nativeType: descriptor
|
|
1648
|
-
typeParams: descriptor
|
|
1836
|
+
codecId: descriptor.codecId,
|
|
1837
|
+
nativeType: descriptor.nativeType,
|
|
1838
|
+
typeParams: descriptor.typeParams ?? {}
|
|
1649
1839
|
};
|
|
1650
1840
|
continue;
|
|
1651
1841
|
}
|
|
@@ -1682,16 +1872,20 @@ function buildModelNodeFromPsl(input) {
|
|
|
1682
1872
|
sourceId,
|
|
1683
1873
|
scalarTypeDescriptors: input.scalarTypeDescriptors
|
|
1684
1874
|
});
|
|
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`,
|
|
1875
|
+
const inlineIdFields = resolvedFields.filter((field) => field.isId);
|
|
1876
|
+
if (inlineIdFields.length > 1) diagnostics.push({
|
|
1877
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
1878
|
+
message: `Model "${model.name}" cannot declare inline @id on multiple fields; use model-level @@id([...]) for composite identity`,
|
|
1692
1879
|
sourceId,
|
|
1693
1880
|
span: model.span
|
|
1694
1881
|
});
|
|
1882
|
+
const singleInlineIdField = inlineIdFields.length === 1 ? inlineIdFields[0] : void 0;
|
|
1883
|
+
let primaryKey = singleInlineIdField ? {
|
|
1884
|
+
columns: [singleInlineIdField.columnName],
|
|
1885
|
+
...ifDefined("name", singleInlineIdField.idName)
|
|
1886
|
+
} : void 0;
|
|
1887
|
+
const hasInlinePrimaryKey = primaryKey !== void 0;
|
|
1888
|
+
let blockPrimaryKeyDeclared = false;
|
|
1695
1889
|
const resultBackrelationCandidates = [];
|
|
1696
1890
|
for (const field of model.fields) {
|
|
1697
1891
|
if (!field.list || !input.modelNames.has(field.typeName)) continue;
|
|
@@ -1700,6 +1894,7 @@ function buildModelNodeFromPsl(input) {
|
|
|
1700
1894
|
field,
|
|
1701
1895
|
sourceId,
|
|
1702
1896
|
composedExtensions: input.composedExtensions,
|
|
1897
|
+
authoringContributions: input.authoringContributions,
|
|
1703
1898
|
diagnostics,
|
|
1704
1899
|
familyId: input.familyId,
|
|
1705
1900
|
targetId: input.targetId
|
|
@@ -1757,15 +1952,98 @@ function buildModelNodeFromPsl(input) {
|
|
|
1757
1952
|
for (const modelAttribute of model.attributes) {
|
|
1758
1953
|
if (modelAttribute.name === "map") continue;
|
|
1759
1954
|
if (modelAttribute.name === "discriminator" || modelAttribute.name === "base") continue;
|
|
1955
|
+
const attributeLabel = `Model "${model.name}" @@${modelAttribute.name}`;
|
|
1956
|
+
if (modelAttribute.name === "id") {
|
|
1957
|
+
if (blockPrimaryKeyDeclared) {
|
|
1958
|
+
diagnostics.push({
|
|
1959
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
1960
|
+
message: `Model "${model.name}" declares @@id more than once`,
|
|
1961
|
+
sourceId,
|
|
1962
|
+
span: modelAttribute.span
|
|
1963
|
+
});
|
|
1964
|
+
continue;
|
|
1965
|
+
}
|
|
1966
|
+
if (hasInlinePrimaryKey) {
|
|
1967
|
+
diagnostics.push({
|
|
1968
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
1969
|
+
message: `Model "${model.name}" cannot declare both field-level @id and model-level @@id`,
|
|
1970
|
+
sourceId,
|
|
1971
|
+
span: modelAttribute.span
|
|
1972
|
+
});
|
|
1973
|
+
blockPrimaryKeyDeclared = true;
|
|
1974
|
+
continue;
|
|
1975
|
+
}
|
|
1976
|
+
const fieldNames = parseAttributeFieldList({
|
|
1977
|
+
attribute: modelAttribute,
|
|
1978
|
+
sourceId,
|
|
1979
|
+
diagnostics,
|
|
1980
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
1981
|
+
entityLabel: attributeLabel
|
|
1982
|
+
});
|
|
1983
|
+
if (!fieldNames) continue;
|
|
1984
|
+
const duplicateFieldName = findDuplicateFieldName(fieldNames);
|
|
1985
|
+
if (duplicateFieldName !== void 0) {
|
|
1986
|
+
diagnostics.push({
|
|
1987
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
1988
|
+
message: `${attributeLabel} list contains duplicate field "${duplicateFieldName}"`,
|
|
1989
|
+
sourceId,
|
|
1990
|
+
span: modelAttribute.span
|
|
1991
|
+
});
|
|
1992
|
+
continue;
|
|
1993
|
+
}
|
|
1994
|
+
const nullableFieldName = fieldNames.find((name) => model.fields.find((f) => f.name === name)?.optional === true);
|
|
1995
|
+
if (nullableFieldName !== void 0) {
|
|
1996
|
+
diagnostics.push({
|
|
1997
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
1998
|
+
message: `${attributeLabel} cannot include optional field "${nullableFieldName}"; primary key columns must be NOT NULL`,
|
|
1999
|
+
sourceId,
|
|
2000
|
+
span: modelAttribute.span
|
|
2001
|
+
});
|
|
2002
|
+
continue;
|
|
2003
|
+
}
|
|
2004
|
+
const columnNames = mapFieldNamesToColumns({
|
|
2005
|
+
modelName: model.name,
|
|
2006
|
+
fieldNames,
|
|
2007
|
+
mapping,
|
|
2008
|
+
sourceId,
|
|
2009
|
+
diagnostics,
|
|
2010
|
+
span: modelAttribute.span,
|
|
2011
|
+
entityLabel: attributeLabel
|
|
2012
|
+
});
|
|
2013
|
+
if (!columnNames) continue;
|
|
2014
|
+
primaryKey = {
|
|
2015
|
+
columns: columnNames,
|
|
2016
|
+
...ifDefined("name", parseConstraintMapArgument({
|
|
2017
|
+
attribute: modelAttribute,
|
|
2018
|
+
sourceId,
|
|
2019
|
+
diagnostics,
|
|
2020
|
+
entityLabel: attributeLabel,
|
|
2021
|
+
span: modelAttribute.span,
|
|
2022
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT"
|
|
2023
|
+
}))
|
|
2024
|
+
};
|
|
2025
|
+
blockPrimaryKeyDeclared = true;
|
|
2026
|
+
continue;
|
|
2027
|
+
}
|
|
1760
2028
|
if (modelAttribute.name === "unique" || modelAttribute.name === "index") {
|
|
1761
2029
|
const fieldNames = parseAttributeFieldList({
|
|
1762
2030
|
attribute: modelAttribute,
|
|
1763
2031
|
sourceId,
|
|
1764
2032
|
diagnostics,
|
|
1765
2033
|
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
1766
|
-
|
|
2034
|
+
entityLabel: attributeLabel
|
|
1767
2035
|
});
|
|
1768
2036
|
if (!fieldNames) continue;
|
|
2037
|
+
const duplicateFieldName = findDuplicateFieldName(fieldNames);
|
|
2038
|
+
if (duplicateFieldName !== void 0) {
|
|
2039
|
+
diagnostics.push({
|
|
2040
|
+
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
2041
|
+
message: `${attributeLabel} list contains duplicate field "${duplicateFieldName}"`,
|
|
2042
|
+
sourceId,
|
|
2043
|
+
span: modelAttribute.span
|
|
2044
|
+
});
|
|
2045
|
+
continue;
|
|
2046
|
+
}
|
|
1769
2047
|
const columnNames = mapFieldNamesToColumns({
|
|
1770
2048
|
modelName: model.name,
|
|
1771
2049
|
fieldNames,
|
|
@@ -1773,14 +2051,14 @@ function buildModelNodeFromPsl(input) {
|
|
|
1773
2051
|
sourceId,
|
|
1774
2052
|
diagnostics,
|
|
1775
2053
|
span: modelAttribute.span,
|
|
1776
|
-
|
|
2054
|
+
entityLabel: attributeLabel
|
|
1777
2055
|
});
|
|
1778
2056
|
if (!columnNames) continue;
|
|
1779
2057
|
const constraintName = parseConstraintMapArgument({
|
|
1780
2058
|
attribute: modelAttribute,
|
|
1781
2059
|
sourceId,
|
|
1782
2060
|
diagnostics,
|
|
1783
|
-
entityLabel:
|
|
2061
|
+
entityLabel: attributeLabel,
|
|
1784
2062
|
span: modelAttribute.span,
|
|
1785
2063
|
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT"
|
|
1786
2064
|
});
|
|
@@ -1796,7 +2074,8 @@ function buildModelNodeFromPsl(input) {
|
|
|
1796
2074
|
}
|
|
1797
2075
|
const uncomposedNamespace = checkUncomposedNamespace(modelAttribute.name, input.composedExtensions, {
|
|
1798
2076
|
familyId: input.familyId,
|
|
1799
|
-
targetId: input.targetId
|
|
2077
|
+
targetId: input.targetId,
|
|
2078
|
+
authoringContributions: input.authoringContributions
|
|
1800
2079
|
});
|
|
1801
2080
|
if (uncomposedNamespace) {
|
|
1802
2081
|
reportUncomposedNamespace({
|
|
@@ -1861,7 +2140,7 @@ function buildModelNodeFromPsl(input) {
|
|
|
1861
2140
|
sourceId,
|
|
1862
2141
|
diagnostics,
|
|
1863
2142
|
span: relationAttribute.relation.span,
|
|
1864
|
-
|
|
2143
|
+
entityLabel: `Relation field "${model.name}.${relationAttribute.field.name}"`
|
|
1865
2144
|
});
|
|
1866
2145
|
if (!localColumns) continue;
|
|
1867
2146
|
const referencedColumns = mapFieldNamesToColumns({
|
|
@@ -1871,7 +2150,7 @@ function buildModelNodeFromPsl(input) {
|
|
|
1871
2150
|
sourceId,
|
|
1872
2151
|
diagnostics,
|
|
1873
2152
|
span: relationAttribute.relation.span,
|
|
1874
|
-
|
|
2153
|
+
entityLabel: `Relation field "${model.name}.${relationAttribute.field.name}"`
|
|
1875
2154
|
});
|
|
1876
2155
|
if (!referencedColumns) continue;
|
|
1877
2156
|
if (localColumns.length !== referencedColumns.length) {
|
|
@@ -1933,12 +2212,9 @@ function buildModelNodeFromPsl(input) {
|
|
|
1933
2212
|
descriptor: resolvedField.descriptor,
|
|
1934
2213
|
nullable: resolvedField.field.optional,
|
|
1935
2214
|
...ifDefined("default", resolvedField.defaultValue),
|
|
1936
|
-
...ifDefined("
|
|
2215
|
+
...ifDefined("executionDefaults", resolvedField.executionDefaults)
|
|
1937
2216
|
})),
|
|
1938
|
-
...
|
|
1939
|
-
columns: primaryKeyColumns,
|
|
1940
|
-
...ifDefined("name", primaryKeyName)
|
|
1941
|
-
} } : {},
|
|
2217
|
+
...ifDefined("id", primaryKey),
|
|
1942
2218
|
...uniqueConstraints.length > 0 ? { uniques: uniqueConstraints } : {},
|
|
1943
2219
|
...indexNodes.length > 0 ? { indexes: indexNodes } : {},
|
|
1944
2220
|
...foreignKeyNodes.length > 0 ? { foreignKeys: foreignKeyNodes } : {}
|
|
@@ -2337,7 +2613,7 @@ function interpretPslDocumentToSqlContract(input) {
|
|
|
2337
2613
|
...Object.keys(valueObjects).length > 0 ? { valueObjects } : {}
|
|
2338
2614
|
});
|
|
2339
2615
|
}
|
|
2340
|
-
|
|
2341
2616
|
//#endregion
|
|
2342
2617
|
export { interpretPslDocumentToSqlContract as t };
|
|
2343
|
-
|
|
2618
|
+
|
|
2619
|
+
//# sourceMappingURL=interpreter-C9EP3HJr.mjs.map
|