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.
- package/build/EntityManager.cjs +25 -11
- package/build/EntityManager.cjs.map +1 -1
- package/build/EntityManager.d.cts +11 -4
- package/build/EntityManager.d.cts.map +1 -1
- package/build/EntityManager.d.mts +11 -4
- package/build/EntityManager.d.mts.map +1 -1
- package/build/EntityManager.js +25 -13
- package/build/EntityManager.js.map +1 -1
- package/build/EntityMetadata.cjs +0 -1
- package/build/EntityMetadata.cjs.map +1 -1
- package/build/EntityMetadata.d.cts +8 -4
- package/build/EntityMetadata.d.cts.map +1 -1
- package/build/EntityMetadata.d.mts +8 -4
- package/build/EntityMetadata.d.mts.map +1 -1
- package/build/EntityMetadata.js +0 -1
- package/build/EntityMetadata.js.map +1 -1
- package/build/IndexManager.cjs +23 -5
- package/build/IndexManager.cjs.map +1 -1
- package/build/IndexManager.d.cts.map +1 -1
- package/build/IndexManager.d.mts.map +1 -1
- package/build/IndexManager.js +23 -5
- package/build/IndexManager.js.map +1 -1
- package/build/batchloaders/populateBatchLoader.cjs +2 -2
- package/build/batchloaders/populateBatchLoader.js +2 -2
- package/build/batchloaders/recursiveChildrenBatchLoader.cjs +1 -1
- package/build/batchloaders/recursiveChildrenBatchLoader.js +1 -1
- package/build/batchloaders/recursiveM2mBatchLoader.cjs +1 -1
- package/build/batchloaders/recursiveM2mBatchLoader.js +1 -1
- package/build/batchloaders/recursiveParentsBatchLoader.cjs +1 -1
- package/build/batchloaders/recursiveParentsBatchLoader.js +1 -1
- package/build/config.cjs +74 -1
- package/build/config.cjs.map +1 -1
- package/build/config.d.cts +83 -2
- package/build/config.d.cts.map +1 -1
- package/build/config.d.mts +83 -2
- package/build/config.d.mts.map +1 -1
- package/build/config.js +74 -1
- package/build/config.js.map +1 -1
- package/build/configure.cjs +6 -2
- package/build/configure.cjs.map +1 -1
- package/build/configure.d.cts.map +1 -1
- package/build/configure.d.mts.map +1 -1
- package/build/configure.js +6 -2
- package/build/configure.js.map +1 -1
- package/build/dataloaders/findDataLoader.cjs +1 -1
- package/build/dataloaders/findDataLoader.js +1 -1
- package/build/dataloaders/findOrCreateDataLoader.cjs +6 -2
- package/build/dataloaders/findOrCreateDataLoader.cjs.map +1 -1
- package/build/dataloaders/findOrCreateDataLoader.d.cts.map +1 -1
- package/build/dataloaders/findOrCreateDataLoader.d.mts.map +1 -1
- package/build/dataloaders/findOrCreateDataLoader.js +7 -3
- package/build/dataloaders/findOrCreateDataLoader.js.map +1 -1
- package/build/dataloaders/findPaginatedDataLoader.cjs +1 -1
- package/build/dataloaders/findPaginatedDataLoader.js +1 -1
- package/build/defaults.cjs +2 -2
- package/build/defaults.js +2 -2
- package/build/fields.cjs +1 -0
- package/build/fields.cjs.map +1 -1
- package/build/fields.d.cts.map +1 -1
- package/build/fields.d.mts.map +1 -1
- package/build/fields.js +1 -0
- package/build/fields.js.map +1 -1
- package/build/index.cjs +13 -8
- package/build/index.cjs.map +1 -1
- package/build/index.d.cts +4 -3
- package/build/index.d.cts.map +1 -1
- package/build/index.d.mts +4 -3
- package/build/index.d.mts.map +1 -1
- package/build/index.js +13 -10
- package/build/index.js.map +1 -1
- package/build/json.cjs +3 -3
- package/build/json.js +3 -3
- package/build/loading/loadHints.cjs +1 -1
- package/build/loading/loadHints.js +1 -1
- package/build/loading/withLoaded.cjs +2 -2
- package/build/loading/withLoaded.js +2 -2
- package/build/newTestInstance.cjs +1 -0
- package/build/newTestInstance.cjs.map +1 -1
- package/build/newTestInstance.d.cts.map +1 -1
- package/build/newTestInstance.d.mts.map +1 -1
- package/build/newTestInstance.js +1 -0
- package/build/newTestInstance.js.map +1 -1
- package/build/preloading/partitionHint.cjs +1 -1
- package/build/preloading/partitionHint.js +1 -1
- package/build/queries/sql/execute.cjs +68 -89
- package/build/queries/sql/execute.cjs.map +1 -1
- package/build/queries/sql/execute.d.cts +35 -18
- package/build/queries/sql/execute.d.cts.map +1 -1
- package/build/queries/sql/execute.d.mts +35 -18
- package/build/queries/sql/execute.d.mts.map +1 -1
- package/build/queries/sql/execute.js +70 -91
- package/build/queries/sql/execute.js.map +1 -1
- package/build/queries/sql/query.cjs +77 -30
- package/build/queries/sql/query.cjs.map +1 -1
- package/build/queries/sql/query.d.cts +64 -21
- package/build/queries/sql/query.d.cts.map +1 -1
- package/build/queries/sql/query.d.mts +64 -21
- package/build/queries/sql/query.d.mts.map +1 -1
- package/build/queries/sql/query.js +75 -30
- package/build/queries/sql/query.js.map +1 -1
- package/build/reactivity/ReactionsManager.cjs +168 -2
- package/build/reactivity/ReactionsManager.cjs.map +1 -1
- package/build/reactivity/ReactionsManager.d.cts +54 -1
- package/build/reactivity/ReactionsManager.d.cts.map +1 -1
- package/build/reactivity/ReactionsManager.d.mts +54 -1
- package/build/reactivity/ReactionsManager.d.mts.map +1 -1
- package/build/reactivity/ReactionsManager.js +169 -3
- package/build/reactivity/ReactionsManager.js.map +1 -1
- package/build/reactivity/reactiveHints.cjs +3 -3
- package/build/reactivity/reactiveHints.cjs.map +1 -1
- package/build/reactivity/reactiveHints.d.cts.map +1 -1
- package/build/reactivity/reactiveHints.d.mts.map +1 -1
- package/build/reactivity/reactiveHints.js +3 -3
- package/build/reactivity/reactiveHints.js.map +1 -1
- package/build/relations/AsyncReactiveField.cjs +3 -3
- package/build/relations/AsyncReactiveField.js +3 -3
- package/build/relations/LazyField.cjs +14 -0
- package/build/relations/LazyField.cjs.map +1 -1
- package/build/relations/LazyField.d.cts +6 -0
- package/build/relations/LazyField.d.cts.map +1 -1
- package/build/relations/LazyField.d.mts +6 -0
- package/build/relations/LazyField.d.mts.map +1 -1
- package/build/relations/LazyField.js +14 -0
- package/build/relations/LazyField.js.map +1 -1
- package/build/relations/ReactiveField.cjs +2 -2
- package/build/relations/ReactiveField.js +2 -2
- package/build/relations/ReactiveManyToMany.cjs +1 -1
- package/build/relations/ReactiveManyToMany.js +1 -1
- package/build/relations/ReactiveReference.cjs +1 -1
- package/build/relations/ReactiveReference.js +1 -1
- package/build/relations/RecursiveCollection.cjs +3 -3
- package/build/relations/RecursiveCollection.js +3 -3
- package/build/relations/hasProperty.cjs +2 -2
- package/build/relations/hasProperty.js +2 -2
- package/build/relations/index.cjs +5 -5
- package/build/relations/index.js +5 -5
- package/build/resurrection.cjs +11 -1
- package/build/resurrection.cjs.map +1 -1
- package/build/resurrection.d.cts +4 -1
- package/build/resurrection.d.cts.map +1 -1
- package/build/resurrection.d.mts +4 -1
- package/build/resurrection.d.mts.map +1 -1
- package/build/resurrection.js +11 -2
- package/build/resurrection.js.map +1 -1
- package/build/transitions.cjs +89 -0
- package/build/transitions.cjs.map +1 -0
- package/build/transitions.d.cts +110 -0
- package/build/transitions.d.cts.map +1 -0
- package/build/transitions.d.mts +110 -0
- package/build/transitions.d.mts.map +1 -0
- package/build/transitions.js +84 -0
- package/build/transitions.js.map +1 -0
- 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
|
|
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.
|
|
231
|
-
*
|
|
232
|
-
*
|
|
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
|
|
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(`
|
|
254
|
+
return this.output().columns.find(([name]) => name === key)?.[1] ?? fail(`Query value ${this.describe()} has no column ${key}`);
|
|
250
255
|
}
|
|
251
|
-
/**
|
|
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 =
|
|
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 =
|
|
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
|
|
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 `
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
/**
|
|
1363
|
-
|
|
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,
|
|
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
|