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