prisma-sql 1.70.0 → 1.72.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 +278 -245
- package/dist/generator.cjs.map +1 -1
- package/dist/generator.js +278 -245
- package/dist/generator.js.map +1 -1
- package/dist/index.cjs +456 -394
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +456 -395
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -57,6 +57,265 @@ var __async = (__this, __arguments, generator) => {
|
|
|
57
57
|
});
|
|
58
58
|
};
|
|
59
59
|
|
|
60
|
+
// src/utils/normalize-value.ts
|
|
61
|
+
var globalDateMode = "iso";
|
|
62
|
+
function setNormalizeDateMode(mode) {
|
|
63
|
+
globalDateMode = mode;
|
|
64
|
+
}
|
|
65
|
+
function detectSqliteDateMode(client) {
|
|
66
|
+
try {
|
|
67
|
+
const tables = client.prepare(
|
|
68
|
+
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '_prisma_%' LIMIT 50"
|
|
69
|
+
).all();
|
|
70
|
+
for (const { name } of tables) {
|
|
71
|
+
const row = client.prepare(`SELECT typeof("createdAt") as t FROM "${name}" LIMIT 1`).get();
|
|
72
|
+
if (row) {
|
|
73
|
+
return row.t === "integer" ? "ms" : "iso";
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
} catch (e) {
|
|
77
|
+
}
|
|
78
|
+
return "iso";
|
|
79
|
+
}
|
|
80
|
+
var MAX_DEPTH = 20;
|
|
81
|
+
function normalizeValue(value, seen = /* @__PURE__ */ new WeakSet(), depth = 0) {
|
|
82
|
+
if (depth > MAX_DEPTH) {
|
|
83
|
+
throw new Error(`Max normalization depth exceeded (${MAX_DEPTH} levels)`);
|
|
84
|
+
}
|
|
85
|
+
if (value instanceof Date) {
|
|
86
|
+
return normalizeDateValue(value);
|
|
87
|
+
}
|
|
88
|
+
if (typeof value === "bigint") {
|
|
89
|
+
return value.toString();
|
|
90
|
+
}
|
|
91
|
+
if (Array.isArray(value)) {
|
|
92
|
+
return normalizeArrayValue(value, seen, depth);
|
|
93
|
+
}
|
|
94
|
+
if (value && typeof value === "object") {
|
|
95
|
+
return normalizeObjectValue(value, seen, depth);
|
|
96
|
+
}
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
function normalizeDateValue(date) {
|
|
100
|
+
const t = date.getTime();
|
|
101
|
+
if (!Number.isFinite(t)) {
|
|
102
|
+
throw new Error("Invalid Date value in SQL params");
|
|
103
|
+
}
|
|
104
|
+
if (globalDateMode === "ms") {
|
|
105
|
+
return t;
|
|
106
|
+
}
|
|
107
|
+
return date.toISOString();
|
|
108
|
+
}
|
|
109
|
+
function normalizeArrayValue(value, seen, depth) {
|
|
110
|
+
const arrRef = value;
|
|
111
|
+
if (seen.has(arrRef)) {
|
|
112
|
+
throw new Error("Circular reference in SQL params");
|
|
113
|
+
}
|
|
114
|
+
seen.add(arrRef);
|
|
115
|
+
const out = value.map((v) => normalizeValue(v, seen, depth + 1));
|
|
116
|
+
seen.delete(arrRef);
|
|
117
|
+
return out;
|
|
118
|
+
}
|
|
119
|
+
function normalizeObjectValue(value, seen, depth) {
|
|
120
|
+
if (value instanceof Uint8Array) return value;
|
|
121
|
+
if (typeof Buffer !== "undefined" && Buffer.isBuffer(value)) return value;
|
|
122
|
+
const proto = Object.getPrototypeOf(value);
|
|
123
|
+
const isPlain = proto === Object.prototype || proto === null;
|
|
124
|
+
if (!isPlain) return value;
|
|
125
|
+
const obj = value;
|
|
126
|
+
if (seen.has(obj)) {
|
|
127
|
+
throw new Error("Circular reference in SQL params");
|
|
128
|
+
}
|
|
129
|
+
seen.add(obj);
|
|
130
|
+
const out = {};
|
|
131
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
132
|
+
out[k] = normalizeValue(v, seen, depth + 1);
|
|
133
|
+
}
|
|
134
|
+
seen.delete(obj);
|
|
135
|
+
return out;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// src/sql-builder-dialect.ts
|
|
139
|
+
var globalDialect = "postgres";
|
|
140
|
+
function setGlobalDialect(dialect) {
|
|
141
|
+
if (dialect !== "postgres" && dialect !== "sqlite") {
|
|
142
|
+
throw new Error(
|
|
143
|
+
`Invalid dialect: ${dialect}. Must be 'postgres' or 'sqlite'`
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
globalDialect = dialect;
|
|
147
|
+
}
|
|
148
|
+
function getGlobalDialect() {
|
|
149
|
+
return globalDialect;
|
|
150
|
+
}
|
|
151
|
+
function assertNonEmpty(value, name) {
|
|
152
|
+
if (!value || value.trim().length === 0) {
|
|
153
|
+
throw new Error(`${name} is required and cannot be empty`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function arrayContains(column, value, arrayType, dialect) {
|
|
157
|
+
assertNonEmpty(column, "arrayContains column");
|
|
158
|
+
assertNonEmpty(value, "arrayContains value");
|
|
159
|
+
if (dialect === "postgres") {
|
|
160
|
+
return `${column} @> ARRAY[${value}]::${arrayType}`;
|
|
161
|
+
}
|
|
162
|
+
return `EXISTS (SELECT 1 FROM json_each(${column}) WHERE value = ${value})`;
|
|
163
|
+
}
|
|
164
|
+
function arrayOverlaps(column, value, arrayType, dialect) {
|
|
165
|
+
assertNonEmpty(column, "arrayOverlaps column");
|
|
166
|
+
assertNonEmpty(value, "arrayOverlaps value");
|
|
167
|
+
if (dialect === "postgres") {
|
|
168
|
+
return `${column} && ${value}::${arrayType}`;
|
|
169
|
+
}
|
|
170
|
+
return `EXISTS (
|
|
171
|
+
SELECT 1 FROM json_each(${column}) AS col
|
|
172
|
+
JOIN json_each(${value}) AS val
|
|
173
|
+
WHERE col.value = val.value
|
|
174
|
+
)`;
|
|
175
|
+
}
|
|
176
|
+
function arrayContainsAll(column, value, arrayType, dialect) {
|
|
177
|
+
assertNonEmpty(column, "arrayContainsAll column");
|
|
178
|
+
assertNonEmpty(value, "arrayContainsAll value");
|
|
179
|
+
if (dialect === "postgres") {
|
|
180
|
+
return `${column} @> ${value}::${arrayType}`;
|
|
181
|
+
}
|
|
182
|
+
return `NOT EXISTS (
|
|
183
|
+
SELECT 1 FROM json_each(${value}) AS val
|
|
184
|
+
WHERE NOT EXISTS (
|
|
185
|
+
SELECT 1 FROM json_each(${column}) AS col
|
|
186
|
+
WHERE col.value = val.value
|
|
187
|
+
)
|
|
188
|
+
)`;
|
|
189
|
+
}
|
|
190
|
+
function arrayIsEmpty(column, dialect) {
|
|
191
|
+
assertNonEmpty(column, "arrayIsEmpty column");
|
|
192
|
+
if (dialect === "postgres") {
|
|
193
|
+
return `(${column} IS NULL OR array_length(${column}, 1) IS NULL)`;
|
|
194
|
+
}
|
|
195
|
+
return `(${column} IS NULL OR json_array_length(${column}) = 0)`;
|
|
196
|
+
}
|
|
197
|
+
function arrayIsNotEmpty(column, dialect) {
|
|
198
|
+
assertNonEmpty(column, "arrayIsNotEmpty column");
|
|
199
|
+
if (dialect === "postgres") {
|
|
200
|
+
return `(${column} IS NOT NULL AND array_length(${column}, 1) IS NOT NULL)`;
|
|
201
|
+
}
|
|
202
|
+
return `(${column} IS NOT NULL AND json_array_length(${column}) > 0)`;
|
|
203
|
+
}
|
|
204
|
+
function arrayEquals(column, value, arrayType, dialect) {
|
|
205
|
+
assertNonEmpty(column, "arrayEquals column");
|
|
206
|
+
assertNonEmpty(value, "arrayEquals value");
|
|
207
|
+
if (dialect === "postgres") {
|
|
208
|
+
return `${column} = ${value}::${arrayType}`;
|
|
209
|
+
}
|
|
210
|
+
return `json(${column}) = json(${value})`;
|
|
211
|
+
}
|
|
212
|
+
function caseInsensitiveLike(column, pattern, dialect) {
|
|
213
|
+
assertNonEmpty(column, "caseInsensitiveLike column");
|
|
214
|
+
assertNonEmpty(pattern, "caseInsensitiveLike pattern");
|
|
215
|
+
if (dialect === "postgres") {
|
|
216
|
+
return `${column} ILIKE ${pattern}`;
|
|
217
|
+
}
|
|
218
|
+
return `LOWER(${column}) LIKE LOWER(${pattern})`;
|
|
219
|
+
}
|
|
220
|
+
function caseInsensitiveEquals(column, value, dialect) {
|
|
221
|
+
assertNonEmpty(column, "caseInsensitiveEquals column");
|
|
222
|
+
assertNonEmpty(value, "caseInsensitiveEquals value");
|
|
223
|
+
return `LOWER(${column}) = LOWER(${value})`;
|
|
224
|
+
}
|
|
225
|
+
function jsonExtractText(column, path, dialect) {
|
|
226
|
+
assertNonEmpty(column, "jsonExtractText column");
|
|
227
|
+
assertNonEmpty(path, "jsonExtractText path");
|
|
228
|
+
if (dialect === "postgres") {
|
|
229
|
+
const p = String(path).trim();
|
|
230
|
+
const pathExpr = /^\$\d+$/.test(p) ? `${p}::text[]` : p;
|
|
231
|
+
return `${column}#>>${pathExpr}`;
|
|
232
|
+
}
|
|
233
|
+
return `json_extract(${column}, ${path})`;
|
|
234
|
+
}
|
|
235
|
+
function jsonExtractNumeric(column, path, dialect) {
|
|
236
|
+
assertNonEmpty(column, "jsonExtractNumeric column");
|
|
237
|
+
assertNonEmpty(path, "jsonExtractNumeric path");
|
|
238
|
+
if (dialect === "postgres") {
|
|
239
|
+
const p = String(path).trim();
|
|
240
|
+
const pathExpr = /^\$\d+$/.test(p) ? `${p}::text[]` : p;
|
|
241
|
+
return `(${column}#>>${pathExpr})::numeric`;
|
|
242
|
+
}
|
|
243
|
+
return `CAST(json_extract(${column}, ${path}) AS REAL)`;
|
|
244
|
+
}
|
|
245
|
+
function jsonToText(column, dialect) {
|
|
246
|
+
assertNonEmpty(column, "jsonToText column");
|
|
247
|
+
if (dialect === "postgres") {
|
|
248
|
+
return `${column}::text`;
|
|
249
|
+
}
|
|
250
|
+
return column;
|
|
251
|
+
}
|
|
252
|
+
function inArray(column, value, dialect) {
|
|
253
|
+
assertNonEmpty(column, "inArray column");
|
|
254
|
+
assertNonEmpty(value, "inArray value");
|
|
255
|
+
if (dialect === "postgres") {
|
|
256
|
+
return `${column} = ANY(${value})`;
|
|
257
|
+
}
|
|
258
|
+
return `${column} IN (SELECT value FROM json_each(${value}))`;
|
|
259
|
+
}
|
|
260
|
+
function notInArray(column, value, dialect) {
|
|
261
|
+
assertNonEmpty(column, "notInArray column");
|
|
262
|
+
assertNonEmpty(value, "notInArray value");
|
|
263
|
+
if (dialect === "postgres") {
|
|
264
|
+
return `${column} != ALL(${value})`;
|
|
265
|
+
}
|
|
266
|
+
return `${column} NOT IN (SELECT value FROM json_each(${value}))`;
|
|
267
|
+
}
|
|
268
|
+
function getArrayType(prismaType, dialect) {
|
|
269
|
+
if (!prismaType || prismaType.length === 0) {
|
|
270
|
+
return dialect === "sqlite" ? "TEXT" : "text[]";
|
|
271
|
+
}
|
|
272
|
+
if (dialect === "sqlite") {
|
|
273
|
+
return "TEXT";
|
|
274
|
+
}
|
|
275
|
+
const baseType = prismaType.replace(/\[\]|\?/g, "");
|
|
276
|
+
switch (baseType) {
|
|
277
|
+
case "String":
|
|
278
|
+
return "text[]";
|
|
279
|
+
case "Int":
|
|
280
|
+
return "integer[]";
|
|
281
|
+
case "Float":
|
|
282
|
+
return "double precision[]";
|
|
283
|
+
case "Decimal":
|
|
284
|
+
return "numeric[]";
|
|
285
|
+
case "Boolean":
|
|
286
|
+
return "boolean[]";
|
|
287
|
+
case "BigInt":
|
|
288
|
+
return "bigint[]";
|
|
289
|
+
case "DateTime":
|
|
290
|
+
return "timestamptz[]";
|
|
291
|
+
default:
|
|
292
|
+
return `"${baseType}"[]`;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
function jsonAgg(content, dialect) {
|
|
296
|
+
assertNonEmpty(content, "jsonAgg content");
|
|
297
|
+
if (dialect === "postgres") {
|
|
298
|
+
return `json_agg(${content})`;
|
|
299
|
+
}
|
|
300
|
+
return `json_group_array(${content})`;
|
|
301
|
+
}
|
|
302
|
+
function jsonBuildObject(pairs, dialect) {
|
|
303
|
+
const safePairs = (pairs != null ? pairs : "").trim();
|
|
304
|
+
if (dialect === "postgres") {
|
|
305
|
+
return safePairs.length > 0 ? `json_build_object(${safePairs})` : `json_build_object()`;
|
|
306
|
+
}
|
|
307
|
+
return safePairs.length > 0 ? `json_object(${safePairs})` : `json_object()`;
|
|
308
|
+
}
|
|
309
|
+
function prepareArrayParam(value, dialect) {
|
|
310
|
+
if (!Array.isArray(value)) {
|
|
311
|
+
throw new Error("prepareArrayParam requires array value");
|
|
312
|
+
}
|
|
313
|
+
if (dialect === "postgres") {
|
|
314
|
+
return value.map((v) => normalizeValue(v));
|
|
315
|
+
}
|
|
316
|
+
return JSON.stringify(value.map((v) => normalizeValue(v)));
|
|
317
|
+
}
|
|
318
|
+
|
|
60
319
|
// src/builder/shared/constants.ts
|
|
61
320
|
var IS_PRODUCTION = process.env.NODE_ENV === "production";
|
|
62
321
|
var SQL_SEPARATORS = Object.freeze({
|
|
@@ -753,414 +1012,163 @@ function normalizeKeyList(input) {
|
|
|
753
1012
|
if (raw.length === 0) return [];
|
|
754
1013
|
if (raw.includes(",")) {
|
|
755
1014
|
return raw.split(",").map((s2) => s2.trim()).filter((s2) => s2.length > 0);
|
|
756
|
-
}
|
|
757
|
-
return [raw];
|
|
758
|
-
}
|
|
759
|
-
const s = String(input).trim();
|
|
760
|
-
return s.length > 0 ? [s] : [];
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
// src/builder/shared/model-field-cache.ts
|
|
764
|
-
var FIELD_INDICES_CACHE = /* @__PURE__ */ new WeakMap();
|
|
765
|
-
function normalizeField(field) {
|
|
766
|
-
return field;
|
|
767
|
-
}
|
|
768
|
-
function getFieldIndices(model) {
|
|
769
|
-
var _a3;
|
|
770
|
-
let cached = FIELD_INDICES_CACHE.get(model);
|
|
771
|
-
if (cached) return cached;
|
|
772
|
-
const scalarFields = /* @__PURE__ */ new Map();
|
|
773
|
-
const relationFields = /* @__PURE__ */ new Map();
|
|
774
|
-
const allFieldsByName = /* @__PURE__ */ new Map();
|
|
775
|
-
const scalarNames = [];
|
|
776
|
-
const relationNames = [];
|
|
777
|
-
const jsonFields = /* @__PURE__ */ new Set();
|
|
778
|
-
const pkFields = [];
|
|
779
|
-
const columnMap = /* @__PURE__ */ new Map();
|
|
780
|
-
const quotedColumns = /* @__PURE__ */ new Map();
|
|
781
|
-
for (const rawField of model.fields) {
|
|
782
|
-
const field = normalizeField(rawField);
|
|
783
|
-
allFieldsByName.set(field.name, field);
|
|
784
|
-
if (field.isRelation) {
|
|
785
|
-
relationFields.set(field.name, field);
|
|
786
|
-
relationNames.push(field.name);
|
|
787
|
-
} else {
|
|
788
|
-
scalarFields.set(field.name, field);
|
|
789
|
-
scalarNames.push(field.name);
|
|
790
|
-
const fieldType = String((_a3 = field.type) != null ? _a3 : "").toLowerCase();
|
|
791
|
-
if (fieldType === "json") {
|
|
792
|
-
jsonFields.add(field.name);
|
|
793
|
-
}
|
|
794
|
-
if (field.isId || field.isPrimaryKey || field.primaryKey) {
|
|
795
|
-
pkFields.push(field.name);
|
|
796
|
-
}
|
|
797
|
-
if (field.dbName && field.dbName !== field.name) {
|
|
798
|
-
columnMap.set(field.name, field.dbName);
|
|
799
|
-
}
|
|
800
|
-
const columnName = field.dbName || field.name;
|
|
801
|
-
quotedColumns.set(field.name, quote(columnName));
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
cached = Object.freeze({
|
|
805
|
-
scalarFields,
|
|
806
|
-
relationFields,
|
|
807
|
-
allFieldsByName,
|
|
808
|
-
scalarNames,
|
|
809
|
-
relationNames,
|
|
810
|
-
jsonFields,
|
|
811
|
-
pkFields,
|
|
812
|
-
columnMap,
|
|
813
|
-
quotedColumns
|
|
814
|
-
});
|
|
815
|
-
FIELD_INDICES_CACHE.set(model, cached);
|
|
816
|
-
return cached;
|
|
817
|
-
}
|
|
818
|
-
function getRelationFieldSet(model) {
|
|
819
|
-
return new Set(getFieldIndices(model).relationNames);
|
|
820
|
-
}
|
|
821
|
-
function getScalarFieldSet(model) {
|
|
822
|
-
return new Set(getFieldIndices(model).scalarNames);
|
|
823
|
-
}
|
|
824
|
-
function getColumnMap(model) {
|
|
825
|
-
return getFieldIndices(model).columnMap;
|
|
826
|
-
}
|
|
827
|
-
function getScalarFieldNames(model) {
|
|
828
|
-
return [...getFieldIndices(model).scalarNames];
|
|
829
|
-
}
|
|
830
|
-
function getQuotedColumn(model, fieldName) {
|
|
831
|
-
return getFieldIndices(model).quotedColumns.get(fieldName);
|
|
832
|
-
}
|
|
833
|
-
function getJsonFieldSet(model) {
|
|
834
|
-
return getFieldIndices(model).jsonFields;
|
|
835
|
-
}
|
|
836
|
-
function parseJsonIfNeeded(isJson, value) {
|
|
837
|
-
if (!isJson) return value;
|
|
838
|
-
if (value == null) return value;
|
|
839
|
-
if (typeof value !== "string") return value;
|
|
840
|
-
try {
|
|
841
|
-
return JSON.parse(value);
|
|
842
|
-
} catch (e) {
|
|
843
|
-
return value;
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
function maybeParseJson(value, jsonSet, fieldName) {
|
|
847
|
-
if (!jsonSet.has(fieldName)) return value;
|
|
848
|
-
if (value == null) return value;
|
|
849
|
-
if (typeof value !== "string") return value;
|
|
850
|
-
try {
|
|
851
|
-
return JSON.parse(value);
|
|
852
|
-
} catch (e) {
|
|
853
|
-
return value;
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
// src/builder/joins.ts
|
|
858
|
-
function isRelationField(fieldName, model) {
|
|
859
|
-
return getRelationFieldSet(model).has(fieldName);
|
|
860
|
-
}
|
|
861
|
-
function isValidRelationField(field) {
|
|
862
|
-
if (!isNotNullish(field)) return false;
|
|
863
|
-
if (!field.isRelation) return false;
|
|
864
|
-
if (!isNotNullish(field.relatedModel) || field.relatedModel.trim().length === 0)
|
|
865
|
-
return false;
|
|
866
|
-
const fk = normalizeKeyList(field.foreignKey);
|
|
867
|
-
if (fk.length === 0) return false;
|
|
868
|
-
const refs = normalizeKeyList(field.references);
|
|
869
|
-
if (refs.length === 0) {
|
|
870
|
-
return fk.length === 1;
|
|
871
|
-
}
|
|
872
|
-
if (refs.length !== fk.length) return false;
|
|
873
|
-
return true;
|
|
874
|
-
}
|
|
875
|
-
function getReferenceFieldNames(field, foreignKeyCount) {
|
|
876
|
-
const refs = normalizeKeyList(field.references);
|
|
877
|
-
if (refs.length === 0) {
|
|
878
|
-
if (foreignKeyCount === 1) return [SPECIAL_FIELDS.ID];
|
|
879
|
-
return [];
|
|
880
|
-
}
|
|
881
|
-
if (refs.length !== foreignKeyCount) return [];
|
|
882
|
-
return refs;
|
|
883
|
-
}
|
|
884
|
-
function joinCondition(field, parentModel, childModel, parentAlias, childAlias) {
|
|
885
|
-
assertSafeAlias(parentAlias);
|
|
886
|
-
assertSafeAlias(childAlias);
|
|
887
|
-
const fkFields = normalizeKeyList(field.foreignKey);
|
|
888
|
-
if (fkFields.length === 0) {
|
|
889
|
-
throw createError(
|
|
890
|
-
`Relation '${field.name}' is missing foreignKey. This indicates a schema parsing error. Relations must specify fields/references.`,
|
|
891
|
-
{ field: field.name }
|
|
892
|
-
);
|
|
893
|
-
}
|
|
894
|
-
const refFields = getReferenceFieldNames(field, fkFields.length);
|
|
895
|
-
if (refFields.length !== fkFields.length) {
|
|
896
|
-
throw createError(
|
|
897
|
-
`Relation '${field.name}' is missing references (or references count does not match foreignKey count). This is required to support non-id and composite keys.`,
|
|
898
|
-
{ field: field.name }
|
|
899
|
-
);
|
|
900
|
-
}
|
|
901
|
-
const parts = [];
|
|
902
|
-
for (let i = 0; i < fkFields.length; i++) {
|
|
903
|
-
const fk = fkFields[i];
|
|
904
|
-
const ref = refFields[i];
|
|
905
|
-
const left = field.isForeignKeyLocal ? `${childAlias}.${quoteColumn(childModel, ref)}` : `${childAlias}.${quoteColumn(childModel, fk)}`;
|
|
906
|
-
const right = field.isForeignKeyLocal ? `${parentAlias}.${quoteColumn(parentModel, fk)}` : `${parentAlias}.${quoteColumn(parentModel, ref)}`;
|
|
907
|
-
parts.push(`${left} = ${right}`);
|
|
908
|
-
}
|
|
909
|
-
return parts.length === 1 ? parts[0] : `(${parts.join(" AND ")})`;
|
|
910
|
-
}
|
|
911
|
-
function getModelByName(schemas, name) {
|
|
912
|
-
return schemas.find((m) => m.name === name);
|
|
913
|
-
}
|
|
914
|
-
|
|
915
|
-
// src/utils/normalize-value.ts
|
|
916
|
-
var globalDateMode = "iso";
|
|
917
|
-
function setNormalizeDateMode(mode) {
|
|
918
|
-
globalDateMode = mode;
|
|
919
|
-
}
|
|
920
|
-
function detectSqliteDateMode(client) {
|
|
921
|
-
try {
|
|
922
|
-
const tables = client.prepare(
|
|
923
|
-
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '_prisma_%' LIMIT 50"
|
|
924
|
-
).all();
|
|
925
|
-
for (const { name } of tables) {
|
|
926
|
-
const row = client.prepare(`SELECT typeof("createdAt") as t FROM "${name}" LIMIT 1`).get();
|
|
927
|
-
if (row) {
|
|
928
|
-
return row.t === "integer" ? "ms" : "iso";
|
|
929
|
-
}
|
|
930
|
-
}
|
|
931
|
-
} catch (e) {
|
|
932
|
-
}
|
|
933
|
-
return "iso";
|
|
934
|
-
}
|
|
935
|
-
var MAX_DEPTH = 20;
|
|
936
|
-
function normalizeValue(value, seen = /* @__PURE__ */ new WeakSet(), depth = 0) {
|
|
937
|
-
if (depth > MAX_DEPTH) {
|
|
938
|
-
throw new Error(`Max normalization depth exceeded (${MAX_DEPTH} levels)`);
|
|
939
|
-
}
|
|
940
|
-
if (value instanceof Date) {
|
|
941
|
-
return normalizeDateValue(value);
|
|
942
|
-
}
|
|
943
|
-
if (typeof value === "bigint") {
|
|
944
|
-
return value.toString();
|
|
945
|
-
}
|
|
946
|
-
if (Array.isArray(value)) {
|
|
947
|
-
return normalizeArrayValue(value, seen, depth);
|
|
948
|
-
}
|
|
949
|
-
if (value && typeof value === "object") {
|
|
950
|
-
return normalizeObjectValue(value, seen, depth);
|
|
951
|
-
}
|
|
952
|
-
return value;
|
|
953
|
-
}
|
|
954
|
-
function normalizeDateValue(date) {
|
|
955
|
-
const t = date.getTime();
|
|
956
|
-
if (!Number.isFinite(t)) {
|
|
957
|
-
throw new Error("Invalid Date value in SQL params");
|
|
958
|
-
}
|
|
959
|
-
if (globalDateMode === "ms") {
|
|
960
|
-
return t;
|
|
961
|
-
}
|
|
962
|
-
return date.toISOString();
|
|
963
|
-
}
|
|
964
|
-
function normalizeArrayValue(value, seen, depth) {
|
|
965
|
-
const arrRef = value;
|
|
966
|
-
if (seen.has(arrRef)) {
|
|
967
|
-
throw new Error("Circular reference in SQL params");
|
|
968
|
-
}
|
|
969
|
-
seen.add(arrRef);
|
|
970
|
-
const out = value.map((v) => normalizeValue(v, seen, depth + 1));
|
|
971
|
-
seen.delete(arrRef);
|
|
972
|
-
return out;
|
|
973
|
-
}
|
|
974
|
-
function normalizeObjectValue(value, seen, depth) {
|
|
975
|
-
if (value instanceof Uint8Array) return value;
|
|
976
|
-
if (typeof Buffer !== "undefined" && Buffer.isBuffer(value)) return value;
|
|
977
|
-
const proto = Object.getPrototypeOf(value);
|
|
978
|
-
const isPlain = proto === Object.prototype || proto === null;
|
|
979
|
-
if (!isPlain) return value;
|
|
980
|
-
const obj = value;
|
|
981
|
-
if (seen.has(obj)) {
|
|
982
|
-
throw new Error("Circular reference in SQL params");
|
|
983
|
-
}
|
|
984
|
-
seen.add(obj);
|
|
985
|
-
const out = {};
|
|
986
|
-
for (const [k, v] of Object.entries(obj)) {
|
|
987
|
-
out[k] = normalizeValue(v, seen, depth + 1);
|
|
988
|
-
}
|
|
989
|
-
seen.delete(obj);
|
|
990
|
-
return out;
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
// src/sql-builder-dialect.ts
|
|
994
|
-
var globalDialect = "postgres";
|
|
995
|
-
function getGlobalDialect() {
|
|
996
|
-
return globalDialect;
|
|
997
|
-
}
|
|
998
|
-
function assertNonEmpty(value, name) {
|
|
999
|
-
if (!value || value.trim().length === 0) {
|
|
1000
|
-
throw new Error(`${name} is required and cannot be empty`);
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1003
|
-
function arrayContains(column, value, arrayType, dialect) {
|
|
1004
|
-
assertNonEmpty(column, "arrayContains column");
|
|
1005
|
-
assertNonEmpty(value, "arrayContains value");
|
|
1006
|
-
if (dialect === "postgres") {
|
|
1007
|
-
return `${column} @> ARRAY[${value}]::${arrayType}`;
|
|
1008
|
-
}
|
|
1009
|
-
return `EXISTS (SELECT 1 FROM json_each(${column}) WHERE value = ${value})`;
|
|
1010
|
-
}
|
|
1011
|
-
function arrayOverlaps(column, value, arrayType, dialect) {
|
|
1012
|
-
assertNonEmpty(column, "arrayOverlaps column");
|
|
1013
|
-
assertNonEmpty(value, "arrayOverlaps value");
|
|
1014
|
-
if (dialect === "postgres") {
|
|
1015
|
-
return `${column} && ${value}::${arrayType}`;
|
|
1016
|
-
}
|
|
1017
|
-
return `EXISTS (
|
|
1018
|
-
SELECT 1 FROM json_each(${column}) AS col
|
|
1019
|
-
JOIN json_each(${value}) AS val
|
|
1020
|
-
WHERE col.value = val.value
|
|
1021
|
-
)`;
|
|
1022
|
-
}
|
|
1023
|
-
function arrayContainsAll(column, value, arrayType, dialect) {
|
|
1024
|
-
assertNonEmpty(column, "arrayContainsAll column");
|
|
1025
|
-
assertNonEmpty(value, "arrayContainsAll value");
|
|
1026
|
-
if (dialect === "postgres") {
|
|
1027
|
-
return `${column} @> ${value}::${arrayType}`;
|
|
1028
|
-
}
|
|
1029
|
-
return `NOT EXISTS (
|
|
1030
|
-
SELECT 1 FROM json_each(${value}) AS val
|
|
1031
|
-
WHERE NOT EXISTS (
|
|
1032
|
-
SELECT 1 FROM json_each(${column}) AS col
|
|
1033
|
-
WHERE col.value = val.value
|
|
1034
|
-
)
|
|
1035
|
-
)`;
|
|
1036
|
-
}
|
|
1037
|
-
function arrayIsEmpty(column, dialect) {
|
|
1038
|
-
assertNonEmpty(column, "arrayIsEmpty column");
|
|
1039
|
-
if (dialect === "postgres") {
|
|
1040
|
-
return `(${column} IS NULL OR array_length(${column}, 1) IS NULL)`;
|
|
1015
|
+
}
|
|
1016
|
+
return [raw];
|
|
1041
1017
|
}
|
|
1042
|
-
|
|
1018
|
+
const s = String(input).trim();
|
|
1019
|
+
return s.length > 0 ? [s] : [];
|
|
1043
1020
|
}
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
return `(${column} IS NOT NULL AND json_array_length(${column}) > 0)`;
|
|
1021
|
+
|
|
1022
|
+
// src/builder/shared/model-field-cache.ts
|
|
1023
|
+
var FIELD_INDICES_CACHE = /* @__PURE__ */ new WeakMap();
|
|
1024
|
+
function normalizeField(field) {
|
|
1025
|
+
return field;
|
|
1050
1026
|
}
|
|
1051
|
-
function
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
if (
|
|
1055
|
-
|
|
1027
|
+
function getFieldIndices(model) {
|
|
1028
|
+
var _a3;
|
|
1029
|
+
let cached = FIELD_INDICES_CACHE.get(model);
|
|
1030
|
+
if (cached) return cached;
|
|
1031
|
+
const scalarFields = /* @__PURE__ */ new Map();
|
|
1032
|
+
const relationFields = /* @__PURE__ */ new Map();
|
|
1033
|
+
const allFieldsByName = /* @__PURE__ */ new Map();
|
|
1034
|
+
const scalarNames = [];
|
|
1035
|
+
const relationNames = [];
|
|
1036
|
+
const jsonFields = /* @__PURE__ */ new Set();
|
|
1037
|
+
const pkFields = [];
|
|
1038
|
+
const columnMap = /* @__PURE__ */ new Map();
|
|
1039
|
+
const quotedColumns = /* @__PURE__ */ new Map();
|
|
1040
|
+
for (const rawField of model.fields) {
|
|
1041
|
+
const field = normalizeField(rawField);
|
|
1042
|
+
allFieldsByName.set(field.name, field);
|
|
1043
|
+
if (field.isRelation) {
|
|
1044
|
+
relationFields.set(field.name, field);
|
|
1045
|
+
relationNames.push(field.name);
|
|
1046
|
+
} else {
|
|
1047
|
+
scalarFields.set(field.name, field);
|
|
1048
|
+
scalarNames.push(field.name);
|
|
1049
|
+
const fieldType = String((_a3 = field.type) != null ? _a3 : "").toLowerCase();
|
|
1050
|
+
if (fieldType === "json") {
|
|
1051
|
+
jsonFields.add(field.name);
|
|
1052
|
+
}
|
|
1053
|
+
if (field.isId || field.isPrimaryKey || field.primaryKey) {
|
|
1054
|
+
pkFields.push(field.name);
|
|
1055
|
+
}
|
|
1056
|
+
if (field.dbName && field.dbName !== field.name) {
|
|
1057
|
+
columnMap.set(field.name, field.dbName);
|
|
1058
|
+
}
|
|
1059
|
+
const columnName = field.dbName || field.name;
|
|
1060
|
+
quotedColumns.set(field.name, quote(columnName));
|
|
1061
|
+
}
|
|
1056
1062
|
}
|
|
1057
|
-
|
|
1063
|
+
cached = Object.freeze({
|
|
1064
|
+
scalarFields,
|
|
1065
|
+
relationFields,
|
|
1066
|
+
allFieldsByName,
|
|
1067
|
+
scalarNames,
|
|
1068
|
+
relationNames,
|
|
1069
|
+
jsonFields,
|
|
1070
|
+
pkFields,
|
|
1071
|
+
columnMap,
|
|
1072
|
+
quotedColumns
|
|
1073
|
+
});
|
|
1074
|
+
FIELD_INDICES_CACHE.set(model, cached);
|
|
1075
|
+
return cached;
|
|
1058
1076
|
}
|
|
1059
|
-
function
|
|
1060
|
-
|
|
1061
|
-
assertNonEmpty(pattern, "caseInsensitiveLike pattern");
|
|
1062
|
-
if (dialect === "postgres") {
|
|
1063
|
-
return `${column} ILIKE ${pattern}`;
|
|
1064
|
-
}
|
|
1065
|
-
return `LOWER(${column}) LIKE LOWER(${pattern})`;
|
|
1077
|
+
function getRelationFieldSet(model) {
|
|
1078
|
+
return new Set(getFieldIndices(model).relationNames);
|
|
1066
1079
|
}
|
|
1067
|
-
function
|
|
1068
|
-
|
|
1069
|
-
assertNonEmpty(value, "caseInsensitiveEquals value");
|
|
1070
|
-
return `LOWER(${column}) = LOWER(${value})`;
|
|
1080
|
+
function getScalarFieldSet(model) {
|
|
1081
|
+
return new Set(getFieldIndices(model).scalarNames);
|
|
1071
1082
|
}
|
|
1072
|
-
function
|
|
1073
|
-
|
|
1074
|
-
assertNonEmpty(path, "jsonExtractText path");
|
|
1075
|
-
if (dialect === "postgres") {
|
|
1076
|
-
const p = String(path).trim();
|
|
1077
|
-
const pathExpr = /^\$\d+$/.test(p) ? `${p}::text[]` : p;
|
|
1078
|
-
return `${column}#>>${pathExpr}`;
|
|
1079
|
-
}
|
|
1080
|
-
return `json_extract(${column}, ${path})`;
|
|
1083
|
+
function getColumnMap(model) {
|
|
1084
|
+
return getFieldIndices(model).columnMap;
|
|
1081
1085
|
}
|
|
1082
|
-
function
|
|
1083
|
-
|
|
1084
|
-
assertNonEmpty(path, "jsonExtractNumeric path");
|
|
1085
|
-
if (dialect === "postgres") {
|
|
1086
|
-
const p = String(path).trim();
|
|
1087
|
-
const pathExpr = /^\$\d+$/.test(p) ? `${p}::text[]` : p;
|
|
1088
|
-
return `(${column}#>>${pathExpr})::numeric`;
|
|
1089
|
-
}
|
|
1090
|
-
return `CAST(json_extract(${column}, ${path}) AS REAL)`;
|
|
1086
|
+
function getScalarFieldNames(model) {
|
|
1087
|
+
return [...getFieldIndices(model).scalarNames];
|
|
1091
1088
|
}
|
|
1092
|
-
function
|
|
1093
|
-
|
|
1094
|
-
if (dialect === "postgres") {
|
|
1095
|
-
return `${column}::text`;
|
|
1096
|
-
}
|
|
1097
|
-
return column;
|
|
1089
|
+
function getQuotedColumn(model, fieldName) {
|
|
1090
|
+
return getFieldIndices(model).quotedColumns.get(fieldName);
|
|
1098
1091
|
}
|
|
1099
|
-
function
|
|
1100
|
-
|
|
1101
|
-
assertNonEmpty(value, "inArray value");
|
|
1102
|
-
if (dialect === "postgres") {
|
|
1103
|
-
return `${column} = ANY(${value})`;
|
|
1104
|
-
}
|
|
1105
|
-
return `${column} IN (SELECT value FROM json_each(${value}))`;
|
|
1092
|
+
function getJsonFieldSet(model) {
|
|
1093
|
+
return getFieldIndices(model).jsonFields;
|
|
1106
1094
|
}
|
|
1107
|
-
function
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
if (
|
|
1111
|
-
|
|
1095
|
+
function parseJsonIfNeeded(isJson, value) {
|
|
1096
|
+
if (!isJson) return value;
|
|
1097
|
+
if (value == null) return value;
|
|
1098
|
+
if (typeof value !== "string") return value;
|
|
1099
|
+
try {
|
|
1100
|
+
return JSON.parse(value);
|
|
1101
|
+
} catch (e) {
|
|
1102
|
+
return value;
|
|
1112
1103
|
}
|
|
1113
|
-
return `${column} NOT IN (SELECT value FROM json_each(${value}))`;
|
|
1114
1104
|
}
|
|
1115
|
-
function
|
|
1116
|
-
if (!
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
return
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1123
|
-
switch (baseType) {
|
|
1124
|
-
case "String":
|
|
1125
|
-
return "text[]";
|
|
1126
|
-
case "Int":
|
|
1127
|
-
return "integer[]";
|
|
1128
|
-
case "Float":
|
|
1129
|
-
return "double precision[]";
|
|
1130
|
-
case "Decimal":
|
|
1131
|
-
return "numeric[]";
|
|
1132
|
-
case "Boolean":
|
|
1133
|
-
return "boolean[]";
|
|
1134
|
-
case "BigInt":
|
|
1135
|
-
return "bigint[]";
|
|
1136
|
-
case "DateTime":
|
|
1137
|
-
return "timestamptz[]";
|
|
1138
|
-
default:
|
|
1139
|
-
return `"${baseType}"[]`;
|
|
1105
|
+
function maybeParseJson(value, jsonSet, fieldName) {
|
|
1106
|
+
if (!jsonSet.has(fieldName)) return value;
|
|
1107
|
+
if (value == null) return value;
|
|
1108
|
+
if (typeof value !== "string") return value;
|
|
1109
|
+
try {
|
|
1110
|
+
return JSON.parse(value);
|
|
1111
|
+
} catch (e) {
|
|
1112
|
+
return value;
|
|
1140
1113
|
}
|
|
1141
1114
|
}
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1115
|
+
|
|
1116
|
+
// src/builder/joins.ts
|
|
1117
|
+
function isRelationField(fieldName, model) {
|
|
1118
|
+
return getRelationFieldSet(model).has(fieldName);
|
|
1119
|
+
}
|
|
1120
|
+
function isValidRelationField(field) {
|
|
1121
|
+
if (!isNotNullish(field)) return false;
|
|
1122
|
+
if (!field.isRelation) return false;
|
|
1123
|
+
if (!isNotNullish(field.relatedModel) || field.relatedModel.trim().length === 0)
|
|
1124
|
+
return false;
|
|
1125
|
+
const fk = normalizeKeyList(field.foreignKey);
|
|
1126
|
+
if (fk.length === 0) return false;
|
|
1127
|
+
const refs = normalizeKeyList(field.references);
|
|
1128
|
+
if (refs.length === 0) {
|
|
1129
|
+
return fk.length === 1;
|
|
1146
1130
|
}
|
|
1147
|
-
|
|
1131
|
+
if (refs.length !== fk.length) return false;
|
|
1132
|
+
return true;
|
|
1148
1133
|
}
|
|
1149
|
-
function
|
|
1150
|
-
const
|
|
1151
|
-
if (
|
|
1152
|
-
|
|
1134
|
+
function getReferenceFieldNames(field, foreignKeyCount) {
|
|
1135
|
+
const refs = normalizeKeyList(field.references);
|
|
1136
|
+
if (refs.length === 0) {
|
|
1137
|
+
if (foreignKeyCount === 1) return [SPECIAL_FIELDS.ID];
|
|
1138
|
+
return [];
|
|
1153
1139
|
}
|
|
1154
|
-
|
|
1140
|
+
if (refs.length !== foreignKeyCount) return [];
|
|
1141
|
+
return refs;
|
|
1155
1142
|
}
|
|
1156
|
-
function
|
|
1157
|
-
|
|
1158
|
-
|
|
1143
|
+
function joinCondition(field, parentModel, childModel, parentAlias, childAlias) {
|
|
1144
|
+
assertSafeAlias(parentAlias);
|
|
1145
|
+
assertSafeAlias(childAlias);
|
|
1146
|
+
const fkFields = normalizeKeyList(field.foreignKey);
|
|
1147
|
+
if (fkFields.length === 0) {
|
|
1148
|
+
throw createError(
|
|
1149
|
+
`Relation '${field.name}' is missing foreignKey. This indicates a schema parsing error. Relations must specify fields/references.`,
|
|
1150
|
+
{ field: field.name }
|
|
1151
|
+
);
|
|
1159
1152
|
}
|
|
1160
|
-
|
|
1161
|
-
|
|
1153
|
+
const refFields = getReferenceFieldNames(field, fkFields.length);
|
|
1154
|
+
if (refFields.length !== fkFields.length) {
|
|
1155
|
+
throw createError(
|
|
1156
|
+
`Relation '${field.name}' is missing references (or references count does not match foreignKey count). This is required to support non-id and composite keys.`,
|
|
1157
|
+
{ field: field.name }
|
|
1158
|
+
);
|
|
1162
1159
|
}
|
|
1163
|
-
|
|
1160
|
+
const parts = [];
|
|
1161
|
+
for (let i = 0; i < fkFields.length; i++) {
|
|
1162
|
+
const fk = fkFields[i];
|
|
1163
|
+
const ref = refFields[i];
|
|
1164
|
+
const left = field.isForeignKeyLocal ? `${childAlias}.${quoteColumn(childModel, ref)}` : `${childAlias}.${quoteColumn(childModel, fk)}`;
|
|
1165
|
+
const right = field.isForeignKeyLocal ? `${parentAlias}.${quoteColumn(parentModel, fk)}` : `${parentAlias}.${quoteColumn(parentModel, ref)}`;
|
|
1166
|
+
parts.push(`${left} = ${right}`);
|
|
1167
|
+
}
|
|
1168
|
+
return parts.length === 1 ? parts[0] : `(${parts.join(" AND ")})`;
|
|
1169
|
+
}
|
|
1170
|
+
function getModelByName(schemas, name) {
|
|
1171
|
+
return schemas.find((m) => m.name === name);
|
|
1164
1172
|
}
|
|
1165
1173
|
function normalizeIntLike(name, v, opts = {}) {
|
|
1166
1174
|
var _a3, _b;
|
|
@@ -4868,7 +4876,6 @@ var DEFAULT_SELECT_CACHE = /* @__PURE__ */ new WeakMap();
|
|
|
4868
4876
|
function toSelectEntries(select) {
|
|
4869
4877
|
const out = [];
|
|
4870
4878
|
for (const [k, v] of Object.entries(select)) {
|
|
4871
|
-
if (k === "_count") continue;
|
|
4872
4879
|
if (v !== false && v !== void 0) out.push([k, v]);
|
|
4873
4880
|
}
|
|
4874
4881
|
return out;
|
|
@@ -4961,7 +4968,9 @@ function validateFieldKeys(entries, scalarSet, relationSet, allowCount = false)
|
|
|
4961
4968
|
if (!scalarSet.has(k) && !relationSet.has(k)) unknown.push(k);
|
|
4962
4969
|
}
|
|
4963
4970
|
if (unknown.length > 0) {
|
|
4964
|
-
throw new Error(
|
|
4971
|
+
throw new Error(
|
|
4972
|
+
`Unknown field '${unknown.join("', '")}' does not exist on this model`
|
|
4973
|
+
);
|
|
4965
4974
|
}
|
|
4966
4975
|
}
|
|
4967
4976
|
function buildSelectedScalarParts(entries, scalarNames, alias, model) {
|
|
@@ -5153,12 +5162,41 @@ function buildNestedToOneSelects(relations, aliasMap) {
|
|
|
5153
5162
|
}
|
|
5154
5163
|
return selects;
|
|
5155
5164
|
}
|
|
5165
|
+
function extractCountSelectFromRelArgs(relArgs) {
|
|
5166
|
+
if (!isPlainObject(relArgs)) return null;
|
|
5167
|
+
const obj = relArgs;
|
|
5168
|
+
if (!isPlainObject(obj.select)) return null;
|
|
5169
|
+
const sel = obj.select;
|
|
5170
|
+
const countRaw = sel["_count"];
|
|
5171
|
+
if (!countRaw) return null;
|
|
5172
|
+
if (isPlainObject(countRaw) && "select" in countRaw) {
|
|
5173
|
+
return countRaw.select;
|
|
5174
|
+
}
|
|
5175
|
+
return null;
|
|
5176
|
+
}
|
|
5156
5177
|
function buildSelectWithNestedIncludes(relArgs, relModel, relAlias, ctx) {
|
|
5157
5178
|
const nestedToOnes = extractNestedToOneRelations(
|
|
5158
5179
|
relArgs,
|
|
5159
5180
|
relModel,
|
|
5160
5181
|
ctx.schemaByName
|
|
5161
5182
|
);
|
|
5183
|
+
const countSelect = extractCountSelectFromRelArgs(relArgs);
|
|
5184
|
+
const countJoins = [];
|
|
5185
|
+
function appendCountToSelect(baseSelect2) {
|
|
5186
|
+
if (!countSelect || Object.keys(countSelect).length === 0) return baseSelect2;
|
|
5187
|
+
const countBuild = buildRelationCountSql(
|
|
5188
|
+
countSelect,
|
|
5189
|
+
relModel,
|
|
5190
|
+
ctx.schemas,
|
|
5191
|
+
relAlias,
|
|
5192
|
+
ctx.params,
|
|
5193
|
+
ctx.dialect
|
|
5194
|
+
);
|
|
5195
|
+
if (!countBuild.jsonPairs) return baseSelect2;
|
|
5196
|
+
countJoins.push(...countBuild.joins);
|
|
5197
|
+
const countExpr = `'_count', ${jsonBuildObject(countBuild.jsonPairs, ctx.dialect)}`;
|
|
5198
|
+
return baseSelect2 ? `${baseSelect2}${SQL_SEPARATORS.FIELD_LIST}${countExpr}` : countExpr;
|
|
5199
|
+
}
|
|
5162
5200
|
if (nestedToOnes.length === 0) {
|
|
5163
5201
|
let relSelect = buildRelationSelect(relArgs, relModel, relAlias);
|
|
5164
5202
|
let nestedIncludes = [];
|
|
@@ -5187,7 +5225,8 @@ function buildSelectWithNestedIncludes(relArgs, relModel, relAlias, ctx) {
|
|
|
5187
5225
|
).join(SQL_SEPARATORS.FIELD_LIST);
|
|
5188
5226
|
relSelect = isNotNullish(relSelect) && relSelect.trim().length > 0 ? `${relSelect}${SQL_SEPARATORS.FIELD_LIST}${nestedSelects2}` : nestedSelects2;
|
|
5189
5227
|
}
|
|
5190
|
-
|
|
5228
|
+
relSelect = appendCountToSelect(relSelect);
|
|
5229
|
+
return { select: relSelect, nestedJoins: countJoins };
|
|
5191
5230
|
}
|
|
5192
5231
|
const { joins, aliasMap } = buildNestedToOneJoins(
|
|
5193
5232
|
nestedToOnes,
|
|
@@ -5205,9 +5244,11 @@ function buildSelectWithNestedIncludes(relArgs, relModel, relAlias, ctx) {
|
|
|
5205
5244
|
for (const ns of nestedSelects) {
|
|
5206
5245
|
allParts.push(ns);
|
|
5207
5246
|
}
|
|
5247
|
+
let finalSelect = allParts.join(SQL_SEPARATORS.FIELD_LIST);
|
|
5248
|
+
finalSelect = appendCountToSelect(finalSelect);
|
|
5208
5249
|
return {
|
|
5209
|
-
select:
|
|
5210
|
-
nestedJoins: joins
|
|
5250
|
+
select: finalSelect,
|
|
5251
|
+
nestedJoins: [...joins, ...countJoins]
|
|
5211
5252
|
};
|
|
5212
5253
|
}
|
|
5213
5254
|
function buildWhereParts(whereInput, relModel, relAlias, ctx) {
|
|
@@ -5589,7 +5630,7 @@ function validateDistinct(model, distinct) {
|
|
|
5589
5630
|
const relationSet = getRelationFieldSet(model);
|
|
5590
5631
|
if (relationSet.has(f)) {
|
|
5591
5632
|
throw new Error(
|
|
5592
|
-
`distinct field '${f}' is a relation. Only scalar fields are allowed.
|
|
5633
|
+
`distinct field '${f}' is a relation field. Only scalar fields are allowed.
|
|
5593
5634
|
Available scalar fields: ${[...scalarSet].join(", ")}`
|
|
5594
5635
|
);
|
|
5595
5636
|
}
|
|
@@ -5627,7 +5668,7 @@ function validateOrderBy(model, orderBy) {
|
|
|
5627
5668
|
if (!scalarSet.has(f)) {
|
|
5628
5669
|
if (relationSet.has(f)) {
|
|
5629
5670
|
throw new Error(
|
|
5630
|
-
`orderBy field '${f}' is a relation. Only scalar fields are allowed.
|
|
5671
|
+
`orderBy field '${f}' is a relation field. Only scalar fields are allowed.
|
|
5631
5672
|
Available scalar fields: ${[...scalarSet].join(", ")}`
|
|
5632
5673
|
);
|
|
5633
5674
|
}
|
|
@@ -9367,6 +9408,26 @@ function executeRaw(client, sql, params, dialect) {
|
|
|
9367
9408
|
function buildSQL(model, models, method, args, dialect) {
|
|
9368
9409
|
return buildSQLWithCache(model, models, method, args, dialect);
|
|
9369
9410
|
}
|
|
9411
|
+
function createToSQLFunction(models, dialect) {
|
|
9412
|
+
if (!models || !Array.isArray(models) || models.length === 0) {
|
|
9413
|
+
throw new Error("createToSQL requires non-empty models array");
|
|
9414
|
+
}
|
|
9415
|
+
const modelMap = new Map(models.map((m) => [m.name, m]));
|
|
9416
|
+
setGlobalDialect(dialect);
|
|
9417
|
+
return function toSQL(model, method, args = {}) {
|
|
9418
|
+
const m = modelMap.get(model);
|
|
9419
|
+
if (!m) {
|
|
9420
|
+
throw new Error(
|
|
9421
|
+
`Model '${model}' not found. Available: ${[...modelMap.keys()].join(", ")}`
|
|
9422
|
+
);
|
|
9423
|
+
}
|
|
9424
|
+
return buildSQL(m, models, method, args, dialect);
|
|
9425
|
+
};
|
|
9426
|
+
}
|
|
9427
|
+
function createToSQL(modelsOrDmmf, dialect) {
|
|
9428
|
+
const models = Array.isArray(modelsOrDmmf) ? modelsOrDmmf : schemaParser.convertDMMFToModels(modelsOrDmmf.datamodel);
|
|
9429
|
+
return createToSQLFunction(models, dialect);
|
|
9430
|
+
}
|
|
9370
9431
|
function generateSQL2(directive) {
|
|
9371
9432
|
return generateSQL(directive);
|
|
9372
9433
|
}
|
|
@@ -9379,6 +9440,7 @@ exports.buildSQL = buildSQL;
|
|
|
9379
9440
|
exports.countIncludeDepth = countIncludeDepth;
|
|
9380
9441
|
exports.createProgressiveReducer = createProgressiveReducer;
|
|
9381
9442
|
exports.createStreamingReducer = createStreamingReducer;
|
|
9443
|
+
exports.createToSQL = createToSQL;
|
|
9382
9444
|
exports.createTransactionExecutor = createTransactionExecutor;
|
|
9383
9445
|
exports.detectSqliteDateMode = detectSqliteDateMode;
|
|
9384
9446
|
exports.executePostgresQuery = executePostgresQuery;
|