@prisma-next/sql-contract-psl 0.12.0-dev.47 → 0.12.0-dev.49
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/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{interpreter-BTfcjVFM.mjs → interpreter-Rn_Vzvt-.mjs} +173 -13
- package/dist/interpreter-Rn_Vzvt-.mjs.map +1 -0
- package/dist/provider.mjs +1 -1
- package/package.json +12 -12
- package/src/interpreter.ts +239 -9
- package/dist/interpreter-BTfcjVFM.mjs.map +0 -1
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/psl-column-resolution.ts","../src/interpreter.ts"],"mappings":";;;;;;;;;;;KA0CY,gBAAA;EAAA,SACD,OAAA;EAAA,SACA,UAAA;EAAA,SACA,OAAA;EAAA,SACA,UAAA,GAAa,MAAM;AAAA;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/psl-column-resolution.ts","../src/interpreter.ts"],"mappings":";;;;;;;;;;;KA0CY,gBAAA;EAAA,SACD,OAAA;EAAA,SACA,UAAA;EAAA,SACA,OAAA;EAAA,SACA,UAAA,GAAa,MAAM;AAAA;;;UCiDb,sCAAA;EAAA,SACN,QAAA,EAAU,sBAAA;EAAA,SACV,MAAA,EAAQ,aAAA;EAAA,SACR,qBAAA,EAAuB,WAAA,SAAoB,gBAAA;EAAA,SAC3C,sBAAA;EAAA,SACA,yBAAA,YAAqC,gBAAA;EAAA,SACrC,uBAAA,GAA0B,yBAAA;EAAA,SAC1B,sBAAA,GAAyB,sBAAA;EDxDzB;;;AAAmB;;;;ACiD9B;;EDjDW,SCkEA,eAAA,IAAmB,KAAA,EAAO,uBAAA,KAA4B,SAAA;AAAA;AAAA,iBAwgDjD,iCAAA,CACd,KAAA,EAAO,sCAAA,GACN,MAAA,CAAO,QAAA,EAAU,yBAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as interpretPslDocumentToSqlContract } from "./interpreter-
|
|
1
|
+
import { t as interpretPslDocumentToSqlContract } from "./interpreter-Rn_Vzvt-.mjs";
|
|
2
2
|
export { interpretPslDocumentToSqlContract };
|
|
@@ -2,10 +2,10 @@ import { crossRef } from "@prisma-next/contract/types";
|
|
|
2
2
|
import { hasRegisteredFieldNamespace, instantiateAuthoringEntityType, instantiateAuthoringFieldPreset, instantiateAuthoringTypeConstructor, isAuthoringEntityTypeDescriptor, isAuthoringFieldPresetDescriptor, isAuthoringTypeConstructorDescriptor, validateAuthoringHelperArguments } from "@prisma-next/framework-components/authoring";
|
|
3
3
|
import { isPostgresEnumStorageEntry } from "@prisma-next/sql-contract/types";
|
|
4
4
|
import { buildSqlContractFromDefinition } from "@prisma-next/sql-contract-ts/contract-builder";
|
|
5
|
+
import { blindCast } from "@prisma-next/utils/casts";
|
|
5
6
|
import { ifDefined } from "@prisma-next/utils/defined";
|
|
6
7
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
7
8
|
import { getPositionalArgument, parseQuotedStringLiteral } from "@prisma-next/psl-parser";
|
|
8
|
-
import { blindCast } from "@prisma-next/utils/casts";
|
|
9
9
|
import { assertDefined, invariant } from "@prisma-next/utils/assertions";
|
|
10
10
|
//#region src/psl-attribute-parsing.ts
|
|
11
11
|
function lowerFirst(value) {
|
|
@@ -2757,8 +2757,16 @@ function collectPolymorphismDeclarations(models, sourceId, diagnostics) {
|
|
|
2757
2757
|
baseDeclarations
|
|
2758
2758
|
};
|
|
2759
2759
|
}
|
|
2760
|
-
function resolvePolymorphism(models, discriminatorDeclarations, baseDeclarations, modelNames, modelMappings, modelNamespaceIds, defaultNamespaceId, sourceId, diagnostics) {
|
|
2760
|
+
function resolvePolymorphism(models, discriminatorDeclarations, baseDeclarations, modelNames, modelMappings, modelNamespaceIds, defaultNamespaceId, syntheticPkFieldsByVariant, stiBaseFieldsByBase, sourceId, diagnostics) {
|
|
2761
2761
|
let patched = models;
|
|
2762
|
+
for (const [baseName, fieldNames] of stiBaseFieldsByBase) {
|
|
2763
|
+
const baseModel = patched[baseName];
|
|
2764
|
+
if (!baseModel || fieldNames.length === 0) continue;
|
|
2765
|
+
patched = {
|
|
2766
|
+
...patched,
|
|
2767
|
+
[baseName]: stripStorageOnlyDomainFields(baseModel, fieldNames)
|
|
2768
|
+
};
|
|
2769
|
+
}
|
|
2762
2770
|
for (const [modelName, decl] of discriminatorDeclarations) {
|
|
2763
2771
|
if (baseDeclarations.has(modelName)) {
|
|
2764
2772
|
diagnostics.push({
|
|
@@ -2840,20 +2848,168 @@ function resolvePolymorphism(models, discriminatorDeclarations, baseDeclarations
|
|
|
2840
2848
|
const baseMapping = modelMappings.get(baseDecl.baseName);
|
|
2841
2849
|
const variantMapping = modelMappings.get(variantName);
|
|
2842
2850
|
const resolvedTable = variantMapping?.model.attributes.some((attr) => attr.name === "map") ?? false ? variantMapping?.tableName : baseMapping?.tableName;
|
|
2851
|
+
const patchedVariant = {
|
|
2852
|
+
...variantModel,
|
|
2853
|
+
base: crossRef(baseDecl.baseName, modelNamespaceIds.get(baseDecl.baseName) ?? defaultNamespaceId),
|
|
2854
|
+
...resolvedTable ? { storage: {
|
|
2855
|
+
...variantModel.storage,
|
|
2856
|
+
table: resolvedTable
|
|
2857
|
+
} } : {}
|
|
2858
|
+
};
|
|
2843
2859
|
patched = {
|
|
2844
2860
|
...patched,
|
|
2845
|
-
[variantName]:
|
|
2846
|
-
...variantModel,
|
|
2847
|
-
base: crossRef(baseDecl.baseName, modelNamespaceIds.get(baseDecl.baseName) ?? defaultNamespaceId),
|
|
2848
|
-
...resolvedTable ? { storage: {
|
|
2849
|
-
...variantModel.storage,
|
|
2850
|
-
table: resolvedTable
|
|
2851
|
-
} } : {}
|
|
2852
|
-
}
|
|
2861
|
+
[variantName]: stripStorageOnlyDomainFields(patchedVariant, syntheticPkFieldsByVariant.get(variantName) ?? [])
|
|
2853
2862
|
};
|
|
2854
2863
|
}
|
|
2855
2864
|
return patched;
|
|
2856
2865
|
}
|
|
2866
|
+
/**
|
|
2867
|
+
* Multi-table-inheritance variants (`@@base` + their own `@@map`) live in a
|
|
2868
|
+
* separate table from their base. The ORM joins that table to the base on the
|
|
2869
|
+
* shared primary key (`base.id = variant.id`), so the variant storage table
|
|
2870
|
+
* must carry the base PK column even though the variant domain model declares
|
|
2871
|
+
* only its own fields. This enriches each MTI variant's `ModelNode` with that
|
|
2872
|
+
* link column, a primary key on it, and a FK back to the base table.
|
|
2873
|
+
*
|
|
2874
|
+
* The link column is reported back per variant in `syntheticPkFieldsByVariant`
|
|
2875
|
+
* so the domain-model patch can drop it again — keeping the variant's domain
|
|
2876
|
+
* surface thin (its create/read inputs don't gain a redundant `id`) while the
|
|
2877
|
+
* storage table stays joinable. Single-table-inheritance variants (no own
|
|
2878
|
+
* table) are left untouched.
|
|
2879
|
+
*/
|
|
2880
|
+
function materializeMtiVariantStorageLinks(modelNodes, baseDeclarations, stiVariantNames) {
|
|
2881
|
+
const nodeByModel = new Map(modelNodes.map((node) => [node.modelName, node]));
|
|
2882
|
+
const syntheticPkFieldsByVariant = /* @__PURE__ */ new Map();
|
|
2883
|
+
return {
|
|
2884
|
+
modelNodes: modelNodes.map((node) => {
|
|
2885
|
+
const baseDecl = baseDeclarations.get(node.modelName);
|
|
2886
|
+
if (!baseDecl) return node;
|
|
2887
|
+
const baseNode = nodeByModel.get(baseDecl.baseName);
|
|
2888
|
+
if (!baseNode) return node;
|
|
2889
|
+
if (stiVariantNames.has(node.modelName)) return node;
|
|
2890
|
+
const basePrimaryKey = baseNode.id;
|
|
2891
|
+
if (!basePrimaryKey || basePrimaryKey.columns.length === 0) return node;
|
|
2892
|
+
const existingColumns = new Set(node.fields.map((field) => field.columnName));
|
|
2893
|
+
const linkFields = [];
|
|
2894
|
+
for (const pkColumn of basePrimaryKey.columns) {
|
|
2895
|
+
if (existingColumns.has(pkColumn)) continue;
|
|
2896
|
+
const baseField = baseNode.fields.find((field) => "descriptor" in field && field.columnName === pkColumn);
|
|
2897
|
+
if (!baseField) continue;
|
|
2898
|
+
linkFields.push({
|
|
2899
|
+
fieldName: baseField.fieldName,
|
|
2900
|
+
columnName: pkColumn,
|
|
2901
|
+
descriptor: baseField.descriptor,
|
|
2902
|
+
nullable: false
|
|
2903
|
+
});
|
|
2904
|
+
}
|
|
2905
|
+
if (linkFields.length === 0) return node;
|
|
2906
|
+
syntheticPkFieldsByVariant.set(node.modelName, linkFields.map((field) => field.fieldName));
|
|
2907
|
+
const foreignKey = {
|
|
2908
|
+
columns: basePrimaryKey.columns,
|
|
2909
|
+
references: {
|
|
2910
|
+
model: baseNode.modelName,
|
|
2911
|
+
table: baseNode.tableName,
|
|
2912
|
+
columns: basePrimaryKey.columns,
|
|
2913
|
+
...ifDefined("namespaceId", baseNode.namespaceId)
|
|
2914
|
+
},
|
|
2915
|
+
constraint: true,
|
|
2916
|
+
index: false,
|
|
2917
|
+
onDelete: "cascade"
|
|
2918
|
+
};
|
|
2919
|
+
return {
|
|
2920
|
+
...node,
|
|
2921
|
+
fields: [...linkFields, ...node.fields],
|
|
2922
|
+
id: { columns: basePrimaryKey.columns },
|
|
2923
|
+
foreignKeys: [...node.foreignKeys ?? [], foreignKey]
|
|
2924
|
+
};
|
|
2925
|
+
}),
|
|
2926
|
+
syntheticPkFieldsByVariant
|
|
2927
|
+
};
|
|
2928
|
+
}
|
|
2929
|
+
/**
|
|
2930
|
+
* Single-table-inheritance variants (`@@base` with no own `@@map`) share the
|
|
2931
|
+
* base table: `resolvePolymorphism` points the variant's `storage.table` at the
|
|
2932
|
+
* base, and the ORM reads variant-declared fields straight off the base table.
|
|
2933
|
+
* For that to validate and round-trip, the base storage table must physically
|
|
2934
|
+
* carry every STI variant's declared columns. This enriches the base
|
|
2935
|
+
* `ModelNode` with those columns.
|
|
2936
|
+
*
|
|
2937
|
+
* The materialised columns are always nullable in storage: the base table hosts
|
|
2938
|
+
* every variant's rows, so a column a variant declares as required is still
|
|
2939
|
+
* NULL on sibling-variant rows. The variant's domain field keeps its declared
|
|
2940
|
+
* nullability — required-in-domain / nullable-in-storage is the intended STI
|
|
2941
|
+
* shape.
|
|
2942
|
+
*
|
|
2943
|
+
* Collisions (two variants declaring the same column, or a variant column name
|
|
2944
|
+
* clashing with a base column) are resolved skip-if-exists here, mirroring the
|
|
2945
|
+
* MTI link guard; surfacing them as diagnostics is tracked separately
|
|
2946
|
+
* (TML-2827).
|
|
2947
|
+
*/
|
|
2948
|
+
function materializeStiVariantStorageColumns(modelNodes, baseDeclarations, stiVariantNames) {
|
|
2949
|
+
if (stiVariantNames.size === 0) return {
|
|
2950
|
+
modelNodes: [...modelNodes],
|
|
2951
|
+
stiBaseFieldsByBase: /* @__PURE__ */ new Map()
|
|
2952
|
+
};
|
|
2953
|
+
const nodeByModel = new Map(modelNodes.map((node) => [node.modelName, node]));
|
|
2954
|
+
const stiColumnsByBase = /* @__PURE__ */ new Map();
|
|
2955
|
+
for (const variantName of stiVariantNames) {
|
|
2956
|
+
const variantNode = nodeByModel.get(variantName);
|
|
2957
|
+
const baseDecl = baseDeclarations.get(variantName);
|
|
2958
|
+
if (!variantNode || !baseDecl) continue;
|
|
2959
|
+
const baseNode = nodeByModel.get(baseDecl.baseName);
|
|
2960
|
+
if (!baseNode) continue;
|
|
2961
|
+
const baseColumns = new Set(baseNode.fields.map((field) => field.columnName));
|
|
2962
|
+
const claimed = stiColumnsByBase.get(baseDecl.baseName) ?? [];
|
|
2963
|
+
const claimedColumns = new Set(claimed.map((field) => field.columnName));
|
|
2964
|
+
for (const field of variantNode.fields) {
|
|
2965
|
+
if (baseColumns.has(field.columnName) || claimedColumns.has(field.columnName)) continue;
|
|
2966
|
+
claimedColumns.add(field.columnName);
|
|
2967
|
+
claimed.push({
|
|
2968
|
+
...field,
|
|
2969
|
+
nullable: true
|
|
2970
|
+
});
|
|
2971
|
+
}
|
|
2972
|
+
stiColumnsByBase.set(baseDecl.baseName, claimed);
|
|
2973
|
+
}
|
|
2974
|
+
const stiBaseFieldsByBase = /* @__PURE__ */ new Map();
|
|
2975
|
+
for (const [baseName, columns] of stiColumnsByBase) stiBaseFieldsByBase.set(baseName, columns.map((field) => field.fieldName));
|
|
2976
|
+
return {
|
|
2977
|
+
modelNodes: modelNodes.map((node) => {
|
|
2978
|
+
if (stiVariantNames.has(node.modelName)) return {
|
|
2979
|
+
...node,
|
|
2980
|
+
sharesBaseTable: true
|
|
2981
|
+
};
|
|
2982
|
+
const stiColumns = stiColumnsByBase.get(node.modelName);
|
|
2983
|
+
if (!stiColumns || stiColumns.length === 0) return node;
|
|
2984
|
+
return {
|
|
2985
|
+
...node,
|
|
2986
|
+
fields: [...node.fields, ...stiColumns]
|
|
2987
|
+
};
|
|
2988
|
+
}),
|
|
2989
|
+
stiBaseFieldsByBase
|
|
2990
|
+
};
|
|
2991
|
+
}
|
|
2992
|
+
/**
|
|
2993
|
+
* Drop the storage-only link fields (added by
|
|
2994
|
+
* {@link materializeMtiVariantStorageLinks}) from a variant's domain model, so
|
|
2995
|
+
* the domain surface stays thin while the storage table keeps the link column.
|
|
2996
|
+
*/
|
|
2997
|
+
function stripStorageOnlyDomainFields(model, fieldNames) {
|
|
2998
|
+
if (fieldNames.length === 0) return model;
|
|
2999
|
+
const fields = { ...model.fields };
|
|
3000
|
+
for (const name of fieldNames) delete fields[name];
|
|
3001
|
+
const storage = blindCast(model.storage);
|
|
3002
|
+
const storageFields = { ...storage.fields };
|
|
3003
|
+
for (const name of fieldNames) delete storageFields[name];
|
|
3004
|
+
return {
|
|
3005
|
+
...model,
|
|
3006
|
+
fields,
|
|
3007
|
+
storage: {
|
|
3008
|
+
...storage,
|
|
3009
|
+
fields: storageFields
|
|
3010
|
+
}
|
|
3011
|
+
};
|
|
3012
|
+
}
|
|
2857
3013
|
function interpretPslDocumentToSqlContract(input) {
|
|
2858
3014
|
const sourceId = input.document.ast.sourceId;
|
|
2859
3015
|
if (!input.target) return notOk({
|
|
@@ -2998,6 +3154,10 @@ function interpretPslDocumentToSqlContract(input) {
|
|
|
2998
3154
|
sourceId
|
|
2999
3155
|
});
|
|
3000
3156
|
const { discriminatorDeclarations, baseDeclarations } = collectPolymorphismDeclarations(models, sourceId, diagnostics);
|
|
3157
|
+
const stiVariantNames = /* @__PURE__ */ new Set();
|
|
3158
|
+
for (const variantName of baseDeclarations.keys()) if (!(modelMappings.get(variantName)?.model.attributes.some((attr) => attr.name === "map") ?? false)) stiVariantNames.add(variantName);
|
|
3159
|
+
const { modelNodes: mtiLinkedModelNodes, syntheticPkFieldsByVariant } = materializeMtiVariantStorageLinks(modelNodes, baseDeclarations, stiVariantNames);
|
|
3160
|
+
const { modelNodes: stiColumnModelNodes, stiBaseFieldsByBase } = materializeStiVariantStorageColumns(mtiLinkedModelNodes, baseDeclarations, stiVariantNames);
|
|
3001
3161
|
const valueObjects = buildValueObjects({
|
|
3002
3162
|
compositeTypes,
|
|
3003
3163
|
enumTypeDescriptors: allEnumTypeDescriptors,
|
|
@@ -3020,7 +3180,7 @@ function interpretPslDocumentToSqlContract(input) {
|
|
|
3020
3180
|
...Object.keys(storageTypes).length > 0 ? { storageTypes } : {},
|
|
3021
3181
|
...Object.keys(namespaceEnumStorageTypes).length > 0 ? { namespaceTypes: namespaceEnumStorageTypes } : {},
|
|
3022
3182
|
...ifDefined("createNamespace", input.createNamespace),
|
|
3023
|
-
models:
|
|
3183
|
+
models: stiColumnModelNodes.map((model) => ({
|
|
3024
3184
|
...model,
|
|
3025
3185
|
...modelRelations.has(model.modelName) ? { relations: [...modelRelations.get(model.modelName) ?? []].sort((left, right) => compareStrings(left.fieldName, right.fieldName)) } : {}
|
|
3026
3186
|
}))
|
|
@@ -3032,7 +3192,7 @@ function interpretPslDocumentToSqlContract(input) {
|
|
|
3032
3192
|
}
|
|
3033
3193
|
let patchedModels = patchModelDomainFields(modelsForPatch, modelResolvedFields);
|
|
3034
3194
|
const polyDiagnostics = [];
|
|
3035
|
-
patchedModels = resolvePolymorphism(patchedModels, discriminatorDeclarations, baseDeclarations, modelNames, modelMappings, modelNamespaceIds, input.target.defaultNamespaceId, sourceId, polyDiagnostics);
|
|
3195
|
+
patchedModels = resolvePolymorphism(patchedModels, discriminatorDeclarations, baseDeclarations, modelNames, modelMappings, modelNamespaceIds, input.target.defaultNamespaceId, syntheticPkFieldsByVariant, stiBaseFieldsByBase, sourceId, polyDiagnostics);
|
|
3036
3196
|
if (polyDiagnostics.length > 0) return notOk({
|
|
3037
3197
|
summary: "PSL to SQL contract interpretation failed",
|
|
3038
3198
|
diagnostics: polyDiagnostics
|
|
@@ -3052,4 +3212,4 @@ function interpretPslDocumentToSqlContract(input) {
|
|
|
3052
3212
|
//#endregion
|
|
3053
3213
|
export { interpretPslDocumentToSqlContract as t };
|
|
3054
3214
|
|
|
3055
|
-
//# sourceMappingURL=interpreter-
|
|
3215
|
+
//# sourceMappingURL=interpreter-Rn_Vzvt-.mjs.map
|