joist-core 2.3.0-next.62 → 2.3.0-next.64

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 (119) hide show
  1. package/build/Aliases.cjs +134 -462
  2. package/build/Aliases.cjs.map +1 -1
  3. package/build/Aliases.d.cts +79 -165
  4. package/build/Aliases.d.cts.map +1 -1
  5. package/build/Aliases.d.mts +79 -165
  6. package/build/Aliases.d.mts.map +1 -1
  7. package/build/Aliases.js +129 -454
  8. package/build/Aliases.js.map +1 -1
  9. package/build/ConditionBuilder.cjs +2 -2
  10. package/build/ConditionBuilder.cjs.map +1 -1
  11. package/build/ConditionBuilder.js +1 -1
  12. package/build/ConditionBuilder.js.map +1 -1
  13. package/build/DeferredAlias.cjs +26 -0
  14. package/build/DeferredAlias.cjs.map +1 -0
  15. package/build/DeferredAlias.d.cts +23 -0
  16. package/build/DeferredAlias.d.cts.map +1 -0
  17. package/build/DeferredAlias.d.mts +23 -0
  18. package/build/DeferredAlias.d.mts.map +1 -0
  19. package/build/DeferredAlias.js +23 -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 +230 -66
  36. package/build/Expr.cjs.map +1 -1
  37. package/build/Expr.d.cts +91 -54
  38. package/build/Expr.d.cts.map +1 -1
  39. package/build/Expr.d.mts +91 -54
  40. package/build/Expr.d.mts.map +1 -1
  41. package/build/Expr.js +227 -61
  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 +591 -0
  48. package/build/Tables.cjs.map +1 -0
  49. package/build/Tables.d.cts +214 -0
  50. package/build/Tables.d.cts.map +1 -0
  51. package/build/Tables.d.mts +214 -0
  52. package/build/Tables.d.mts.map +1 -0
  53. package/build/Tables.js +581 -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/buildUtils.cjs +5 -1
  64. package/build/drivers/buildUtils.cjs.map +1 -1
  65. package/build/drivers/buildUtils.d.cts +4 -2
  66. package/build/drivers/buildUtils.d.cts.map +1 -1
  67. package/build/drivers/buildUtils.d.mts +4 -2
  68. package/build/drivers/buildUtils.d.mts.map +1 -1
  69. package/build/drivers/buildUtils.js +5 -2
  70. package/build/drivers/buildUtils.js.map +1 -1
  71. package/build/drivers/index.cjs +1 -0
  72. package/build/drivers/index.d.cts +3 -3
  73. package/build/drivers/index.d.mts +3 -3
  74. package/build/drivers/index.js +2 -2
  75. package/build/execute.cjs +240 -0
  76. package/build/execute.cjs.map +1 -0
  77. package/build/execute.d.cts +190 -0
  78. package/build/execute.d.cts.map +1 -0
  79. package/build/execute.d.mts +190 -0
  80. package/build/execute.d.mts.map +1 -0
  81. package/build/execute.js +237 -0
  82. package/build/execute.js.map +1 -0
  83. package/build/index.cjs +12 -2
  84. package/build/index.cjs.map +1 -1
  85. package/build/index.d.cts +12 -9
  86. package/build/index.d.cts.map +1 -1
  87. package/build/index.d.mts +12 -9
  88. package/build/index.d.mts.map +1 -1
  89. package/build/index.js +5 -3
  90. package/build/index.js.map +1 -1
  91. package/build/query.cjs +464 -104
  92. package/build/query.cjs.map +1 -1
  93. package/build/query.d.cts +266 -38
  94. package/build/query.d.cts.map +1 -1
  95. package/build/query.d.mts +266 -38
  96. package/build/query.d.mts.map +1 -1
  97. package/build/query.js +457 -102
  98. package/build/query.js.map +1 -1
  99. package/build/serde.cjs +289 -50
  100. package/build/serde.cjs.map +1 -1
  101. package/build/serde.d.cts +115 -24
  102. package/build/serde.d.cts.map +1 -1
  103. package/build/serde.d.mts +115 -24
  104. package/build/serde.d.mts.map +1 -1
  105. package/build/serde.js +289 -50
  106. package/build/serde.js.map +1 -1
  107. package/build/skipCondition.cjs +15 -0
  108. package/build/skipCondition.cjs.map +1 -0
  109. package/build/skipCondition.d.cts +7 -0
  110. package/build/skipCondition.d.cts.map +1 -0
  111. package/build/skipCondition.d.mts +7 -0
  112. package/build/skipCondition.d.mts.map +1 -0
  113. package/build/skipCondition.js +14 -0
  114. package/build/skipCondition.js.map +1 -0
  115. package/build/typeMap.d.cts +4 -2
  116. package/build/typeMap.d.cts.map +1 -1
  117. package/build/typeMap.d.mts +4 -2
  118. package/build/typeMap.d.mts.map +1 -1
  119. package/package.json +2 -2
package/build/Aliases.cjs CHANGED
@@ -1,374 +1,220 @@
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_skipCondition = require("./skipCondition.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");
9
+ const require_DeferredAlias = require("./DeferredAlias.cjs");
10
10
  require("./EntityManager.cjs");
11
11
  require("./Entity.cjs");
12
12
  const require_configure = require("./configure.cjs");
13
13
  const require_QueryParser = require("./QueryParser.cjs");
14
14
  let joist_utils = require("joist-utils");
15
15
  //#region src/Aliases.ts
16
- function alias(cstr, _name) {
16
+ /** Creates an alias for complex domain filtering in `em.find`. */
17
+ function alias(cstr) {
17
18
  return newAliasProxy(cstr);
18
19
  }
19
20
  /** Creates multiple aliases for complex filtering. */
20
- function aliases(...type) {
21
- return type.map((t) => newAliasProxy(t));
21
+ function aliases(...types) {
22
+ return types.map((t) => newAliasProxy(t));
22
23
  }
23
24
  const aliasMgmt = Symbol("aliasMgmt");
25
+ /** Returns the runtime identity bound by the find parser. */
24
26
  function getAliasMgmt(alias) {
25
27
  return alias[aliasMgmt];
26
28
  }
27
- /** Returns the metadata for the entity that `alias` is bound to. */
29
+ /** Returns the original metadata, preserving STI subtype identity. */
28
30
  function getAliasMetadata(alias) {
29
31
  return alias[aliasMgmt].meta;
30
32
  }
33
+ /** Creates domain predicates lazily from entity field metadata. */
31
34
  function newAliasProxy(cstr) {
32
35
  const meta = require_EntityMetadata.getMetadata(cstr);
33
36
  const mgmt = {
34
37
  tableName: meta.tableName,
35
38
  meta
36
39
  };
37
- const proxy = new Proxy(cstr, {
38
- /** Create a column alias, or a relation join factory, for the given field. */
40
+ return new Proxy(cstr, {
39
41
  get(_, key) {
40
42
  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
- }
43
+ if (typeof key !== "string") return void 0;
44
+ const field = meta.allFields[key] ?? require_utils.fail(`No field ${key} on ${cstr.name}`);
45
+ if (field.kind === "poly") return new PolyReferenceAlias(meta, mgmt, field);
46
+ if ([
47
+ "primaryKey",
48
+ "primitive",
49
+ "enum",
50
+ "m2o"
51
+ ].includes(field.kind)) return new AliasColumnImpl(meta, field, field.serde.columns[0], mgmt);
52
+ return require_utils.fail(`Unsupported alias field kind ${field.kind}`);
54
53
  },
55
54
  has(_, key) {
56
55
  return key === aliasMgmt || key in meta.allFields;
57
56
  }
58
57
  });
59
- return proxy;
60
58
  }
61
- function isAlias(obj) {
62
- return obj && typeof obj === "function" && obj[aliasMgmt] !== void 0;
59
+ /** Recognizes only domain aliases, not physical tables. */
60
+ function isAlias(value) {
61
+ return typeof value === "function" && aliasMgmt in value;
63
62
  }
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 {
63
+ /** Builds field conditions without implementing the SQL expression protocol. */
64
+ var AliasColumnImpl = class AliasColumnImpl {
74
65
  meta;
75
66
  field;
76
67
  column;
77
68
  mgmt;
78
69
  constructor(meta, field, column, mgmt) {
79
- super();
80
70
  this.meta = meta;
81
71
  this.field = field;
82
72
  this.column = column;
83
73
  this.mgmt = mgmt;
84
74
  }
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
75
  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
- });
76
+ return this.compare("eq", "=", value);
152
77
  }
153
78
  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
- });
79
+ return this.compare("ne", "!=", value);
161
80
  }
162
81
  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
- });
82
+ return this.compare("gt", ">", value);
169
83
  }
170
84
  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
- });
85
+ return this.compare("gte", ">=", value);
177
86
  }
178
87
  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
- });
88
+ return this.compare("lt", "<", value);
185
89
  }
186
90
  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
- });
91
+ return this.compare("lte", "<=", value);
193
92
  }
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
- });
93
+ contains(value) {
94
+ return this.compare("contains", "@>", value);
200
95
  }
201
- like(value) {
202
- if (value === void 0) return require_Expr.skipCondition;
96
+ ncontains(value) {
97
+ if (value instanceof AliasColumnImpl) return crossColumnCondition(this, value, "@>", true);
203
98
  return this.addCondition({
204
- kind: "like",
99
+ kind: "ncontains",
205
100
  value
206
101
  });
207
102
  }
208
- ilike(value) {
209
- if (value === void 0) return require_Expr.skipCondition;
210
- return this.addCondition({
211
- kind: "ilike",
212
- value
213
- });
103
+ overlaps(value) {
104
+ return this.compare("overlaps", "&&", value);
214
105
  }
215
- search(value) {
216
- if (!value) return require_Expr.skipCondition;
106
+ noverlaps(value) {
107
+ if (value instanceof AliasColumnImpl) return crossColumnCondition(this, value, "&&", true);
217
108
  return this.addCondition({
218
- kind: "ilike",
219
- value: require_QueryParser.makeLike(value)
109
+ kind: "noverlaps",
110
+ value
220
111
  });
221
112
  }
222
113
  in(values) {
223
- if (values === void 0) return require_Expr.skipCondition;
224
- if (require_Expr.isExpr(values)) return this.inList("IN", values);
114
+ if (values === void 0) return require_skipCondition.skipCondition;
115
+ if (values === null) return require_utils.fail("Unsupported");
225
116
  if (values.includes(null)) return { or: [this.addCondition({ kind: "is-null" }), this.addCondition({
226
117
  kind: "in",
227
118
  value: values.filter((v) => v !== null)
228
119
  })] };
229
- else return this.addCondition({
120
+ return this.addCondition({
230
121
  kind: "in",
231
- value: values
122
+ value: [...values]
232
123
  });
233
124
  }
234
125
  nin(values) {
235
- if (values === void 0) return require_Expr.skipCondition;
236
- if (require_Expr.isExpr(values)) return this.inList("NOT IN", values);
126
+ if (values === void 0) return require_skipCondition.skipCondition;
127
+ if (values === null) return require_utils.fail("Unsupported");
237
128
  return this.addCondition({
238
129
  kind: "nin",
239
130
  value: values.filter((v) => v !== null)
240
131
  });
241
132
  }
242
- contains(v1) {
243
- if (v1 === void 0) return require_Expr.skipCondition;
133
+ between(v1, v2) {
134
+ if (v1 === void 0 || v2 === void 0) return require_skipCondition.skipCondition;
244
135
  return this.addCondition({
245
- kind: "contains",
246
- value: v1
136
+ kind: "between",
137
+ value: [v1, v2]
247
138
  });
248
139
  }
249
- ncontains(v1) {
250
- if (v1 === void 0) return require_Expr.skipCondition;
140
+ like(value) {
251
141
  return this.addCondition({
252
- kind: "ncontains",
253
- value: v1
142
+ kind: "like",
143
+ value
254
144
  });
255
145
  }
256
- overlaps(v1) {
257
- if (v1 === void 0) return require_Expr.skipCondition;
146
+ ilike(value) {
258
147
  return this.addCondition({
259
- kind: "overlaps",
260
- value: v1
148
+ kind: "ilike",
149
+ value
261
150
  });
262
151
  }
263
- noverlaps(v1) {
264
- if (v1 === void 0) return require_Expr.skipCondition;
265
- return this.addCondition({
266
- kind: "noverlaps",
267
- value: v1
152
+ search(value) {
153
+ return !value ? require_skipCondition.skipCondition : this.addCondition({
154
+ kind: "ilike",
155
+ value: require_QueryParser.makeLike(value)
268
156
  });
269
157
  }
270
- pathExists(jsonPath) {
271
- if (jsonPath === void 0) return require_Expr.skipCondition;
158
+ pathExists(value) {
272
159
  return this.addCondition({
273
160
  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
161
  value
297
162
  });
298
163
  }
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);
164
+ pathIsTrue(value) {
303
165
  return this.addCondition({
304
- kind: "ne",
166
+ kind: "jsonPathPredicate",
305
167
  value
306
168
  });
307
169
  }
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
170
  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);
171
+ if (bindings === void 0) return require_skipCondition.skipCondition;
172
+ return require_DeferredAlias.withDeferredAlias({
173
+ kind: "raw",
174
+ aliases: [],
175
+ condition: "unset",
176
+ pruneable: false,
177
+ bindings
178
+ }, (resolve, copy) => {
179
+ const r = resolve(this.mgmt);
180
+ const alias = getMaybeCtiAlias(this.meta, this.field, r.meta, r.alias);
181
+ copy.aliases = [alias];
182
+ copy.condition = `${alias}.${this.column.columnName} ${exp}`;
183
+ });
355
184
  }
356
- joinEntry(kind, other) {
357
- return {
358
- [kind]: requireAlias(other),
359
- on: this.eq(idColumnOf(other))
185
+ /** Maps literal values through the field serde and binds aliases only when parsing. */
186
+ addCondition(value) {
187
+ if ("value" in value && value.value === void 0) return require_skipCondition.skipCondition;
188
+ const cond = {
189
+ kind: "column",
190
+ alias: "unset",
191
+ column: this.column.columnName,
192
+ dbType: this.column.dbType,
193
+ cond: require_QueryParser.mapToDb(this.column, value)
360
194
  };
195
+ return require_DeferredAlias.withDeferredAlias(cond, (resolve, copy) => {
196
+ const r = resolve(this.mgmt);
197
+ copy.alias = getMaybeCtiAlias(this.meta, this.field, r.meta, r.alias);
198
+ });
361
199
  }
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);
200
+ /** Handles literal values, NULL, and domain cross-alias comparisons. */
201
+ compare(kind, op, value) {
202
+ if (value === void 0) return require_skipCondition.skipCondition;
203
+ if (value instanceof AliasColumnImpl) return crossColumnCondition(this, value, op);
204
+ if (value === null && (kind === "eq" || kind === "ne")) return this.addCondition({ kind: kind === "eq" ? "is-null" : "not-null" });
205
+ if (value === null && [
206
+ "gt",
207
+ "gte",
208
+ "lt",
209
+ "lte"
210
+ ].includes(kind)) return require_utils.fail("Unsupported");
366
211
  return this.addCondition({
367
212
  kind,
368
213
  value
369
214
  });
370
215
  }
371
216
  };
217
+ /** Resolves polymorphic predicates to their physical component columns. */
372
218
  var PolyReferenceAlias = class {
373
219
  meta;
374
220
  mgmt;
@@ -378,7 +224,6 @@ var PolyReferenceAlias = class {
378
224
  this.mgmt = mgmt;
379
225
  this.field = field;
380
226
  }
381
- /** Compares to a tagged id, an entity, or another alias's id column, which picks the component (`c.parent.eq(a.id)`). */
382
227
  eq(value) {
383
228
  return this.addEqOrNe("eq", value);
384
229
  }
@@ -386,237 +231,64 @@ var PolyReferenceAlias = class {
386
231
  return this.addEqOrNe("ne", value);
387
232
  }
388
233
  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, {
234
+ if (values === void 0) return require_skipCondition.skipCondition;
235
+ const groups = (0, joist_utils.groupBy)(values, (id) => require_configure.getConstructorFromTaggedId(require_keys.maybeResolveReferenceToId(id)).name);
236
+ return { or: Object.entries(groups).map(([name, ids]) => {
237
+ const comp = this.field.components.find((c) => c.otherMetadata().cstr.name === name) ?? require_utils.fail(`No component for ${name}`);
238
+ return this.component(comp).addCondition({
395
239
  kind: "in",
396
240
  value: ids
397
241
  });
398
242
  }) };
399
243
  }
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
- }
244
+ /** Picks the component from an entity, tagged id, or another domain alias column. */
435
245
  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) {
246
+ if (value === void 0) return require_skipCondition.skipCondition;
247
+ if (value === null) return { and: this.field.components.map((c) => this.component(c).addCondition({ kind: kind === "eq" ? "is-null" : "not-null" })) };
248
+ const otherMeta = value instanceof AliasColumnImpl ? value.field.kind === "m2o" ? value.field.otherMetadata() : value.meta : require_EntityMetadata.getMetadata(require_configure.getConstructorFromTaggedId(require_keys.maybeResolveReferenceToId(value)));
249
+ 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}`);
250
+ const column = this.component(comp);
251
+ return kind === "eq" ? column.eq(value) : column.ne(value);
252
+ }
253
+ /** Uses the component serde, not the first component's codec. */
254
+ component(comp) {
454
255
  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
- });
256
+ return new AliasColumnImpl(this.meta, this.field, column, this.mgmt);
466
257
  }
467
258
  };
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
- */
259
+ /** Adjusts a field's SQL alias when a base alias is bound to a CTI subtype in the join tree. */
472
260
  function getMaybeCtiAlias(meta, field, newMeta, newAlias) {
473
261
  if (newMeta !== meta && newMeta.inheritanceType === "cti") {
474
262
  if (require_EntityMetadata.getBaseAndSelfMetas(newMeta).includes(newMeta)) return `${newAlias}_b0`;
475
263
  }
476
264
  return `${newAlias}${field.aliasSuffix}`;
477
265
  }
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 = {
266
+ /** Compares domain columns with per-parse aliases, preserving condition reuse across find calls. */
267
+ function crossColumnCondition(left, right, op, negate = false) {
268
+ return require_DeferredAlias.withDeferredAlias({
585
269
  kind: "raw",
586
270
  aliases: [],
587
271
  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}`;
272
+ bindings: [],
273
+ pruneable: false
274
+ }, (resolve, copy) => {
275
+ const l = resolve(left.mgmt);
276
+ const r = resolve(right.mgmt);
277
+ const a1 = getMaybeCtiAlias(left.meta, left.field, l.meta, l.alias);
278
+ const a2 = getMaybeCtiAlias(right.meta, right.field, r.meta, r.alias);
279
+ copy.aliases = [a1, a2];
280
+ const sql = `${a1}.${left.column.columnName} ${op} ${a2}.${right.column.columnName}`;
281
+ copy.condition = negate ? `NOT (${sql})` : sql;
598
282
  });
599
283
  }
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
284
  //#endregion
610
- exports.JoinTableHandle = JoinTableHandle;
611
285
  exports.alias = alias;
612
286
  exports.aliasMgmt = aliasMgmt;
613
287
  exports.aliases = aliases;
614
- exports.collectionJoin = collectionJoin;
615
288
  exports.getAliasMetadata = getAliasMetadata;
616
289
  exports.getAliasMgmt = getAliasMgmt;
617
290
  exports.getMaybeCtiAlias = getMaybeCtiAlias;
618
291
  exports.isAlias = isAlias;
619
- exports.m2mJoinTable = m2mJoinTable;
620
292
  exports.newAliasProxy = newAliasProxy;
621
293
 
622
294
  //# sourceMappingURL=Aliases.cjs.map