prisma-ts-select 0.0.34 → 0.1.3

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 +1343 -362
  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/{whereisNull.gif → whereIsNull.gif} +0 -0
  9. package/assets/whereNotNull.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 +194 -0
  16. package/dist/extend/dialects/mysql-v6.d.ts +103 -0
  17. package/dist/extend/dialects/mysql-v6.js +157 -0
  18. package/dist/extend/dialects/mysql-v7.d.ts +6 -0
  19. package/dist/extend/dialects/mysql-v7.js +143 -0
  20. package/dist/extend/dialects/mysql.d.ts +93 -0
  21. package/dist/extend/dialects/mysql.js +161 -0
  22. package/dist/extend/dialects/postgresql-v6.d.ts +101 -0
  23. package/dist/extend/dialects/postgresql-v6.js +147 -0
  24. package/dist/extend/dialects/postgresql-v7.d.ts +101 -0
  25. package/dist/extend/dialects/postgresql-v7.js +147 -0
  26. package/dist/extend/dialects/postgresql.d.ts +92 -0
  27. package/dist/extend/dialects/postgresql.js +158 -0
  28. package/dist/extend/dialects/shared.d.ts +10 -0
  29. package/dist/extend/dialects/shared.js +14 -0
  30. package/dist/extend/dialects/sqlite.d.ts +68 -0
  31. package/dist/extend/dialects/sqlite.js +146 -0
  32. package/dist/extend/dialects/types.d.ts +13 -0
  33. package/dist/extend/dialects/types.js +4 -0
  34. package/dist/extend/extend.d.ts +292 -46
  35. package/dist/extend/extend.js +769 -162
  36. package/dist/extend/sql-expr-BaKWzJ-r.d.ts +10 -0
  37. package/dist/extend/types-B0F8m0ok.d.ts +8 -0
  38. package/dist/generator.cjs +1 -1
  39. package/dist/generator.js +1 -1
  40. package/package.json +44 -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/sql-expr.ts
266
+ function sqlExpr(sql) {
267
+ return { sql, toString() {
268
+ return sql;
269
+ } };
270
+ }
271
+ function lit(value) {
272
+ if (value === null) return sqlExpr("NULL");
273
+ if (typeof value === "boolean") return sqlExpr(value ? "1" : "0");
274
+ if (typeof value === "string") return sqlExpr(`'${value.replace(/'/g, "''")}'`);
275
+ return sqlExpr(String(value));
276
+ }
277
+ function resolveArg(arg, quoteFn) {
278
+ if (typeof arg !== "string") return arg.sql;
279
+ return quoteFn(arg);
280
+ }
281
+
282
+ // src/dialects/shared.ts
283
+ var esc = (s2) => s2.replace(/'/g, "''");
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() + ")";
351
+ }
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();
18
392
  }
19
- class _fRun {
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,178 +562,401 @@ 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
+ if (select === "*" && this.values.tables.length > 1) {
579
+ throw new Error(`select("*", alias) is not supported on multi-table queries \u2014 use explicit column names or select("*") without alias`);
580
+ }
581
+ const quotedSelect2 = select === "*" ? "*" : select.includes(".") ? dialect.quoteQualifiedColumn(select) : dialect.quote(select, false);
582
+ return new __fSelect(this.db, {
195
583
  ...this.values,
196
- selects: [...this.values.selects, `${select} AS \`${alias}\``]
584
+ selects: [...this.values.selects, `${quotedSelect2} AS ${dialect.quote(alias, true)}`]
197
585
  });
198
586
  }
199
- return new _fSelect(this.db, {
587
+ if (select === "*" && this.values.tables.length > 1) {
588
+ const expandedSelects = this.values.tables.flatMap(
589
+ (tableObj) => expandToQualifiedSelects(tableObj, this.values.withs)
590
+ );
591
+ return new __fSelect(this.db, { ...this.values, selects: [...this.values.selects, ...expandedSelects] });
592
+ }
593
+ const quotedSelect = select === "*" ? "*" : select.includes(".") ? dialect.quoteQualifiedColumn(select) : dialect.quote(select, false);
594
+ return new __fSelect(this.db, {
200
595
  ...this.values,
201
- selects: [...this.values.selects, select]
596
+ selects: [...this.values.selects, quotedSelect]
202
597
  });
203
598
  }
204
- }
205
- class _fSelectDistinct extends _fSelect {
599
+ };
600
+ var _fSelectDistinct = class extends _fSelect {
206
601
  selectDistinct() {
207
602
  return new _fSelect(this.db, { ...this.values, selectDistinct: true });
208
603
  }
209
604
  selectAll() {
210
605
  const selects = function(values) {
211
606
  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}\``));
607
+ return values.tables.reduce((acc, tableObj) => {
608
+ return acc.concat(expandToQualifiedSelects(tableObj, values.withs));
217
609
  }, []);
218
610
  }
219
- return Object.keys(DB[values.tables[0].table].fields);
611
+ const t2 = values.tables[0];
612
+ 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.`);
613
+ return Object.keys(DB[t2.table].fields).map((field) => dialect.quote(field, false));
220
614
  }(this.values);
221
615
  return new _fOrderBy(this.db, {
222
616
  ...this.values,
223
617
  selects
224
618
  });
225
619
  }
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, {
620
+ selectAllOmit(omit) {
621
+ const omitSet = new Set(omit);
622
+ const selects = function(values) {
623
+ if (values.tables.length === 1) {
624
+ const t2 = values.tables[0];
625
+ const tableIdentifier = t2.alias || t2.table;
626
+ return Object.keys(DB[t2.table].fields).filter((f2) => !omitSet.has(f2) && !omitSet.has(`${tableIdentifier}.${f2}`)).map((f2) => dialect.quote(f2, false));
627
+ }
628
+ return values.tables.reduce((acc, tableObj) => {
629
+ const tableIdentifier = tableObj.alias || tableObj.table;
630
+ if (!DB[tableObj.table]) return acc;
631
+ return acc.concat(
632
+ Object.keys(DB[tableObj.table].fields).filter((f2) => !omitSet.has(f2) && !omitSet.has(`${tableIdentifier}.${f2}`)).map((f2) => {
633
+ const q = `${tableIdentifier}.${f2}`;
634
+ return `${dialect.quoteQualifiedColumn(q)} AS ${dialect.quote(q, true)}`;
635
+ })
636
+ );
637
+ }, []);
638
+ }(this.values);
639
+ return new _fOrderBy(this.db, {
236
640
  ...this.values,
237
- having: [criteria]
641
+ selects
238
642
  });
239
643
  }
240
- }
241
- class _fGroupBy extends _fHaving {
644
+ };
645
+ var _fHaving = class __fHaving extends _fSelect {
646
+ // Keep selectDistinct() available after groupBy(), but not selectAll()
647
+ selectDistinct() {
648
+ return new _fSelect(this.db, { ...this.values, selectDistinct: true });
649
+ }
650
+ having(criteriaOrFn) {
651
+ const existing = this.values.having ?? [];
652
+ if (typeof criteriaOrFn === "function") {
653
+ const ctx = buildContext(dialect);
654
+ const sql = processExprPairs(criteriaOrFn(ctx));
655
+ return new __fHaving(this.db, { ...this.values, having: [...existing, sql] });
656
+ }
657
+ return new __fHaving(this.db, { ...this.values, having: [...existing, criteriaOrFn] });
658
+ }
659
+ };
660
+ var _fGroupBy = class extends _fSelectDistinct {
661
+ having(criteriaOrFn) {
662
+ const existing = this.values.having ?? [];
663
+ if (typeof criteriaOrFn === "function") {
664
+ const ctx = buildContext(dialect);
665
+ const sql = processExprPairs(criteriaOrFn(ctx));
666
+ return new _fSelectDistinct(this.db, { ...this.values, having: [...existing, sql] });
667
+ }
668
+ return new _fSelectDistinct(this.db, { ...this.values, having: [...existing, criteriaOrFn] });
669
+ }
242
670
  //TODO this should only accept columns for tables in play
243
671
  groupBy(groupBy) {
244
672
  return new _fHaving(this.db, { ...this.values, groupBy });
245
673
  }
246
- }
247
- class _fWhere extends _fGroupBy {
674
+ };
675
+ var _fWhere = class __fWhere extends _fGroupBy {
248
676
  whereNotNull(col) {
249
- return new _fWhere(this.db, {
677
+ return new __fWhere(this.db, {
250
678
  ...this.values,
251
679
  where: [
252
680
  ...this.values.where || [],
253
681
  {
254
- $AND: (
255
- //@ts-expect-error todo comeback to, col is a string or never
256
- [{ [col]: { op: "IS NOT NULL" } }]
257
- )
682
+ $AND: [{ [col]: { op: "IS NOT NULL" } }]
258
683
  }
259
684
  ]
260
685
  });
261
686
  }
262
687
  whereIsNull(col) {
263
- return new _fWhere(this.db, {
688
+ return new __fWhere(this.db, {
264
689
  ...this.values,
265
690
  where: [
266
691
  ...this.values.where || [],
267
692
  {
268
- $AND: (
269
- //@ts-expect-error todo comeback to, col is a string or never
270
- [{ [col]: { op: "IS NULL" } }]
271
- )
693
+ $AND: [{ [col]: { op: "IS NULL" } }]
272
694
  }
273
695
  ]
274
696
  });
275
697
  }
276
- where(criteria) {
698
+ where(criteriaOrFn) {
699
+ if (typeof criteriaOrFn === "function") {
700
+ const ctx = buildContext(dialect);
701
+ const sql = processExprPairs(criteriaOrFn(ctx));
702
+ return new _fGroupBy(this.db, {
703
+ ...this.values,
704
+ where: [...this.values.where || [], sql]
705
+ });
706
+ }
277
707
  return new _fGroupBy(this.db, {
278
708
  ...this.values,
279
- where: [...this.values.where || [], criteria]
709
+ where: [...this.values.where || [], criteriaOrFn]
280
710
  });
281
711
  }
712
+ /**
713
+ * @security NEVER pass user-supplied input. Inserts SQL verbatim into $queryRawUnsafe without parameterization.
714
+ */
282
715
  whereRaw(where) {
283
716
  return new _fGroupBy(this.db, {
284
717
  ...this.values,
285
718
  where: [...this.values.where || [], where.replace(/^\s*where\s*/i, "").trim()]
286
719
  });
287
720
  }
721
+ };
722
+ function buildContext(d2) {
723
+ const quoteFn = (col) => d2.quoteQualifiedColumn(col);
724
+ return {
725
+ lit,
726
+ min: (col) => sqlExpr(`MIN(${resolveArg(col, quoteFn)})`),
727
+ max: (col) => sqlExpr(`MAX(${resolveArg(col, quoteFn)})`),
728
+ replace: (col, from, to) => sqlExpr(`REPLACE(${resolveArg(col, quoteFn)}, '${from.replace(/'/g, "''")}', '${to.replace(/'/g, "''")}')`),
729
+ upper: (col) => sqlExpr(`UPPER(${resolveArg(col, quoteFn)})`),
730
+ lower: (col) => sqlExpr(`LOWER(${resolveArg(col, quoteFn)})`),
731
+ trim: (col) => sqlExpr(`TRIM(${resolveArg(col, quoteFn)})`),
732
+ ltrim: (col) => sqlExpr(`LTRIM(${resolveArg(col, quoteFn)})`),
733
+ rtrim: (col) => sqlExpr(`RTRIM(${resolveArg(col, quoteFn)})`),
734
+ cond: (criteria) => sqlExpr(processCriteria([criteria])),
735
+ coalesce: (...args) => {
736
+ if (args.length === 0) throw new Error("coalesce: requires at least one argument");
737
+ return sqlExpr(`COALESCE(${args.map((a2) => resolveArg(a2, quoteFn)).join(", ")})`);
738
+ },
739
+ nullif: (expr1, expr2) => sqlExpr(`NULLIF(${expr1.sql}, ${expr2.sql})`),
740
+ caseWhen: (cases, elseVal) => {
741
+ if (cases.length === 0) throw new Error("caseWhen: requires at least one WHEN clause");
742
+ const parts = cases.map((c2) => `WHEN ${processCriteria([c2.when])} THEN ${c2.then.sql}`).join(" ");
743
+ return sqlExpr(`CASE ${parts}${elseVal ? ` ELSE ${elseVal.sql}` : ""} END`);
744
+ },
745
+ // Partial<> cast: SelectFnContext is a stub here; generator injects DialectFns at codegen time.
746
+ ...dialectContextFns(quoteFn, (c2) => processCriteria([c2]))
747
+ };
288
748
  }
289
- class _fJoin extends _fWhere {
749
+ var _fJoin = class __fJoin extends _fWhere {
290
750
  // Implementation
291
- join(tableOrOptions, field, reference) {
751
+ join(tableOrOptions, field, reference, _opts) {
752
+ return this._joinImpl(void 0, tableOrOptions, field, reference, _opts);
753
+ }
754
+ _joinImpl(joinType, tableOrOptions, field, reference, _opts) {
292
755
  let table;
293
756
  let local;
294
757
  let remote;
295
758
  let tableAlias;
759
+ let joinWhere;
296
760
  if (typeof tableOrOptions === "object" && "table" in tableOrOptions) {
297
761
  table = tableOrOptions.table.trim();
298
762
  local = tableOrOptions.src;
299
763
  remote = tableOrOptions.on;
300
764
  tableAlias = tableOrOptions.alias?.trim();
765
+ joinWhere = tableOrOptions.where ? [tableOrOptions.where] : void 0;
766
+ joinType = tableOrOptions.joinType ?? joinType;
301
767
  } else {
302
768
  const parts = tableOrOptions.split(" ");
303
769
  table = parts[0];
304
770
  tableAlias = parts[1]?.trim();
305
- local = field;
306
- remote = reference;
771
+ local = field ?? "";
772
+ remote = reference ?? "";
773
+ joinWhere = _opts?.where ? [_opts.where] : void 0;
774
+ joinType = _opts?.joinType ?? joinType;
307
775
  }
308
- return new _fJoin(this.db, {
776
+ return new __fJoin(this.db, {
309
777
  ...this.values,
310
778
  tables: [...this.values.tables || [], {
311
779
  table,
312
780
  local,
313
781
  remote,
314
- alias: tableAlias
782
+ alias: tableAlias,
783
+ ...joinWhere ? { joinWhere } : {},
784
+ ...joinType ? { joinType } : {}
315
785
  }]
316
786
  });
317
787
  }
318
788
  // Implementation
319
- joinUnsafeTypeEnforced(tableOrOptions, field, reference) {
320
- return this.join(tableOrOptions, field, reference);
789
+ joinUnsafeTypeEnforced(tableOrOptions, field, reference, _opts) {
790
+ return this.join(tableOrOptions, field, reference, _opts);
321
791
  }
322
792
  // 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
- // }
793
+ joinUnsafeIgnoreType(tableOrOptions, field, reference, _opts) {
794
+ return this.join(tableOrOptions, field, reference, _opts);
795
+ }
796
+ manyToManyJoin(targetTable, options) {
797
+ const opts = options;
798
+ const refName = opts?.refName;
799
+ const [tbl, alias] = targetTable.split(" ");
800
+ let sourceTableName;
801
+ let sourceAlias;
802
+ let srcLocalCol;
803
+ if (opts?.source) {
804
+ const [srcAliasOrTable, col] = opts.source.split(".");
805
+ const entry = this.values.tables.find((t2) => (t2.alias || t2.table) === srcAliasOrTable);
806
+ sourceTableName = entry?.table ?? srcAliasOrTable;
807
+ sourceAlias = srcAliasOrTable;
808
+ srcLocalCol = col;
809
+ } else {
810
+ const candidates = this.values.tables.filter((entry) => {
811
+ const relations = DB[entry.table]?.relations;
812
+ return relations && Object.keys(relations).some(
813
+ (k2) => k2.startsWith("_") && DB[k2]?.relations?.[tbl] !== void 0
814
+ );
815
+ });
816
+ if (candidates.length === 0) throw new Error(
817
+ `manyToManyJoin: no source with junction to "${tbl}" among joined tables`
818
+ );
819
+ if (candidates.length > 1) {
820
+ const names = candidates.map((c2) => c2.alias ?? c2.table).join(", ");
821
+ throw new Error(`manyToManyJoin: ambiguous source for "${tbl}" (${names}). Pass { source: "alias.col" }.`);
822
+ }
823
+ const found = candidates[0];
824
+ sourceTableName = found.table;
825
+ sourceAlias = found.alias || found.table;
826
+ const srcRelations2 = DB[sourceTableName]?.relations;
827
+ const junctionKey = refName ? `_${refName}` : Object.keys(srcRelations2 ?? {}).find(
828
+ (k2) => k2.startsWith("_") && DB[k2]?.relations?.[tbl] !== void 0
829
+ );
830
+ const junctionRelEntry = junctionKey ? srcRelations2[junctionKey] : void 0;
831
+ srcLocalCol = junctionRelEntry ? Object.keys(junctionRelEntry)[0] : "id";
832
+ }
833
+ const srcEntry = DB[sourceTableName];
834
+ if (!srcEntry) throw new Error(`manyToManyJoin: unknown source table "${sourceTableName}"`);
835
+ const srcRelations = srcEntry.relations;
836
+ const junctionTable = refName ? `_${refName}` : Object.keys(srcRelations).find(
837
+ (k2) => k2.startsWith("_") && DB[k2]?.relations?.[tbl] !== void 0
838
+ );
839
+ if (!junctionTable) throw new Error(
840
+ `manyToManyJoin: no junction between "${sourceTableName}" and "${tbl}"`
841
+ );
842
+ const srcJunctionCol = srcRelations[junctionTable]?.[srcLocalCol]?.[0] ?? "A";
843
+ const tgtRelEntry = DB[junctionTable]?.relations?.[tbl];
844
+ const tgtJunctionCol = tgtRelEntry ? Object.keys(tgtRelEntry)[0] : "B";
845
+ const tgtLocalCol = tgtRelEntry?.[tgtJunctionCol]?.[0] ?? "id";
846
+ const remoteRef = `${sourceAlias}.${srcLocalCol}`;
847
+ return this.joinUnsafeIgnoreType(junctionTable, srcJunctionCol, remoteRef).joinUnsafeIgnoreType(alias ? `${tbl} ${alias}` : tbl, tgtLocalCol, `${junctionTable}.${tgtJunctionCol}`);
848
+ }
849
+ innerJoin(tableOrOptions, field, reference) {
850
+ return this._joinImpl("INNER", tableOrOptions, field, reference);
851
+ }
852
+ leftJoin(tableOrOptions, field, reference) {
853
+ return this._joinImpl("LEFT", tableOrOptions, field, reference);
854
+ }
855
+ rightJoin(tableOrOptions, field, reference) {
856
+ return this._joinImpl("RIGHT", tableOrOptions, field, reference);
857
+ }
858
+ fullJoin(tableOrOptions, field, reference) {
859
+ return this._joinImpl("FULL", tableOrOptions, field, reference);
860
+ }
861
+ // crossJoin: no ON clause — table only (with optional inline alias)
862
+ crossJoin(table) {
863
+ return this._joinImpl("CROSS", table);
864
+ }
865
+ innerJoinUnsafeTypeEnforced(tableOrOptions, field, reference) {
866
+ return this._joinImpl("INNER", tableOrOptions, field, reference);
867
+ }
868
+ innerJoinUnsafeIgnoreType(tableOrOptions, field, reference) {
869
+ return this._joinImpl("INNER", tableOrOptions, field, reference);
870
+ }
871
+ leftJoinUnsafeTypeEnforced(tableOrOptions, field, reference) {
872
+ return this._joinImpl("LEFT", tableOrOptions, field, reference);
873
+ }
874
+ leftJoinUnsafeIgnoreType(tableOrOptions, field, reference) {
875
+ return this._joinImpl("LEFT", tableOrOptions, field, reference);
876
+ }
877
+ rightJoinUnsafeTypeEnforced(tableOrOptions, field, reference) {
878
+ return this._joinImpl("RIGHT", tableOrOptions, field, reference);
879
+ }
880
+ rightJoinUnsafeIgnoreType(tableOrOptions, field, reference) {
881
+ return this._joinImpl("RIGHT", tableOrOptions, field, reference);
882
+ }
883
+ fullJoinUnsafeTypeEnforced(tableOrOptions, field, reference) {
884
+ return this._joinImpl("FULL", tableOrOptions, field, reference);
885
+ }
886
+ fullJoinUnsafeIgnoreType(tableOrOptions, field, reference) {
887
+ return this._joinImpl("FULL", tableOrOptions, field, reference);
888
+ }
889
+ // crossJoinUnsafeTypeEnforced — CROSS semantics, type-enforced columns
890
+ crossJoinUnsafeTypeEnforced(table) {
891
+ return this._joinImpl("CROSS", table);
892
+ }
893
+ // crossJoinUnsafeIgnoreType — CROSS semantics, any columns
894
+ crossJoinUnsafeIgnoreType(table) {
895
+ return this._joinImpl("CROSS", table);
896
+ }
897
+ };
898
+ function expandToQualifiedSelects(tableObj, withs) {
899
+ const tId = tableObj.alias || tableObj.table;
900
+ if (DB[tableObj.table]) {
901
+ return Object.keys(DB[tableObj.table].fields).map((field) => {
902
+ const q = `${tId}.${field}`;
903
+ return `${dialect.quoteQualifiedColumn(q)} AS ${dialect.quote(q, true)}`;
904
+ });
905
+ }
906
+ const cte = withs?.find((w2) => w2.name === tableObj.table);
907
+ if (!cte?.columns?.length) throw new Error(`Cannot expand * for CTE "${tableObj.table}" \u2014 select columns explicitly`);
908
+ return cte.columns.map((col) => {
909
+ const q = `${tId}.${col}`;
910
+ return `${dialect.quoteQualifiedColumn(q)} AS ${dialect.quote(q, true)}`;
911
+ });
912
+ }
913
+ function extractSelectAlias(expr) {
914
+ const aliased = / AS ["'`](.+?)["'`]\s*$/i.exec(expr);
915
+ if (aliased) return aliased[1];
916
+ const quoted = /^["'`](.+?)["'`]$/.exec(expr);
917
+ if (quoted) return quoted[1];
918
+ if (/^\w+$/.test(expr)) return expr;
919
+ return null;
344
920
  }
345
- var extend_default = {
921
+ function extractCTEColumns(query) {
922
+ return query.values.selects.map(extractSelectAlias).filter((c2) => c2 !== null);
923
+ }
924
+ var DbWith = class _DbWith {
925
+ constructor(db, _withs) {
926
+ this.db = db;
927
+ this._withs = _withs;
928
+ }
929
+ with(name, query) {
930
+ const columns = extractCTEColumns(query);
931
+ return new _DbWith(this.db, [
932
+ ...this._withs,
933
+ { name, sql: query.getSQL().replace(/;$/, ""), columns }
934
+ ]);
935
+ }
936
+ from(baseTableOrCTE, alias) {
937
+ return new _fJoin(this.db, {
938
+ tables: [{ table: baseTableOrCTE, alias }],
939
+ selects: [],
940
+ withs: this._withs
941
+ });
942
+ }
943
+ };
944
+ var extendedPrismaClient = {
945
+ name: "prisma-ts-select",
346
946
  client: {
347
947
  $from(table) {
348
948
  const client = Prisma.getExtensionContext(this);
349
949
  const [base, ...aliases] = table.split(" ");
350
950
  return new DbSelect(client).from(base.trim(), aliases.join().trim() || void 0);
951
+ },
952
+ /** @note `query` must be produced by the same prisma-ts-select builder instance. */
953
+ $with(name, query) {
954
+ const client = Prisma.getExtensionContext(this);
955
+ const columns = extractCTEColumns(query);
956
+ return new DbWith(client, [{ name, sql: query.getSQL().replace(/;$/, ""), columns }]);
351
957
  }
352
958
  }
353
959
  };
960
+ var extend_default = extendedPrismaClient;
354
961
 
355
962
  export { extend_default as default };