prisma-ts-select 0.0.34 → 0.1.2

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.
Files changed (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1242 -315
  3. package/assets/groupBy.gif +0 -0
  4. package/assets/joinUnsafeIgnoreType.gif +0 -0
  5. package/assets/joinUnsafeTypeEnforced.gif +0 -0
  6. package/assets/typesafe-join.gif +0 -0
  7. package/assets/typesafe-join.png +0 -0
  8. package/assets/whereNotNull.gif +0 -0
  9. package/assets/whereisNull.gif +0 -0
  10. package/dist/bin.cjs +1 -1
  11. package/dist/bin.js +1 -1
  12. package/dist/chunk-47KZVQLD.js +283 -0
  13. package/dist/chunk-54D2J5AR.cjs +291 -0
  14. package/dist/extend/dialects/index.d.ts +13 -0
  15. package/dist/extend/dialects/index.js +186 -0
  16. package/dist/extend/dialects/mysql-v6.d.ts +100 -0
  17. package/dist/extend/dialects/mysql-v6.js +152 -0
  18. package/dist/extend/dialects/mysql-v7.d.ts +6 -0
  19. package/dist/extend/dialects/mysql-v7.js +138 -0
  20. package/dist/extend/dialects/mysql.d.ts +90 -0
  21. package/dist/extend/dialects/mysql.js +156 -0
  22. package/dist/extend/dialects/postgresql-v6.d.ts +97 -0
  23. package/dist/extend/dialects/postgresql-v6.js +136 -0
  24. package/dist/extend/dialects/postgresql-v7.d.ts +97 -0
  25. package/dist/extend/dialects/postgresql-v7.js +136 -0
  26. package/dist/extend/dialects/postgresql.d.ts +89 -0
  27. package/dist/extend/dialects/postgresql.js +147 -0
  28. package/dist/extend/dialects/shared.d.ts +6 -0
  29. package/dist/extend/dialects/shared.js +5 -0
  30. package/dist/extend/dialects/sqlite.d.ts +63 -0
  31. package/dist/extend/dialects/sqlite.js +138 -0
  32. package/dist/extend/dialects/types.d.ts +12 -0
  33. package/dist/extend/dialects/types.js +4 -0
  34. package/dist/extend/extend.d.ts +286 -43
  35. package/dist/extend/extend.js +735 -163
  36. package/dist/extend/sql-expr-BaKWzJ-r.d.ts +10 -0
  37. package/dist/extend/types-D84lxYVc.d.ts +5 -0
  38. package/dist/generator.cjs +1 -1
  39. package/dist/generator.js +1 -1
  40. package/package.json +46 -42
  41. package/built/extend.cjs +0 -680
  42. package/built/extend.d.cts +0 -520
  43. package/built/extend.d.ts +0 -520
  44. package/built/extend.js +0 -678
  45. package/dist/chunk-TBO3MX7Q.cjs +0 -195
  46. package/dist/chunk-X3N5N5KQ.js +0 -187
  47. package/dist/extend/extend.cjs +0 -357
  48. package/dist/extend/extend.d.cts +0 -264
@@ -1,8 +1,290 @@
1
1
  import { Prisma } from '@prisma/client/extension';
2
- import { match, P } from 'ts-pattern';
2
+ import { dialectContextFns, dialect } from './dialects/index.js';
3
3
 
4
- const DB = {};
5
- class DbSelect {
4
+ // src/extend.ts
5
+
6
+ // ../../node_modules/.pnpm/ts-pattern@5.3.1/node_modules/ts-pattern/dist/index.js
7
+ var t = Symbol.for("@ts-pattern/matcher");
8
+ var e = Symbol.for("@ts-pattern/isVariadic");
9
+ var n = "@ts-pattern/anonymous-select-key";
10
+ var r = (t2) => Boolean(t2 && "object" == typeof t2);
11
+ var i = (e2) => e2 && !!e2[t];
12
+ var s = (n2, o2, c2) => {
13
+ if (i(n2)) {
14
+ const e2 = n2[t](), { matched: r2, selections: i2 } = e2.match(o2);
15
+ return r2 && i2 && Object.keys(i2).forEach((t2) => c2(t2, i2[t2])), r2;
16
+ }
17
+ if (r(n2)) {
18
+ if (!r(o2)) return false;
19
+ if (Array.isArray(n2)) {
20
+ if (!Array.isArray(o2)) return false;
21
+ let t2 = [], r2 = [], a2 = [];
22
+ for (const s2 of n2.keys()) {
23
+ const o3 = n2[s2];
24
+ i(o3) && o3[e] ? a2.push(o3) : a2.length ? r2.push(o3) : t2.push(o3);
25
+ }
26
+ if (a2.length) {
27
+ if (a2.length > 1) throw new Error("Pattern error: Using `...P.array(...)` several times in a single pattern is not allowed.");
28
+ if (o2.length < t2.length + r2.length) return false;
29
+ const e2 = o2.slice(0, t2.length), n3 = 0 === r2.length ? [] : o2.slice(-r2.length), i2 = o2.slice(t2.length, 0 === r2.length ? Infinity : -r2.length);
30
+ return t2.every((t3, n4) => s(t3, e2[n4], c2)) && r2.every((t3, e3) => s(t3, n3[e3], c2)) && (0 === a2.length || s(a2[0], i2, c2));
31
+ }
32
+ return n2.length === o2.length && n2.every((t3, e2) => s(t3, o2[e2], c2));
33
+ }
34
+ return Reflect.ownKeys(n2).every((e2) => {
35
+ const r2 = n2[e2];
36
+ return (e2 in o2 || i(a2 = r2) && "optional" === a2[t]().matcherType) && s(r2, o2[e2], c2);
37
+ var a2;
38
+ });
39
+ }
40
+ return Object.is(o2, n2);
41
+ };
42
+ var o = (e2) => {
43
+ var n2, s2, a2;
44
+ return r(e2) ? i(e2) ? null != (n2 = null == (s2 = (a2 = e2[t]()).getSelectionKeys) ? void 0 : s2.call(a2)) ? n2 : [] : Array.isArray(e2) ? c(e2, o) : c(Object.values(e2), o) : [];
45
+ };
46
+ var c = (t2, e2) => t2.reduce((t3, n2) => t3.concat(e2(n2)), []);
47
+ function a(...t2) {
48
+ if (1 === t2.length) {
49
+ const [e2] = t2;
50
+ return (t3) => s(e2, t3, () => {
51
+ });
52
+ }
53
+ if (2 === t2.length) {
54
+ const [e2, n2] = t2;
55
+ return s(e2, n2, () => {
56
+ });
57
+ }
58
+ throw new Error(`isMatching wasn't given the right number of arguments: expected 1 or 2, received ${t2.length}.`);
59
+ }
60
+ function u(t2) {
61
+ return Object.assign(t2, { optional: () => h(t2), and: (e2) => m(t2, e2), or: (e2) => d(t2, e2), select: (e2) => void 0 === e2 ? y(t2) : y(e2, t2) });
62
+ }
63
+ function l(t2) {
64
+ return Object.assign(((t3) => Object.assign(t3, { [Symbol.iterator]() {
65
+ let n2 = 0;
66
+ const r2 = [{ value: Object.assign(t3, { [e]: true }), done: false }, { done: true, value: void 0 }];
67
+ return { next: () => {
68
+ var t4;
69
+ return null != (t4 = r2[n2++]) ? t4 : r2.at(-1);
70
+ } };
71
+ } }))(t2), { optional: () => l(h(t2)), select: (e2) => l(void 0 === e2 ? y(t2) : y(e2, t2)) });
72
+ }
73
+ function h(e2) {
74
+ return u({ [t]: () => ({ match: (t2) => {
75
+ let n2 = {};
76
+ const r2 = (t3, e3) => {
77
+ n2[t3] = e3;
78
+ };
79
+ return void 0 === t2 ? (o(e2).forEach((t3) => r2(t3, void 0)), { matched: true, selections: n2 }) : { matched: s(e2, t2, r2), selections: n2 };
80
+ }, getSelectionKeys: () => o(e2), matcherType: "optional" }) });
81
+ }
82
+ var f = (t2, e2) => {
83
+ for (const n2 of t2) if (!e2(n2)) return false;
84
+ return true;
85
+ };
86
+ var g = (t2, e2) => {
87
+ for (const [n2, r2] of t2.entries()) if (!e2(r2, n2)) return false;
88
+ return true;
89
+ };
90
+ function m(...e2) {
91
+ return u({ [t]: () => ({ match: (t2) => {
92
+ let n2 = {};
93
+ const r2 = (t3, e3) => {
94
+ n2[t3] = e3;
95
+ };
96
+ return { matched: e2.every((e3) => s(e3, t2, r2)), selections: n2 };
97
+ }, getSelectionKeys: () => c(e2, o), matcherType: "and" }) });
98
+ }
99
+ function d(...e2) {
100
+ return u({ [t]: () => ({ match: (t2) => {
101
+ let n2 = {};
102
+ const r2 = (t3, e3) => {
103
+ n2[t3] = e3;
104
+ };
105
+ return c(e2, o).forEach((t3) => r2(t3, void 0)), { matched: e2.some((e3) => s(e3, t2, r2)), selections: n2 };
106
+ }, getSelectionKeys: () => c(e2, o), matcherType: "or" }) });
107
+ }
108
+ function p(e2) {
109
+ return { [t]: () => ({ match: (t2) => ({ matched: Boolean(e2(t2)) }) }) };
110
+ }
111
+ function y(...e2) {
112
+ const r2 = "string" == typeof e2[0] ? e2[0] : void 0, i2 = 2 === e2.length ? e2[1] : "string" == typeof e2[0] ? void 0 : e2[0];
113
+ return u({ [t]: () => ({ match: (t2) => {
114
+ let e3 = { [null != r2 ? r2 : n]: t2 };
115
+ return { matched: void 0 === i2 || s(i2, t2, (t3, n2) => {
116
+ e3[t3] = n2;
117
+ }), selections: e3 };
118
+ }, getSelectionKeys: () => [null != r2 ? r2 : n].concat(void 0 === i2 ? [] : o(i2)) }) });
119
+ }
120
+ function v(t2) {
121
+ return "number" == typeof t2;
122
+ }
123
+ function b(t2) {
124
+ return "string" == typeof t2;
125
+ }
126
+ function w(t2) {
127
+ return "bigint" == typeof t2;
128
+ }
129
+ var S = u(p(function(t2) {
130
+ return true;
131
+ }));
132
+ var O = S;
133
+ var j = (t2) => Object.assign(u(t2), { startsWith: (e2) => {
134
+ return j(m(t2, (n2 = e2, p((t3) => b(t3) && t3.startsWith(n2)))));
135
+ var n2;
136
+ }, endsWith: (e2) => {
137
+ return j(m(t2, (n2 = e2, p((t3) => b(t3) && t3.endsWith(n2)))));
138
+ var n2;
139
+ }, minLength: (e2) => j(m(t2, ((t3) => p((e3) => b(e3) && e3.length >= t3))(e2))), length: (e2) => j(m(t2, ((t3) => p((e3) => b(e3) && e3.length === t3))(e2))), maxLength: (e2) => j(m(t2, ((t3) => p((e3) => b(e3) && e3.length <= t3))(e2))), includes: (e2) => {
140
+ return j(m(t2, (n2 = e2, p((t3) => b(t3) && t3.includes(n2)))));
141
+ var n2;
142
+ }, regex: (e2) => {
143
+ return j(m(t2, (n2 = e2, p((t3) => b(t3) && Boolean(t3.match(n2))))));
144
+ var n2;
145
+ } });
146
+ var K = j(p(b));
147
+ var x = (t2) => Object.assign(u(t2), { between: (e2, n2) => x(m(t2, ((t3, e3) => p((n3) => v(n3) && t3 <= n3 && e3 >= n3))(e2, n2))), lt: (e2) => x(m(t2, ((t3) => p((e3) => v(e3) && e3 < t3))(e2))), gt: (e2) => x(m(t2, ((t3) => p((e3) => v(e3) && e3 > t3))(e2))), lte: (e2) => x(m(t2, ((t3) => p((e3) => v(e3) && e3 <= t3))(e2))), gte: (e2) => x(m(t2, ((t3) => p((e3) => v(e3) && e3 >= t3))(e2))), int: () => x(m(t2, p((t3) => v(t3) && Number.isInteger(t3)))), finite: () => x(m(t2, p((t3) => v(t3) && Number.isFinite(t3)))), positive: () => x(m(t2, p((t3) => v(t3) && t3 > 0))), negative: () => x(m(t2, p((t3) => v(t3) && t3 < 0))) });
148
+ var E = x(p(v));
149
+ var A = (t2) => Object.assign(u(t2), { between: (e2, n2) => A(m(t2, ((t3, e3) => p((n3) => w(n3) && t3 <= n3 && e3 >= n3))(e2, n2))), lt: (e2) => A(m(t2, ((t3) => p((e3) => w(e3) && e3 < t3))(e2))), gt: (e2) => A(m(t2, ((t3) => p((e3) => w(e3) && e3 > t3))(e2))), lte: (e2) => A(m(t2, ((t3) => p((e3) => w(e3) && e3 <= t3))(e2))), gte: (e2) => A(m(t2, ((t3) => p((e3) => w(e3) && e3 >= t3))(e2))), positive: () => A(m(t2, p((t3) => w(t3) && t3 > 0))), negative: () => A(m(t2, p((t3) => w(t3) && t3 < 0))) });
150
+ var P = A(p(w));
151
+ var T = u(p(function(t2) {
152
+ return "boolean" == typeof t2;
153
+ }));
154
+ var B = u(p(function(t2) {
155
+ return "symbol" == typeof t2;
156
+ }));
157
+ var _ = u(p(function(t2) {
158
+ return null == t2;
159
+ }));
160
+ var k = u(p(function(t2) {
161
+ return null != t2;
162
+ }));
163
+ var N = { __proto__: null, matcher: t, optional: h, array: function(...e2) {
164
+ return l({ [t]: () => ({ match: (t2) => {
165
+ if (!Array.isArray(t2)) return { matched: false };
166
+ if (0 === e2.length) return { matched: true };
167
+ const n2 = e2[0];
168
+ let r2 = {};
169
+ if (0 === t2.length) return o(n2).forEach((t3) => {
170
+ r2[t3] = [];
171
+ }), { matched: true, selections: r2 };
172
+ const i2 = (t3, e3) => {
173
+ r2[t3] = (r2[t3] || []).concat([e3]);
174
+ };
175
+ return { matched: t2.every((t3) => s(n2, t3, i2)), selections: r2 };
176
+ }, getSelectionKeys: () => 0 === e2.length ? [] : o(e2[0]) }) });
177
+ }, set: function(...e2) {
178
+ return u({ [t]: () => ({ match: (t2) => {
179
+ if (!(t2 instanceof Set)) return { matched: false };
180
+ let n2 = {};
181
+ if (0 === t2.size) return { matched: true, selections: n2 };
182
+ if (0 === e2.length) return { matched: true };
183
+ const r2 = (t3, e3) => {
184
+ n2[t3] = (n2[t3] || []).concat([e3]);
185
+ }, i2 = e2[0];
186
+ return { matched: f(t2, (t3) => s(i2, t3, r2)), selections: n2 };
187
+ }, getSelectionKeys: () => 0 === e2.length ? [] : o(e2[0]) }) });
188
+ }, map: function(...e2) {
189
+ return u({ [t]: () => ({ match: (t2) => {
190
+ if (!(t2 instanceof Map)) return { matched: false };
191
+ let n2 = {};
192
+ if (0 === t2.size) return { matched: true, selections: n2 };
193
+ const r2 = (t3, e3) => {
194
+ n2[t3] = (n2[t3] || []).concat([e3]);
195
+ };
196
+ if (0 === e2.length) return { matched: true };
197
+ var i2;
198
+ if (1 === e2.length) throw new Error(`\`P.map\` wasn't given enough arguments. Expected (key, value), received ${null == (i2 = e2[0]) ? void 0 : i2.toString()}`);
199
+ const [o2, c2] = e2;
200
+ return { matched: g(t2, (t3, e3) => {
201
+ const n3 = s(o2, e3, r2), i3 = s(c2, t3, r2);
202
+ return n3 && i3;
203
+ }), selections: n2 };
204
+ }, getSelectionKeys: () => 0 === e2.length ? [] : [...o(e2[0]), ...o(e2[1])] }) });
205
+ }, intersection: m, union: d, not: function(e2) {
206
+ return u({ [t]: () => ({ match: (t2) => ({ matched: !s(e2, t2, () => {
207
+ }) }), getSelectionKeys: () => [], matcherType: "not" }) });
208
+ }, when: p, select: y, any: S, _: O, string: K, number: E, bigint: P, boolean: T, symbol: B, nullish: _, nonNullable: k, instanceOf: function(t2) {
209
+ return u(p(/* @__PURE__ */ function(t3) {
210
+ return (e2) => e2 instanceof t3;
211
+ }(t2)));
212
+ }, shape: function(t2) {
213
+ return u(p(a(t2)));
214
+ } };
215
+ var W = class extends Error {
216
+ constructor(t2) {
217
+ let e2;
218
+ try {
219
+ e2 = JSON.stringify(t2);
220
+ } catch (n2) {
221
+ e2 = t2;
222
+ }
223
+ super(`Pattern matching error: no pattern matches value ${e2}`), this.input = void 0, this.input = t2;
224
+ }
225
+ };
226
+ var $ = { matched: false, value: void 0 };
227
+ function z(t2) {
228
+ return new I(t2, $);
229
+ }
230
+ var I = class _I {
231
+ constructor(t2, e2) {
232
+ this.input = void 0, this.state = void 0, this.input = t2, this.state = e2;
233
+ }
234
+ with(...t2) {
235
+ if (this.state.matched) return this;
236
+ const e2 = t2[t2.length - 1], r2 = [t2[0]];
237
+ let i2;
238
+ 3 === t2.length && "function" == typeof t2[1] ? i2 = t2[1] : t2.length > 2 && r2.push(...t2.slice(1, t2.length - 1));
239
+ let o2 = false, c2 = {};
240
+ const a2 = (t3, e3) => {
241
+ o2 = true, c2[t3] = e3;
242
+ }, u2 = !r2.some((t3) => s(t3, this.input, a2)) || i2 && !Boolean(i2(this.input)) ? $ : { matched: true, value: e2(o2 ? n in c2 ? c2[n] : c2 : this.input, this.input) };
243
+ return new _I(this.input, u2);
244
+ }
245
+ when(t2, e2) {
246
+ if (this.state.matched) return this;
247
+ const n2 = Boolean(t2(this.input));
248
+ return new _I(this.input, n2 ? { matched: true, value: e2(this.input, this.input) } : $);
249
+ }
250
+ otherwise(t2) {
251
+ return this.state.matched ? this.state.value : t2(this.input);
252
+ }
253
+ exhaustive() {
254
+ if (this.state.matched) return this.state.value;
255
+ throw new W(this.input);
256
+ }
257
+ run() {
258
+ return this.exhaustive();
259
+ }
260
+ returnType() {
261
+ return this;
262
+ }
263
+ };
264
+
265
+ // src/dialects/shared.ts
266
+ var esc = (s2) => s2.replace(/'/g, "''");
267
+
268
+ // src/sql-expr.ts
269
+ function sqlExpr(sql) {
270
+ return { sql, toString() {
271
+ return sql;
272
+ } };
273
+ }
274
+ function lit(value) {
275
+ if (value === null) return sqlExpr("NULL");
276
+ if (typeof value === "boolean") return sqlExpr(value ? "1" : "0");
277
+ if (typeof value === "string") return sqlExpr(`'${value.replace(/'/g, "''")}'`);
278
+ return sqlExpr(String(value));
279
+ }
280
+ function resolveArg(arg, quoteFn) {
281
+ if (typeof arg !== "string") return arg.sql;
282
+ return quoteFn(arg);
283
+ }
284
+
285
+ // src/extend.ts
286
+ var DB = {};
287
+ var DbSelect = class {
6
288
  constructor(db) {
7
289
  this.db = db;
8
290
  }
@@ -15,18 +297,148 @@ class DbSelect {
15
297
  selects: []
16
298
  });
17
299
  }
300
+ };
301
+ function applyCondition(quotedField, value) {
302
+ if (typeof value === "object" && value !== null && !Array.isArray(value) && "op" in value) {
303
+ const opObj = value;
304
+ switch (opObj.op) {
305
+ case "IN":
306
+ case "NOT IN": {
307
+ const valuesList = opObj.values.map((v2) => typeof v2 === "string" ? `'${esc(v2)}'` : v2).join(", ");
308
+ return `${quotedField} ${opObj.op} (${valuesList})`;
309
+ }
310
+ case "BETWEEN": {
311
+ const [start, end] = opObj.values;
312
+ return `${quotedField} BETWEEN ${typeof start === "string" ? `'${esc(start)}'` : start} AND ${typeof end === "string" ? `'${esc(end)}'` : end}`;
313
+ }
314
+ case "LIKE":
315
+ case "NOT LIKE":
316
+ return `${quotedField} ${opObj.op} '${esc(opObj.value)}'`;
317
+ case "IS NULL":
318
+ case "IS NOT NULL":
319
+ return `${quotedField} ${opObj.op}`;
320
+ case ">":
321
+ case ">=":
322
+ case "<":
323
+ case "<=":
324
+ case "!=":
325
+ case "=":
326
+ return `${quotedField} ${opObj.op} ${typeof opObj.value === "string" ? `'${esc(opObj.value)}'` : opObj.value}`;
327
+ default:
328
+ throw new Error(`Unsupported operation: ${opObj.op}`);
329
+ }
330
+ } else if (value === null) {
331
+ return `${quotedField} IS NULL`;
332
+ } else if (Array.isArray(value)) {
333
+ if (value.length === 0) throw new Error(`empty array is not allowed for field "${quotedField}"`);
334
+ if (typeof value[0] === "object" && value[0] !== null && "op" in value[0]) {
335
+ const parts = value.map((opObj) => applyCondition(quotedField, opObj));
336
+ return parts.length === 1 ? parts[0] : "(" + parts.join(" OR ") + ")";
337
+ }
338
+ const valuesList = value.map((v2) => typeof v2 === "string" ? `'${esc(v2)}'` : v2).join(", ");
339
+ return `${quotedField} IN (${valuesList})`;
340
+ } else {
341
+ return `${quotedField} = ${typeof value === "string" ? `'${esc(value)}'` : value}`;
342
+ }
343
+ }
344
+ function processConditions(condition, formatted = false) {
345
+ const r2 = Object.keys(condition).map((field) => {
346
+ const value = condition[field];
347
+ const quotedField = dialect.quoteQualifiedColumn(String(field));
348
+ return applyCondition(quotedField, value);
349
+ });
350
+ return r2.length === 1 ? r2[0].trim() : "(" + r2.join(" AND " + (formatted ? "\n" : "")).trim() + ")";
18
351
  }
19
- class _fRun {
352
+ function processCriteria(main, joinType = "AND", formatted = false) {
353
+ const results = [];
354
+ for (const criteria of main) {
355
+ if (typeof criteria === "string") {
356
+ results.push(criteria);
357
+ continue;
358
+ }
359
+ let toProcess = {};
360
+ const processPending = () => {
361
+ if (Object.keys(toProcess).length > 0) {
362
+ results.push(processConditions(toProcess, formatted));
363
+ toProcess = {};
364
+ }
365
+ };
366
+ for (const criterion in criteria) {
367
+ const r2 = z(criterion).returnType().with("$AND", (criterion2) => {
368
+ processPending();
369
+ return "(" + //@ts-expect-error criterion
370
+ processCriteria(criteria[criterion2], "AND", formatted) + ")";
371
+ }).with("$OR", (criterion2) => {
372
+ processPending();
373
+ return "(" + //@ts-expect-error criterion
374
+ processCriteria(criteria[criterion2], "OR", formatted) + ")";
375
+ }).with("$NOT", (criterion2) => {
376
+ processPending();
377
+ return "(NOT(" + //@ts-expect-error criterion
378
+ processCriteria(criteria[criterion2], "AND", formatted) + "))";
379
+ }).with("$NOR", (criterion2) => {
380
+ processPending();
381
+ return "(NOT(" + //@ts-expect-error criterion
382
+ processCriteria(criteria[criterion2], "OR", formatted) + "))";
383
+ }).with(N.string, (key) => {
384
+ toProcess[key] = criteria[key];
385
+ return "";
386
+ }).exhaustive();
387
+ if (r2) results.push(r2);
388
+ }
389
+ processPending();
390
+ }
391
+ return results.join((formatted ? "\n" : " ") + joinType + (formatted ? "\n" : " ")).trim();
392
+ }
393
+ function processExprPairs(pairs) {
394
+ const parts = pairs.map(([expr, value]) => applyCondition(expr.sql, value));
395
+ return parts.length === 1 ? parts[0] : parts.join(" AND ");
396
+ }
397
+ var _fRun = class {
20
398
  constructor(db, values) {
21
399
  this.db = db;
22
400
  this.values = values;
23
401
  this.values.limit = typeof this.values.limit === "number" ? this.values.limit : void 0;
24
402
  this.values.offset = typeof this.values.offset === "number" ? this.values.offset : void 0;
25
403
  }
26
- run() {
27
- return this.db.$queryRawUnsafe(
404
+ async run() {
405
+ const results = await this.db.$queryRawUnsafe(
28
406
  this.getSQL()
29
407
  );
408
+ if (dialect.needsBooleanCoercion()) {
409
+ return results.map((row) => {
410
+ const coerced = { ...row };
411
+ for (const key in coerced) {
412
+ const value = coerced[key];
413
+ if (typeof value !== "number" || value !== 0 && value !== 1) continue;
414
+ const parts = key.split(".");
415
+ let table;
416
+ let column;
417
+ if (parts.length === 2 && parts[0] && parts[1]) {
418
+ table = parts[0];
419
+ column = parts[1];
420
+ } else {
421
+ column = key;
422
+ let foundTable;
423
+ for (const tableObj of this.values.tables) {
424
+ const tableName = tableObj.table;
425
+ if (DB[tableName]?.fields[column]) {
426
+ foundTable = tableName;
427
+ break;
428
+ }
429
+ }
430
+ if (!foundTable) continue;
431
+ table = foundTable;
432
+ }
433
+ const fieldType = DB[table]?.fields[column];
434
+ if (fieldType && fieldType.replace("?", "") === "Boolean") {
435
+ coerced[key] = value === 1;
436
+ }
437
+ }
438
+ return coerced;
439
+ });
440
+ }
441
+ return results;
30
442
  }
31
443
  getTables() {
32
444
  return {};
@@ -38,137 +450,109 @@ class _fRun {
38
450
  return {};
39
451
  }
40
452
  getSQL(formatted = false) {
41
- function processCondition(condition, formatted2) {
42
- return "(" + Object.keys(condition).map((field) => {
43
- const value = condition[field];
44
- if (typeof value === "object" && value !== null && !Array.isArray(value) && "op" in value) {
45
- switch (value.op) {
46
- case "IN":
47
- case "NOT IN":
48
- const valuesList = value.values.map((v) => typeof v === "string" ? `'${v}'` : v).join(", ");
49
- return `${String(field)} ${value.op} (${valuesList})`;
50
- case "BETWEEN":
51
- if (value.values.length > 2) throw new Error("Too many items supplied to op BETWEEN");
52
- const [start, end] = value.values;
53
- return `${String(field)} BETWEEN ${typeof start === "string" ? `'${start}'` : start} AND ${typeof end === "string" ? `'${end}'` : end}`;
54
- case "LIKE":
55
- case "NOT LIKE":
56
- return `${String(field)} ${value.op} '${value.value}'`;
57
- case "IS NULL":
58
- case "IS NOT NULL":
59
- return `${String(field)} ${value.op}`;
60
- case ">":
61
- case ">=":
62
- case "<":
63
- case "<=":
64
- case "!=":
65
- return `${String(field)} ${value.op} ${typeof value.value === "string" ? `'${value.value}'` : value.value}`;
66
- default:
67
- throw new Error(`Unsupported operation: ${value.op}`);
68
- }
69
- } else if (Array.isArray(value)) {
70
- const valuesList = value.map((v) => typeof v === "string" ? `'${v}'` : v).join(", ");
71
- return `${String(field)} IN (${valuesList})`;
72
- } else if (value === null) {
73
- return `${String(field)} IS NULL`;
74
- } else {
75
- return `${String(field)} = ${typeof value === "string" ? `'${value}'` : value}`;
76
- }
77
- }).join(" AND " + (" ")) + " )";
78
- }
79
- function processCriteria(main, joinType = "AND", formatted2 = false) {
80
- const results = [];
81
- for (const criteria of main) {
82
- if (typeof criteria === "string") {
83
- results.push(criteria);
84
- continue;
85
- }
86
- for (const criterion in criteria) {
87
- results.push(match(criterion).returnType().with("$AND", (criterion2) => {
88
- return "(" + //@ts-expect-error criterion
89
- processCriteria(criteria[criterion2], "AND", formatted2) + ")";
90
- }).with("$OR", (criterion2) => {
91
- return "(" + //@ts-expect-error criterion
92
- processCriteria(criteria[criterion2], "OR", formatted2) + ")";
93
- }).with("$NOT", (criterion2) => {
94
- return "(NOT(" + //@ts-expect-error criterion
95
- processCriteria(criteria[criterion2], "AND", formatted2) + "))";
96
- }).with("$NOR", (criterion2) => {
97
- return "(NOT(" + //@ts-expect-error criterion
98
- processCriteria(criteria[criterion2], "OR", formatted2) + "))";
99
- }).with(P.string, () => {
100
- return processCondition(criteria);
101
- }).exhaustive());
102
- }
103
- }
104
- return results.join((formatted2 ? "\n" : " ") + joinType + (formatted2 ? "\n" : " "));
105
- }
453
+ const withClause = this.values.withs?.length ? `WITH ${this.values.withs.map(
454
+ (w2) => `${dialect.quoteTableIdentifier(w2.name, false)} AS (${w2.sql})`
455
+ ).join(", ")}` : "";
106
456
  const whereClause = this.values.where !== void 0 ? processCriteria(this.values.where, "AND", formatted) : void 0;
107
457
  const havingClause = this.values.having !== void 0 ? processCriteria(this.values.having, "AND", formatted) : void 0;
108
458
  const [base, ...joins] = this.values.tables;
109
- const baseTable = base.alias ? `${base.table} AS \`${base.alias}\`` : base.table;
459
+ const quotedTable = dialect.quoteTableIdentifier(base.table, false);
460
+ const baseTable = base.alias ? `${quotedTable} AS ${dialect.quoteTableIdentifier(base.alias, true)}` : quotedTable;
110
461
  return [
462
+ withClause,
111
463
  this.values.selects.length === 0 ? "" : "SELECT " + (this.values.selectDistinct === true ? "DISTINCT " : "") + this.values.selects.join(", "),
112
464
  `FROM ${baseTable}`,
113
465
  joins.map(({
114
466
  table,
115
467
  local,
116
468
  remote,
117
- alias
469
+ alias,
470
+ joinWhere,
471
+ joinType
118
472
  }) => {
473
+ const quotedTable2 = dialect.quoteTableIdentifier(table, false);
474
+ const tableStr = alias ? `${quotedTable2} AS ${dialect.quoteTableIdentifier(alias, true)}` : quotedTable2;
475
+ const typePrefix = joinType ? `${joinType} ` : "";
476
+ if (joinType === "CROSS") {
477
+ return `${typePrefix}JOIN ${tableStr}`;
478
+ }
119
479
  const tLocal = (alias || table) + "." + local;
120
- return `JOIN ${!!alias ? table + " AS `" + alias + "`" : table} ON ${tLocal} = ${remote}`;
480
+ const quotedLocal = dialect.quoteQualifiedColumn(tLocal);
481
+ const quotedRemote = dialect.quoteQualifiedColumn(remote);
482
+ const onClause = `${quotedLocal} = ${quotedRemote}`;
483
+ const joinWhereStr = joinWhere ? ` AND ${processCriteria(joinWhere, "AND", formatted)}` : "";
484
+ return `${typePrefix}JOIN ${tableStr} ON ${onClause}${joinWhereStr}`;
121
485
  }).join(formatted ? "\n" : " ") ?? "",
122
486
  !whereClause ? "" : `WHERE ${whereClause}`,
123
- !this.values.groupBy?.length ? "" : `GROUP BY ${this.values.groupBy.join(", ")}`,
487
+ !this.values.groupBy?.length ? "" : `GROUP BY ${this.values.groupBy.map((g2) => dialect.quoteQualifiedColumn(g2)).join(", ")}`,
124
488
  !havingClause ? "" : `HAVING ${havingClause}`,
125
- !(this.values.orderBy && this.values.orderBy.length > 0) ? "" : "ORDER BY " + this.values.orderBy.join(", "),
489
+ !(this.values.orderBy && this.values.orderBy.length > 0) ? "" : "ORDER BY " + this.values.orderBy.map((o2) => dialect.quoteOrderByClause(o2)).join(", "),
126
490
  !this.values.limit ? "" : `LIMIT ${this.values.limit}`,
127
491
  !this.values.offset ? "" : `OFFSET ${this.values.offset}`
128
492
  ].filter(Boolean).join(formatted ? "\n" : " ").trim() + ";";
129
493
  }
130
- }
131
- class _fOffset extends _fRun {
494
+ };
495
+ var _fOffset = class extends _fRun {
132
496
  offset(offset) {
133
497
  return new _fRun(this.db, { ...this.values, offset });
134
498
  }
135
- }
136
- class _fLimit extends _fRun {
499
+ };
500
+ var _fLimit = class extends _fRun {
137
501
  limit(limit) {
138
502
  return new _fOffset(this.db, { ...this.values, limit });
139
503
  }
140
- }
141
- class _fOrderBy extends _fLimit {
504
+ };
505
+ var _fOrderBy = class extends _fLimit {
142
506
  orderBy(orderBy) {
143
507
  return new _fLimit(this.db, { ...this.values, orderBy });
144
508
  }
145
- }
146
- class _fSelect extends _fOrderBy {
509
+ };
510
+ var _fSelect = class __fSelect extends _fOrderBy {
511
+ // Implementation (not visible to callers)
147
512
  select(select, alias) {
513
+ if (typeof select === "function") {
514
+ const ctx = buildContext(dialect);
515
+ const expr = select(ctx);
516
+ const aliasArg = alias;
517
+ const sqlStr = aliasArg !== void 0 ? `${expr.sql} AS ${dialect.quote(aliasArg, true)}` : expr.sql;
518
+ return new __fSelect(this.db, {
519
+ ...this.values,
520
+ selects: [...this.values.selects, sqlStr]
521
+ });
522
+ }
148
523
  const tableColMatch = select.match(/^(\w+)\.(.*?)$/);
149
524
  if (tableColMatch) {
150
525
  const [, tableName, colName] = tableColMatch;
151
- const tableObject = this.values.tables.find((t) => (t.alias || t.table) === tableName);
526
+ const tableObject = this.values.tables.find((t2) => (t2.alias || t2.table) === tableName);
152
527
  if (!tableObject) throw new Error(`Table "${tableName}" not found in query`);
153
528
  const tableFields = DB[tableObject.table];
154
529
  if (!tableFields) {
155
- throw new Error(`Table "${tableName}" not found in database schema`);
530
+ if (colName === "*") {
531
+ throw new Error(`Cannot expand "${tableName}.*" \u2014 CTE columns must be selected explicitly`);
532
+ }
533
+ return new __fSelect(this.db, {
534
+ ...this.values,
535
+ selects: [...this.values.selects, `${dialect.quoteQualifiedColumn(select)} AS ${dialect.quote(select, true)}`]
536
+ });
156
537
  }
157
538
  if (colName === "*") {
158
539
  const hasMultipleTables = this.values.tables && this.values.tables.length > 1 || false;
159
540
  const expandedSelects = Object.keys(tableFields.fields).map((field) => {
160
541
  if (hasMultipleTables) {
161
- return `${tableName}.${field} AS \`${tableName}.${field}\``;
542
+ const tableIdentifier = tableObject.alias || tableName;
543
+ const qualifiedCol = `${tableIdentifier}.${field}`;
544
+ return `${dialect.quoteQualifiedColumn(qualifiedCol)} AS ${dialect.quote(`${tableName}.${field}`, true)}`;
162
545
  }
163
- return `${field}`;
546
+ return field === "*" ? "*" : dialect.quote(field, false);
164
547
  });
165
- return new _fSelect(this.db, {
548
+ return new __fSelect(this.db, {
166
549
  ...this.values,
167
550
  selects: [...this.values.selects, ...expandedSelects]
168
551
  });
169
552
  } else if (!alias && !!colName) {
170
553
  const currentTablesWithFields = this.values.tables.reduce((acc, table) => {
171
554
  const { table: real } = table;
555
+ if (!DB[real]) return acc;
172
556
  for (const col in DB[real].fields) {
173
557
  acc[col] = acc[col] ? acc[col] + 1 : 1;
174
558
  }
@@ -178,105 +562,148 @@ class _fSelect extends _fOrderBy {
178
562
  throw new Error(`Column "${colName}" not found in database schema`);
179
563
  }
180
564
  if (currentTablesWithFields[colName] > 1) {
181
- return new _fSelect(this.db, {
565
+ return new __fSelect(this.db, {
182
566
  ...this.values,
183
- selects: [...this.values.selects, `${select} AS \`${select}\``]
567
+ selects: [...this.values.selects, `${dialect.quoteQualifiedColumn(select)} AS ${dialect.quote(select, true)}`]
184
568
  });
185
569
  } else {
186
- return new _fSelect(this.db, {
570
+ return new __fSelect(this.db, {
187
571
  ...this.values,
188
- selects: [...this.values.selects, `${colName}`]
572
+ selects: [...this.values.selects, dialect.quote(colName, false)]
189
573
  });
190
574
  }
191
575
  }
192
576
  }
193
577
  if (alias !== void 0) {
194
- return new _fSelect(this.db, {
578
+ const quotedSelect2 = select === "*" ? "*" : select.includes(".") ? dialect.quoteQualifiedColumn(select) : dialect.quote(select, false);
579
+ return new __fSelect(this.db, {
195
580
  ...this.values,
196
- selects: [...this.values.selects, `${select} AS \`${alias}\``]
581
+ selects: [...this.values.selects, `${quotedSelect2} AS ${dialect.quote(alias, true)}`]
197
582
  });
198
583
  }
199
- return new _fSelect(this.db, {
584
+ const quotedSelect = select === "*" ? "*" : select.includes(".") ? dialect.quoteQualifiedColumn(select) : dialect.quote(select, false);
585
+ return new __fSelect(this.db, {
200
586
  ...this.values,
201
- selects: [...this.values.selects, select]
587
+ selects: [...this.values.selects, quotedSelect]
202
588
  });
203
589
  }
204
- }
205
- class _fSelectDistinct extends _fSelect {
590
+ };
591
+ var _fSelectDistinct = class extends _fSelect {
206
592
  selectDistinct() {
207
593
  return new _fSelect(this.db, { ...this.values, selectDistinct: true });
208
594
  }
209
595
  selectAll() {
210
596
  const selects = function(values) {
211
597
  if (values.tables && values.tables.length > 1) {
212
- return [
213
- /*values.baseTable,*/
214
- ...values.tables.map((t) => t.table)
215
- ].reduce((acc, table) => {
216
- return acc.concat(Object.keys(DB[table].fields).map((field) => `${table}.${field} AS \`${table}.${field}\``));
598
+ return values.tables.reduce((acc, tableObj) => {
599
+ const tableIdentifier = tableObj.alias || tableObj.table;
600
+ const actualTable = tableObj.table;
601
+ if (!DB[actualTable]) return acc;
602
+ return acc.concat(Object.keys(DB[actualTable].fields).map((field) => {
603
+ const qualifiedCol = `${tableIdentifier}.${field}`;
604
+ return `${dialect.quoteQualifiedColumn(qualifiedCol)} AS ${dialect.quote(`${tableIdentifier}.${field}`, true)}`;
605
+ }));
217
606
  }, []);
218
607
  }
219
- return Object.keys(DB[values.tables[0].table].fields);
608
+ const t2 = values.tables[0];
609
+ if (!DB[t2.table]) throw new Error(`selectAll() is not supported when the base table is a CTE ("${t2.table}"). Use select() with explicit column references.`);
610
+ return Object.keys(DB[t2.table].fields).map((field) => dialect.quote(field, false));
220
611
  }(this.values);
221
612
  return new _fOrderBy(this.db, {
222
613
  ...this.values,
223
614
  selects
224
615
  });
225
616
  }
226
- //TODO
227
- // selectAllOmit() {
228
- // throw new Error("Not implemented yet")
229
- // }
230
- }
231
- class _fHaving extends _fSelectDistinct {
232
- // TODO Allowed Fields
233
- // - specified in groupBy
234
- having(criteria) {
235
- return new _fSelectDistinct(this.db, {
617
+ selectAllOmit(omit) {
618
+ const omitSet = new Set(omit);
619
+ const selects = function(values) {
620
+ if (values.tables.length === 1) {
621
+ const t2 = values.tables[0];
622
+ const tableIdentifier = t2.alias || t2.table;
623
+ return Object.keys(DB[t2.table].fields).filter((f2) => !omitSet.has(f2) && !omitSet.has(`${tableIdentifier}.${f2}`)).map((f2) => dialect.quote(f2, false));
624
+ }
625
+ return values.tables.reduce((acc, tableObj) => {
626
+ const tableIdentifier = tableObj.alias || tableObj.table;
627
+ if (!DB[tableObj.table]) return acc;
628
+ return acc.concat(
629
+ Object.keys(DB[tableObj.table].fields).filter((f2) => !omitSet.has(f2) && !omitSet.has(`${tableIdentifier}.${f2}`)).map((f2) => {
630
+ const q = `${tableIdentifier}.${f2}`;
631
+ return `${dialect.quoteQualifiedColumn(q)} AS ${dialect.quote(q, true)}`;
632
+ })
633
+ );
634
+ }, []);
635
+ }(this.values);
636
+ return new _fOrderBy(this.db, {
236
637
  ...this.values,
237
- having: [criteria]
638
+ selects
238
639
  });
239
640
  }
240
- }
241
- class _fGroupBy extends _fHaving {
641
+ };
642
+ var _fHaving = class __fHaving extends _fSelect {
643
+ // Keep selectDistinct() available after groupBy(), but not selectAll()
644
+ selectDistinct() {
645
+ return new _fSelect(this.db, { ...this.values, selectDistinct: true });
646
+ }
647
+ having(criteriaOrFn) {
648
+ const existing = this.values.having ?? [];
649
+ if (typeof criteriaOrFn === "function") {
650
+ const ctx = buildContext(dialect);
651
+ const sql = processExprPairs(criteriaOrFn(ctx));
652
+ return new __fHaving(this.db, { ...this.values, having: [...existing, sql] });
653
+ }
654
+ return new __fHaving(this.db, { ...this.values, having: [...existing, criteriaOrFn] });
655
+ }
656
+ };
657
+ var _fGroupBy = class extends _fSelectDistinct {
658
+ having(criteriaOrFn) {
659
+ const existing = this.values.having ?? [];
660
+ if (typeof criteriaOrFn === "function") {
661
+ const ctx = buildContext(dialect);
662
+ const sql = processExprPairs(criteriaOrFn(ctx));
663
+ return new _fSelectDistinct(this.db, { ...this.values, having: [...existing, sql] });
664
+ }
665
+ return new _fSelectDistinct(this.db, { ...this.values, having: [...existing, criteriaOrFn] });
666
+ }
242
667
  //TODO this should only accept columns for tables in play
243
668
  groupBy(groupBy) {
244
669
  return new _fHaving(this.db, { ...this.values, groupBy });
245
670
  }
246
- }
247
- class _fWhere extends _fGroupBy {
671
+ };
672
+ var _fWhere = class __fWhere extends _fGroupBy {
248
673
  whereNotNull(col) {
249
- return new _fWhere(this.db, {
674
+ return new __fWhere(this.db, {
250
675
  ...this.values,
251
676
  where: [
252
677
  ...this.values.where || [],
253
678
  {
254
- $AND: (
255
- //@ts-expect-error todo comeback to, col is a string or never
256
- [{ [col]: { op: "IS NOT NULL" } }]
257
- )
679
+ $AND: [{ [col]: { op: "IS NOT NULL" } }]
258
680
  }
259
681
  ]
260
682
  });
261
683
  }
262
684
  whereIsNull(col) {
263
- return new _fWhere(this.db, {
685
+ return new __fWhere(this.db, {
264
686
  ...this.values,
265
687
  where: [
266
688
  ...this.values.where || [],
267
689
  {
268
- $AND: (
269
- //@ts-expect-error todo comeback to, col is a string or never
270
- [{ [col]: { op: "IS NULL" } }]
271
- )
690
+ $AND: [{ [col]: { op: "IS NULL" } }]
272
691
  }
273
692
  ]
274
693
  });
275
694
  }
276
- where(criteria) {
695
+ where(criteriaOrFn) {
696
+ if (typeof criteriaOrFn === "function") {
697
+ const ctx = buildContext(dialect);
698
+ const sql = processExprPairs(criteriaOrFn(ctx));
699
+ return new _fGroupBy(this.db, {
700
+ ...this.values,
701
+ where: [...this.values.where || [], sql]
702
+ });
703
+ }
277
704
  return new _fGroupBy(this.db, {
278
705
  ...this.values,
279
- where: [...this.values.where || [], criteria]
706
+ where: [...this.values.where || [], criteriaOrFn]
280
707
  });
281
708
  }
282
709
  whereRaw(where) {
@@ -285,71 +712,216 @@ class _fWhere extends _fGroupBy {
285
712
  where: [...this.values.where || [], where.replace(/^\s*where\s*/i, "").trim()]
286
713
  });
287
714
  }
715
+ };
716
+ function buildContext(d2) {
717
+ const quoteFn = (col) => d2.quoteQualifiedColumn(col);
718
+ return {
719
+ lit,
720
+ min: (col) => sqlExpr(`MIN(${resolveArg(col, quoteFn)})`),
721
+ max: (col) => sqlExpr(`MAX(${resolveArg(col, quoteFn)})`),
722
+ replace: (col, from, to) => sqlExpr(`REPLACE(${resolveArg(col, quoteFn)}, '${from.replace(/'/g, "''")}', '${to.replace(/'/g, "''")}')`),
723
+ upper: (col) => sqlExpr(`UPPER(${resolveArg(col, quoteFn)})`),
724
+ lower: (col) => sqlExpr(`LOWER(${resolveArg(col, quoteFn)})`),
725
+ trim: (col) => sqlExpr(`TRIM(${resolveArg(col, quoteFn)})`),
726
+ ltrim: (col) => sqlExpr(`LTRIM(${resolveArg(col, quoteFn)})`),
727
+ rtrim: (col) => sqlExpr(`RTRIM(${resolveArg(col, quoteFn)})`),
728
+ cond: (criteria) => sqlExpr(processCriteria([criteria])),
729
+ coalesce: (...args) => {
730
+ if (args.length === 0) throw new Error("coalesce: requires at least one argument");
731
+ return sqlExpr(`COALESCE(${args.map((a2) => resolveArg(a2, quoteFn)).join(", ")})`);
732
+ },
733
+ nullif: (expr1, expr2) => sqlExpr(`NULLIF(${expr1.sql}, ${expr2.sql})`),
734
+ caseWhen: (cases, elseVal) => {
735
+ if (cases.length === 0) throw new Error("caseWhen: requires at least one WHEN clause");
736
+ const parts = cases.map((c2) => `WHEN ${processCriteria([c2.when])} THEN ${c2.then.sql}`).join(" ");
737
+ return sqlExpr(`CASE ${parts}${elseVal ? ` ELSE ${elseVal.sql}` : ""} END`);
738
+ },
739
+ // Partial<> cast: SelectFnContext is a stub here; generator injects DialectFns at codegen time.
740
+ ...dialectContextFns(quoteFn, (c2) => processCriteria([c2]))
741
+ };
288
742
  }
289
- class _fJoin extends _fWhere {
743
+ var _fJoin = class __fJoin extends _fWhere {
290
744
  // Implementation
291
- join(tableOrOptions, field, reference) {
745
+ join(tableOrOptions, field, reference, _opts) {
746
+ return this._joinImpl(void 0, tableOrOptions, field, reference, _opts);
747
+ }
748
+ _joinImpl(joinType, tableOrOptions, field, reference, _opts) {
292
749
  let table;
293
750
  let local;
294
751
  let remote;
295
752
  let tableAlias;
753
+ let joinWhere;
296
754
  if (typeof tableOrOptions === "object" && "table" in tableOrOptions) {
297
755
  table = tableOrOptions.table.trim();
298
756
  local = tableOrOptions.src;
299
757
  remote = tableOrOptions.on;
300
758
  tableAlias = tableOrOptions.alias?.trim();
759
+ joinWhere = tableOrOptions.where ? [tableOrOptions.where] : void 0;
760
+ joinType = tableOrOptions.joinType ?? joinType;
301
761
  } else {
302
762
  const parts = tableOrOptions.split(" ");
303
763
  table = parts[0];
304
764
  tableAlias = parts[1]?.trim();
305
- local = field;
306
- remote = reference;
765
+ local = field ?? "";
766
+ remote = reference ?? "";
767
+ joinWhere = _opts?.where ? [_opts.where] : void 0;
768
+ joinType = _opts?.joinType ?? joinType;
307
769
  }
308
- return new _fJoin(this.db, {
770
+ return new __fJoin(this.db, {
309
771
  ...this.values,
310
772
  tables: [...this.values.tables || [], {
311
773
  table,
312
774
  local,
313
775
  remote,
314
- alias: tableAlias
776
+ alias: tableAlias,
777
+ ...joinWhere ? { joinWhere } : {},
778
+ ...joinType ? { joinType } : {}
315
779
  }]
316
780
  });
317
781
  }
318
782
  // Implementation
319
- joinUnsafeTypeEnforced(tableOrOptions, field, reference) {
320
- return this.join(tableOrOptions, field, reference);
783
+ joinUnsafeTypeEnforced(tableOrOptions, field, reference, _opts) {
784
+ return this.join(tableOrOptions, field, reference, _opts);
321
785
  }
322
786
  // Implementation
323
- joinUnsafeIgnoreType(tableOrOptions, field, reference) {
324
- return this.join(tableOrOptions, field, reference);
325
- }
326
- // innerJoin(table: TTableSources, col1:string, col2:string){
327
- // return new _fJoin<TDBBase>(this.db, {...this.values, tables: [...this.values.tables || [], table]});
328
- // }
329
- // leftJoin(table: TTableSources, col1:string, col2:string){
330
- // return new _fJoin<TDBBase>(this.db, {...this.values, tables: [...this.values.tables || [], table]});
331
- // }
332
- // rightJoin(table: TTableSources, col1:string, col2:string){
333
- // return new _fJoin<TDBBase>(this.db, {...this.values, tables: [...this.values.tables || [], table]});
334
- // }
335
- // fullJoin(table: TTableSources, col1:string, col2:string){
336
- // return new _fJoin<TDBBase>(this.db, {...this.values, tables: [...this.values.tables || [], table]});
337
- // }
338
- // crossJoin(table: TTableSources, col1:string, col2:string){
339
- // return new _fJoin<TDBBase>(this.db, {...this.values, tables: [...this.values.tables || [], table]});
340
- // }
341
- // outerJoin(table: TTableSources, col1:string, col2:string){
342
- // return new _fJoin<TDBBase>(this.db, {...this.values, tables: [...this.values.tables || [], table]});
343
- // }
344
- }
345
- var extend_default = {
787
+ joinUnsafeIgnoreType(tableOrOptions, field, reference, _opts) {
788
+ return this.join(tableOrOptions, field, reference, _opts);
789
+ }
790
+ manyToManyJoin(targetTable, options) {
791
+ const opts = options;
792
+ const refName = opts?.refName;
793
+ const [tbl, alias] = targetTable.split(" ");
794
+ let sourceTableName;
795
+ let sourceAlias;
796
+ let srcLocalCol;
797
+ if (opts?.source) {
798
+ const [srcAliasOrTable, col] = opts.source.split(".");
799
+ const entry = this.values.tables.find((t2) => (t2.alias || t2.table) === srcAliasOrTable);
800
+ sourceTableName = entry?.table ?? srcAliasOrTable;
801
+ sourceAlias = srcAliasOrTable;
802
+ srcLocalCol = col;
803
+ } else {
804
+ const candidates = this.values.tables.filter((entry) => {
805
+ const relations = DB[entry.table]?.relations;
806
+ return relations && Object.keys(relations).some(
807
+ (k2) => k2.startsWith("_") && DB[k2]?.relations?.[tbl] !== void 0
808
+ );
809
+ });
810
+ if (candidates.length === 0) throw new Error(
811
+ `manyToManyJoin: no source with junction to "${tbl}" among joined tables`
812
+ );
813
+ if (candidates.length > 1) {
814
+ const names = candidates.map((c2) => c2.alias ?? c2.table).join(", ");
815
+ throw new Error(`manyToManyJoin: ambiguous source for "${tbl}" (${names}). Pass { source: "alias.col" }.`);
816
+ }
817
+ const found = candidates[0];
818
+ sourceTableName = found.table;
819
+ sourceAlias = found.alias || found.table;
820
+ const srcRelations2 = DB[sourceTableName]?.relations;
821
+ const junctionKey = refName ? `_${refName}` : Object.keys(srcRelations2 ?? {}).find(
822
+ (k2) => k2.startsWith("_") && DB[k2]?.relations?.[tbl] !== void 0
823
+ );
824
+ const junctionRelEntry = junctionKey ? srcRelations2[junctionKey] : void 0;
825
+ srcLocalCol = junctionRelEntry ? Object.keys(junctionRelEntry)[0] : "id";
826
+ }
827
+ const srcEntry = DB[sourceTableName];
828
+ if (!srcEntry) throw new Error(`manyToManyJoin: unknown source table "${sourceTableName}"`);
829
+ const srcRelations = srcEntry.relations;
830
+ const junctionTable = refName ? `_${refName}` : Object.keys(srcRelations).find(
831
+ (k2) => k2.startsWith("_") && DB[k2]?.relations?.[tbl] !== void 0
832
+ );
833
+ if (!junctionTable) throw new Error(
834
+ `manyToManyJoin: no junction between "${sourceTableName}" and "${tbl}"`
835
+ );
836
+ const srcJunctionCol = srcRelations[junctionTable]?.[srcLocalCol]?.[0] ?? "A";
837
+ const tgtRelEntry = DB[junctionTable]?.relations?.[tbl];
838
+ const tgtJunctionCol = tgtRelEntry ? Object.keys(tgtRelEntry)[0] : "B";
839
+ const tgtLocalCol = tgtRelEntry?.[tgtJunctionCol]?.[0] ?? "id";
840
+ const remoteRef = `${sourceAlias}.${srcLocalCol}`;
841
+ return this.joinUnsafeIgnoreType(junctionTable, srcJunctionCol, remoteRef).joinUnsafeIgnoreType(alias ? `${tbl} ${alias}` : tbl, tgtLocalCol, `${junctionTable}.${tgtJunctionCol}`);
842
+ }
843
+ innerJoin(tableOrOptions, field, reference) {
844
+ return this._joinImpl("INNER", tableOrOptions, field, reference);
845
+ }
846
+ leftJoin(tableOrOptions, field, reference) {
847
+ return this._joinImpl("LEFT", tableOrOptions, field, reference);
848
+ }
849
+ rightJoin(tableOrOptions, field, reference) {
850
+ return this._joinImpl("RIGHT", tableOrOptions, field, reference);
851
+ }
852
+ fullJoin(tableOrOptions, field, reference) {
853
+ return this._joinImpl("FULL", tableOrOptions, field, reference);
854
+ }
855
+ // crossJoin: no ON clause — table only (with optional inline alias)
856
+ crossJoin(table) {
857
+ return this._joinImpl("CROSS", table);
858
+ }
859
+ innerJoinUnsafeTypeEnforced(tableOrOptions, field, reference) {
860
+ return this._joinImpl("INNER", tableOrOptions, field, reference);
861
+ }
862
+ innerJoinUnsafeIgnoreType(tableOrOptions, field, reference) {
863
+ return this._joinImpl("INNER", tableOrOptions, field, reference);
864
+ }
865
+ leftJoinUnsafeTypeEnforced(tableOrOptions, field, reference) {
866
+ return this._joinImpl("LEFT", tableOrOptions, field, reference);
867
+ }
868
+ leftJoinUnsafeIgnoreType(tableOrOptions, field, reference) {
869
+ return this._joinImpl("LEFT", tableOrOptions, field, reference);
870
+ }
871
+ rightJoinUnsafeTypeEnforced(tableOrOptions, field, reference) {
872
+ return this._joinImpl("RIGHT", tableOrOptions, field, reference);
873
+ }
874
+ rightJoinUnsafeIgnoreType(tableOrOptions, field, reference) {
875
+ return this._joinImpl("RIGHT", tableOrOptions, field, reference);
876
+ }
877
+ fullJoinUnsafeTypeEnforced(tableOrOptions, field, reference) {
878
+ return this._joinImpl("FULL", tableOrOptions, field, reference);
879
+ }
880
+ fullJoinUnsafeIgnoreType(tableOrOptions, field, reference) {
881
+ return this._joinImpl("FULL", tableOrOptions, field, reference);
882
+ }
883
+ // crossJoinUnsafeTypeEnforced — CROSS semantics, type-enforced columns
884
+ crossJoinUnsafeTypeEnforced(table) {
885
+ return this._joinImpl("CROSS", table);
886
+ }
887
+ // crossJoinUnsafeIgnoreType — CROSS semantics, any columns
888
+ crossJoinUnsafeIgnoreType(table) {
889
+ return this._joinImpl("CROSS", table);
890
+ }
891
+ };
892
+ var DbWith = class _DbWith {
893
+ constructor(db, _withs) {
894
+ this.db = db;
895
+ this._withs = _withs;
896
+ }
897
+ with(name, query) {
898
+ return new _DbWith(this.db, [
899
+ ...this._withs,
900
+ { name, sql: query.getSQL().replace(/;$/, "") }
901
+ ]);
902
+ }
903
+ from(baseTableOrCTE, alias) {
904
+ return new _fJoin(this.db, {
905
+ tables: [{ table: baseTableOrCTE, alias }],
906
+ selects: [],
907
+ withs: this._withs
908
+ });
909
+ }
910
+ };
911
+ var extendedPrismaClient = {
912
+ name: "prisma-ts-select",
346
913
  client: {
347
914
  $from(table) {
348
915
  const client = Prisma.getExtensionContext(this);
349
916
  const [base, ...aliases] = table.split(" ");
350
917
  return new DbSelect(client).from(base.trim(), aliases.join().trim() || void 0);
918
+ },
919
+ $with(name, query) {
920
+ const client = Prisma.getExtensionContext(this);
921
+ return new DbWith(client, [{ name, sql: query.getSQL().replace(/;$/, "") }]);
351
922
  }
352
923
  }
353
924
  };
925
+ var extend_default = extendedPrismaClient;
354
926
 
355
927
  export { extend_default as default };