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
@@ -168,7 +168,7 @@ sql.condition = function condition(strings, ...values) {
168
168
  * `EntityManager.query` runs the plan; this module deliberately does not import `EntityManager` (see
169
169
  * `EntityHydrator`), so it parses and hands back `{ sql, bindings, decodeRows }` instead of executing.
170
170
  */
171
- function parseUserQuery(arg) {
171
+ function parseRootQuery(arg) {
172
172
  if (arg instanceof SubqueryExpr) require_utils.fail("Scalar query values are expressions, not executable read inputs");
173
173
  return parseQuery(toQuery(arg), void 0, new require_queries_sql_AliasAssigner.AliasAssigner());
174
174
  }
@@ -220,6 +220,7 @@ function projectionToSql(select, ctx, joins) {
220
220
  var SubqueryHandle = class {
221
221
  recursive;
222
222
  #q;
223
+ #output;
223
224
  constructor(q, recursive = false) {
224
225
  this.recursive = recursive;
225
226
  this.#q = q;
@@ -228,13 +229,17 @@ var SubqueryHandle = class {
228
229
  return this.#q;
229
230
  }
230
231
  /**
231
- * Gives a recursive CTE its finished body. `recursiveQuery` starts the handle on its base term, so
232
- * the step term can read the CTE's columns while the body that will hold that step is still being
233
- * built. The base term supplies the CTE's columns either way, PostgreSQL's rule for a recursive WITH.
232
+ * Gives a recursive CTE its finished body.
233
+ *
234
+ * `recursiveQuery(name, base, step)` cannot hand us the real body up front: it has to call `step` to
235
+ * get it, and `step` needs this handle first, because the recursive half of the query references the
236
+ * CTE's own columns. So the handle starts out holding `base` alone, and the real body, `base UNION
237
+ * step`, arrives here afterwards. Either way PostgreSQL takes the CTE's column names from `base`.
234
238
  */
235
239
  setBody(q) {
236
240
  if (!this.recursive) require_utils.fail("Only a recursive CTE replaces its body");
237
241
  this.#q = q;
242
+ this.#output = void 0;
238
243
  }
239
244
  get name() {
240
245
  return this.q.as;
@@ -243,15 +248,27 @@ var SubqueryHandle = class {
243
248
  columnKeys() {
244
249
  const output = this.output();
245
250
  if (output.kind === "pojo") return output.columns.map(([key]) => key);
246
- return require_utils.fail(`A subquery with an entity or scalar select has no columns`);
251
+ return require_utils.fail(`A query value with an entity or scalar select has no columns`);
247
252
  }
248
253
  /** The inner expression behind `key`, for its decoder/encoder. */
249
254
  columnExpr(key) {
250
- return this.output().columns.find(([name]) => name === key)?.[1] ?? require_utils.fail(`Subquery ${this.describe()} has no column ${key}`);
255
+ return this.output().columns.find(([name]) => name === key)?.[1] ?? require_utils.fail(`Query value ${this.describe()} has no column ${key}`);
251
256
  }
252
- /** Resolve output metadata without parsing SQL or caching aliases from an enclosing query. */
257
+ /**
258
+ * The output columns, in order, with the codec for each; worked out without generating any SQL.
259
+ *
260
+ * Cached, because the answer is expensive to work out and gets asked for a lot:
261
+ *
262
+ * - `queryOutput` re-checks the whole query, converts a `join: { books: ... }` relationship tree
263
+ * back into a flat list of joins, and repeats all of that for every operand of a set query.
264
+ * - A `query(...)` value has no real properties. `bookStats.n` runs a `Proxy` get that builds a new
265
+ * column expression, and building one needs this method's answer to find `n`. So selecting two of
266
+ * a value's columns asked for the whole shape twice, before parsing then asked a third time.
267
+ *
268
+ * `setBody` is the only thing that changes the shape, so it is the only thing that clears this.
269
+ */
253
270
  output() {
254
- return queryOutput(this.q);
271
+ return this.#output ??= queryOutput(this.q);
255
272
  }
256
273
  column(key) {
257
274
  return new SubqueryColumnExpr(this, key, this.columnExpr(key));
@@ -477,15 +494,15 @@ function queryOutput(q) {
477
494
  validateReadQuery(q);
478
495
  if (isSetQuery(q)) {
479
496
  const [operation, operands] = setOperands(q);
480
- const first = queryOutput(toQuery(operands[0]));
497
+ const first = requirePojoOperand(queryOutput(toQuery(operands[0])));
481
498
  const columns = [...first.columns];
482
- for (const operand of operands) {
483
- const output = operand === operands[0] ? first : queryOutput(toQuery(operand));
484
- if (output.kind !== "pojo") require_utils.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");
499
+ for (const operand of operands.slice(1)) {
500
+ const output = requirePojoOperand(queryOutput(toQuery(operand)));
485
501
  if (output.columns.length !== first.columns.length) require_utils.fail("Set operands must have the same POJO keys");
502
+ const byKey = new Map(output.columns);
486
503
  for (let i = 0; i < columns.length; i++) {
487
504
  const [key, expr] = columns[i];
488
- const other = output.columns.find(([name]) => name === key)?.[1];
505
+ const other = byKey.get(key);
489
506
  if (!other) require_utils.fail(`Set operands must have the same POJO keys; missing '${key}'`);
490
507
  const left = expr.outputType;
491
508
  const right = other.outputType;
@@ -512,6 +529,11 @@ function queryOutput(q) {
512
529
  if (isSubqueryValue(select)) return readValueHandle(select).output();
513
530
  return joinedOutput(projectionOutput(select), q.join);
514
531
  }
532
+ /** Only named POJO operands combine; entity and scalar reads have no columns to line up. */
533
+ function requirePojoOperand(output) {
534
+ if (output.kind !== "pojo") require_utils.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");
535
+ return output;
536
+ }
515
537
  /** Validates the projection before compiling SQL or exposing reusable query columns. */
516
538
  function projectionOutput(select) {
517
539
  if (require_queries_sql_Expr.isExpr(select)) return {
@@ -642,17 +664,12 @@ function parseSetQuery(q, parent, assigner, recursiveSelf) {
642
664
  sql += " OFFSET ?";
643
665
  bindings.push(q.offset);
644
666
  }
645
- const keptCtes = pruneCtes(ctes, new Set(plans.flatMap((plan) => plan.outerRefs)));
646
- if (keptCtes.length > 0) {
647
- const clause = withFragment(keptCtes);
648
- sql = clause.sql + sql;
649
- bindings.unshift(...clause.bindings);
650
- }
667
+ const withCtes = prependCtes(ctes, new Set(plans.flatMap((plan) => plan.outerRefs)), sql, bindings);
651
668
  const cteAliases = new Set(ctes.map((cte) => cte.alias));
652
669
  const outerRefs = [...ctx.outerRefs, ...plans.flatMap((plan) => plan.outerRefs)];
653
670
  return {
654
- sql,
655
- bindings,
671
+ sql: withCtes.sql,
672
+ bindings: withCtes.bindings,
656
673
  outerRefs: [...new Set(outerRefs.filter((ref) => !cteAliases.has(ref)))],
657
674
  output,
658
675
  decodeRows: (_, rows) => rows.map((row) => decodeRow(row, output.columns))
@@ -777,7 +794,7 @@ var Ctx = class {
777
794
  }
778
795
  };
779
796
  function describeHandle(handle) {
780
- if (handle instanceof SubqueryHandle) return `Subquery ${handle.describe()}`;
797
+ if (handle instanceof SubqueryHandle) return `Query value ${handle.describe()}`;
781
798
  if (handle instanceof require_queries_sql_Tables.JoinTableHandle) return `Join table ${handle.joinTableName}`;
782
799
  if ("tableName" in handle) return `Table for ${handle.tableName}`;
783
800
  return "Table";
@@ -1294,19 +1311,19 @@ function checkCondition(value) {
1294
1311
  if ("and" in condition || "or" in condition) {
1295
1312
  if ("and" in condition === "or" in condition) require_utils.fail("Query conditions require exactly one and/or group");
1296
1313
  const key = "and" in condition ? "and" : "or";
1297
- checkConditionKeys(condition, [key, "pruneIfUndefined"], "Query condition group");
1314
+ checkPojoKeys(condition, [key, "pruneIfUndefined"], "Query condition group");
1298
1315
  if (!Array.isArray(condition[key])) require_utils.fail("Query condition groups require an array");
1299
1316
  if (condition.pruneIfUndefined !== void 0 && condition.pruneIfUndefined !== "any" && condition.pruneIfUndefined !== "all") require_utils.fail("Invalid query pruneIfUndefined policy");
1300
1317
  for (const child of condition[key]) checkCondition(child);
1301
1318
  } else if ("exists" in condition || "notExists" in condition) {
1302
1319
  const key = "exists" in condition ? "exists" : "notExists";
1303
- checkConditionKeys(condition, [key], "Query existence condition");
1320
+ checkPojoKeys(condition, [key], "Query existence condition");
1304
1321
  const query = condition[key];
1305
1322
  if (query === void 0) return;
1306
1323
  if (!(query instanceof SubqueryExpr) && !isReadQueryValue(query)) require_utils.fail(`Query ${key} requires a query(...) value`);
1307
1324
  toQuery(query);
1308
1325
  } else if (condition.kind === "raw") {
1309
- checkConditionKeys(condition, [
1326
+ checkPojoKeys(condition, [
1310
1327
  "kind",
1311
1328
  "aliases",
1312
1329
  "condition",
@@ -1317,7 +1334,7 @@ function checkCondition(value) {
1317
1334
  ], "Query raw condition");
1318
1335
  if (typeof condition.condition !== "string" || !Array.isArray(condition.aliases) || !condition.aliases.every((alias) => typeof alias === "string") || !Array.isArray(condition.bindings) || typeof condition.pruneable !== "boolean") require_utils.fail("Malformed query raw condition");
1319
1336
  } else if (condition.kind === "column") {
1320
- checkConditionKeys(condition, [
1337
+ checkPojoKeys(condition, [
1321
1338
  "kind",
1322
1339
  "alias",
1323
1340
  "column",
@@ -1329,7 +1346,7 @@ function checkCondition(value) {
1329
1346
  if (typeof condition.alias !== "string" || typeof condition.column !== "string" || typeof condition.dbType !== "string" || condition.pruneable !== void 0 && typeof condition.pruneable !== "boolean") require_utils.fail("Malformed query column condition");
1330
1347
  const filter = condition.cond;
1331
1348
  if (!filter) require_utils.fail("Malformed query column filter");
1332
- checkConditionKeys(filter, ["kind", "value"], "Query column filter");
1349
+ checkPojoKeys(filter, ["kind", "value"], "Query column filter");
1333
1350
  const unary = filter.kind === "is-null" || filter.kind === "not-null";
1334
1351
  if (!unary && (![
1335
1352
  "eq",
@@ -1360,8 +1377,18 @@ function checkCondition(value) {
1360
1377
  if (unary && "value" in filter) require_utils.fail("Unary query filters do not accept values");
1361
1378
  } else require_utils.fail("Unknown query condition");
1362
1379
  }
1363
- /** Conditions use own enumerable POJO fields, with predicate-brand and SQL-resolver symbols allowed. */
1364
- function checkConditionKeys(value, allowed, description) {
1380
+ /**
1381
+ * Accepts only own enumerable POJO fields, so nothing a caller supplied can be silently ignored: the
1382
+ * compilers read these POJOs back with `Object.entries`/`Object.keys`, which skip inherited,
1383
+ * non-enumerable, and symbol keys, so a field hidden behind one of those would never reach the SQL.
1384
+ * I.e. an UPDATE whose `set` carries `title` on a prototype would leave `title` unchanged and still
1385
+ * report success.
1386
+ *
1387
+ * Conditions, mutation clauses, and assignment POJOs all share this rule; `allowed` may include symbol
1388
+ * keys, i.e. a condition's predicate brand and SQL resolver. Read-query clauses instead use
1389
+ * `validateQueryKeys`, which walks the prototype chain and reports mutation clauses by name.
1390
+ */
1391
+ function checkPojoKeys(value, allowed, description) {
1365
1392
  if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) require_utils.fail(`${description} must be a plain POJO`);
1366
1393
  for (const key of Reflect.ownKeys(value)) {
1367
1394
  if (!allowed.includes(key)) require_utils.fail(`${description} does not support '${String(key)}'`);
@@ -1512,6 +1539,24 @@ function withEntryHandle(entry) {
1512
1539
  return readValueHandle(entry);
1513
1540
  }
1514
1541
  /**
1542
+ * Puts a statement's surviving `with` entries in front of it, dropping the ones nothing reads.
1543
+ *
1544
+ * `referenced` is the aliases the rest of the statement used. The WITH clause leads the statement, so
1545
+ * its bindings lead the statement's bindings too.
1546
+ */
1547
+ function prependCtes(ctes, referenced, sql, bindings) {
1548
+ const kept = pruneCtes(ctes, referenced);
1549
+ if (kept.length === 0) return {
1550
+ sql,
1551
+ bindings
1552
+ };
1553
+ const clause = withFragment(kept);
1554
+ return {
1555
+ sql: clause.sql + sql,
1556
+ bindings: [...clause.bindings, ...bindings]
1557
+ };
1558
+ }
1559
+ /**
1515
1560
  * Drops the CTEs that nothing reads, given the aliases the rest of the statement referenced.
1516
1561
  *
1517
1562
  * A CTE can only read earlier siblings, so going last to first means every CTE that could read this one
@@ -1590,12 +1635,14 @@ function typedSql(strings, ...values) {
1590
1635
  //#endregion
1591
1636
  exports.Ctx = Ctx;
1592
1637
  exports.SubqueryHandle = SubqueryHandle;
1638
+ exports.checkPojoKeys = checkPojoKeys;
1593
1639
  exports.conditionToSql = conditionToSql;
1594
1640
  exports.entityQueryBrand = entityQueryBrand;
1595
1641
  exports.injectedConditions = injectedConditions;
1596
1642
  exports.isReadQueryValue = isReadQueryValue;
1597
1643
  exports.parseNestedQuery = parseNestedQuery;
1598
- exports.parseUserQuery = parseUserQuery;
1644
+ exports.parseRootQuery = parseRootQuery;
1645
+ exports.prependCtes = prependCtes;
1599
1646
  exports.projectionToSql = projectionToSql;
1600
1647
  exports.pruneCtes = pruneCtes;
1601
1648
  exports.query = query;