prisma-sql 1.29.0 → 1.32.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 +118 -52
- package/dist/generator.cjs.map +1 -1
- package/dist/generator.js +118 -52
- package/dist/generator.js.map +1 -1
- package/dist/index.cjs +129 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +64 -3
- package/dist/index.d.ts +64 -3
- package/dist/index.js +130 -44
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/readme.md +125 -184
package/dist/generator.js
CHANGED
|
@@ -54,7 +54,7 @@ var require_package = __commonJS({
|
|
|
54
54
|
"package.json"(exports$1, module) {
|
|
55
55
|
module.exports = {
|
|
56
56
|
name: "prisma-sql",
|
|
57
|
-
version: "1.
|
|
57
|
+
version: "1.32.0",
|
|
58
58
|
description: "Convert Prisma queries to optimized SQL with type safety. 2-7x faster than Prisma Client.",
|
|
59
59
|
main: "dist/index.cjs",
|
|
60
60
|
module: "dist/index.js",
|
|
@@ -119,7 +119,7 @@ var require_package = __commonJS({
|
|
|
119
119
|
author: "multipliedtwice <multipliedtwice@gmail.com>",
|
|
120
120
|
license: "MIT",
|
|
121
121
|
dependencies: {
|
|
122
|
-
"@dee-wan/schema-parser": "1.
|
|
122
|
+
"@dee-wan/schema-parser": "1.4.0",
|
|
123
123
|
"@prisma/generator-helper": "^7.2.0",
|
|
124
124
|
"@prisma/internals": "^7.2.0"
|
|
125
125
|
},
|
|
@@ -943,14 +943,54 @@ function quote(id) {
|
|
|
943
943
|
}
|
|
944
944
|
return id;
|
|
945
945
|
}
|
|
946
|
-
function
|
|
946
|
+
function pickDbFieldName(field) {
|
|
947
|
+
const candidates = [
|
|
948
|
+
field == null ? void 0 : field.dbName,
|
|
949
|
+
field == null ? void 0 : field.columnName,
|
|
950
|
+
field == null ? void 0 : field.databaseName,
|
|
951
|
+
field == null ? void 0 : field.mappedName
|
|
952
|
+
];
|
|
953
|
+
for (const c of candidates) {
|
|
954
|
+
if (typeof c === "string") {
|
|
955
|
+
const s = c.trim();
|
|
956
|
+
if (s.length > 0) return s;
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
return void 0;
|
|
960
|
+
}
|
|
961
|
+
function resolveColumnName(model, fieldName) {
|
|
962
|
+
var _a;
|
|
963
|
+
if (!model) return fieldName;
|
|
964
|
+
const f = model.fields.find((x) => (x == null ? void 0 : x.name) === fieldName);
|
|
965
|
+
if (!f) return fieldName;
|
|
966
|
+
return (_a = pickDbFieldName(f)) != null ? _a : fieldName;
|
|
967
|
+
}
|
|
968
|
+
function quoteColumn(model, fieldName) {
|
|
969
|
+
return quote(resolveColumnName(model, fieldName));
|
|
970
|
+
}
|
|
971
|
+
function col(alias, field, model) {
|
|
947
972
|
if (isEmptyString(alias)) {
|
|
948
973
|
throw new Error("col: alias is required and cannot be empty");
|
|
949
974
|
}
|
|
950
975
|
if (isEmptyString(field)) {
|
|
951
976
|
throw new Error("col: field is required and cannot be empty");
|
|
952
977
|
}
|
|
953
|
-
|
|
978
|
+
const columnName = resolveColumnName(model, field);
|
|
979
|
+
return `${alias}.${quote(columnName)}`;
|
|
980
|
+
}
|
|
981
|
+
function colWithAlias(alias, field, model) {
|
|
982
|
+
if (isEmptyString(alias)) {
|
|
983
|
+
throw new Error("colWithAlias: alias is required and cannot be empty");
|
|
984
|
+
}
|
|
985
|
+
if (isEmptyString(field)) {
|
|
986
|
+
throw new Error("colWithAlias: field is required and cannot be empty");
|
|
987
|
+
}
|
|
988
|
+
const columnName = resolveColumnName(model, field);
|
|
989
|
+
const columnRef = `${alias}.${quote(columnName)}`;
|
|
990
|
+
if (columnName !== field) {
|
|
991
|
+
return `${columnRef} AS ${quote(field)}`;
|
|
992
|
+
}
|
|
993
|
+
return columnRef;
|
|
954
994
|
}
|
|
955
995
|
function sqlStringLiteral(value) {
|
|
956
996
|
if (containsControlChars(value)) {
|
|
@@ -1053,7 +1093,7 @@ function getReferenceFieldNames(field, foreignKeyCount) {
|
|
|
1053
1093
|
if (refs.length !== foreignKeyCount) return [];
|
|
1054
1094
|
return refs;
|
|
1055
1095
|
}
|
|
1056
|
-
function joinCondition(field, parentAlias, childAlias) {
|
|
1096
|
+
function joinCondition(field, parentModel, childModel, parentAlias, childAlias) {
|
|
1057
1097
|
const fkFields = normalizeKeyList(field.foreignKey);
|
|
1058
1098
|
if (fkFields.length === 0) {
|
|
1059
1099
|
throw createError(
|
|
@@ -1072,8 +1112,8 @@ function joinCondition(field, parentAlias, childAlias) {
|
|
|
1072
1112
|
for (let i = 0; i < fkFields.length; i++) {
|
|
1073
1113
|
const fk = fkFields[i];
|
|
1074
1114
|
const ref = refFields[i];
|
|
1075
|
-
const left = field.isForeignKeyLocal ? `${childAlias}.${
|
|
1076
|
-
const right = field.isForeignKeyLocal ? `${parentAlias}.${
|
|
1115
|
+
const left = field.isForeignKeyLocal ? `${childAlias}.${quoteColumn(childModel, ref)}` : `${childAlias}.${quoteColumn(childModel, fk)}`;
|
|
1116
|
+
const right = field.isForeignKeyLocal ? `${parentAlias}.${quoteColumn(parentModel, fk)}` : `${parentAlias}.${quoteColumn(parentModel, ref)}`;
|
|
1077
1117
|
parts.push(`${left} = ${right}`);
|
|
1078
1118
|
}
|
|
1079
1119
|
return parts.length === 1 ? parts[0] : `(${parts.join(" AND ")})`;
|
|
@@ -1678,7 +1718,7 @@ function buildRelation(fieldName, value, ctx, whereBuilder) {
|
|
|
1678
1718
|
ctx.dialect
|
|
1679
1719
|
);
|
|
1680
1720
|
const relAlias = ctx.aliasGen.next(fieldName);
|
|
1681
|
-
const join3 = joinCondition(field, ctx.alias, relAlias);
|
|
1721
|
+
const join3 = joinCondition(field, ctx.model, relModel, ctx.alias, relAlias);
|
|
1682
1722
|
const args = {
|
|
1683
1723
|
fieldName,
|
|
1684
1724
|
value,
|
|
@@ -2423,12 +2463,12 @@ function readSkipTake(relArgs) {
|
|
|
2423
2463
|
const takeVal = hasTake ? normalizeIntegerOrDynamic("take", obj.take) : void 0;
|
|
2424
2464
|
return { hasSkip, hasTake, skipVal, takeVal };
|
|
2425
2465
|
}
|
|
2426
|
-
function buildOrderByFragment(entries, alias, dialect) {
|
|
2466
|
+
function buildOrderByFragment(entries, alias, dialect, model) {
|
|
2427
2467
|
if (entries.length === 0) return "";
|
|
2428
2468
|
const out = [];
|
|
2429
2469
|
for (const e of entries) {
|
|
2430
2470
|
const dir = e.direction.toUpperCase();
|
|
2431
|
-
const c = col(alias, e.field);
|
|
2471
|
+
const c = col(alias, e.field, model);
|
|
2432
2472
|
if (dialect === "postgres") {
|
|
2433
2473
|
const nulls = isNotNullish(e.nulls) ? ` NULLS ${e.nulls.toUpperCase()}` : "";
|
|
2434
2474
|
out.push(`${c} ${dir}${nulls}`);
|
|
@@ -2463,7 +2503,7 @@ function ensureCursorFieldsInOrder(orderEntries, cursorEntries) {
|
|
|
2463
2503
|
}
|
|
2464
2504
|
return out;
|
|
2465
2505
|
}
|
|
2466
|
-
function buildCursorFilterParts(cursor, cursorAlias, params) {
|
|
2506
|
+
function buildCursorFilterParts(cursor, cursorAlias, params, model) {
|
|
2467
2507
|
const entries = Object.entries(cursor);
|
|
2468
2508
|
if (entries.length === 0) {
|
|
2469
2509
|
throw new Error("cursor must have at least one field");
|
|
@@ -2485,8 +2525,9 @@ function buildCursorFilterParts(cursor, cursorAlias, params) {
|
|
|
2485
2525
|
placeholdersByField
|
|
2486
2526
|
};
|
|
2487
2527
|
}
|
|
2488
|
-
function cursorValueExpr(tableName, cursorAlias, cursorWhereSql, field) {
|
|
2489
|
-
|
|
2528
|
+
function cursorValueExpr(tableName, cursorAlias, cursorWhereSql, field, model) {
|
|
2529
|
+
const colName = quote(field);
|
|
2530
|
+
return `(SELECT ${cursorAlias}.${colName} ${SQL_TEMPLATES.FROM} ${tableName} ${cursorAlias} ${SQL_TEMPLATES.WHERE} ${cursorWhereSql} ${SQL_TEMPLATES.LIMIT} 1)`;
|
|
2490
2531
|
}
|
|
2491
2532
|
function buildCursorRowExistsExpr(tableName, cursorAlias, cursorWhereSql) {
|
|
2492
2533
|
return `EXISTS (${SQL_TEMPLATES.SELECT} 1 ${SQL_TEMPLATES.FROM} ${tableName} ${cursorAlias} ${SQL_TEMPLATES.WHERE} ${cursorWhereSql} ${SQL_TEMPLATES.LIMIT} 1)`;
|
|
@@ -2501,10 +2542,10 @@ function buildCursorInequalityExpr(columnExpr, direction, nulls, valueExpr) {
|
|
|
2501
2542
|
}
|
|
2502
2543
|
return `(CASE WHEN ${valueExpr} IS NULL THEN 0=1 ELSE ((${columnExpr} ${op} ${valueExpr}) OR (${columnExpr} IS NULL)) END)`;
|
|
2503
2544
|
}
|
|
2504
|
-
function buildOuterCursorMatch(cursor, outerAlias, placeholdersByField, params) {
|
|
2545
|
+
function buildOuterCursorMatch(cursor, outerAlias, placeholdersByField, params, model) {
|
|
2505
2546
|
const parts = [];
|
|
2506
2547
|
for (const [field, value] of Object.entries(cursor)) {
|
|
2507
|
-
const c = col(outerAlias, field);
|
|
2548
|
+
const c = col(outerAlias, field, model);
|
|
2508
2549
|
if (value === null) {
|
|
2509
2550
|
parts.push(`${c} IS NULL`);
|
|
2510
2551
|
continue;
|
|
@@ -2537,7 +2578,7 @@ function buildOrderEntries(orderBy) {
|
|
|
2537
2578
|
}
|
|
2538
2579
|
return entries;
|
|
2539
2580
|
}
|
|
2540
|
-
function buildCursorCondition(cursor, orderBy, tableName, alias, params, dialect) {
|
|
2581
|
+
function buildCursorCondition(cursor, orderBy, tableName, alias, params, dialect, model) {
|
|
2541
2582
|
var _a;
|
|
2542
2583
|
const d = dialect != null ? dialect : getGlobalDialect();
|
|
2543
2584
|
const cursorEntries = Object.entries(cursor);
|
|
@@ -2564,20 +2605,29 @@ function buildCursorCondition(cursor, orderBy, tableName, alias, params, dialect
|
|
|
2564
2605
|
cursor,
|
|
2565
2606
|
alias,
|
|
2566
2607
|
placeholdersByField,
|
|
2567
|
-
params
|
|
2608
|
+
params,
|
|
2609
|
+
model
|
|
2568
2610
|
);
|
|
2569
2611
|
const orClauses = [];
|
|
2570
2612
|
for (let level = 0; level < orderEntries.length; level++) {
|
|
2571
2613
|
const andParts = [];
|
|
2572
2614
|
for (let i = 0; i < level; i++) {
|
|
2573
2615
|
const e2 = orderEntries[i];
|
|
2574
|
-
const c2 = col(alias, e2.field);
|
|
2575
|
-
const v2 = cursorValueExpr(
|
|
2616
|
+
const c2 = col(alias, e2.field, model);
|
|
2617
|
+
const v2 = cursorValueExpr(
|
|
2618
|
+
tableName,
|
|
2619
|
+
cursorAlias,
|
|
2620
|
+
cursorWhereSql,
|
|
2621
|
+
e2.field);
|
|
2576
2622
|
andParts.push(buildCursorEqualityExpr(c2, v2));
|
|
2577
2623
|
}
|
|
2578
2624
|
const e = orderEntries[level];
|
|
2579
|
-
const c = col(alias, e.field);
|
|
2580
|
-
const v = cursorValueExpr(
|
|
2625
|
+
const c = col(alias, e.field, model);
|
|
2626
|
+
const v = cursorValueExpr(
|
|
2627
|
+
tableName,
|
|
2628
|
+
cursorAlias,
|
|
2629
|
+
cursorWhereSql,
|
|
2630
|
+
e.field);
|
|
2581
2631
|
const nulls = (_a = e.nulls) != null ? _a : defaultNullsFor(d, e.direction);
|
|
2582
2632
|
andParts.push(buildCursorInequalityExpr(c, e.direction, nulls, v));
|
|
2583
2633
|
orClauses.push(`(${andParts.join(SQL_SEPARATORS.CONDITION_AND)})`);
|
|
@@ -2585,15 +2635,15 @@ function buildCursorCondition(cursor, orderBy, tableName, alias, params, dialect
|
|
|
2585
2635
|
const exclusive = orClauses.join(SQL_SEPARATORS.CONDITION_OR);
|
|
2586
2636
|
return `(${existsExpr} ${SQL_SEPARATORS.CONDITION_AND} ((${exclusive})${SQL_SEPARATORS.CONDITION_OR}(${outerCursorMatch})))`;
|
|
2587
2637
|
}
|
|
2588
|
-
function buildOrderBy(orderBy, alias, dialect) {
|
|
2638
|
+
function buildOrderBy(orderBy, alias, dialect, model) {
|
|
2589
2639
|
const entries = buildOrderEntries(orderBy);
|
|
2590
2640
|
if (entries.length === 0) return "";
|
|
2591
2641
|
const d = dialect != null ? dialect : getGlobalDialect();
|
|
2592
|
-
return buildOrderByFragment(entries, alias, d);
|
|
2642
|
+
return buildOrderByFragment(entries, alias, d, model);
|
|
2593
2643
|
}
|
|
2594
|
-
function buildOrderByClause(args, alias, dialect) {
|
|
2644
|
+
function buildOrderByClause(args, alias, dialect, model) {
|
|
2595
2645
|
if (!isNotNullish(args.orderBy)) return "";
|
|
2596
|
-
const result = buildOrderBy(args.orderBy, alias, dialect);
|
|
2646
|
+
const result = buildOrderBy(args.orderBy, alias, dialect, model);
|
|
2597
2647
|
if (!isNonEmptyString(result)) {
|
|
2598
2648
|
throw new Error(
|
|
2599
2649
|
"buildOrderByClause: orderBy specified but produced empty result"
|
|
@@ -2678,7 +2728,7 @@ function buildDefaultScalarFields(model, alias) {
|
|
|
2678
2728
|
for (const f of model.fields) {
|
|
2679
2729
|
if (f.isRelation) continue;
|
|
2680
2730
|
const excluded = excludedPrefixes.some((p) => f.name.startsWith(p));
|
|
2681
|
-
if (!excluded) out.push(
|
|
2731
|
+
if (!excluded) out.push(colWithAlias(alias, f.name, model));
|
|
2682
2732
|
}
|
|
2683
2733
|
if (!isNonEmptyArray(out)) {
|
|
2684
2734
|
throw new Error(`Model ${model.name} has no selectable fields`);
|
|
@@ -2696,7 +2746,9 @@ function buildSelectFields(args, model, alias) {
|
|
|
2696
2746
|
const entries = toSelectEntries(args.select);
|
|
2697
2747
|
validateSelectKeys(entries, scalarSet, relationSet);
|
|
2698
2748
|
const { scalarSelected, hasRelationSelection, hasCount } = analyzeSelectEntries(entries, scalarSet, relationSet);
|
|
2699
|
-
const fields = scalarSelected.map(
|
|
2749
|
+
const fields = scalarSelected.map(
|
|
2750
|
+
(field) => colWithAlias(alias, field, model)
|
|
2751
|
+
);
|
|
2700
2752
|
if (!isNonEmptyArray(fields)) {
|
|
2701
2753
|
if (hasRelationSelection) return "";
|
|
2702
2754
|
if (!hasCount) {
|
|
@@ -2712,7 +2764,9 @@ function buildAllScalarParts(model, alias) {
|
|
|
2712
2764
|
}
|
|
2713
2765
|
const parts = [];
|
|
2714
2766
|
for (const field of scalarFields) {
|
|
2715
|
-
parts.push(
|
|
2767
|
+
parts.push(
|
|
2768
|
+
`${sqlStringLiteral(field.name)}, ${col(alias, field.name, model)}`
|
|
2769
|
+
);
|
|
2716
2770
|
}
|
|
2717
2771
|
return parts;
|
|
2718
2772
|
}
|
|
@@ -2725,12 +2779,12 @@ function validateRelationSelectKeys(entries, scalarNames, relationNames) {
|
|
|
2725
2779
|
throw new Error(`Select contains unknown fields: ${unknown.join(", ")}`);
|
|
2726
2780
|
}
|
|
2727
2781
|
}
|
|
2728
|
-
function buildSelectedScalarParts(entries, scalarNames, alias) {
|
|
2782
|
+
function buildSelectedScalarParts(entries, scalarNames, alias, model) {
|
|
2729
2783
|
const parts = [];
|
|
2730
2784
|
for (const [key, value] of entries) {
|
|
2731
2785
|
if (!scalarNames.has(key)) continue;
|
|
2732
2786
|
if (value === true) {
|
|
2733
|
-
parts.push(`${sqlStringLiteral(key)}, ${col(alias, key)}`);
|
|
2787
|
+
parts.push(`${sqlStringLiteral(key)}, ${col(alias, key, model)}`);
|
|
2734
2788
|
}
|
|
2735
2789
|
}
|
|
2736
2790
|
return parts;
|
|
@@ -2756,9 +2810,12 @@ function buildRelationSelect(relArgs, relModel, relAlias) {
|
|
|
2756
2810
|
);
|
|
2757
2811
|
const entries = toSelectEntries(sel);
|
|
2758
2812
|
validateRelationSelectKeys(entries, scalarNames, relationNames);
|
|
2759
|
-
return buildSelectedScalarParts(
|
|
2760
|
-
|
|
2761
|
-
|
|
2813
|
+
return buildSelectedScalarParts(
|
|
2814
|
+
entries,
|
|
2815
|
+
scalarNames,
|
|
2816
|
+
relAlias,
|
|
2817
|
+
relModel
|
|
2818
|
+
).join(SQL_SEPARATORS.FIELD_LIST);
|
|
2762
2819
|
}
|
|
2763
2820
|
return buildAllScalarParts(relModel, relAlias).join(SQL_SEPARATORS.FIELD_LIST);
|
|
2764
2821
|
}
|
|
@@ -3045,8 +3102,8 @@ function limitOneSql(sql, params, skipVal, scope) {
|
|
|
3045
3102
|
}
|
|
3046
3103
|
return `${sql} ${SQL_TEMPLATES.LIMIT} 1`;
|
|
3047
3104
|
}
|
|
3048
|
-
function buildOrderBySql(finalOrderByInput, relAlias, dialect) {
|
|
3049
|
-
return isNotNullish(finalOrderByInput) ? buildOrderBy(finalOrderByInput, relAlias, dialect) : "";
|
|
3105
|
+
function buildOrderBySql(finalOrderByInput, relAlias, dialect, relModel) {
|
|
3106
|
+
return isNotNullish(finalOrderByInput) ? buildOrderBy(finalOrderByInput, relAlias, dialect, relModel) : "";
|
|
3050
3107
|
}
|
|
3051
3108
|
function buildBaseSql(args) {
|
|
3052
3109
|
return `${SQL_TEMPLATES.SELECT} ${args.selectExpr} ${SQL_TEMPLATES.FROM} ${args.relTable} ${args.relAlias} ${args.joins} ${SQL_TEMPLATES.WHERE} ${args.joinPredicate}${args.whereClause}`;
|
|
@@ -3133,7 +3190,13 @@ function buildSingleInclude(relName, relArgs, field, relModel, ctx) {
|
|
|
3133
3190
|
const relTable = getRelationTableReference(relModel, ctx.dialect);
|
|
3134
3191
|
const relAlias = ctx.aliasGen.next(relName);
|
|
3135
3192
|
const isList = typeof field.type === "string" && field.type.endsWith("[]");
|
|
3136
|
-
const joinPredicate = joinCondition(
|
|
3193
|
+
const joinPredicate = joinCondition(
|
|
3194
|
+
field,
|
|
3195
|
+
ctx.model,
|
|
3196
|
+
relModel,
|
|
3197
|
+
ctx.parentAlias,
|
|
3198
|
+
relAlias
|
|
3199
|
+
);
|
|
3137
3200
|
const whereInput = readWhereInput(relArgs);
|
|
3138
3201
|
const relSelect = buildSelectWithNestedIncludes(
|
|
3139
3202
|
relArgs,
|
|
@@ -3158,7 +3221,12 @@ function buildSingleInclude(relName, relArgs, field, relModel, ctx) {
|
|
|
3158
3221
|
adjusted.orderByInput,
|
|
3159
3222
|
hasPagination
|
|
3160
3223
|
);
|
|
3161
|
-
const orderBySql = buildOrderBySql(
|
|
3224
|
+
const orderBySql = buildOrderBySql(
|
|
3225
|
+
finalOrderByInput,
|
|
3226
|
+
relAlias,
|
|
3227
|
+
ctx.dialect,
|
|
3228
|
+
relModel
|
|
3229
|
+
);
|
|
3162
3230
|
if (!isList) {
|
|
3163
3231
|
const sql = buildOneToOneIncludeSql({
|
|
3164
3232
|
relName,
|
|
@@ -4521,9 +4589,9 @@ function generateClient(options) {
|
|
|
4521
4589
|
if (!modelQueries.has(method)) {
|
|
4522
4590
|
modelQueries.set(method, /* @__PURE__ */ new Map());
|
|
4523
4591
|
}
|
|
4524
|
-
const
|
|
4592
|
+
const methodQueriesMap = modelQueries.get(method);
|
|
4525
4593
|
const queryKey = createQueryKey(directive.query.processed);
|
|
4526
|
-
|
|
4594
|
+
methodQueriesMap.set(queryKey, {
|
|
4527
4595
|
sql: sqlDirective.sql,
|
|
4528
4596
|
params: sqlDirective.staticParams,
|
|
4529
4597
|
dynamicKeys: sqlDirective.dynamicKeys,
|
|
@@ -4546,7 +4614,9 @@ function generateClient(options) {
|
|
|
4546
4614
|
),
|
|
4547
4615
|
0
|
|
4548
4616
|
);
|
|
4549
|
-
console.log(
|
|
4617
|
+
console.log(
|
|
4618
|
+
`\u2713 Generated ${queries.size} models, ${totalQueries} prebaked queries`
|
|
4619
|
+
);
|
|
4550
4620
|
console.log(`\u2713 Output: ${outputPath}`);
|
|
4551
4621
|
});
|
|
4552
4622
|
}
|
|
@@ -4569,7 +4639,10 @@ function generateCode(models, queries, dialect) {
|
|
|
4569
4639
|
return `// Generated by @prisma-sql/generator - DO NOT EDIT
|
|
4570
4640
|
import { buildSQL, transformQueryResults, type PrismaMethod } from 'prisma-sql'
|
|
4571
4641
|
|
|
4572
|
-
|
|
4642
|
+
// Export models for advanced use cases (createToSQL, etc)
|
|
4643
|
+
export const MODELS = ${JSON.stringify(cleanModels, null, 2)} as const
|
|
4644
|
+
|
|
4645
|
+
export type Models = typeof MODELS
|
|
4573
4646
|
|
|
4574
4647
|
const QUERIES: Record<string, Record<string, Record<string, {
|
|
4575
4648
|
sql: string
|
|
@@ -4581,17 +4654,14 @@ const QUERIES: Record<string, Record<string, Record<string, {
|
|
|
4581
4654
|
const DIALECT = ${JSON.stringify(dialect)}
|
|
4582
4655
|
|
|
4583
4656
|
function isDynamicParam(key: string): boolean {
|
|
4584
|
-
// Common dynamic parameters that should be replaced with markers
|
|
4585
4657
|
return key === 'skip' || key === 'take' || key === 'cursor'
|
|
4586
4658
|
}
|
|
4587
4659
|
|
|
4588
4660
|
function normalizeQuery(args: any): string {
|
|
4589
4661
|
if (!args) return '{}'
|
|
4590
4662
|
|
|
4591
|
-
// Clone and normalize the args
|
|
4592
4663
|
const normalized = JSON.parse(JSON.stringify(args))
|
|
4593
4664
|
|
|
4594
|
-
// Replace dynamic params with markers to match prebaked keys
|
|
4595
4665
|
function replaceDynamicParams(obj: any): any {
|
|
4596
4666
|
if (!obj || typeof obj !== 'object') return obj
|
|
4597
4667
|
|
|
@@ -4601,7 +4671,6 @@ function normalizeQuery(args: any): string {
|
|
|
4601
4671
|
|
|
4602
4672
|
const result: any = {}
|
|
4603
4673
|
for (const [key, value] of Object.entries(obj)) {
|
|
4604
|
-
// Replace top-level dynamic params with markers
|
|
4605
4674
|
if (isDynamicParam(key)) {
|
|
4606
4675
|
result[key] = \`__DYNAMIC_\${key}__\`
|
|
4607
4676
|
} else {
|
|
@@ -4613,13 +4682,11 @@ function normalizeQuery(args: any): string {
|
|
|
4613
4682
|
|
|
4614
4683
|
const withMarkers = replaceDynamicParams(normalized)
|
|
4615
4684
|
|
|
4616
|
-
// Remove empty objects to match prebaked keys
|
|
4617
4685
|
function removeEmptyObjects(obj: any): any {
|
|
4618
4686
|
if (!obj || typeof obj !== 'object' || Array.isArray(obj)) return obj
|
|
4619
4687
|
|
|
4620
4688
|
const result: any = {}
|
|
4621
4689
|
for (const [key, value] of Object.entries(obj)) {
|
|
4622
|
-
// Skip empty objects (but keep empty arrays)
|
|
4623
4690
|
if (value && typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length === 0) {
|
|
4624
4691
|
continue
|
|
4625
4692
|
}
|
|
@@ -4630,7 +4697,6 @@ function normalizeQuery(args: any): string {
|
|
|
4630
4697
|
|
|
4631
4698
|
const cleaned = removeEmptyObjects(withMarkers)
|
|
4632
4699
|
|
|
4633
|
-
// Sort keys recursively for deterministic matching
|
|
4634
4700
|
return JSON.stringify(cleaned, (key, value) => {
|
|
4635
4701
|
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
4636
4702
|
const sorted: Record<string, unknown> = {}
|
|
@@ -4648,9 +4714,7 @@ function extractDynamicParams(args: any, dynamicKeys: string[]): unknown[] {
|
|
|
4648
4714
|
|
|
4649
4715
|
for (const key of dynamicKeys) {
|
|
4650
4716
|
const parts = key.split(':')
|
|
4651
|
-
|
|
4652
4717
|
const lookupKey = parts.length === 2 ? parts[1] : key
|
|
4653
|
-
|
|
4654
4718
|
const value = args[lookupKey]
|
|
4655
4719
|
|
|
4656
4720
|
if (value === undefined) {
|
|
@@ -4677,7 +4741,7 @@ async function executeQuery(client: any, sql: string, params: unknown[]): Promis
|
|
|
4677
4741
|
return stmt.all(...params)
|
|
4678
4742
|
}
|
|
4679
4743
|
|
|
4680
|
-
export function
|
|
4744
|
+
export function speedExtension(config: {
|
|
4681
4745
|
postgres?: any
|
|
4682
4746
|
sqlite?: any
|
|
4683
4747
|
debug?: boolean
|
|
@@ -4690,10 +4754,11 @@ export function createExtension(config: {
|
|
|
4690
4754
|
prebaked: boolean
|
|
4691
4755
|
}) => void
|
|
4692
4756
|
}) {
|
|
4757
|
+
// models is NOT a parameter - uses internal MODELS
|
|
4693
4758
|
const { postgres, sqlite, debug, onQuery } = config
|
|
4694
4759
|
|
|
4695
4760
|
if (!postgres && !sqlite) {
|
|
4696
|
-
throw new Error('
|
|
4761
|
+
throw new Error('speedExtension requires postgres or sqlite client')
|
|
4697
4762
|
}
|
|
4698
4763
|
|
|
4699
4764
|
const client = postgres || sqlite
|
|
@@ -4720,6 +4785,7 @@ export function createExtension(config: {
|
|
|
4720
4785
|
params = [...prebakedQuery.params, ...extractDynamicParams(args, prebakedQuery.dynamicKeys)]
|
|
4721
4786
|
prebaked = true
|
|
4722
4787
|
} else {
|
|
4788
|
+
// Use internal MODELS directly
|
|
4723
4789
|
const model = MODELS.find((m: any) => m.name === modelName)
|
|
4724
4790
|
|
|
4725
4791
|
if (!model) {
|