joist-core 2.4.0-next.2 → 2.4.0-next.21

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 (153) hide show
  1. package/build/EntityManager.cjs +25 -11
  2. package/build/EntityManager.cjs.map +1 -1
  3. package/build/EntityManager.d.cts +11 -4
  4. package/build/EntityManager.d.cts.map +1 -1
  5. package/build/EntityManager.d.mts +11 -4
  6. package/build/EntityManager.d.mts.map +1 -1
  7. package/build/EntityManager.js +25 -13
  8. package/build/EntityManager.js.map +1 -1
  9. package/build/EntityMetadata.cjs +0 -1
  10. package/build/EntityMetadata.cjs.map +1 -1
  11. package/build/EntityMetadata.d.cts +8 -4
  12. package/build/EntityMetadata.d.cts.map +1 -1
  13. package/build/EntityMetadata.d.mts +8 -4
  14. package/build/EntityMetadata.d.mts.map +1 -1
  15. package/build/EntityMetadata.js +0 -1
  16. package/build/EntityMetadata.js.map +1 -1
  17. package/build/IndexManager.cjs +23 -5
  18. package/build/IndexManager.cjs.map +1 -1
  19. package/build/IndexManager.d.cts.map +1 -1
  20. package/build/IndexManager.d.mts.map +1 -1
  21. package/build/IndexManager.js +23 -5
  22. package/build/IndexManager.js.map +1 -1
  23. package/build/batchloaders/populateBatchLoader.cjs +2 -2
  24. package/build/batchloaders/populateBatchLoader.js +2 -2
  25. package/build/batchloaders/recursiveChildrenBatchLoader.cjs +1 -1
  26. package/build/batchloaders/recursiveChildrenBatchLoader.js +1 -1
  27. package/build/batchloaders/recursiveM2mBatchLoader.cjs +1 -1
  28. package/build/batchloaders/recursiveM2mBatchLoader.js +1 -1
  29. package/build/batchloaders/recursiveParentsBatchLoader.cjs +1 -1
  30. package/build/batchloaders/recursiveParentsBatchLoader.js +1 -1
  31. package/build/config.cjs +74 -1
  32. package/build/config.cjs.map +1 -1
  33. package/build/config.d.cts +83 -2
  34. package/build/config.d.cts.map +1 -1
  35. package/build/config.d.mts +83 -2
  36. package/build/config.d.mts.map +1 -1
  37. package/build/config.js +74 -1
  38. package/build/config.js.map +1 -1
  39. package/build/configure.cjs +6 -2
  40. package/build/configure.cjs.map +1 -1
  41. package/build/configure.d.cts.map +1 -1
  42. package/build/configure.d.mts.map +1 -1
  43. package/build/configure.js +6 -2
  44. package/build/configure.js.map +1 -1
  45. package/build/dataloaders/findDataLoader.cjs +1 -1
  46. package/build/dataloaders/findDataLoader.js +1 -1
  47. package/build/dataloaders/findOrCreateDataLoader.cjs +6 -2
  48. package/build/dataloaders/findOrCreateDataLoader.cjs.map +1 -1
  49. package/build/dataloaders/findOrCreateDataLoader.d.cts.map +1 -1
  50. package/build/dataloaders/findOrCreateDataLoader.d.mts.map +1 -1
  51. package/build/dataloaders/findOrCreateDataLoader.js +7 -3
  52. package/build/dataloaders/findOrCreateDataLoader.js.map +1 -1
  53. package/build/dataloaders/findPaginatedDataLoader.cjs +1 -1
  54. package/build/dataloaders/findPaginatedDataLoader.js +1 -1
  55. package/build/defaults.cjs +2 -2
  56. package/build/defaults.js +2 -2
  57. package/build/fields.cjs +1 -0
  58. package/build/fields.cjs.map +1 -1
  59. package/build/fields.d.cts.map +1 -1
  60. package/build/fields.d.mts.map +1 -1
  61. package/build/fields.js +1 -0
  62. package/build/fields.js.map +1 -1
  63. package/build/index.cjs +13 -8
  64. package/build/index.cjs.map +1 -1
  65. package/build/index.d.cts +4 -3
  66. package/build/index.d.cts.map +1 -1
  67. package/build/index.d.mts +4 -3
  68. package/build/index.d.mts.map +1 -1
  69. package/build/index.js +13 -10
  70. package/build/index.js.map +1 -1
  71. package/build/json.cjs +3 -3
  72. package/build/json.js +3 -3
  73. package/build/loading/loadHints.cjs +1 -1
  74. package/build/loading/loadHints.js +1 -1
  75. package/build/loading/withLoaded.cjs +2 -2
  76. package/build/loading/withLoaded.js +2 -2
  77. package/build/newTestInstance.cjs +1 -0
  78. package/build/newTestInstance.cjs.map +1 -1
  79. package/build/newTestInstance.d.cts.map +1 -1
  80. package/build/newTestInstance.d.mts.map +1 -1
  81. package/build/newTestInstance.js +1 -0
  82. package/build/newTestInstance.js.map +1 -1
  83. package/build/preloading/partitionHint.cjs +1 -1
  84. package/build/preloading/partitionHint.js +1 -1
  85. package/build/queries/sql/execute.cjs +68 -89
  86. package/build/queries/sql/execute.cjs.map +1 -1
  87. package/build/queries/sql/execute.d.cts +35 -18
  88. package/build/queries/sql/execute.d.cts.map +1 -1
  89. package/build/queries/sql/execute.d.mts +35 -18
  90. package/build/queries/sql/execute.d.mts.map +1 -1
  91. package/build/queries/sql/execute.js +70 -91
  92. package/build/queries/sql/execute.js.map +1 -1
  93. package/build/queries/sql/query.cjs +77 -30
  94. package/build/queries/sql/query.cjs.map +1 -1
  95. package/build/queries/sql/query.d.cts +64 -21
  96. package/build/queries/sql/query.d.cts.map +1 -1
  97. package/build/queries/sql/query.d.mts +64 -21
  98. package/build/queries/sql/query.d.mts.map +1 -1
  99. package/build/queries/sql/query.js +75 -30
  100. package/build/queries/sql/query.js.map +1 -1
  101. package/build/reactivity/ReactionsManager.cjs +168 -2
  102. package/build/reactivity/ReactionsManager.cjs.map +1 -1
  103. package/build/reactivity/ReactionsManager.d.cts +54 -1
  104. package/build/reactivity/ReactionsManager.d.cts.map +1 -1
  105. package/build/reactivity/ReactionsManager.d.mts +54 -1
  106. package/build/reactivity/ReactionsManager.d.mts.map +1 -1
  107. package/build/reactivity/ReactionsManager.js +169 -3
  108. package/build/reactivity/ReactionsManager.js.map +1 -1
  109. package/build/reactivity/reactiveHints.cjs +3 -3
  110. package/build/reactivity/reactiveHints.cjs.map +1 -1
  111. package/build/reactivity/reactiveHints.d.cts.map +1 -1
  112. package/build/reactivity/reactiveHints.d.mts.map +1 -1
  113. package/build/reactivity/reactiveHints.js +3 -3
  114. package/build/reactivity/reactiveHints.js.map +1 -1
  115. package/build/relations/AsyncReactiveField.cjs +3 -3
  116. package/build/relations/AsyncReactiveField.js +3 -3
  117. package/build/relations/LazyField.cjs +14 -0
  118. package/build/relations/LazyField.cjs.map +1 -1
  119. package/build/relations/LazyField.d.cts +6 -0
  120. package/build/relations/LazyField.d.cts.map +1 -1
  121. package/build/relations/LazyField.d.mts +6 -0
  122. package/build/relations/LazyField.d.mts.map +1 -1
  123. package/build/relations/LazyField.js +14 -0
  124. package/build/relations/LazyField.js.map +1 -1
  125. package/build/relations/ReactiveField.cjs +2 -2
  126. package/build/relations/ReactiveField.js +2 -2
  127. package/build/relations/ReactiveManyToMany.cjs +1 -1
  128. package/build/relations/ReactiveManyToMany.js +1 -1
  129. package/build/relations/ReactiveReference.cjs +1 -1
  130. package/build/relations/ReactiveReference.js +1 -1
  131. package/build/relations/RecursiveCollection.cjs +3 -3
  132. package/build/relations/RecursiveCollection.js +3 -3
  133. package/build/relations/hasProperty.cjs +2 -2
  134. package/build/relations/hasProperty.js +2 -2
  135. package/build/relations/index.cjs +5 -5
  136. package/build/relations/index.js +5 -5
  137. package/build/resurrection.cjs +11 -1
  138. package/build/resurrection.cjs.map +1 -1
  139. package/build/resurrection.d.cts +4 -1
  140. package/build/resurrection.d.cts.map +1 -1
  141. package/build/resurrection.d.mts +4 -1
  142. package/build/resurrection.d.mts.map +1 -1
  143. package/build/resurrection.js +11 -2
  144. package/build/resurrection.js.map +1 -1
  145. package/build/transitions.cjs +89 -0
  146. package/build/transitions.cjs.map +1 -0
  147. package/build/transitions.d.cts +110 -0
  148. package/build/transitions.d.cts.map +1 -0
  149. package/build/transitions.d.mts +110 -0
  150. package/build/transitions.d.mts.map +1 -0
  151. package/build/transitions.js +84 -0
  152. package/build/transitions.js.map +1 -0
  153. package/package.json +2 -2
@@ -167,7 +167,7 @@ sql.condition = function condition(strings, ...values) {
167
167
  * `EntityManager.query` runs the plan; this module deliberately does not import `EntityManager` (see
168
168
  * `EntityHydrator`), so it parses and hands back `{ sql, bindings, decodeRows }` instead of executing.
169
169
  */
170
- function parseUserQuery(arg) {
170
+ function parseRootQuery(arg) {
171
171
  if (arg instanceof SubqueryExpr) fail("Scalar query values are expressions, not executable read inputs");
172
172
  return parseQuery(toQuery(arg), void 0, new AliasAssigner());
173
173
  }
@@ -219,6 +219,7 @@ function projectionToSql(select, ctx, joins) {
219
219
  var SubqueryHandle = class {
220
220
  recursive;
221
221
  #q;
222
+ #output;
222
223
  constructor(q, recursive = false) {
223
224
  this.recursive = recursive;
224
225
  this.#q = q;
@@ -227,13 +228,17 @@ var SubqueryHandle = class {
227
228
  return this.#q;
228
229
  }
229
230
  /**
230
- * Gives a recursive CTE its finished body. `recursiveQuery` starts the handle on its base term, so
231
- * the step term can read the CTE's columns while the body that will hold that step is still being
232
- * built. The base term supplies the CTE's columns either way, PostgreSQL's rule for a recursive WITH.
231
+ * Gives a recursive CTE its finished body.
232
+ *
233
+ * `recursiveQuery(name, base, step)` cannot hand us the real body up front: it has to call `step` to
234
+ * get it, and `step` needs this handle first, because the recursive half of the query references the
235
+ * CTE's own columns. So the handle starts out holding `base` alone, and the real body, `base UNION
236
+ * step`, arrives here afterwards. Either way PostgreSQL takes the CTE's column names from `base`.
233
237
  */
234
238
  setBody(q) {
235
239
  if (!this.recursive) fail("Only a recursive CTE replaces its body");
236
240
  this.#q = q;
241
+ this.#output = void 0;
237
242
  }
238
243
  get name() {
239
244
  return this.q.as;
@@ -242,15 +247,27 @@ var SubqueryHandle = class {
242
247
  columnKeys() {
243
248
  const output = this.output();
244
249
  if (output.kind === "pojo") return output.columns.map(([key]) => key);
245
- return fail(`A subquery with an entity or scalar select has no columns`);
250
+ return fail(`A query value with an entity or scalar select has no columns`);
246
251
  }
247
252
  /** The inner expression behind `key`, for its decoder/encoder. */
248
253
  columnExpr(key) {
249
- return this.output().columns.find(([name]) => name === key)?.[1] ?? fail(`Subquery ${this.describe()} has no column ${key}`);
254
+ return this.output().columns.find(([name]) => name === key)?.[1] ?? fail(`Query value ${this.describe()} has no column ${key}`);
250
255
  }
251
- /** Resolve output metadata without parsing SQL or caching aliases from an enclosing query. */
256
+ /**
257
+ * The output columns, in order, with the codec for each; worked out without generating any SQL.
258
+ *
259
+ * Cached, because the answer is expensive to work out and gets asked for a lot:
260
+ *
261
+ * - `queryOutput` re-checks the whole query, converts a `join: { books: ... }` relationship tree
262
+ * back into a flat list of joins, and repeats all of that for every operand of a set query.
263
+ * - A `query(...)` value has no real properties. `bookStats.n` runs a `Proxy` get that builds a new
264
+ * column expression, and building one needs this method's answer to find `n`. So selecting two of
265
+ * a value's columns asked for the whole shape twice, before parsing then asked a third time.
266
+ *
267
+ * `setBody` is the only thing that changes the shape, so it is the only thing that clears this.
268
+ */
252
269
  output() {
253
- return queryOutput(this.q);
270
+ return this.#output ??= queryOutput(this.q);
254
271
  }
255
272
  column(key) {
256
273
  return new SubqueryColumnExpr(this, key, this.columnExpr(key));
@@ -476,15 +493,15 @@ function queryOutput(q) {
476
493
  validateReadQuery(q);
477
494
  if (isSetQuery(q)) {
478
495
  const [operation, operands] = setOperands(q);
479
- const first = queryOutput(toQuery(operands[0]));
496
+ const first = requirePojoOperand(queryOutput(toQuery(operands[0])));
480
497
  const columns = [...first.columns];
481
- for (const operand of operands) {
482
- const output = operand === operands[0] ? first : queryOutput(toQuery(operand));
483
- if (output.kind !== "pojo") fail(output.kind === "entity" ? "Set operations do not support entity-mode operands" : "Set operations require POJO operands; wrap scalar expressions in a named select projection");
498
+ for (const operand of operands.slice(1)) {
499
+ const output = requirePojoOperand(queryOutput(toQuery(operand)));
484
500
  if (output.columns.length !== first.columns.length) fail("Set operands must have the same POJO keys");
501
+ const byKey = new Map(output.columns);
485
502
  for (let i = 0; i < columns.length; i++) {
486
503
  const [key, expr] = columns[i];
487
- const other = output.columns.find(([name]) => name === key)?.[1];
504
+ const other = byKey.get(key);
488
505
  if (!other) fail(`Set operands must have the same POJO keys; missing '${key}'`);
489
506
  const left = expr.outputType;
490
507
  const right = other.outputType;
@@ -511,6 +528,11 @@ function queryOutput(q) {
511
528
  if (isSubqueryValue(select)) return readValueHandle(select).output();
512
529
  return joinedOutput(projectionOutput(select), q.join);
513
530
  }
531
+ /** Only named POJO operands combine; entity and scalar reads have no columns to line up. */
532
+ function requirePojoOperand(output) {
533
+ if (output.kind !== "pojo") fail(output.kind === "entity" ? "Set operations do not support entity-mode operands" : "Set operations require POJO operands; wrap scalar expressions in a named select projection");
534
+ return output;
535
+ }
514
536
  /** Validates the projection before compiling SQL or exposing reusable query columns. */
515
537
  function projectionOutput(select) {
516
538
  if (isExpr(select)) return {
@@ -641,17 +663,12 @@ function parseSetQuery(q, parent, assigner, recursiveSelf) {
641
663
  sql += " OFFSET ?";
642
664
  bindings.push(q.offset);
643
665
  }
644
- const keptCtes = pruneCtes(ctes, new Set(plans.flatMap((plan) => plan.outerRefs)));
645
- if (keptCtes.length > 0) {
646
- const clause = withFragment(keptCtes);
647
- sql = clause.sql + sql;
648
- bindings.unshift(...clause.bindings);
649
- }
666
+ const withCtes = prependCtes(ctes, new Set(plans.flatMap((plan) => plan.outerRefs)), sql, bindings);
650
667
  const cteAliases = new Set(ctes.map((cte) => cte.alias));
651
668
  const outerRefs = [...ctx.outerRefs, ...plans.flatMap((plan) => plan.outerRefs)];
652
669
  return {
653
- sql,
654
- bindings,
670
+ sql: withCtes.sql,
671
+ bindings: withCtes.bindings,
655
672
  outerRefs: [...new Set(outerRefs.filter((ref) => !cteAliases.has(ref)))],
656
673
  output,
657
674
  decodeRows: (_, rows) => rows.map((row) => decodeRow(row, output.columns))
@@ -776,7 +793,7 @@ var Ctx = class {
776
793
  }
777
794
  };
778
795
  function describeHandle(handle) {
779
- if (handle instanceof SubqueryHandle) return `Subquery ${handle.describe()}`;
796
+ if (handle instanceof SubqueryHandle) return `Query value ${handle.describe()}`;
780
797
  if (handle instanceof JoinTableHandle) return `Join table ${handle.joinTableName}`;
781
798
  if ("tableName" in handle) return `Table for ${handle.tableName}`;
782
799
  return "Table";
@@ -1293,19 +1310,19 @@ function checkCondition(value) {
1293
1310
  if ("and" in condition || "or" in condition) {
1294
1311
  if ("and" in condition === "or" in condition) fail("Query conditions require exactly one and/or group");
1295
1312
  const key = "and" in condition ? "and" : "or";
1296
- checkConditionKeys(condition, [key, "pruneIfUndefined"], "Query condition group");
1313
+ checkPojoKeys(condition, [key, "pruneIfUndefined"], "Query condition group");
1297
1314
  if (!Array.isArray(condition[key])) fail("Query condition groups require an array");
1298
1315
  if (condition.pruneIfUndefined !== void 0 && condition.pruneIfUndefined !== "any" && condition.pruneIfUndefined !== "all") fail("Invalid query pruneIfUndefined policy");
1299
1316
  for (const child of condition[key]) checkCondition(child);
1300
1317
  } else if ("exists" in condition || "notExists" in condition) {
1301
1318
  const key = "exists" in condition ? "exists" : "notExists";
1302
- checkConditionKeys(condition, [key], "Query existence condition");
1319
+ checkPojoKeys(condition, [key], "Query existence condition");
1303
1320
  const query = condition[key];
1304
1321
  if (query === void 0) return;
1305
1322
  if (!(query instanceof SubqueryExpr) && !isReadQueryValue(query)) fail(`Query ${key} requires a query(...) value`);
1306
1323
  toQuery(query);
1307
1324
  } else if (condition.kind === "raw") {
1308
- checkConditionKeys(condition, [
1325
+ checkPojoKeys(condition, [
1309
1326
  "kind",
1310
1327
  "aliases",
1311
1328
  "condition",
@@ -1316,7 +1333,7 @@ function checkCondition(value) {
1316
1333
  ], "Query raw condition");
1317
1334
  if (typeof condition.condition !== "string" || !Array.isArray(condition.aliases) || !condition.aliases.every((alias) => typeof alias === "string") || !Array.isArray(condition.bindings) || typeof condition.pruneable !== "boolean") fail("Malformed query raw condition");
1318
1335
  } else if (condition.kind === "column") {
1319
- checkConditionKeys(condition, [
1336
+ checkPojoKeys(condition, [
1320
1337
  "kind",
1321
1338
  "alias",
1322
1339
  "column",
@@ -1328,7 +1345,7 @@ function checkCondition(value) {
1328
1345
  if (typeof condition.alias !== "string" || typeof condition.column !== "string" || typeof condition.dbType !== "string" || condition.pruneable !== void 0 && typeof condition.pruneable !== "boolean") fail("Malformed query column condition");
1329
1346
  const filter = condition.cond;
1330
1347
  if (!filter) fail("Malformed query column filter");
1331
- checkConditionKeys(filter, ["kind", "value"], "Query column filter");
1348
+ checkPojoKeys(filter, ["kind", "value"], "Query column filter");
1332
1349
  const unary = filter.kind === "is-null" || filter.kind === "not-null";
1333
1350
  if (!unary && (![
1334
1351
  "eq",
@@ -1359,8 +1376,18 @@ function checkCondition(value) {
1359
1376
  if (unary && "value" in filter) fail("Unary query filters do not accept values");
1360
1377
  } else fail("Unknown query condition");
1361
1378
  }
1362
- /** Conditions use own enumerable POJO fields, with predicate-brand and SQL-resolver symbols allowed. */
1363
- function checkConditionKeys(value, allowed, description) {
1379
+ /**
1380
+ * Accepts only own enumerable POJO fields, so nothing a caller supplied can be silently ignored: the
1381
+ * compilers read these POJOs back with `Object.entries`/`Object.keys`, which skip inherited,
1382
+ * non-enumerable, and symbol keys, so a field hidden behind one of those would never reach the SQL.
1383
+ * I.e. an UPDATE whose `set` carries `title` on a prototype would leave `title` unchanged and still
1384
+ * report success.
1385
+ *
1386
+ * Conditions, mutation clauses, and assignment POJOs all share this rule; `allowed` may include symbol
1387
+ * keys, i.e. a condition's predicate brand and SQL resolver. Read-query clauses instead use
1388
+ * `validateQueryKeys`, which walks the prototype chain and reports mutation clauses by name.
1389
+ */
1390
+ function checkPojoKeys(value, allowed, description) {
1364
1391
  if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) fail(`${description} must be a plain POJO`);
1365
1392
  for (const key of Reflect.ownKeys(value)) {
1366
1393
  if (!allowed.includes(key)) fail(`${description} does not support '${String(key)}'`);
@@ -1511,6 +1538,24 @@ function withEntryHandle(entry) {
1511
1538
  return readValueHandle(entry);
1512
1539
  }
1513
1540
  /**
1541
+ * Puts a statement's surviving `with` entries in front of it, dropping the ones nothing reads.
1542
+ *
1543
+ * `referenced` is the aliases the rest of the statement used. The WITH clause leads the statement, so
1544
+ * its bindings lead the statement's bindings too.
1545
+ */
1546
+ function prependCtes(ctes, referenced, sql, bindings) {
1547
+ const kept = pruneCtes(ctes, referenced);
1548
+ if (kept.length === 0) return {
1549
+ sql,
1550
+ bindings
1551
+ };
1552
+ const clause = withFragment(kept);
1553
+ return {
1554
+ sql: clause.sql + sql,
1555
+ bindings: [...clause.bindings, ...bindings]
1556
+ };
1557
+ }
1558
+ /**
1514
1559
  * Drops the CTEs that nothing reads, given the aliases the rest of the statement referenced.
1515
1560
  *
1516
1561
  * A CTE can only read earlier siblings, so going last to first means every CTE that could read this one
@@ -1587,6 +1632,6 @@ function typedSql(strings, ...values) {
1587
1632
  return new TemplateExpr(strings, values);
1588
1633
  }
1589
1634
  //#endregion
1590
- export { Ctx, SubqueryHandle, conditionToSql, entityQueryBrand, injectedConditions, isReadQueryValue, parseNestedQuery, parseUserQuery, projectionToSql, pruneCtes, query, queryMaybe, recursiveQuery, registerCtes, scalarQueryBrand, sql, subqueryBrand, withFragment };
1635
+ export { Ctx, SubqueryHandle, checkPojoKeys, conditionToSql, entityQueryBrand, injectedConditions, isReadQueryValue, parseNestedQuery, parseRootQuery, prependCtes, projectionToSql, pruneCtes, query, queryMaybe, recursiveQuery, registerCtes, scalarQueryBrand, sql, subqueryBrand, withFragment };
1591
1636
 
1592
1637
  //# sourceMappingURL=query.js.map