joist-core 2.3.0-next.99 → 2.4.0
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 +1 -1
- package/build/EntityManager.cjs.map +1 -1
- package/build/EntityManager.d.cts +9 -8
- package/build/EntityManager.d.cts.map +1 -1
- package/build/EntityManager.d.mts +9 -8
- package/build/EntityManager.d.mts.map +1 -1
- package/build/EntityManager.js +1 -1
- package/build/EntityManager.js.map +1 -1
- package/build/dataloaders/findCountDataLoader.cjs +2 -0
- package/build/dataloaders/findCountDataLoader.cjs.map +1 -1
- package/build/dataloaders/findCountDataLoader.d.cts.map +1 -1
- package/build/dataloaders/findCountDataLoader.d.mts.map +1 -1
- package/build/dataloaders/findCountDataLoader.js +2 -0
- package/build/dataloaders/findCountDataLoader.js.map +1 -1
- package/build/dataloaders/findDataLoader.cjs +1 -0
- package/build/dataloaders/findDataLoader.cjs.map +1 -1
- package/build/dataloaders/findDataLoader.d.cts.map +1 -1
- package/build/dataloaders/findDataLoader.d.mts.map +1 -1
- package/build/dataloaders/findDataLoader.js +2 -1
- package/build/dataloaders/findDataLoader.js.map +1 -1
- package/build/dataloaders/findIdsDataLoader.cjs +2 -0
- package/build/dataloaders/findIdsDataLoader.cjs.map +1 -1
- package/build/dataloaders/findIdsDataLoader.d.cts.map +1 -1
- package/build/dataloaders/findIdsDataLoader.d.mts.map +1 -1
- package/build/dataloaders/findIdsDataLoader.js +2 -0
- package/build/dataloaders/findIdsDataLoader.js.map +1 -1
- package/build/dataloaders/findPaginatedDataLoader.cjs +2 -0
- package/build/dataloaders/findPaginatedDataLoader.cjs.map +1 -1
- package/build/dataloaders/findPaginatedDataLoader.d.cts.map +1 -1
- package/build/dataloaders/findPaginatedDataLoader.d.mts.map +1 -1
- package/build/dataloaders/findPaginatedDataLoader.js +2 -0
- package/build/dataloaders/findPaginatedDataLoader.js.map +1 -1
- package/build/index.cjs +6 -3
- package/build/index.cjs.map +1 -1
- package/build/index.d.cts +6 -4
- package/build/index.d.cts.map +1 -1
- package/build/index.d.mts +6 -4
- package/build/index.d.mts.map +1 -1
- package/build/index.js +6 -5
- package/build/index.js.map +1 -1
- package/build/keys.cjs +6 -1
- package/build/keys.cjs.map +1 -1
- package/build/keys.d.cts +3 -1
- package/build/keys.d.cts.map +1 -1
- package/build/keys.d.mts +3 -1
- package/build/keys.d.mts.map +1 -1
- package/build/keys.js +6 -2
- package/build/keys.js.map +1 -1
- package/build/queries/find/QueryParser.cjs +1 -2
- package/build/queries/find/QueryParser.cjs.map +1 -1
- package/build/queries/find/QueryParser.d.cts.map +1 -1
- package/build/queries/find/QueryParser.d.mts.map +1 -1
- package/build/queries/find/QueryParser.js +2 -3
- package/build/queries/find/QueryParser.js.map +1 -1
- package/build/queries/find/QueryVisitor.cjs +17 -0
- package/build/queries/find/QueryVisitor.cjs.map +1 -1
- package/build/queries/find/QueryVisitor.d.cts +3 -1
- package/build/queries/find/QueryVisitor.d.cts.map +1 -1
- package/build/queries/find/QueryVisitor.d.mts +3 -1
- package/build/queries/find/QueryVisitor.d.mts.map +1 -1
- package/build/queries/find/QueryVisitor.js +17 -1
- package/build/queries/find/QueryVisitor.js.map +1 -1
- package/build/queries/sql/Expr.cjs +18 -1
- package/build/queries/sql/Expr.cjs.map +1 -1
- package/build/queries/sql/Expr.d.cts +13 -3
- package/build/queries/sql/Expr.d.cts.map +1 -1
- package/build/queries/sql/Expr.d.mts +13 -3
- package/build/queries/sql/Expr.d.mts.map +1 -1
- package/build/queries/sql/Expr.js +18 -2
- package/build/queries/sql/Expr.js.map +1 -1
- package/build/queries/sql/JoinTree.cjs +72 -0
- package/build/queries/sql/JoinTree.cjs.map +1 -0
- package/build/queries/sql/JoinTree.d.cts +107 -0
- package/build/queries/sql/JoinTree.d.cts.map +1 -0
- package/build/queries/sql/JoinTree.d.mts +107 -0
- package/build/queries/sql/JoinTree.d.mts.map +1 -0
- package/build/queries/sql/JoinTree.js +71 -0
- package/build/queries/sql/JoinTree.js.map +1 -0
- package/build/queries/sql/Tables.cjs +103 -6
- package/build/queries/sql/Tables.cjs.map +1 -1
- package/build/queries/sql/Tables.d.cts +72 -13
- package/build/queries/sql/Tables.d.cts.map +1 -1
- package/build/queries/sql/Tables.d.mts +72 -13
- package/build/queries/sql/Tables.d.mts.map +1 -1
- package/build/queries/sql/Tables.js +101 -10
- package/build/queries/sql/Tables.js.map +1 -1
- package/build/queries/sql/custom.cjs +52 -0
- package/build/queries/sql/custom.cjs.map +1 -0
- package/build/queries/sql/custom.d.cts +85 -0
- package/build/queries/sql/custom.d.cts.map +1 -0
- package/build/queries/sql/custom.d.mts +85 -0
- package/build/queries/sql/custom.d.mts.map +1 -0
- package/build/queries/sql/custom.js +49 -0
- package/build/queries/sql/custom.js.map +1 -0
- package/build/queries/sql/execute.cjs +68 -28
- package/build/queries/sql/execute.cjs.map +1 -1
- package/build/queries/sql/execute.d.cts +110 -11
- package/build/queries/sql/execute.d.cts.map +1 -1
- package/build/queries/sql/execute.d.mts +110 -11
- package/build/queries/sql/execute.d.mts.map +1 -1
- package/build/queries/sql/execute.js +69 -29
- package/build/queries/sql/execute.js.map +1 -1
- package/build/queries/sql/expressions/types.d.cts +5 -5
- package/build/queries/sql/expressions/types.d.cts.map +1 -1
- package/build/queries/sql/expressions/types.d.mts +5 -5
- package/build/queries/sql/expressions/types.d.mts.map +1 -1
- package/build/queries/sql/keywords.cjs +1 -1
- package/build/queries/sql/keywords.cjs.map +1 -1
- package/build/queries/sql/keywords.d.cts +1 -1
- package/build/queries/sql/keywords.d.mts +1 -1
- package/build/queries/sql/keywords.js +1 -1
- package/build/queries/sql/keywords.js.map +1 -1
- package/build/queries/sql/query.cjs +100 -38
- package/build/queries/sql/query.cjs.map +1 -1
- package/build/queries/sql/query.d.cts +96 -46
- package/build/queries/sql/query.d.cts.map +1 -1
- package/build/queries/sql/query.d.mts +96 -46
- package/build/queries/sql/query.d.mts.map +1 -1
- package/build/queries/sql/query.js +102 -40
- package/build/queries/sql/query.js.map +1 -1
- package/build/queries/valueFilters.cjs +28 -36
- package/build/queries/valueFilters.cjs.map +1 -1
- package/build/queries/valueFilters.d.cts +2 -4
- package/build/queries/valueFilters.d.cts.map +1 -1
- package/build/queries/valueFilters.d.mts +2 -4
- package/build/queries/valueFilters.d.mts.map +1 -1
- package/build/queries/valueFilters.js +29 -36
- package/build/queries/valueFilters.js.map +1 -1
- package/build/serde/serde.cjs.map +1 -1
- package/build/serde/serde.js.map +1 -1
- package/package.json +2 -2
|
@@ -13,6 +13,7 @@ const require_queries_renderConditions = require("../renderConditions.cjs");
|
|
|
13
13
|
const require_queries_sql_AliasAssigner = require("./AliasAssigner.cjs");
|
|
14
14
|
const require_queries_sql_Tables = require("./Tables.cjs");
|
|
15
15
|
const require_queries_sql_expressions_expression = require("./expressions/expression.cjs");
|
|
16
|
+
const require_queries_sql_JoinTree = require("./JoinTree.cjs");
|
|
16
17
|
//#region src/queries/sql/query.ts
|
|
17
18
|
/**
|
|
18
19
|
* `em.query`: SQL-shaped queries as plain object literals.
|
|
@@ -28,10 +29,10 @@ const require_queries_sql_expressions_expression = require("./expressions/expres
|
|
|
28
29
|
* select: { name: a.first_name, n: bookStats.n },
|
|
29
30
|
* orderBy: { n: "DESC" },
|
|
30
31
|
* });
|
|
31
|
-
* // rows: { name: string; n: number |
|
|
32
|
+
* // rows: { name: string; n: number | undefined }[] (undefined because of the LEFT join)
|
|
32
33
|
*
|
|
33
|
-
* `em.query(pojo)` runs it. `select` decides the row type: a bare table returns entities,
|
|
34
|
-
* `{ key: expr }` object returns typed POJOs, a bare subquery returns
|
|
34
|
+
* `em.query(pojo)` runs it. `select` decides the row type: a bare table returns entities, an array of
|
|
35
|
+
* columns or a `{ key: expr }` object returns typed POJOs, and a bare subquery returns its rows.
|
|
35
36
|
*
|
|
36
37
|
* `query(pojo)` turns the *same* POJO into a value: a derived table with typed columns, a scalar
|
|
37
38
|
* expression, or an entity list. It is the one non-POJO step, and the subquery analog of `table(Author)`:
|
|
@@ -51,24 +52,26 @@ const subqueryBrand = Symbol("joist.subquery");
|
|
|
51
52
|
const entityQueryBrand = Symbol("joist.entityQuery");
|
|
52
53
|
const scalarQueryBrand = Symbol("joist.scalarQuery");
|
|
53
54
|
function query(q) {
|
|
54
|
-
|
|
55
|
-
const output = handle.output();
|
|
56
|
-
if (output.kind === "entity") return { [entityQueryBrand]: handle };
|
|
57
|
-
else if (output.kind === "scalar") return new SubqueryExpr(handle);
|
|
58
|
-
else return newSubqueryProxy(handle);
|
|
55
|
+
return createQueryValue(q);
|
|
59
56
|
}
|
|
60
57
|
/**
|
|
61
|
-
* Builds a query value only when its user-supplied `where`
|
|
58
|
+
* Builds a query value only when its user-supplied `where` or join-tree filters survive pruning.
|
|
62
59
|
*
|
|
63
60
|
* Missing or empty conditions prune the value, including nested groups and `pruneIfUndefined`.
|
|
64
|
-
*
|
|
61
|
+
* Alias-only joins, HAVING, and implicit soft-delete/STI conditions do not keep the value alive.
|
|
65
62
|
*
|
|
66
63
|
* I.e. `queryMaybe({ from: b, where: b.authorId.eq(enabled ? a.id : undefined), select: b.id })`
|
|
67
64
|
* returns `undefined` when `enabled` is false, so an enclosing `notExists` also prunes.
|
|
68
65
|
*/
|
|
69
66
|
function queryMaybe(q) {
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
return createMaybeQueryValue(q);
|
|
68
|
+
}
|
|
69
|
+
/** Applies queryMaybe's structural pruning before creating any kind of read-query value. */
|
|
70
|
+
function createMaybeQueryValue(q) {
|
|
71
|
+
const normalized = normalizeQueryJoins(q);
|
|
72
|
+
const where = normalizeWhere(normalized.where);
|
|
73
|
+
checkCondition(where);
|
|
74
|
+
return isPrunedQueryCondition(where) ? void 0 : createQueryValue(normalized);
|
|
72
75
|
}
|
|
73
76
|
/**
|
|
74
77
|
* Declares a `WITH RECURSIVE` CTE from its two terms, and returns the CTE as a readable value.
|
|
@@ -123,9 +126,9 @@ function recursiveQuery(name, base, step, opts = {}) {
|
|
|
123
126
|
* // Selecting this expression keeps the join to Book b.
|
|
124
127
|
* sql.number`${b.order} * ${2}`
|
|
125
128
|
*
|
|
126
|
-
* // Reference an unmodeled column;
|
|
127
|
-
*
|
|
128
|
-
* sql.condition`${
|
|
129
|
+
* // Reference an unmodeled column; prefer the table's own `column`, which keeps its source key.
|
|
130
|
+
* a.column<string>("ts_search")
|
|
131
|
+
* sql.condition`${a.column("ts_search")} @@ plainto_tsquery(${term})`
|
|
129
132
|
* ```
|
|
130
133
|
*/
|
|
131
134
|
function sql(strings, ...values) {
|
|
@@ -159,10 +162,6 @@ sql.booleanArrayOrNull = typedSql;
|
|
|
159
162
|
sql.condition = function condition(strings, ...values) {
|
|
160
163
|
return require_queries_sql_Expr.deferredCondition((ctx) => new require_queries_sql_Expr.TemplateExpr(strings, values).toSql(ctx));
|
|
161
164
|
};
|
|
162
|
-
/** A column Joist does not model, on a source that is in the query. */
|
|
163
|
-
sql.ref = function ref(source, column) {
|
|
164
|
-
return new require_queries_sql_Expr.RefExpr(handleOf(source), column);
|
|
165
|
-
};
|
|
166
165
|
/**
|
|
167
166
|
* Parses `arg` (a `Query` POJO or `query(...)` value) into a runnable `Plan`.
|
|
168
167
|
*
|
|
@@ -189,8 +188,8 @@ function isReadQueryValue(arg) {
|
|
|
189
188
|
* Compiles scalar or nonempty named expression projections, shared by SELECT and mutation RETURNING.
|
|
190
189
|
* Source-shaped values need read hydration/source rules and are deliberately excluded here.
|
|
191
190
|
*/
|
|
192
|
-
function projectionToSql(select, ctx) {
|
|
193
|
-
const output = projectionOutput(select);
|
|
191
|
+
function projectionToSql(select, ctx, joins) {
|
|
192
|
+
const output = joinedOutput(projectionOutput(select), joins);
|
|
194
193
|
if (output.kind === "scalar") {
|
|
195
194
|
const expr = output.columns[0][1];
|
|
196
195
|
const fragment = expr.toSql(ctx);
|
|
@@ -199,7 +198,7 @@ function projectionToSql(select, ctx) {
|
|
|
199
198
|
...fragment,
|
|
200
199
|
sql: `${fragment.sql} AS value`
|
|
201
200
|
}],
|
|
202
|
-
decodeRows: (_, rows) => rows.map((row) => expr
|
|
201
|
+
decodeRows: (_, rows) => rows.map((row) => decodeValue(expr, row.value)),
|
|
203
202
|
output
|
|
204
203
|
};
|
|
205
204
|
}
|
|
@@ -272,6 +271,9 @@ var SubqueryColumnExpr = class extends require_queries_sql_Expr.BaseExpr {
|
|
|
272
271
|
this.key = key;
|
|
273
272
|
this.inner = inner;
|
|
274
273
|
}
|
|
274
|
+
get [require_queries_sql_Expr.selectKeyBrand]() {
|
|
275
|
+
return this.key;
|
|
276
|
+
}
|
|
275
277
|
toSql(ctx) {
|
|
276
278
|
const alias = ctx.aliasFor(this.handle);
|
|
277
279
|
return {
|
|
@@ -501,6 +503,7 @@ function queryOutput(q) {
|
|
|
501
503
|
columns
|
|
502
504
|
};
|
|
503
505
|
}
|
|
506
|
+
q = normalizeQueryJoins(q);
|
|
504
507
|
const { select } = q;
|
|
505
508
|
if (require_queries_sql_Tables.isTable(select)) return {
|
|
506
509
|
kind: "entity",
|
|
@@ -515,6 +518,20 @@ function projectionOutput(select) {
|
|
|
515
518
|
kind: "scalar",
|
|
516
519
|
columns: [["value", asExpr(select, "select")]]
|
|
517
520
|
};
|
|
521
|
+
if (Array.isArray(select)) {
|
|
522
|
+
if (select.length === 0) require_utils.fail("A column array projection must not be empty");
|
|
523
|
+
const columns = select.map((value, index) => {
|
|
524
|
+
const expr = asExpr(value, `select[${index}]`);
|
|
525
|
+
const key = expr[require_queries_sql_Expr.selectKeyBrand];
|
|
526
|
+
if (typeof key !== "string") require_utils.fail(`select[${index}] must be a physical or subquery column`);
|
|
527
|
+
return [key, expr];
|
|
528
|
+
});
|
|
529
|
+
if (new Set(columns.map(([key]) => key)).size !== columns.length) require_utils.fail("A column array projection must not contain duplicate field names");
|
|
530
|
+
return {
|
|
531
|
+
kind: "pojo",
|
|
532
|
+
columns
|
|
533
|
+
};
|
|
534
|
+
}
|
|
518
535
|
if (isPlainSelect(select)) {
|
|
519
536
|
const columns = [];
|
|
520
537
|
for (const key of Reflect.ownKeys(select)) {
|
|
@@ -530,7 +547,7 @@ function projectionOutput(select) {
|
|
|
530
547
|
return require_utils.fail("Expected a scalar expression or a nonempty named expression projection");
|
|
531
548
|
}
|
|
532
549
|
/**
|
|
533
|
-
* Adds
|
|
550
|
+
* Adds SQL nullability from unmatched LEFT joins without mutating shared expressions or their codecs.
|
|
534
551
|
* Only direct columns carry sqlSource; COUNT and COALESCE retain their own SQL nullability.
|
|
535
552
|
* I.e. selecting Book.title from a LEFT-joined Book makes its output nullable, but COUNT(Book.id) stays NOT NULL.
|
|
536
553
|
*/
|
|
@@ -638,7 +655,7 @@ function parseSetQuery(q, parent, assigner, recursiveSelf) {
|
|
|
638
655
|
bindings,
|
|
639
656
|
outerRefs: [...new Set(outerRefs.filter((ref) => !cteAliases.has(ref)))],
|
|
640
657
|
output,
|
|
641
|
-
decodeRows:
|
|
658
|
+
decodeRows: (_, rows) => rows.map((row) => decodeRow(row, output.columns))
|
|
642
659
|
};
|
|
643
660
|
}
|
|
644
661
|
/** Validate and quote only named set output sorts, including before a reusable value is parsed. */
|
|
@@ -777,6 +794,7 @@ function describeHandle(handle) {
|
|
|
777
794
|
function parseQuery(q, parent, assigner, recursiveSelf) {
|
|
778
795
|
validateReadQuery(q);
|
|
779
796
|
if (isSetQuery(q)) return parseSetQuery(q, parent, assigner, recursiveSelf);
|
|
797
|
+
q = normalizeQueryJoins(q);
|
|
780
798
|
const ctx = new Ctx(assigner, parent);
|
|
781
799
|
if (recursiveSelf) ctx.setRecursiveSelf(recursiveSelf);
|
|
782
800
|
const joinEntries = resolveReferenceJoins(q.join);
|
|
@@ -824,7 +842,8 @@ function parseQuery(q, parent, assigner, recursiveSelf) {
|
|
|
824
842
|
const sti = stiEntityPlan(q, from);
|
|
825
843
|
const { selects, decodeRows, output } = selectsToSql(q, ctx, from, cti.selects ?? sti.selects);
|
|
826
844
|
const fromInjected = [...injectedConditions(from, softDeletes), ...sti.conditions];
|
|
827
|
-
const
|
|
845
|
+
const predicate = normalizeWhere(q.where);
|
|
846
|
+
const where = conditionToSql(fromInjected.length > 0 ? { and: [predicate, ...fromInjected] } : predicate, ctx, true);
|
|
828
847
|
const having = conditionToSql(q.having, ctx, true);
|
|
829
848
|
const groupBys = (q.groupBy ?? []).map((g) => asExpr(g, "groupBy").toSql(ctx));
|
|
830
849
|
const orderBys = orderBysToSql(q, ctx);
|
|
@@ -937,15 +956,17 @@ function registerSource(source, ctx, assigner) {
|
|
|
937
956
|
};
|
|
938
957
|
};
|
|
939
958
|
} else {
|
|
940
|
-
const
|
|
941
|
-
const
|
|
959
|
+
const mgmt = require_queries_sql_Tables.getTableMgmt(source);
|
|
960
|
+
const { tableName } = mgmt;
|
|
961
|
+
const meta = "meta" in mgmt ? mgmt.meta : void 0;
|
|
962
|
+
const alias = assigner.getAlias(tableName);
|
|
942
963
|
ctx.register(handle, alias);
|
|
943
964
|
return () => {
|
|
944
|
-
const entitySelects = meta.hasLazyColumns ? require_queries_entityQueryUtils.lazyExcludedSelects(meta, alias) : [require_queries_sql_keywords.kqStar(alias)];
|
|
965
|
+
const entitySelects = !meta ? [] : meta.hasLazyColumns ? require_queries_entityQueryUtils.lazyExcludedSelects(meta, alias) : [require_queries_sql_keywords.kqStar(alias)];
|
|
945
966
|
return {
|
|
946
967
|
handle,
|
|
947
968
|
alias,
|
|
948
|
-
sql: `${
|
|
969
|
+
sql: `${require_queries_sql_Tables.tableSqlName(mgmt)} AS ${require_queries_sql_keywords.kq(alias)}`,
|
|
949
970
|
bindings: [],
|
|
950
971
|
refs: [],
|
|
951
972
|
entitySelects,
|
|
@@ -997,7 +1018,8 @@ function registerJoinTable(handle, ctx, assigner) {
|
|
|
997
1018
|
/** Generates the `select` clause SQL and returns how to decode the resulting rows. */
|
|
998
1019
|
function selectsToSql(q, ctx, from, entitySelects) {
|
|
999
1020
|
const { select } = q;
|
|
1000
|
-
if (require_queries_sql_Tables.isTable(select))
|
|
1021
|
+
if (require_queries_sql_Tables.isTable(select) && !require_queries_sql_Tables.isEntityTable(select)) require_utils.fail("A custom table cannot be selected as an entity; select its columns individually");
|
|
1022
|
+
if (require_queries_sql_Tables.isEntityTable(select)) {
|
|
1001
1023
|
if (from.handle !== require_queries_sql_Tables.getTableMgmt(select)) require_utils.fail("Selecting a joined table is not supported yet; select the from table, or select its columns individually");
|
|
1002
1024
|
const alias = ctx.aliasFor(require_queries_sql_Tables.getTableMgmt(select));
|
|
1003
1025
|
const meta = require_queries_sql_Tables.getTableMetadata(select);
|
|
@@ -1028,9 +1050,7 @@ function selectsToSql(q, ctx, from, entitySelects) {
|
|
|
1028
1050
|
output
|
|
1029
1051
|
};
|
|
1030
1052
|
}
|
|
1031
|
-
|
|
1032
|
-
projection.output = joinedOutput(projection.output, q.join);
|
|
1033
|
-
return projection;
|
|
1053
|
+
return projectionToSql(select, ctx, q.join);
|
|
1034
1054
|
}
|
|
1035
1055
|
/**
|
|
1036
1056
|
* Builds the mandatory CTI joins and flat row projection needed by entity hydration.
|
|
@@ -1041,7 +1061,7 @@ function selectsToSql(q, ctx, from, entitySelects) {
|
|
|
1041
1061
|
* `_sN` aliases can be made unique before their projection fragments are built.
|
|
1042
1062
|
*/
|
|
1043
1063
|
function ctiEntityPlan(q, from, assigner) {
|
|
1044
|
-
if (!require_queries_sql_Tables.
|
|
1064
|
+
if (!require_queries_sql_Tables.isEntityTable(q.select) || from.handle !== require_queries_sql_Tables.getTableMgmt(q.select)) return {
|
|
1045
1065
|
joins: [],
|
|
1046
1066
|
selects: void 0
|
|
1047
1067
|
};
|
|
@@ -1103,7 +1123,7 @@ function ctiEntityPlan(q, from, assigner) {
|
|
|
1103
1123
|
}
|
|
1104
1124
|
/** Adds the discriminator projection and subtype filter required by STI entity hydration. */
|
|
1105
1125
|
function stiEntityPlan(q, from) {
|
|
1106
|
-
if (!require_queries_sql_Tables.
|
|
1126
|
+
if (!require_queries_sql_Tables.isEntityTable(q.select) || from.handle !== require_queries_sql_Tables.getTableMgmt(q.select)) return {
|
|
1107
1127
|
selects: void 0,
|
|
1108
1128
|
conditions: []
|
|
1109
1129
|
};
|
|
@@ -1169,7 +1189,7 @@ function decodeRow(row, decoders) {
|
|
|
1169
1189
|
const result = {};
|
|
1170
1190
|
for (const [key, expr] of decoders) {
|
|
1171
1191
|
const value = row[key];
|
|
1172
|
-
const decoded =
|
|
1192
|
+
const decoded = decodeValue(expr, value);
|
|
1173
1193
|
if (key === "__proto__") Object.defineProperty(result, key, {
|
|
1174
1194
|
value: decoded,
|
|
1175
1195
|
enumerable: true,
|
|
@@ -1180,6 +1200,10 @@ function decodeRow(row, decoders) {
|
|
|
1180
1200
|
}
|
|
1181
1201
|
return result;
|
|
1182
1202
|
}
|
|
1203
|
+
/** Decodes a top-level projected SQL NULL using Joist's undefined convention. */
|
|
1204
|
+
function decodeValue(expr, value) {
|
|
1205
|
+
return value === null ? void 0 : expr.decode(value);
|
|
1206
|
+
}
|
|
1183
1207
|
const ORDER_BY_DIRECTIONS = [
|
|
1184
1208
|
"ASC",
|
|
1185
1209
|
"DESC",
|
|
@@ -1189,7 +1213,7 @@ const ORDER_BY_DIRECTIONS = [
|
|
|
1189
1213
|
"DESC NULLS LAST"
|
|
1190
1214
|
];
|
|
1191
1215
|
/**
|
|
1192
|
-
* Generates ORDER BY SQL in entry order for keyed/expression arrays or a single
|
|
1216
|
+
* Generates ORDER BY SQL in entry order for keyed/expression arrays or a single entry.
|
|
1193
1217
|
*
|
|
1194
1218
|
* Expression entries retain bindings and alias references for join pruning. Undefined entries and
|
|
1195
1219
|
* directions are omitted before expression references are collected.
|
|
@@ -1218,7 +1242,7 @@ function orderBysToSql(q, ctx) {
|
|
|
1218
1242
|
});
|
|
1219
1243
|
} else {
|
|
1220
1244
|
if (require_queries_sql_Expr.isExpr(select)) return require_utils.fail(`the keyed orderBy form needs a POJO or entity select`);
|
|
1221
|
-
if (!(isSubqueryValue(select) ? select[subqueryBrand].columnKeys() :
|
|
1245
|
+
if (!(isSubqueryValue(select) ? select[subqueryBrand].columnKeys() : projectionOutput(select).columns.map(([key]) => key)).includes(key)) return require_utils.fail(`orderBy key '${key}' is not a key of select`);
|
|
1222
1246
|
result.push({
|
|
1223
1247
|
sql: `${require_queries_sql_keywords.safeKq(key)} ${dir}`,
|
|
1224
1248
|
bindings: [],
|
|
@@ -1261,6 +1285,10 @@ function conditionToSql(cond, ctx, topLevel) {
|
|
|
1261
1285
|
function checkCondition(value) {
|
|
1262
1286
|
if (require_queries_find_DeferredAlias.isDeferredAliasCondition(value) || value && typeof value === "object" && require_queries_conditions.predicateBrand in value && value[require_queries_conditions.predicateBrand] === "domain") require_utils.fail("Domain alias conditions are only supported by em.find; use table(...) predicates in SQL queries and mutations.");
|
|
1263
1287
|
if (value === void 0 || value === require_queries_skipCondition.skipCondition) return;
|
|
1288
|
+
if (isInQueryCondition(value)) {
|
|
1289
|
+
checkCondition(normalizeWhere(normalizeQueryJoins(toQuery(value[require_queries_sql_Tables.inQueryCondition].query)).where));
|
|
1290
|
+
return;
|
|
1291
|
+
}
|
|
1264
1292
|
if (!value || typeof value !== "object" || Array.isArray(value) || require_queries_sql_Expr.isExpr(value)) require_utils.fail("Query predicate must be a condition or an and/or group");
|
|
1265
1293
|
const condition = value;
|
|
1266
1294
|
if ("and" in condition || "or" in condition) {
|
|
@@ -1346,6 +1374,13 @@ function checkConditionKeys(value, allowed, description) {
|
|
|
1346
1374
|
*/
|
|
1347
1375
|
function resolveQueryCondition(cond, ctx) {
|
|
1348
1376
|
if (cond === void 0) return void 0;
|
|
1377
|
+
if (isInQueryCondition(cond)) {
|
|
1378
|
+
const { column, query } = cond[require_queries_sql_Tables.inQueryCondition];
|
|
1379
|
+
const value = createMaybeQueryValue(query);
|
|
1380
|
+
if (value === void 0) return void 0;
|
|
1381
|
+
if (!require_queries_sql_Expr.isExpr(value)) return require_utils.fail("An in query literal must select one expression");
|
|
1382
|
+
return column.in(value);
|
|
1383
|
+
}
|
|
1349
1384
|
if ("and" in cond && cond.and) return {
|
|
1350
1385
|
and: cond.and.map((child) => resolveQueryCondition(child, ctx)),
|
|
1351
1386
|
pruneIfUndefined: cond.pruneIfUndefined
|
|
@@ -1380,6 +1415,7 @@ function isFilter(cond) {
|
|
|
1380
1415
|
*/
|
|
1381
1416
|
function isPrunedQueryCondition(cond) {
|
|
1382
1417
|
if (cond === void 0 || cond === require_queries_skipCondition.skipCondition) return true;
|
|
1418
|
+
if (isInQueryCondition(cond)) return isPrunedQueryCondition(normalizeWhere(normalizeQueryJoins(cond[require_queries_sql_Tables.inQueryCondition].query).where));
|
|
1383
1419
|
if ("and" in cond || "or" in cond) {
|
|
1384
1420
|
const children = (cond.and ?? cond.or ?? []).map(isPrunedQueryCondition);
|
|
1385
1421
|
return children.every((pruned) => pruned) || "pruneIfUndefined" in cond && cond.pruneIfUndefined === "any" && children.some((pruned) => pruned);
|
|
@@ -1388,6 +1424,10 @@ function isPrunedQueryCondition(cond) {
|
|
|
1388
1424
|
if ("notExists" in cond) return cond.notExists === void 0;
|
|
1389
1425
|
return false;
|
|
1390
1426
|
}
|
|
1427
|
+
/** Recognizes the direct query-literal condition created by EntityColumn.in. */
|
|
1428
|
+
function isInQueryCondition(value) {
|
|
1429
|
+
return typeof value === "object" && value !== null && require_queries_sql_Tables.inQueryCondition in value;
|
|
1430
|
+
}
|
|
1391
1431
|
/** The physical source aliases a parsed condition tree references. */
|
|
1392
1432
|
function refsOf(parsed) {
|
|
1393
1433
|
return require_queries_parsedConditions.deepFindConditions(parsed, false).flatMap((c) => c.kind === "column" ? [c.alias] : c.kind === "raw" ? c.aliases : c.outerAliases);
|
|
@@ -1521,6 +1561,28 @@ function joinFragmentParts(parts, sep) {
|
|
|
1521
1561
|
function isDefined(value) {
|
|
1522
1562
|
return value !== void 0;
|
|
1523
1563
|
}
|
|
1564
|
+
/** Lowers a relationship tree before SQL rendering or output nullability is calculated. */
|
|
1565
|
+
function normalizeQueryJoins(q) {
|
|
1566
|
+
if (q.join === void 0 || Array.isArray(q.join)) return q;
|
|
1567
|
+
const tree = require_queries_sql_JoinTree.compileJoinTree(q.from, q.join);
|
|
1568
|
+
return {
|
|
1569
|
+
...q,
|
|
1570
|
+
join: tree.joins,
|
|
1571
|
+
where: { and: [tree.condition, normalizeWhere(q.where)] }
|
|
1572
|
+
};
|
|
1573
|
+
}
|
|
1574
|
+
/** Gives WHERE arrays the same pruning and validation as explicit AND groups. */
|
|
1575
|
+
function normalizeWhere(where) {
|
|
1576
|
+
return Array.isArray(where) ? { and: where } : where;
|
|
1577
|
+
}
|
|
1578
|
+
/** Creates the runtime query value after the public signature has checked its input. */
|
|
1579
|
+
function createQueryValue(q) {
|
|
1580
|
+
const handle = new SubqueryHandle(toQuery(q));
|
|
1581
|
+
const output = handle.output();
|
|
1582
|
+
if (output.kind === "entity") return { [entityQueryBrand]: handle };
|
|
1583
|
+
else if (output.kind === "scalar") return new SubqueryExpr(handle);
|
|
1584
|
+
else return newSubqueryProxy(handle);
|
|
1585
|
+
}
|
|
1524
1586
|
/** Keeps shorthand declarations callable-only, without recursively copying sql's own shorthand properties. */
|
|
1525
1587
|
function typedSql(strings, ...values) {
|
|
1526
1588
|
return new require_queries_sql_Expr.TemplateExpr(strings, values);
|