joist-core 2.3.0-next.61 → 2.3.0-next.63

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 (101) hide show
  1. package/build/Aliases.cjs +133 -462
  2. package/build/Aliases.cjs.map +1 -1
  3. package/build/Aliases.d.cts +64 -168
  4. package/build/Aliases.d.cts.map +1 -1
  5. package/build/Aliases.d.mts +64 -168
  6. package/build/Aliases.d.mts.map +1 -1
  7. package/build/Aliases.js +128 -454
  8. package/build/Aliases.js.map +1 -1
  9. package/build/ConditionBuilder.cjs +3 -2
  10. package/build/ConditionBuilder.cjs.map +1 -1
  11. package/build/ConditionBuilder.js +2 -1
  12. package/build/ConditionBuilder.js.map +1 -1
  13. package/build/DeferredAlias.cjs +33 -0
  14. package/build/DeferredAlias.cjs.map +1 -0
  15. package/build/DeferredAlias.d.cts +25 -0
  16. package/build/DeferredAlias.d.cts.map +1 -0
  17. package/build/DeferredAlias.d.mts +25 -0
  18. package/build/DeferredAlias.d.mts.map +1 -0
  19. package/build/DeferredAlias.js +29 -0
  20. package/build/DeferredAlias.js.map +1 -0
  21. package/build/EntityManager.cjs +20 -1
  22. package/build/EntityManager.cjs.map +1 -1
  23. package/build/EntityManager.d.cts +19 -8
  24. package/build/EntityManager.d.cts.map +1 -1
  25. package/build/EntityManager.d.mts +19 -8
  26. package/build/EntityManager.d.mts.map +1 -1
  27. package/build/EntityManager.js +20 -1
  28. package/build/EntityManager.js.map +1 -1
  29. package/build/EntityMetadata.cjs.map +1 -1
  30. package/build/EntityMetadata.d.cts +6 -0
  31. package/build/EntityMetadata.d.cts.map +1 -1
  32. package/build/EntityMetadata.d.mts +6 -0
  33. package/build/EntityMetadata.d.mts.map +1 -1
  34. package/build/EntityMetadata.js.map +1 -1
  35. package/build/Expr.cjs +241 -58
  36. package/build/Expr.cjs.map +1 -1
  37. package/build/Expr.d.cts +94 -50
  38. package/build/Expr.d.cts.map +1 -1
  39. package/build/Expr.d.mts +94 -50
  40. package/build/Expr.d.mts.map +1 -1
  41. package/build/Expr.js +234 -53
  42. package/build/Expr.js.map +1 -1
  43. package/build/QueryParser.cjs +2 -2
  44. package/build/QueryParser.cjs.map +1 -1
  45. package/build/QueryParser.js +2 -2
  46. package/build/QueryParser.js.map +1 -1
  47. package/build/Tables.cjs +682 -0
  48. package/build/Tables.cjs.map +1 -0
  49. package/build/Tables.d.cts +197 -0
  50. package/build/Tables.d.cts.map +1 -0
  51. package/build/Tables.d.mts +197 -0
  52. package/build/Tables.d.mts.map +1 -0
  53. package/build/Tables.js +672 -0
  54. package/build/Tables.js.map +1 -0
  55. package/build/configure.cjs +4 -0
  56. package/build/configure.cjs.map +1 -1
  57. package/build/configure.js +4 -0
  58. package/build/configure.js.map +1 -1
  59. package/build/drivers/Driver.d.cts +13 -3
  60. package/build/drivers/Driver.d.cts.map +1 -1
  61. package/build/drivers/Driver.d.mts +13 -3
  62. package/build/drivers/Driver.d.mts.map +1 -1
  63. package/build/drivers/index.d.cts +2 -2
  64. package/build/drivers/index.d.mts +2 -2
  65. package/build/execute.cjs +240 -0
  66. package/build/execute.cjs.map +1 -0
  67. package/build/execute.d.cts +190 -0
  68. package/build/execute.d.cts.map +1 -0
  69. package/build/execute.d.mts +190 -0
  70. package/build/execute.d.mts.map +1 -0
  71. package/build/execute.js +237 -0
  72. package/build/execute.js.map +1 -0
  73. package/build/index.cjs +11 -2
  74. package/build/index.cjs.map +1 -1
  75. package/build/index.d.cts +11 -8
  76. package/build/index.d.cts.map +1 -1
  77. package/build/index.d.mts +11 -8
  78. package/build/index.d.mts.map +1 -1
  79. package/build/index.js +4 -2
  80. package/build/index.js.map +1 -1
  81. package/build/query.cjs +477 -110
  82. package/build/query.cjs.map +1 -1
  83. package/build/query.d.cts +280 -45
  84. package/build/query.d.cts.map +1 -1
  85. package/build/query.d.mts +280 -45
  86. package/build/query.d.mts.map +1 -1
  87. package/build/query.js +470 -108
  88. package/build/query.js.map +1 -1
  89. package/build/serde.cjs +289 -50
  90. package/build/serde.cjs.map +1 -1
  91. package/build/serde.d.cts +115 -24
  92. package/build/serde.d.cts.map +1 -1
  93. package/build/serde.d.mts +115 -24
  94. package/build/serde.d.mts.map +1 -1
  95. package/build/serde.js +289 -50
  96. package/build/serde.js.map +1 -1
  97. package/build/typeMap.d.cts +4 -2
  98. package/build/typeMap.d.cts.map +1 -1
  99. package/build/typeMap.d.mts +4 -2
  100. package/build/typeMap.d.mts.map +1 -1
  101. package/package.json +2 -2
package/build/Aliases.cjs CHANGED
@@ -1,374 +1,219 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  require("./typeMap.cjs");
3
- const require_keywords = require("./keywords.cjs");
3
+ require("./EntityFilter.cjs");
4
4
  const require_keys = require("./keys.cjs");
5
+ const require_DeferredAlias = require("./DeferredAlias.cjs");
5
6
  require("./serde.cjs");
6
7
  const require_EntityMetadata = require("./EntityMetadata.cjs");
7
8
  const require_utils = require("./utils.cjs");
8
- const require_Expr = require("./Expr.cjs");
9
- require("./index.cjs");
10
9
  require("./EntityManager.cjs");
11
10
  require("./Entity.cjs");
12
11
  const require_configure = require("./configure.cjs");
13
12
  const require_QueryParser = require("./QueryParser.cjs");
14
13
  let joist_utils = require("joist-utils");
15
14
  //#region src/Aliases.ts
16
- function alias(cstr, _name) {
15
+ /** Creates an alias for complex domain filtering in `em.find`. */
16
+ function alias(cstr) {
17
17
  return newAliasProxy(cstr);
18
18
  }
19
19
  /** Creates multiple aliases for complex filtering. */
20
- function aliases(...type) {
21
- return type.map((t) => newAliasProxy(t));
20
+ function aliases(...types) {
21
+ return types.map((t) => newAliasProxy(t));
22
22
  }
23
23
  const aliasMgmt = Symbol("aliasMgmt");
24
+ /** Returns the runtime identity bound by the find parser. */
24
25
  function getAliasMgmt(alias) {
25
26
  return alias[aliasMgmt];
26
27
  }
27
- /** Returns the metadata for the entity that `alias` is bound to. */
28
+ /** Returns the original metadata, preserving STI subtype identity. */
28
29
  function getAliasMetadata(alias) {
29
30
  return alias[aliasMgmt].meta;
30
31
  }
32
+ /** Creates domain predicates lazily from entity field metadata. */
31
33
  function newAliasProxy(cstr) {
32
34
  const meta = require_EntityMetadata.getMetadata(cstr);
33
35
  const mgmt = {
34
36
  tableName: meta.tableName,
35
37
  meta
36
38
  };
37
- const proxy = new Proxy(cstr, {
38
- /** Create a column alias, or a relation join factory, for the given field. */
39
+ return new Proxy(cstr, {
39
40
  get(_, key) {
40
41
  if (key === aliasMgmt) return mgmt;
41
- const field = meta.allFields[key] ?? require_utils.fail(`No field ${String(key)} on ${cstr.name}`);
42
- switch (field.kind) {
43
- case "primaryKey":
44
- case "primitive":
45
- case "enum": return new PrimitiveAliasImpl(meta, field, field.serde.columns[0], mgmt);
46
- case "m2o": return new EntityAliasImpl(meta, field, field.serde.columns[0], mgmt);
47
- case "poly": return new PolyReferenceAlias(meta, mgmt, field);
48
- case "o2m":
49
- case "o2o":
50
- case "lo2m": return new OneToManyAliasImpl(proxy, field);
51
- case "m2m": return new ManyToManyAliasImpl(proxy, field);
52
- default: throw new Error(`Unsupported alias field kind ${field.kind}`);
53
- }
42
+ if (typeof key !== "string") return void 0;
43
+ const field = meta.allFields[key] ?? require_utils.fail(`No field ${key} on ${cstr.name}`);
44
+ if (field.kind === "poly") return new PolyReferenceAlias(meta, mgmt, field);
45
+ if ([
46
+ "primaryKey",
47
+ "primitive",
48
+ "enum",
49
+ "m2o"
50
+ ].includes(field.kind)) return new AliasColumnImpl(meta, field, field.serde.columns[0], mgmt);
51
+ return require_utils.fail(`Unsupported alias field kind ${field.kind}`);
54
52
  },
55
53
  has(_, key) {
56
54
  return key === aliasMgmt || key in meta.allFields;
57
55
  }
58
56
  });
59
- return proxy;
60
57
  }
61
- function isAlias(obj) {
62
- return obj && typeof obj === "function" && obj[aliasMgmt] !== void 0;
58
+ /** Recognizes only domain aliases, not physical tables. */
59
+ function isAlias(value) {
60
+ return typeof value === "function" && aliasMgmt in value;
63
61
  }
64
- /**
65
- * A single column of an alias.
66
- *
67
- * For `em.find`, its methods create `ColumnCondition`s that resolve their alias against each parse's
68
- * join-literal bindings.
69
- *
70
- * For `em.query`, the column also implements `Expr`: it renders as `alias."column"`, decodes result
71
- * values through the field's serde, and inherits aggregate methods from `BaseExpr`.
72
- */
73
- var AbstractAliasColumn = class AbstractAliasColumn extends require_Expr.BaseExpr {
62
+ /** Builds field conditions without implementing the SQL expression protocol. */
63
+ var AliasColumnImpl = class AliasColumnImpl {
74
64
  meta;
75
65
  field;
76
66
  column;
77
67
  mgmt;
78
68
  constructor(meta, field, column, mgmt) {
79
- super();
80
69
  this.meta = meta;
81
70
  this.field = field;
82
71
  this.column = column;
83
72
  this.mgmt = mgmt;
84
73
  }
85
- toSql(ctx) {
86
- const alias = ctx.aliasFor(this.mgmt);
87
- const ctiAlias = getMaybeCtiAlias(this.meta, this.field, this.meta, alias);
88
- return {
89
- sql: require_keywords.kqDot(ctiAlias, this.column.columnName),
90
- bindings: [],
91
- refs: [alias]
92
- };
93
- }
94
- /** Decodes a result-set value the same way `hydrate` would, i.e. an int into a tagged id. */
95
- decode(value) {
96
- if (value === null || value === void 0) return value;
97
- return this.column.mapFromDb(value);
98
- }
99
- encode(value) {
100
- return this.column.mapToDb(value);
101
- }
102
- addCondition(value) {
103
- const cond = {
104
- kind: "column",
105
- alias: "unset",
106
- column: this.column.columnName,
107
- dbType: this.column.dbType,
108
- cond: require_QueryParser.mapToDb(this.column, value)
109
- };
110
- return require_Expr.withDeferredAlias(cond, (resolve) => {
111
- const r = resolve(this.mgmt);
112
- cond.alias = getMaybeCtiAlias(this.meta, this.field, r.meta, r.alias);
113
- });
114
- }
115
- addRawCondition(exp, bindings) {
116
- const cond = {
117
- kind: "raw",
118
- aliases: [],
119
- condition: "unset",
120
- pruneable: false,
121
- bindings
122
- };
123
- return require_Expr.withDeferredAlias(cond, (resolve) => {
124
- const r = resolve(this.mgmt);
125
- const alias = getMaybeCtiAlias(this.meta, this.field, r.meta, r.alias);
126
- cond.aliases = [alias];
127
- cond.condition = `${alias}.${this.column.columnName} ${exp}`;
128
- });
129
- }
130
- /**
131
- * Compares this column to another expression.
132
- *
133
- * Another alias column becomes a `DeferredAliasCondition`, which both parsers can resolve, so it also
134
- * works inside `em.find`'s complex conditions; every other expression (an aggregate, a subquery column,
135
- * a `sql` template) only exists in `em.query`, so it takes the `ExprContext`-deferred path, which only
136
- * the `em.query` parser resolves.
137
- */
138
- compareToExpr(op, value) {
139
- if (value instanceof AbstractAliasColumn) return newCrossColumnCondition(this.meta, this.field, this.mgmt, this.column.columnName, value, op);
140
- return this.compare(op, value);
141
- }
142
- };
143
- var PrimitiveAliasImpl = class extends AbstractAliasColumn {
144
74
  eq(value) {
145
- if (value === void 0) return require_Expr.skipCondition;
146
- if (value === null) return this.addCondition({ kind: "is-null" });
147
- if (require_Expr.isExpr(value)) return this.compareToExpr("=", value);
148
- return this.addCondition({
149
- kind: "eq",
150
- value
151
- });
75
+ return this.compare("eq", "=", value);
152
76
  }
153
77
  ne(value) {
154
- if (value === void 0) return require_Expr.skipCondition;
155
- if (value === null) return this.addCondition({ kind: "not-null" });
156
- if (require_Expr.isExpr(value)) return this.compareToExpr("!=", value);
157
- return this.addCondition({
158
- kind: "ne",
159
- value
160
- });
78
+ return this.compare("ne", "!=", value);
161
79
  }
162
80
  gt(value) {
163
- if (value === void 0) return require_Expr.skipCondition;
164
- if (require_Expr.isExpr(value)) return this.compareToExpr(">", value);
165
- return this.addCondition({
166
- kind: "gt",
167
- value
168
- });
81
+ return this.compare("gt", ">", value);
169
82
  }
170
83
  gte(value) {
171
- if (value === void 0) return require_Expr.skipCondition;
172
- if (require_Expr.isExpr(value)) return this.compareToExpr(">=", value);
173
- return this.addCondition({
174
- kind: "gte",
175
- value
176
- });
84
+ return this.compare("gte", ">=", value);
177
85
  }
178
86
  lt(value) {
179
- if (value === void 0) return require_Expr.skipCondition;
180
- if (require_Expr.isExpr(value)) return this.compareToExpr("<", value);
181
- return this.addCondition({
182
- kind: "lt",
183
- value
184
- });
87
+ return this.compare("lt", "<", value);
185
88
  }
186
89
  lte(value) {
187
- if (value === void 0) return require_Expr.skipCondition;
188
- if (require_Expr.isExpr(value)) return this.compareToExpr("<=", value);
189
- return this.addCondition({
190
- kind: "lte",
191
- value
192
- });
90
+ return this.compare("lte", "<=", value);
193
91
  }
194
- between(v1, v2) {
195
- if (v1 === void 0 || v2 === void 0) return require_Expr.skipCondition;
196
- return this.addCondition({
197
- kind: "between",
198
- value: [v1, v2]
199
- });
92
+ contains(value) {
93
+ return this.compare("contains", "@>", value);
200
94
  }
201
- like(value) {
202
- if (value === void 0) return require_Expr.skipCondition;
95
+ ncontains(value) {
96
+ if (value instanceof AliasColumnImpl) return crossColumnCondition(this, value, "@>", true);
203
97
  return this.addCondition({
204
- kind: "like",
98
+ kind: "ncontains",
205
99
  value
206
100
  });
207
101
  }
208
- ilike(value) {
209
- if (value === void 0) return require_Expr.skipCondition;
210
- return this.addCondition({
211
- kind: "ilike",
212
- value
213
- });
102
+ overlaps(value) {
103
+ return this.compare("overlaps", "&&", value);
214
104
  }
215
- search(value) {
216
- if (!value) return require_Expr.skipCondition;
105
+ noverlaps(value) {
106
+ if (value instanceof AliasColumnImpl) return crossColumnCondition(this, value, "&&", true);
217
107
  return this.addCondition({
218
- kind: "ilike",
219
- value: require_QueryParser.makeLike(value)
108
+ kind: "noverlaps",
109
+ value
220
110
  });
221
111
  }
222
112
  in(values) {
223
- if (values === void 0) return require_Expr.skipCondition;
224
- if (require_Expr.isExpr(values)) return this.inList("IN", values);
113
+ if (values === void 0) return require_DeferredAlias.skipCondition;
114
+ if (values === null) return require_utils.fail("Unsupported");
225
115
  if (values.includes(null)) return { or: [this.addCondition({ kind: "is-null" }), this.addCondition({
226
116
  kind: "in",
227
117
  value: values.filter((v) => v !== null)
228
118
  })] };
229
- else return this.addCondition({
119
+ return this.addCondition({
230
120
  kind: "in",
231
- value: values
121
+ value: [...values]
232
122
  });
233
123
  }
234
124
  nin(values) {
235
- if (values === void 0) return require_Expr.skipCondition;
236
- if (require_Expr.isExpr(values)) return this.inList("NOT IN", values);
125
+ if (values === void 0) return require_DeferredAlias.skipCondition;
126
+ if (values === null) return require_utils.fail("Unsupported");
237
127
  return this.addCondition({
238
128
  kind: "nin",
239
129
  value: values.filter((v) => v !== null)
240
130
  });
241
131
  }
242
- contains(v1) {
243
- if (v1 === void 0) return require_Expr.skipCondition;
132
+ between(v1, v2) {
133
+ if (v1 === void 0 || v2 === void 0) return require_DeferredAlias.skipCondition;
244
134
  return this.addCondition({
245
- kind: "contains",
246
- value: v1
135
+ kind: "between",
136
+ value: [v1, v2]
247
137
  });
248
138
  }
249
- ncontains(v1) {
250
- if (v1 === void 0) return require_Expr.skipCondition;
139
+ like(value) {
251
140
  return this.addCondition({
252
- kind: "ncontains",
253
- value: v1
141
+ kind: "like",
142
+ value
254
143
  });
255
144
  }
256
- overlaps(v1) {
257
- if (v1 === void 0) return require_Expr.skipCondition;
145
+ ilike(value) {
258
146
  return this.addCondition({
259
- kind: "overlaps",
260
- value: v1
147
+ kind: "ilike",
148
+ value
261
149
  });
262
150
  }
263
- noverlaps(v1) {
264
- if (v1 === void 0) return require_Expr.skipCondition;
265
- return this.addCondition({
266
- kind: "noverlaps",
267
- value: v1
151
+ search(value) {
152
+ return !value ? require_DeferredAlias.skipCondition : this.addCondition({
153
+ kind: "ilike",
154
+ value: require_QueryParser.makeLike(value)
268
155
  });
269
156
  }
270
- pathExists(jsonPath) {
271
- if (jsonPath === void 0) return require_Expr.skipCondition;
157
+ pathExists(value) {
272
158
  return this.addCondition({
273
159
  kind: "jsonPathExists",
274
- value: jsonPath
275
- });
276
- }
277
- pathIsTrue(jsonPath) {
278
- if (jsonPath === void 0) return require_Expr.skipCondition;
279
- return this.addCondition({
280
- kind: "jsonPathPredicate",
281
- value: jsonPath
282
- });
283
- }
284
- raw(exp, bindings) {
285
- if (bindings === void 0) return require_Expr.skipCondition;
286
- return this.addRawCondition(exp, bindings);
287
- }
288
- };
289
- var EntityAliasImpl = class extends AbstractAliasColumn {
290
- eq(value) {
291
- if (value === void 0) return require_Expr.skipCondition;
292
- if (value === null) return this.addCondition({ kind: "is-null" });
293
- if (require_Expr.isExpr(value)) return this.compareToExpr("=", value);
294
- return this.addCondition({
295
- kind: "eq",
296
160
  value
297
161
  });
298
162
  }
299
- ne(value) {
300
- if (value === void 0) return require_Expr.skipCondition;
301
- if (value === null) return this.addCondition({ kind: "not-null" });
302
- if (require_Expr.isExpr(value)) return this.compareToExpr("!=", value);
163
+ pathIsTrue(value) {
303
164
  return this.addCondition({
304
- kind: "ne",
165
+ kind: "jsonPathPredicate",
305
166
  value
306
167
  });
307
168
  }
308
- in(values) {
309
- if (values === void 0) return require_Expr.skipCondition;
310
- else if (values === null) throw new Error("Unsupported");
311
- else if (require_Expr.isExpr(values)) return this.inList("IN", values);
312
- else if (values.includes(null)) return { or: [this.addCondition({ kind: "is-null" }), this.addCondition({
313
- kind: "in",
314
- value: values.filter((v) => v !== null)
315
- })] };
316
- else return this.addCondition({
317
- kind: "in",
318
- value: values
319
- });
320
- }
321
- nin(values) {
322
- if (values === void 0) return require_Expr.skipCondition;
323
- else if (values === null) throw new Error("Unsupported");
324
- else if (require_Expr.isExpr(values)) return this.inList("NOT IN", values);
325
- else return this.addCondition({
326
- kind: "nin",
327
- value: values.filter((v) => v !== null)
328
- });
329
- }
330
- gt(value) {
331
- return this.compareId(">", "gt", value);
332
- }
333
- gte(value) {
334
- return this.compareId(">=", "gte", value);
335
- }
336
- lt(value) {
337
- return this.compareId("<", "lt", value);
338
- }
339
- lte(value) {
340
- return this.compareId("<=", "lte", value);
341
- }
342
169
  raw(exp, bindings) {
343
- if (bindings === void 0) return require_Expr.skipCondition;
344
- return this.addRawCondition(exp, bindings);
345
- }
346
- /** Joins `other` via this FK, INNER for a required reference and LEFT for a nullable one. */
347
- as(other) {
348
- return this.joinEntry(this.field.required ? "inner" : "left", other);
349
- }
350
- inner(other) {
351
- return this.joinEntry("inner", other);
352
- }
353
- left(other) {
354
- return this.joinEntry("left", other);
170
+ if (bindings === void 0) return require_DeferredAlias.skipCondition;
171
+ return require_DeferredAlias.withDeferredAlias({
172
+ kind: "raw",
173
+ aliases: [],
174
+ condition: "unset",
175
+ pruneable: false,
176
+ bindings
177
+ }, (resolve, copy) => {
178
+ const r = resolve(this.mgmt);
179
+ const alias = getMaybeCtiAlias(this.meta, this.field, r.meta, r.alias);
180
+ copy.aliases = [alias];
181
+ copy.condition = `${alias}.${this.column.columnName} ${exp}`;
182
+ });
355
183
  }
356
- joinEntry(kind, other) {
357
- return {
358
- [kind]: requireAlias(other),
359
- on: this.eq(idColumnOf(other))
184
+ /** Maps literal values through the field serde and binds aliases only when parsing. */
185
+ addCondition(value) {
186
+ if ("value" in value && value.value === void 0) return require_DeferredAlias.skipCondition;
187
+ const cond = {
188
+ kind: "column",
189
+ alias: "unset",
190
+ column: this.column.columnName,
191
+ dbType: this.column.dbType,
192
+ cond: require_QueryParser.mapToDb(this.column, value)
360
193
  };
194
+ return require_DeferredAlias.withDeferredAlias(cond, (resolve, copy) => {
195
+ const r = resolve(this.mgmt);
196
+ copy.alias = getMaybeCtiAlias(this.meta, this.field, r.meta, r.alias);
197
+ });
361
198
  }
362
- compareId(op, kind, value) {
363
- if (value === void 0) return require_Expr.skipCondition;
364
- if (value === null) throw new Error("Unsupported");
365
- if (require_Expr.isExpr(value)) return this.compareToExpr(op, value);
199
+ /** Handles literal values, NULL, and domain cross-alias comparisons. */
200
+ compare(kind, op, value) {
201
+ if (value === void 0) return require_DeferredAlias.skipCondition;
202
+ if (value instanceof AliasColumnImpl) return crossColumnCondition(this, value, op);
203
+ if (value === null && (kind === "eq" || kind === "ne")) return this.addCondition({ kind: kind === "eq" ? "is-null" : "not-null" });
204
+ if (value === null && [
205
+ "gt",
206
+ "gte",
207
+ "lt",
208
+ "lte"
209
+ ].includes(kind)) return require_utils.fail("Unsupported");
366
210
  return this.addCondition({
367
211
  kind,
368
212
  value
369
213
  });
370
214
  }
371
215
  };
216
+ /** Resolves polymorphic predicates to their physical component columns. */
372
217
  var PolyReferenceAlias = class {
373
218
  meta;
374
219
  mgmt;
@@ -378,7 +223,6 @@ var PolyReferenceAlias = class {
378
223
  this.mgmt = mgmt;
379
224
  this.field = field;
380
225
  }
381
- /** Compares to a tagged id, an entity, or another alias's id column, which picks the component (`c.parent.eq(a.id)`). */
382
226
  eq(value) {
383
227
  return this.addEqOrNe("eq", value);
384
228
  }
@@ -386,237 +230,64 @@ var PolyReferenceAlias = class {
386
230
  return this.addEqOrNe("ne", value);
387
231
  }
388
232
  in(values) {
389
- if (values === void 0) return require_Expr.skipCondition;
390
- if (require_Expr.isExpr(values)) return this.inSubquery(values);
391
- const idsByConstructor = (0, joist_utils.groupBy)(values, (id) => require_configure.getConstructorFromTaggedId(require_keys.maybeResolveReferenceToId(id)).name);
392
- return { or: Object.entries(idsByConstructor).map(([cstrName, ids]) => {
393
- const comp = this.field.components.find((p) => p.otherMetadata().cstr.name === cstrName) ?? require_utils.fail(`No component for ${cstrName}`);
394
- return this.addCondition(comp, {
233
+ if (values === void 0) return require_DeferredAlias.skipCondition;
234
+ const groups = (0, joist_utils.groupBy)(values, (id) => require_configure.getConstructorFromTaggedId(require_keys.maybeResolveReferenceToId(id)).name);
235
+ return { or: Object.entries(groups).map(([name, ids]) => {
236
+ const comp = this.field.components.find((c) => c.otherMetadata().cstr.name === name) ?? require_utils.fail(`No component for ${name}`);
237
+ return this.component(comp).addCondition({
395
238
  kind: "in",
396
239
  value: ids
397
240
  });
398
241
  }) };
399
242
  }
400
- /** Joins `other` via this poly's component for its entity, INNER when the poly is required. */
401
- as(other) {
402
- return this.joinEntry(this.field.required ? "inner" : "left", other);
403
- }
404
- inner(other) {
405
- return this.joinEntry("inner", other);
406
- }
407
- left(other) {
408
- return this.joinEntry("left", other);
409
- }
410
- joinEntry(kind, other) {
411
- return {
412
- [kind]: requireAlias(other),
413
- on: this.eq(idColumnOf(other))
414
- };
415
- }
416
- /**
417
- * i.e. `c.parent.in(query({ from: a, ..., select: a.id }))`: like `eq` against an alias column, the
418
- * subquery's select column picks the component, i.e. authors pick `parent_author_id`.
419
- */
420
- inSubquery(values) {
421
- const select = require_Expr.asNode(values).subquerySelect;
422
- if (!(select instanceof AbstractAliasColumn)) return require_utils.fail(`${this.field.fieldName} is polymorphic, so \`in\` needs a subquery selecting an id or FK column`);
423
- const otherMeta = select.field.kind === "primaryKey" ? select.meta : select.field.kind === "m2o" ? select.field.otherMetadata() : require_utils.fail(`${this.field.fieldName} \`in\` needs an id or FK column, got ${select.field.fieldName}`);
424
- const comp = this.field.components.find((p) => require_EntityMetadata.getBaseAndSelfMetas(otherMeta).includes(p.otherMetadata())) ?? require_utils.fail(`${this.field.fieldName} has no component for ${otherMeta.type}`);
425
- return require_Expr.deferredCondition((ctx) => {
426
- const alias = getMaybeCtiAlias(this.meta, this.field, this.meta, ctx.aliasFor(this.mgmt));
427
- const sub = require_Expr.asNode(values).toSqlBare(ctx);
428
- return {
429
- sql: `${alias}.${comp.columnName} IN (${sub.sql})`,
430
- bindings: sub.bindings,
431
- refs: [alias, ...sub.refs]
432
- };
433
- });
434
- }
243
+ /** Picks the component from an entity, tagged id, or another domain alias column. */
435
244
  addEqOrNe(kind, value) {
436
- if (value === void 0) return require_Expr.skipCondition;
437
- else if (value instanceof AbstractAliasColumn) {
438
- const otherMeta = value.meta;
439
- const comp = this.field.components.find((p) => require_EntityMetadata.getBaseAndSelfMetas(otherMeta).includes(p.otherMetadata())) ?? require_utils.fail(`${this.field.fieldName} has no component for ${otherMeta.type}`);
440
- return newCrossColumnCondition(this.meta, this.field, this.mgmt, comp.columnName, value, kind === "eq" ? "=" : "!=");
441
- } else if (require_Expr.isExpr(value)) return require_utils.fail(`${this.field.fieldName} is polymorphic, so it can only be compared to tagged ids or entity alias columns`);
442
- else if (value === null) {
443
- const value = kind === "eq" ? { kind: "is-null" } : { kind: "not-null" };
444
- return { and: this.field.components.map((p) => this.addCondition(p, value)) };
445
- } else {
446
- const comp = this.field.components.find((p) => p.otherMetadata().cstr === require_configure.getConstructorFromTaggedId(require_keys.maybeResolveReferenceToId(value))) || require_utils.fail(`Could not find component for ${value}`);
447
- return this.addCondition(comp, {
448
- kind,
449
- value
450
- });
451
- }
452
- }
453
- addCondition(comp, value) {
245
+ if (value === void 0) return require_DeferredAlias.skipCondition;
246
+ if (value === null) return { and: this.field.components.map((c) => this.component(c).addCondition({ kind: kind === "eq" ? "is-null" : "not-null" })) };
247
+ const otherMeta = value instanceof AliasColumnImpl ? value.field.kind === "m2o" ? value.field.otherMetadata() : value.meta : require_EntityMetadata.getMetadata(require_configure.getConstructorFromTaggedId(require_keys.maybeResolveReferenceToId(value)));
248
+ const comp = this.field.components.find((c) => require_EntityMetadata.getBaseAndSelfMetas(otherMeta).includes(c.otherMetadata())) ?? require_utils.fail(`${this.field.fieldName} has no component for ${otherMeta.type}`);
249
+ const column = this.component(comp);
250
+ return kind === "eq" ? column.eq(value) : column.ne(value);
251
+ }
252
+ /** Uses the component serde, not the first component's codec. */
253
+ component(comp) {
454
254
  const column = this.field.serde.columns.find((c) => c.columnName === comp.columnName) ?? require_utils.fail("Missing column");
455
- const cond = {
456
- kind: "column",
457
- alias: "unset",
458
- column: comp.columnName,
459
- dbType: this.field.serde.columns[0].dbType,
460
- cond: require_QueryParser.mapToDb(column, value)
461
- };
462
- return require_Expr.withDeferredAlias(cond, (resolve) => {
463
- const r = resolve(this.mgmt);
464
- cond.alias = getMaybeCtiAlias(this.meta, this.field, r.meta, r.alias);
465
- });
255
+ return new AliasColumnImpl(this.meta, this.field, column, this.mgmt);
466
256
  }
467
257
  };
468
- /**
469
- * Given an alias created for `meta`, adjusts the alias if it's bound to a potentially
470
- * different parent-/sub-meta in the join tree.
471
- */
258
+ /** Adjusts a field's SQL alias when a base alias is bound to a CTI subtype in the join tree. */
472
259
  function getMaybeCtiAlias(meta, field, newMeta, newAlias) {
473
260
  if (newMeta !== meta && newMeta.inheritanceType === "cti") {
474
261
  if (require_EntityMetadata.getBaseAndSelfMetas(newMeta).includes(newMeta)) return `${newAlias}_b0`;
475
262
  }
476
263
  return `${newAlias}${field.aliasSuffix}`;
477
264
  }
478
- /**
479
- * Marks a sugar join entry whose target is a *collection* (o2m/m2m), which filter soft-deletes like
480
- * em.find's "collections filter out soft-deletes, but m2o/o2o references still return them"; see
481
- * `QueryParser.addSoftDeleteCondition`'s call site. Reference joins and explicit joins are unmarked.
482
- */
483
- const collectionJoin = Symbol("joist.collectionJoin");
484
- /** Marks a sugar m2m join entry (`a.tags.as(t)`) with its hidden join-table join; `parseQuery` expands it. */
485
- const m2mJoinTable = Symbol("joist.m2mJoinTable");
486
- /** The runtime identity of an m2m join table in a query, i.e. `authors_to_tags`; it has no entity. */
487
- var JoinTableHandle = class {
488
- joinTableName;
489
- constructor(joinTableName) {
490
- this.joinTableName = joinTableName;
491
- }
492
- };
493
- /**
494
- * The `as`/`inner`/`left` join factory for collection relations, i.e. `a.books.as(b)` joins with the
495
- * relation's default kind (LEFT: a collection may be empty) and `.inner`/`.left` override. m2o/poly
496
- * relations implement the same three methods directly on their column/impl classes, so `b.author`
497
- * stays a plain expression that is also a join factory.
498
- */
499
- var AbstractCollectionAlias = class {
500
- as(other) {
501
- return this.joinEntry("left", requireAlias(other));
502
- }
503
- inner(other) {
504
- return this.joinEntry("inner", requireAlias(other));
505
- }
506
- left(other) {
507
- return this.joinEntry("left", requireAlias(other));
508
- }
509
- };
510
- /** An o2m/lo2m/o2o relation: the ON is the other side's FK (an m2o or a poly component) back to our id. */
511
- var OneToManyAliasImpl = class extends AbstractCollectionAlias {
512
- proxy;
513
- field;
514
- constructor(proxy, field) {
515
- super();
516
- this.proxy = proxy;
517
- this.field = field;
518
- }
519
- joinEntry(kind, other) {
520
- const { field } = this;
521
- const on = other[field.otherFieldName].eq(this.proxy.id);
522
- const filtered = field.kind === "o2m" ? field.softDeletes !== "include" : field.kind === "lo2m";
523
- return {
524
- [kind]: other,
525
- on,
526
- [collectionJoin]: filtered
527
- };
528
- }
529
- };
530
- /**
531
- * An m2m relation, i.e. `a.tags.as(t)`.
532
- *
533
- * The entry's own ON is `t.id = att.tag_id`, and the hidden `[m2mJoinTable]` half is
534
- * `att.author_id = a.id`; only the target's ON references the join table, so reference pruning keeps
535
- * or drops the pair together. Both are deferred conditions: the join table has no entity metadata, so
536
- * its alias only exists once the parser registers it.
537
- */
538
- var ManyToManyAliasImpl = class extends AbstractCollectionAlias {
539
- proxy;
540
- field;
541
- constructor(proxy, field) {
542
- super();
543
- this.proxy = proxy;
544
- this.field = field;
545
- }
546
- joinEntry(kind, other) {
547
- const { joinTableName, columnNames } = this.field;
548
- const [ourColumn, otherColumn] = columnNames;
549
- const jt = new JoinTableHandle(joinTableName);
550
- const ourId = this.proxy.id;
551
- const otherId = idColumnOf(other);
552
- const jtOn = require_Expr.deferredCondition((ctx) => {
553
- const jtAlias = ctx.aliasFor(jt);
554
- const id = ourId.toSql(ctx);
555
- return {
556
- sql: `${require_keywords.kqDot(jtAlias, ourColumn)} = ${id.sql}`,
557
- bindings: id.bindings,
558
- refs: id.refs
559
- };
560
- });
561
- const on = require_Expr.deferredCondition((ctx) => {
562
- const jtAlias = ctx.aliasFor(jt);
563
- const id = otherId.toSql(ctx);
564
- return {
565
- sql: `${id.sql} = ${require_keywords.kqDot(jtAlias, otherColumn)}`,
566
- bindings: id.bindings,
567
- refs: [...id.refs, jtAlias]
568
- };
569
- });
570
- const filtered = this.field.softDeletes !== "include";
571
- return {
572
- [kind]: other,
573
- on,
574
- [collectionJoin]: filtered,
575
- [m2mJoinTable]: {
576
- handle: jt,
577
- on: jtOn
578
- }
579
- };
580
- }
581
- };
582
- /** Compares columns with per-parse aliases, i.e. `parent_author_id = <other id>` for `c.parent.eq(a.id)`. */
583
- function newCrossColumnCondition(meta, field, mgmt, columnName, otherColumn, op) {
584
- const cond = {
265
+ /** Compares domain columns with per-parse aliases, preserving condition reuse across find calls. */
266
+ function crossColumnCondition(left, right, op, negate = false) {
267
+ return require_DeferredAlias.withDeferredAlias({
585
268
  kind: "raw",
586
269
  aliases: [],
587
270
  condition: "unset",
588
- pruneable: false,
589
- bindings: []
590
- };
591
- return require_Expr.withDeferredAlias(cond, (resolve) => {
592
- const r1 = resolve(mgmt);
593
- const r2 = resolve(otherColumn.mgmt);
594
- const a1 = getMaybeCtiAlias(meta, field, r1.meta, r1.alias);
595
- const a2 = getMaybeCtiAlias(otherColumn.meta, otherColumn.field, r2.meta, r2.alias);
596
- cond.aliases = [a1, a2];
597
- cond.condition = `${a1}.${columnName} ${op} ${a2}.${otherColumn.column.columnName}`;
271
+ bindings: [],
272
+ pruneable: false
273
+ }, (resolve, copy) => {
274
+ const l = resolve(left.mgmt);
275
+ const r = resolve(right.mgmt);
276
+ const a1 = getMaybeCtiAlias(left.meta, left.field, l.meta, l.alias);
277
+ const a2 = getMaybeCtiAlias(right.meta, right.field, r.meta, r.alias);
278
+ copy.aliases = [a1, a2];
279
+ const sql = `${a1}.${left.column.columnName} ${op} ${a2}.${right.column.columnName}`;
280
+ copy.condition = negate ? `NOT (${sql})` : sql;
598
281
  });
599
282
  }
600
- /** Fails fast when a join factory is passed something other than an alias. */
601
- function requireAlias(other) {
602
- if (!isAlias(other)) return require_utils.fail(`Expected an alias to join, got ${other}`);
603
- return other;
604
- }
605
- /** The id column of a joined alias, for building sugar ON conditions. */
606
- function idColumnOf(other) {
607
- return other.id;
608
- }
609
283
  //#endregion
610
- exports.JoinTableHandle = JoinTableHandle;
611
284
  exports.alias = alias;
612
285
  exports.aliasMgmt = aliasMgmt;
613
286
  exports.aliases = aliases;
614
- exports.collectionJoin = collectionJoin;
615
287
  exports.getAliasMetadata = getAliasMetadata;
616
288
  exports.getAliasMgmt = getAliasMgmt;
617
289
  exports.getMaybeCtiAlias = getMaybeCtiAlias;
618
290
  exports.isAlias = isAlias;
619
- exports.m2mJoinTable = m2mJoinTable;
620
291
  exports.newAliasProxy = newAliasProxy;
621
292
 
622
293
  //# sourceMappingURL=Aliases.cjs.map