prisma-sql 1.54.0 → 1.56.0
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/generator.cjs +117 -124
- package/dist/generator.cjs.map +1 -1
- package/dist/generator.js +117 -124
- package/dist/generator.js.map +1 -1
- package/dist/index.cjs +829 -79
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +73 -61
- package/dist/index.d.ts +73 -61
- package/dist/index.js +824 -80
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/generator.cjs
CHANGED
|
@@ -56,7 +56,7 @@ var require_package = __commonJS({
|
|
|
56
56
|
"package.json"(exports$1, module) {
|
|
57
57
|
module.exports = {
|
|
58
58
|
name: "prisma-sql",
|
|
59
|
-
version: "1.
|
|
59
|
+
version: "1.56.0",
|
|
60
60
|
description: "Convert Prisma queries to optimized SQL with type safety. 2-7x faster than Prisma Client.",
|
|
61
61
|
main: "dist/index.cjs",
|
|
62
62
|
module: "dist/index.js",
|
|
@@ -815,6 +815,9 @@ function assertNoControlChars(label, s) {
|
|
|
815
815
|
);
|
|
816
816
|
}
|
|
817
817
|
}
|
|
818
|
+
function quoteRawIdent(id) {
|
|
819
|
+
return `"${id.replace(/"/g, '""')}"`;
|
|
820
|
+
}
|
|
818
821
|
function isIdentCharCode(c) {
|
|
819
822
|
return c >= 48 && c <= 57 || c >= 65 && c <= 90 || c >= 97 && c <= 122 || c === 95;
|
|
820
823
|
}
|
|
@@ -836,33 +839,33 @@ function parseQuotedPart(input, start) {
|
|
|
836
839
|
}
|
|
837
840
|
if (!sawAny) {
|
|
838
841
|
throw new Error(
|
|
839
|
-
`
|
|
842
|
+
`qualified name has empty quoted identifier part: ${JSON.stringify(input)}`
|
|
840
843
|
);
|
|
841
844
|
}
|
|
842
845
|
return i + 1;
|
|
843
846
|
}
|
|
844
847
|
if (c === 10 || c === 13 || c === 0) {
|
|
845
848
|
throw new Error(
|
|
846
|
-
`
|
|
849
|
+
`qualified name contains invalid characters: ${JSON.stringify(input)}`
|
|
847
850
|
);
|
|
848
851
|
}
|
|
849
852
|
sawAny = true;
|
|
850
853
|
i++;
|
|
851
854
|
}
|
|
852
855
|
throw new Error(
|
|
853
|
-
`
|
|
856
|
+
`qualified name has unterminated quoted identifier: ${JSON.stringify(input)}`
|
|
854
857
|
);
|
|
855
858
|
}
|
|
856
859
|
function parseUnquotedPart(input, start) {
|
|
857
860
|
const n = input.length;
|
|
858
861
|
let i = start;
|
|
859
862
|
if (i >= n) {
|
|
860
|
-
throw new Error(`
|
|
863
|
+
throw new Error(`qualified name is invalid: ${JSON.stringify(input)}`);
|
|
861
864
|
}
|
|
862
865
|
const c0 = input.charCodeAt(i);
|
|
863
866
|
if (!isIdentStartCharCode(c0)) {
|
|
864
867
|
throw new Error(
|
|
865
|
-
`
|
|
868
|
+
`qualified name must use identifiers (or quoted identifiers). Got: ${JSON.stringify(input)}`
|
|
866
869
|
);
|
|
867
870
|
}
|
|
868
871
|
i++;
|
|
@@ -871,15 +874,15 @@ function parseUnquotedPart(input, start) {
|
|
|
871
874
|
if (c === 46) break;
|
|
872
875
|
if (!isIdentCharCode(c)) {
|
|
873
876
|
throw new Error(
|
|
874
|
-
`
|
|
877
|
+
`qualified name contains invalid identifier characters: ${JSON.stringify(input)}`
|
|
875
878
|
);
|
|
876
879
|
}
|
|
877
880
|
i++;
|
|
878
881
|
}
|
|
879
882
|
return i;
|
|
880
883
|
}
|
|
881
|
-
function assertSafeQualifiedName(
|
|
882
|
-
const raw = String(
|
|
884
|
+
function assertSafeQualifiedName(input) {
|
|
885
|
+
const raw = String(input);
|
|
883
886
|
const trimmed = raw.trim();
|
|
884
887
|
if (trimmed.length === 0) {
|
|
885
888
|
throw new Error("tableName/tableRef is required and cannot be empty");
|
|
@@ -953,7 +956,7 @@ function quote2(id) {
|
|
|
953
956
|
);
|
|
954
957
|
}
|
|
955
958
|
if (needsQuoting(id)) {
|
|
956
|
-
return
|
|
959
|
+
return quoteRawIdent(id);
|
|
957
960
|
}
|
|
958
961
|
return id;
|
|
959
962
|
}
|
|
@@ -2592,28 +2595,24 @@ function buildOperator(expr, op, val, ctx, mode, fieldType) {
|
|
|
2592
2595
|
function toSafeSqlIdentifier(input) {
|
|
2593
2596
|
const raw = String(input);
|
|
2594
2597
|
const n = raw.length;
|
|
2598
|
+
if (n === 0) return "_t";
|
|
2595
2599
|
let out = "";
|
|
2596
2600
|
for (let i = 0; i < n; i++) {
|
|
2597
2601
|
const c = raw.charCodeAt(i);
|
|
2598
2602
|
const isAZ = c >= 65 && c <= 90 || c >= 97 && c <= 122;
|
|
2599
2603
|
const is09 = c >= 48 && c <= 57;
|
|
2600
2604
|
const isUnderscore = c === 95;
|
|
2601
|
-
|
|
2602
|
-
out += raw[i];
|
|
2603
|
-
} else {
|
|
2604
|
-
out += "_";
|
|
2605
|
-
}
|
|
2605
|
+
out += isAZ || is09 || isUnderscore ? raw[i] : "_";
|
|
2606
2606
|
}
|
|
2607
|
-
if (out.length === 0) out = "_t";
|
|
2608
2607
|
const c0 = out.charCodeAt(0);
|
|
2609
2608
|
const startsOk = c0 >= 65 && c0 <= 90 || c0 >= 97 && c0 <= 122 || c0 === 95;
|
|
2610
|
-
|
|
2611
|
-
const lowered = out.toLowerCase();
|
|
2609
|
+
const lowered = (startsOk ? out : `_${out}`).toLowerCase();
|
|
2612
2610
|
return ALIAS_FORBIDDEN_KEYWORDS.has(lowered) ? `_${lowered}` : lowered;
|
|
2613
2611
|
}
|
|
2614
2612
|
function createAliasGenerator(maxAliases = 1e4) {
|
|
2615
2613
|
let counter = 0;
|
|
2616
2614
|
const usedAliases = /* @__PURE__ */ new Set();
|
|
2615
|
+
const maxLen = 63;
|
|
2617
2616
|
return {
|
|
2618
2617
|
next(baseName) {
|
|
2619
2618
|
if (usedAliases.size >= maxAliases) {
|
|
@@ -2623,14 +2622,13 @@ function createAliasGenerator(maxAliases = 1e4) {
|
|
|
2623
2622
|
}
|
|
2624
2623
|
const base = toSafeSqlIdentifier(baseName);
|
|
2625
2624
|
const suffix = `_${counter}`;
|
|
2626
|
-
const maxLen = 63;
|
|
2627
2625
|
const baseMax = Math.max(1, maxLen - suffix.length);
|
|
2628
2626
|
const trimmedBase = base.length > baseMax ? base.slice(0, baseMax) : base;
|
|
2629
2627
|
const alias = `${trimmedBase}${suffix}`;
|
|
2630
2628
|
counter += 1;
|
|
2631
2629
|
if (usedAliases.has(alias)) {
|
|
2632
2630
|
throw new Error(
|
|
2633
|
-
`CRITICAL: Duplicate alias '${alias}' at counter=${counter}
|
|
2631
|
+
`CRITICAL: Duplicate alias '${alias}' at counter=${counter}.`
|
|
2634
2632
|
);
|
|
2635
2633
|
}
|
|
2636
2634
|
usedAliases.add(alias);
|
|
@@ -2682,24 +2680,19 @@ function normalizeDynamicNameOrThrow(dynamicName, index) {
|
|
|
2682
2680
|
}
|
|
2683
2681
|
return dn;
|
|
2684
2682
|
}
|
|
2685
|
-
function assertUniqueDynamicName(dn, seen) {
|
|
2686
|
-
if (seen.has(dn)) {
|
|
2687
|
-
throw new Error(`CRITICAL: Duplicate dynamic param name in mappings: ${dn}`);
|
|
2688
|
-
}
|
|
2689
|
-
seen.add(dn);
|
|
2690
|
-
}
|
|
2691
|
-
function validateMappingEntry(m, expectedIndex, seenDynamic) {
|
|
2692
|
-
assertSequentialIndex(m.index, expectedIndex);
|
|
2693
|
-
assertExactlyOneOfDynamicOrValue(m);
|
|
2694
|
-
if (typeof m.dynamicName === "string") {
|
|
2695
|
-
const dn = normalizeDynamicNameOrThrow(m.dynamicName, m.index);
|
|
2696
|
-
assertUniqueDynamicName(dn, seenDynamic);
|
|
2697
|
-
}
|
|
2698
|
-
}
|
|
2699
2683
|
function validateMappings(mappings) {
|
|
2700
2684
|
const seenDynamic = /* @__PURE__ */ new Set();
|
|
2701
2685
|
for (let i = 0; i < mappings.length; i++) {
|
|
2702
|
-
|
|
2686
|
+
const m = mappings[i];
|
|
2687
|
+
assertSequentialIndex(m.index, i + 1);
|
|
2688
|
+
assertExactlyOneOfDynamicOrValue(m);
|
|
2689
|
+
if (typeof m.dynamicName === "string") {
|
|
2690
|
+
const dn = normalizeDynamicNameOrThrow(m.dynamicName, m.index);
|
|
2691
|
+
if (seenDynamic.has(dn)) {
|
|
2692
|
+
throw new Error(`CRITICAL: Duplicate dynamic param name: ${dn}`);
|
|
2693
|
+
}
|
|
2694
|
+
seenDynamic.add(dn);
|
|
2695
|
+
}
|
|
2703
2696
|
}
|
|
2704
2697
|
}
|
|
2705
2698
|
function validateState(params, mappings, index) {
|
|
@@ -2711,16 +2704,19 @@ function validateState(params, mappings, index) {
|
|
|
2711
2704
|
}
|
|
2712
2705
|
function createStoreInternal(startIndex, initialParams = [], initialMappings = []) {
|
|
2713
2706
|
let index = startIndex;
|
|
2714
|
-
const params = initialParams.length > 0 ?
|
|
2715
|
-
const mappings = initialMappings.length > 0 ?
|
|
2707
|
+
const params = initialParams.length > 0 ? initialParams.slice() : [];
|
|
2708
|
+
const mappings = initialMappings.length > 0 ? initialMappings.slice() : [];
|
|
2716
2709
|
const dynamicNameToIndex = /* @__PURE__ */ new Map();
|
|
2717
|
-
for (
|
|
2710
|
+
for (let i = 0; i < mappings.length; i++) {
|
|
2711
|
+
const m = mappings[i];
|
|
2718
2712
|
if (typeof m.dynamicName === "string") {
|
|
2719
2713
|
dynamicNameToIndex.set(m.dynamicName.trim(), m.index);
|
|
2720
2714
|
}
|
|
2721
2715
|
}
|
|
2722
2716
|
let dirty = true;
|
|
2723
2717
|
let cachedSnapshot = null;
|
|
2718
|
+
let frozenParams = null;
|
|
2719
|
+
let frozenMappings = null;
|
|
2724
2720
|
function assertCanAdd() {
|
|
2725
2721
|
if (index > MAX_PARAM_INDEX) {
|
|
2726
2722
|
throw new Error(
|
|
@@ -2772,13 +2768,17 @@ function createStoreInternal(startIndex, initialParams = [], initialMappings = [
|
|
|
2772
2768
|
}
|
|
2773
2769
|
function snapshot() {
|
|
2774
2770
|
if (!dirty && cachedSnapshot) return cachedSnapshot;
|
|
2771
|
+
if (!frozenParams) frozenParams = Object.freeze(params.slice());
|
|
2772
|
+
if (!frozenMappings) frozenMappings = Object.freeze(mappings.slice());
|
|
2775
2773
|
const snap = {
|
|
2776
2774
|
index,
|
|
2777
|
-
params,
|
|
2778
|
-
mappings
|
|
2775
|
+
params: frozenParams,
|
|
2776
|
+
mappings: frozenMappings
|
|
2779
2777
|
};
|
|
2780
2778
|
cachedSnapshot = snap;
|
|
2781
2779
|
dirty = false;
|
|
2780
|
+
frozenParams = null;
|
|
2781
|
+
frozenMappings = null;
|
|
2782
2782
|
return snap;
|
|
2783
2783
|
}
|
|
2784
2784
|
return {
|
|
@@ -2802,11 +2802,11 @@ function createParamStore(startIndex = 1) {
|
|
|
2802
2802
|
return createStoreInternal(startIndex);
|
|
2803
2803
|
}
|
|
2804
2804
|
function createParamStoreFrom(existingParams, existingMappings, nextIndex) {
|
|
2805
|
-
validateState(
|
|
2805
|
+
validateState(existingParams, existingMappings, nextIndex);
|
|
2806
2806
|
return createStoreInternal(
|
|
2807
2807
|
nextIndex,
|
|
2808
|
-
|
|
2809
|
-
|
|
2808
|
+
existingParams.slice(),
|
|
2809
|
+
existingMappings.slice()
|
|
2810
2810
|
);
|
|
2811
2811
|
}
|
|
2812
2812
|
|
|
@@ -2988,7 +2988,7 @@ function getRelationTableReference(relModel, dialect) {
|
|
|
2988
2988
|
dialect
|
|
2989
2989
|
);
|
|
2990
2990
|
}
|
|
2991
|
-
function resolveRelationOrThrow(model,
|
|
2991
|
+
function resolveRelationOrThrow(model, schemaByName, relName) {
|
|
2992
2992
|
const field = model.fields.find((f) => f.name === relName);
|
|
2993
2993
|
if (!isNotNullish(field)) {
|
|
2994
2994
|
throw new Error(
|
|
@@ -3042,8 +3042,9 @@ function validateOrderByForModel(model, orderBy) {
|
|
|
3042
3042
|
throw new Error("orderBy array entries must have exactly one field");
|
|
3043
3043
|
}
|
|
3044
3044
|
const fieldName = String(entries[0][0]).trim();
|
|
3045
|
-
if (fieldName.length === 0)
|
|
3045
|
+
if (fieldName.length === 0) {
|
|
3046
3046
|
throw new Error("orderBy field name cannot be empty");
|
|
3047
|
+
}
|
|
3047
3048
|
if (!scalarSet.has(fieldName)) {
|
|
3048
3049
|
throw new Error(
|
|
3049
3050
|
`orderBy references unknown or non-scalar field '${fieldName}' on model ${model.name}`
|
|
@@ -3102,8 +3103,9 @@ function extractRelationPaginationConfig(relArgs) {
|
|
|
3102
3103
|
function maybeReverseNegativeTake(takeVal, hasOrderBy, orderByInput) {
|
|
3103
3104
|
if (typeof takeVal !== "number") return { takeVal, orderByInput };
|
|
3104
3105
|
if (takeVal >= 0) return { takeVal, orderByInput };
|
|
3105
|
-
if (!hasOrderBy)
|
|
3106
|
+
if (!hasOrderBy) {
|
|
3106
3107
|
throw new Error("Negative take requires orderBy for deterministic results");
|
|
3108
|
+
}
|
|
3107
3109
|
return {
|
|
3108
3110
|
takeVal: Math.abs(takeVal),
|
|
3109
3111
|
orderByInput: reverseOrderByInput(orderByInput)
|
|
@@ -3113,9 +3115,7 @@ function finalizeOrderByForInclude(args) {
|
|
|
3113
3115
|
if (args.hasOrderBy && isNotNullish(args.orderByInput)) {
|
|
3114
3116
|
validateOrderByForModel(args.relModel, args.orderByInput);
|
|
3115
3117
|
}
|
|
3116
|
-
if (!args.hasPagination)
|
|
3117
|
-
return args.orderByInput;
|
|
3118
|
-
}
|
|
3118
|
+
if (!args.hasPagination) return args.orderByInput;
|
|
3119
3119
|
return ensureDeterministicOrderByInput({
|
|
3120
3120
|
orderBy: args.hasOrderBy ? args.orderByInput : void 0,
|
|
3121
3121
|
model: args.relModel,
|
|
@@ -3176,7 +3176,9 @@ function buildOrderBySql(finalOrderByInput, relAlias, dialect, relModel) {
|
|
|
3176
3176
|
return isNotNullish(finalOrderByInput) ? buildOrderBy(finalOrderByInput, relAlias, dialect, relModel) : "";
|
|
3177
3177
|
}
|
|
3178
3178
|
function buildBaseSql(args) {
|
|
3179
|
-
|
|
3179
|
+
const joins = args.joins ? ` ${args.joins}` : "";
|
|
3180
|
+
const where = `${SQL_TEMPLATES.WHERE} ${args.joinPredicate}${args.whereClause}`;
|
|
3181
|
+
return `${SQL_TEMPLATES.SELECT} ${args.selectExpr} ${SQL_TEMPLATES.FROM} ${args.relTable} ${args.relAlias}${joins} ` + where;
|
|
3180
3182
|
}
|
|
3181
3183
|
function buildOneToOneIncludeSql(args) {
|
|
3182
3184
|
const objExpr = jsonBuildObject(args.relSelect, args.ctx.dialect);
|
|
@@ -3188,9 +3190,7 @@ function buildOneToOneIncludeSql(args) {
|
|
|
3188
3190
|
joinPredicate: args.joinPredicate,
|
|
3189
3191
|
whereClause: args.whereClause
|
|
3190
3192
|
});
|
|
3191
|
-
if (args.orderBySql) {
|
|
3192
|
-
sql += ` ${SQL_TEMPLATES.ORDER_BY} ${args.orderBySql}`;
|
|
3193
|
-
}
|
|
3193
|
+
if (args.orderBySql) sql += ` ${SQL_TEMPLATES.ORDER_BY} ${args.orderBySql}`;
|
|
3194
3194
|
if (isNotNullish(args.takeVal)) {
|
|
3195
3195
|
return appendLimitOffset(
|
|
3196
3196
|
sql,
|
|
@@ -3243,7 +3243,7 @@ function buildListIncludeSpec(args) {
|
|
|
3243
3243
|
`include.${args.relName}`
|
|
3244
3244
|
);
|
|
3245
3245
|
const selectExpr = jsonAgg("row", args.ctx.dialect);
|
|
3246
|
-
const sql = `${SQL_TEMPLATES.SELECT} ${selectExpr} ${SQL_TEMPLATES.FROM} (${base}) ${rowAlias}`;
|
|
3246
|
+
const sql = `${SQL_TEMPLATES.SELECT} ${selectExpr} ${SQL_TEMPLATES.FROM} (${base}) ${SQL_TEMPLATES.AS} ${rowAlias}`;
|
|
3247
3247
|
return Object.freeze({ name: args.relName, sql, isOneToOne: false });
|
|
3248
3248
|
}
|
|
3249
3249
|
function buildSingleInclude(relName, relArgs, field, relModel, ctx) {
|
|
@@ -3341,12 +3341,7 @@ function buildIncludeSqlInternal(args, model, schemas, schemaByName, parentAlias
|
|
|
3341
3341
|
`Query complexity limit exceeded: ${stats.totalSubqueries} subqueries generated. Maximum allowed: ${MAX_TOTAL_SUBQUERIES}. This indicates exponential include nesting. Stats: depth=${stats.maxDepth}, includes=${stats.totalIncludes}. Path: ${visitPath.join(" -> ")}. Simplify your include structure or split into multiple queries.`
|
|
3342
3342
|
);
|
|
3343
3343
|
}
|
|
3344
|
-
const resolved = resolveRelationOrThrow(
|
|
3345
|
-
model,
|
|
3346
|
-
schemas,
|
|
3347
|
-
schemaByName,
|
|
3348
|
-
relName
|
|
3349
|
-
);
|
|
3344
|
+
const resolved = resolveRelationOrThrow(model, schemaByName, relName);
|
|
3350
3345
|
const relationPath = `${model.name}.${relName}`;
|
|
3351
3346
|
const currentPath = [...visitPath, relationPath];
|
|
3352
3347
|
if (visitPath.includes(relationPath)) {
|
|
@@ -3402,7 +3397,7 @@ function buildIncludeSql(args, model, schemas, parentAlias, params, dialect) {
|
|
|
3402
3397
|
stats
|
|
3403
3398
|
);
|
|
3404
3399
|
}
|
|
3405
|
-
function resolveCountRelationOrThrow(relName, model,
|
|
3400
|
+
function resolveCountRelationOrThrow(relName, model, schemaByName) {
|
|
3406
3401
|
const relationSet = getRelationFieldSet(model);
|
|
3407
3402
|
if (!relationSet.has(relName)) {
|
|
3408
3403
|
throw new Error(
|
|
@@ -3410,10 +3405,11 @@ function resolveCountRelationOrThrow(relName, model, schemas, schemaByName) {
|
|
|
3410
3405
|
);
|
|
3411
3406
|
}
|
|
3412
3407
|
const field = model.fields.find((f) => f.name === relName);
|
|
3413
|
-
if (!field)
|
|
3408
|
+
if (!field) {
|
|
3414
3409
|
throw new Error(
|
|
3415
3410
|
`_count.${relName} references unknown relation on model ${model.name}`
|
|
3416
3411
|
);
|
|
3412
|
+
}
|
|
3417
3413
|
if (!isValidRelationField(field)) {
|
|
3418
3414
|
throw new Error(
|
|
3419
3415
|
`_count.${relName} has invalid relation metadata on model ${model.name}`
|
|
@@ -3441,8 +3437,9 @@ function defaultReferencesForCount(fkCount) {
|
|
|
3441
3437
|
}
|
|
3442
3438
|
function resolveCountKeyPairs(field) {
|
|
3443
3439
|
const fkFields = normalizeKeyList(field.foreignKey);
|
|
3444
|
-
if (fkFields.length === 0)
|
|
3440
|
+
if (fkFields.length === 0) {
|
|
3445
3441
|
throw new Error("Relation count requires foreignKey");
|
|
3442
|
+
}
|
|
3446
3443
|
const refsRaw = field.references;
|
|
3447
3444
|
const refs = normalizeKeyList(refsRaw);
|
|
3448
3445
|
const refFields = refs.length > 0 ? refs : defaultReferencesForCount(fkFields.length);
|
|
@@ -3518,12 +3515,7 @@ function buildRelationCountSql(countSelect, model, schemas, parentAlias, _params
|
|
|
3518
3515
|
for (const m of schemas) schemaByName.set(m.name, m);
|
|
3519
3516
|
for (const [relName, shouldCount] of Object.entries(countSelect)) {
|
|
3520
3517
|
if (!shouldCount) continue;
|
|
3521
|
-
const resolved = resolveCountRelationOrThrow(
|
|
3522
|
-
relName,
|
|
3523
|
-
model,
|
|
3524
|
-
schemas,
|
|
3525
|
-
schemaByName
|
|
3526
|
-
);
|
|
3518
|
+
const resolved = resolveCountRelationOrThrow(relName, model, schemaByName);
|
|
3527
3519
|
const built = buildCountJoinAndPair({
|
|
3528
3520
|
relName,
|
|
3529
3521
|
field: resolved.field,
|
|
@@ -4953,24 +4945,7 @@ function generateCode(models, queries, dialect, datamodel) {
|
|
|
4953
4945
|
}));
|
|
4954
4946
|
const { mappings, fieldTypes } = extractEnumMappings(datamodel);
|
|
4955
4947
|
return `// Generated by @prisma-sql/generator - DO NOT EDIT
|
|
4956
|
-
import { buildSQL, buildBatchSql, parseBatchResults, buildBatchCountSql, parseBatchCountResults, createTransactionExecutor, transformQueryResults, type PrismaMethod, type Model, type BatchQuery, type TransactionQuery, type TransactionOptions } from 'prisma-sql'
|
|
4957
|
-
|
|
4958
|
-
export interface BatchCountQuery {
|
|
4959
|
-
model: string
|
|
4960
|
-
method: 'count'
|
|
4961
|
-
args?: { where?: Record<string, unknown> }
|
|
4962
|
-
}
|
|
4963
|
-
|
|
4964
|
-
export interface TransactionQuery {
|
|
4965
|
-
model: string
|
|
4966
|
-
method: PrismaMethod
|
|
4967
|
-
args?: Record<string, unknown>
|
|
4968
|
-
}
|
|
4969
|
-
|
|
4970
|
-
export interface TransactionOptions {
|
|
4971
|
-
isolationLevel?: 'ReadCommitted' | 'RepeatableRead' | 'Serializable'
|
|
4972
|
-
timeout?: number
|
|
4973
|
-
}
|
|
4948
|
+
import { buildSQL, buildBatchSql, parseBatchResults, buildBatchCountSql, parseBatchCountResults, createTransactionExecutor, transformQueryResults, type PrismaMethod, type Model, type BatchQuery, type BatchCountQuery, type TransactionQuery, type TransactionOptions } from 'prisma-sql'
|
|
4974
4949
|
|
|
4975
4950
|
class DeferredQuery {
|
|
4976
4951
|
constructor(
|
|
@@ -5091,6 +5066,10 @@ function normalizeValue(value: unknown, seen = new WeakSet<object>(), depth = 0)
|
|
|
5091
5066
|
return value
|
|
5092
5067
|
}
|
|
5093
5068
|
|
|
5069
|
+
function normalizeParams(params: unknown[]): unknown[] {
|
|
5070
|
+
return params.map(p => normalizeValue(p))
|
|
5071
|
+
}
|
|
5072
|
+
|
|
5094
5073
|
function getByPath(obj: any, path: string): unknown {
|
|
5095
5074
|
if (!obj || !path) return undefined
|
|
5096
5075
|
const keys = path.split('.')
|
|
@@ -5102,11 +5081,6 @@ function getByPath(obj: any, path: string): unknown {
|
|
|
5102
5081
|
return result
|
|
5103
5082
|
}
|
|
5104
5083
|
|
|
5105
|
-
function normalizeParams(params: unknown[]): unknown[] {
|
|
5106
|
-
return params.map(p => normalizeValue(p))
|
|
5107
|
-
}
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
5084
|
export const MODELS: Model[] = ${JSON.stringify(cleanModels, null, 2)}
|
|
5111
5085
|
|
|
5112
5086
|
const ENUM_MAPPINGS: Record<string, Record<string, string>> = ${JSON.stringify(mappings, null, 2)}
|
|
@@ -5124,8 +5098,11 @@ const DIALECT = ${JSON.stringify(dialect)}
|
|
|
5124
5098
|
|
|
5125
5099
|
const MODEL_MAP = new Map(MODELS.map(m => [m.name, m]))
|
|
5126
5100
|
|
|
5127
|
-
function
|
|
5128
|
-
|
|
5101
|
+
function isDynamicKeyForQueryKey(path: string[], key: string): boolean {
|
|
5102
|
+
if (key !== 'skip' && key !== 'take' && key !== 'cursor') return false
|
|
5103
|
+
if (path.includes('where')) return false
|
|
5104
|
+
if (path.includes('data')) return false
|
|
5105
|
+
return true
|
|
5129
5106
|
}
|
|
5130
5107
|
|
|
5131
5108
|
function transformEnumInValue(value: unknown, enumType: string | undefined): unknown {
|
|
@@ -5154,28 +5131,43 @@ function transformEnumInValue(value: unknown, enumType: string | undefined): unk
|
|
|
5154
5131
|
return value
|
|
5155
5132
|
}
|
|
5156
5133
|
|
|
5157
|
-
function
|
|
5134
|
+
function getRelatedModelName(currentModelName: string, relationFieldName: string): string | null {
|
|
5135
|
+
const m = MODEL_MAP.get(currentModelName)
|
|
5136
|
+
if (!m) return null
|
|
5137
|
+
const f: any = (m as any).fields?.find((x: any) => x?.name === relationFieldName)
|
|
5138
|
+
if (!f || !f.isRelation) return null
|
|
5139
|
+
return f.relatedModel || null
|
|
5140
|
+
}
|
|
5141
|
+
|
|
5142
|
+
function transformEnumValuesByModel(modelName: string, obj: any, path: string[] = []): any {
|
|
5158
5143
|
if (obj === null || obj === undefined) {
|
|
5159
5144
|
return obj
|
|
5160
5145
|
}
|
|
5161
|
-
|
|
5146
|
+
|
|
5162
5147
|
if (Array.isArray(obj)) {
|
|
5163
|
-
return obj.map(item =>
|
|
5148
|
+
return obj.map(item => transformEnumValuesByModel(modelName, item, path))
|
|
5164
5149
|
}
|
|
5165
|
-
|
|
5150
|
+
|
|
5166
5151
|
if (obj instanceof Date) {
|
|
5167
5152
|
return obj
|
|
5168
5153
|
}
|
|
5169
|
-
|
|
5154
|
+
|
|
5170
5155
|
if (typeof obj === 'object') {
|
|
5171
5156
|
const transformed: any = {}
|
|
5172
5157
|
const modelFields = ENUM_FIELDS[modelName] || {}
|
|
5173
|
-
|
|
5158
|
+
|
|
5174
5159
|
for (const [key, value] of Object.entries(obj)) {
|
|
5175
|
-
const
|
|
5176
|
-
|
|
5160
|
+
const nextPath = [...path, key]
|
|
5161
|
+
|
|
5162
|
+
const relModel = getRelatedModelName(modelName, key)
|
|
5163
|
+
|
|
5164
|
+
if (relModel && value && typeof value === 'object') {
|
|
5165
|
+
transformed[key] = transformEnumValuesByModel(relModel, value, nextPath)
|
|
5166
|
+
continue
|
|
5167
|
+
}
|
|
5168
|
+
|
|
5177
5169
|
const enumType = modelFields[key]
|
|
5178
|
-
|
|
5170
|
+
|
|
5179
5171
|
if (enumType) {
|
|
5180
5172
|
if (value && typeof value === 'object' && !Array.isArray(value) && !(value instanceof Date)) {
|
|
5181
5173
|
const transformedOperators: any = {}
|
|
@@ -5189,46 +5181,46 @@ function transformEnumValues(modelName: string, obj: any, currentPath: string[]
|
|
|
5189
5181
|
} else if (value instanceof Date) {
|
|
5190
5182
|
transformed[key] = value
|
|
5191
5183
|
} else if (typeof value === 'object' && value !== null) {
|
|
5192
|
-
transformed[key] =
|
|
5184
|
+
transformed[key] = transformEnumValuesByModel(modelName, value, nextPath)
|
|
5193
5185
|
} else {
|
|
5194
5186
|
transformed[key] = value
|
|
5195
5187
|
}
|
|
5196
5188
|
}
|
|
5189
|
+
|
|
5197
5190
|
return transformed
|
|
5198
5191
|
}
|
|
5199
|
-
|
|
5192
|
+
|
|
5200
5193
|
return obj
|
|
5201
5194
|
}
|
|
5202
5195
|
|
|
5203
|
-
|
|
5204
5196
|
function normalizeQuery(args: any): string {
|
|
5205
5197
|
if (!args) return '{}'
|
|
5206
|
-
|
|
5198
|
+
|
|
5207
5199
|
const normalized = JSON.parse(JSON.stringify(args))
|
|
5208
|
-
|
|
5209
|
-
function replaceDynamicParams(obj: any): any {
|
|
5200
|
+
|
|
5201
|
+
function replaceDynamicParams(obj: any, path: string[] = []): any {
|
|
5210
5202
|
if (!obj || typeof obj !== 'object') return obj
|
|
5211
|
-
|
|
5203
|
+
|
|
5212
5204
|
if (Array.isArray(obj)) {
|
|
5213
|
-
return obj.map(replaceDynamicParams)
|
|
5205
|
+
return obj.map((v) => replaceDynamicParams(v, path))
|
|
5214
5206
|
}
|
|
5215
|
-
|
|
5207
|
+
|
|
5216
5208
|
const result: any = {}
|
|
5217
5209
|
for (const [key, value] of Object.entries(obj)) {
|
|
5218
|
-
if (
|
|
5210
|
+
if (isDynamicKeyForQueryKey(path, key)) {
|
|
5219
5211
|
result[key] = \`__DYNAMIC_\${key}__\`
|
|
5220
5212
|
} else {
|
|
5221
|
-
result[key] = replaceDynamicParams(value)
|
|
5213
|
+
result[key] = replaceDynamicParams(value, [...path, key])
|
|
5222
5214
|
}
|
|
5223
5215
|
}
|
|
5224
5216
|
return result
|
|
5225
5217
|
}
|
|
5226
|
-
|
|
5218
|
+
|
|
5227
5219
|
const withMarkers = replaceDynamicParams(normalized)
|
|
5228
|
-
|
|
5220
|
+
|
|
5229
5221
|
function removeEmptyObjects(obj: any): any {
|
|
5230
5222
|
if (!obj || typeof obj !== 'object' || Array.isArray(obj)) return obj
|
|
5231
|
-
|
|
5223
|
+
|
|
5232
5224
|
const result: any = {}
|
|
5233
5225
|
for (const [key, value] of Object.entries(obj)) {
|
|
5234
5226
|
if (value && typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length === 0) {
|
|
@@ -5238,14 +5230,14 @@ function normalizeQuery(args: any): string {
|
|
|
5238
5230
|
}
|
|
5239
5231
|
return result
|
|
5240
5232
|
}
|
|
5241
|
-
|
|
5233
|
+
|
|
5242
5234
|
const cleaned = removeEmptyObjects(withMarkers)
|
|
5243
|
-
|
|
5235
|
+
|
|
5244
5236
|
return JSON.stringify(cleaned, (key, value) => {
|
|
5245
5237
|
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
5246
5238
|
const sorted: Record<string, unknown> = {}
|
|
5247
5239
|
for (const k of Object.keys(value).sort()) {
|
|
5248
|
-
sorted[k] = value[k]
|
|
5240
|
+
sorted[k] = (value as any)[k]
|
|
5249
5241
|
}
|
|
5250
5242
|
return sorted
|
|
5251
5243
|
}
|
|
@@ -5273,7 +5265,6 @@ function extractDynamicParams(args: any, dynamicKeys: string[]): unknown[] {
|
|
|
5273
5265
|
return params
|
|
5274
5266
|
}
|
|
5275
5267
|
|
|
5276
|
-
|
|
5277
5268
|
async function executeQuery(client: any, sql: string, params: unknown[]): Promise<unknown[]> {
|
|
5278
5269
|
const normalizedParams = normalizeParams(params)
|
|
5279
5270
|
|
|
@@ -5336,7 +5327,7 @@ export function speedExtension(config: {
|
|
|
5336
5327
|
const modelName = this?.name || this?.$name
|
|
5337
5328
|
const startTime = Date.now()
|
|
5338
5329
|
|
|
5339
|
-
const transformedArgs =
|
|
5330
|
+
const transformedArgs = transformEnumValuesByModel(modelName, args || {})
|
|
5340
5331
|
|
|
5341
5332
|
const queryKey = normalizeQuery(transformedArgs)
|
|
5342
5333
|
const prebakedQuery = QUERIES[modelName]?.[method]?.[queryKey]
|
|
@@ -5489,7 +5480,7 @@ export function speedExtension(config: {
|
|
|
5489
5480
|
|
|
5490
5481
|
onQuery?.({
|
|
5491
5482
|
model: '_transaction',
|
|
5492
|
-
method: '
|
|
5483
|
+
method: 'transaction',
|
|
5493
5484
|
sql: \`TRANSACTION(\${queries.length})\`,
|
|
5494
5485
|
params: [],
|
|
5495
5486
|
duration,
|
|
@@ -5501,7 +5492,7 @@ export function speedExtension(config: {
|
|
|
5501
5492
|
|
|
5502
5493
|
return prisma.$extends({
|
|
5503
5494
|
name: 'prisma-sql-generated',
|
|
5504
|
-
|
|
5495
|
+
|
|
5505
5496
|
client: {
|
|
5506
5497
|
$original: prisma,
|
|
5507
5498
|
$batch: batch as <T extends Record<string, DeferredQuery>>(
|
|
@@ -5546,6 +5537,8 @@ export type SpeedClient<T> = T & {
|
|
|
5546
5537
|
$batchCount(queries: BatchCountQuery[]): Promise<number[]>
|
|
5547
5538
|
$transaction(queries: TransactionQuery[], options?: TransactionOptions): Promise<unknown[]>
|
|
5548
5539
|
}
|
|
5540
|
+
|
|
5541
|
+
export type { BatchCountQuery, TransactionQuery, TransactionOptions }
|
|
5549
5542
|
`;
|
|
5550
5543
|
}
|
|
5551
5544
|
function formatQueries(queries) {
|