joist-orm 1.245.1 → 1.246.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/ConditionBuilder.d.ts +50 -0
- package/build/ConditionBuilder.d.ts.map +1 -0
- package/build/ConditionBuilder.js +178 -0
- package/build/ConditionBuilder.js.map +1 -0
- package/build/QueryParser.d.ts +36 -30
- package/build/QueryParser.d.ts.map +1 -1
- package/build/QueryParser.js +18 -175
- package/build/QueryParser.js.map +1 -1
- package/build/QueryParser.pruning.d.ts +5 -0
- package/build/QueryParser.pruning.d.ts.map +1 -0
- package/build/QueryParser.pruning.js +118 -0
- package/build/QueryParser.pruning.js.map +1 -0
- package/build/QueryVisitor.d.ts +3 -2
- package/build/QueryVisitor.d.ts.map +1 -1
- package/build/QueryVisitor.js +37 -9
- package/build/QueryVisitor.js.map +1 -1
- package/build/dataloaders/findCountDataLoader.d.ts.map +1 -1
- package/build/dataloaders/findCountDataLoader.js +32 -25
- package/build/dataloaders/findCountDataLoader.js.map +1 -1
- package/build/dataloaders/findDataLoader.d.ts +7 -14
- package/build/dataloaders/findDataLoader.d.ts.map +1 -1
- package/build/dataloaders/findDataLoader.js +70 -88
- package/build/dataloaders/findDataLoader.js.map +1 -1
- package/build/drivers/buildRawQuery.d.ts.map +1 -1
- package/build/drivers/buildRawQuery.js +20 -7
- package/build/drivers/buildRawQuery.js.map +1 -1
- package/build/drivers/buildUtils.js +1 -4
- package/build/drivers/buildUtils.js.map +1 -1
- package/build/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +4 -2
- package/build/index.js.map +1 -1
- package/build/plugins/PreloadPlugin.d.ts +2 -4
- package/build/plugins/PreloadPlugin.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ExpressionFilter } from "./EntityFilter";
|
|
2
|
+
import { ColumnCondition, ParsedExpressionFilter, ParsedValueFilter, RawCondition } from "./QueryParser";
|
|
3
|
+
import { Column } from "./serde";
|
|
4
|
+
type PartialSome<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
|
5
|
+
/** Converts domain-level values like string ids/enums into their db equivalent. */
|
|
6
|
+
export declare class ConditionBuilder {
|
|
7
|
+
/** Simple, single-column conditions, which will be AND-d together. */
|
|
8
|
+
private conditions;
|
|
9
|
+
/** Complex expressions, which will also be AND-d together with `conditions`. */
|
|
10
|
+
private expressions;
|
|
11
|
+
/** Accepts a raw user-facing DSL filter, and parses it into a `ParsedExpressionFilter`. */
|
|
12
|
+
maybeAddExpression(expression: ExpressionFilter): void;
|
|
13
|
+
/** Adds an already-db-level condition to the simple conditions list. */
|
|
14
|
+
addSimpleCondition(condition: ColumnCondition): void;
|
|
15
|
+
/** Adds an already-db-level condition to the simple conditions list. */
|
|
16
|
+
addRawCondition(condition: PartialSome<RawCondition, "kind" | "bindings">): void;
|
|
17
|
+
/** Adds an already-db-level expression to the expressions list. */
|
|
18
|
+
addParsedExpression(parsed: ParsedExpressionFilter): void;
|
|
19
|
+
/**
|
|
20
|
+
* Adds a user-facing `ParsedValueFilter` to the inline conditions.
|
|
21
|
+
*
|
|
22
|
+
* Unless it's something like `in: [a1, null]`, in which case we split it into two `is-null` and `in` conditions.
|
|
23
|
+
*/
|
|
24
|
+
addValueFilter(alias: string, column: Column, filter: ParsedValueFilter<any>): void;
|
|
25
|
+
/** Combines our collected `conditions` & `expressions` into a single `ParsedExpressionFilter`. */
|
|
26
|
+
toExpressionFilter(): ParsedExpressionFilter | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Finds `child.column.eq(...)` complex conditions that need pushed down into each lateral join.
|
|
29
|
+
*
|
|
30
|
+
* Once we find something like `{ column: "first_name", cond: { eq: "a1" } }`, we return it to the
|
|
31
|
+
* caller (for injection into the lateral join's `SELECT` clause), and replace it with a boolean
|
|
32
|
+
* expression that is basically "did any of my children match this condition?".
|
|
33
|
+
*
|
|
34
|
+
* We also assume that `findAndRewrite` is only called on the top-level/user-facing `ParsedFindQuery`,
|
|
35
|
+
* and not any intermediate `CteJoinTable` queries (which are allowed to have their own
|
|
36
|
+
* `ConditionBuilder`s for building their internal query, but it's not exposed to the user,
|
|
37
|
+
* so won't have any truly-complex conditions that should need rewritten).
|
|
38
|
+
*
|
|
39
|
+
* @param topLevelLateralJoin the outermost lateral join alias, as that will be the only alias
|
|
40
|
+
* that is visible to the rewritten condition, i.e. `_alias._whatever_condition_`.
|
|
41
|
+
* @param alias the alias being "hidden" in a lateral join, and so its columns/data won't be
|
|
42
|
+
* available for the top-level condition to directly AND/OR against.
|
|
43
|
+
*/
|
|
44
|
+
findAndRewrite(topLevelLateralJoin: string, alias: string): {
|
|
45
|
+
cond: ColumnCondition;
|
|
46
|
+
as: string;
|
|
47
|
+
}[];
|
|
48
|
+
}
|
|
49
|
+
export {};
|
|
50
|
+
//# sourceMappingURL=ConditionBuilder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConditionBuilder.d.ts","sourceRoot":"","sources":["../src/ConditionBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,EACL,eAAe,EAGf,sBAAsB,EACtB,iBAAiB,EACjB,YAAY,EAEb,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAGjC,KAAK,WAAW,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAE1E,mFAAmF;AACnF,qBAAa,gBAAgB;IAC3B,sEAAsE;IACtE,OAAO,CAAC,UAAU,CAA0C;IAC5D,gFAAgF;IAChF,OAAO,CAAC,WAAW,CAAgC;IAEnD,2FAA2F;IAC3F,kBAAkB,CAAC,UAAU,EAAE,gBAAgB,GAAG,IAAI;IAKtD,wEAAwE;IACxE,kBAAkB,CAAC,SAAS,EAAE,eAAe,GAAG,IAAI;IAIpD,wEAAwE;IACxE,eAAe,CAAC,SAAS,EAAE,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,UAAU,CAAC,GAAG,IAAI;IAQhF,mEAAmE;IACnE,mBAAmB,CAAC,MAAM,EAAE,sBAAsB,GAAG,IAAI;IAIzD;;;;OAIG;IACH,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,CAAC,GAAG,CAAC,GAAG,IAAI;IAoCnF,kGAAkG;IAClG,kBAAkB,IAAI,sBAAsB,GAAG,SAAS;IAexD;;;;;;;;;;;;;;;;OAgBG;IACH,cAAc,CAAC,mBAAmB,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,eAAe,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE;CA4CpG"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConditionBuilder = void 0;
|
|
4
|
+
const EntityManager_1 = require("./EntityManager");
|
|
5
|
+
const QueryParser_1 = require("./QueryParser");
|
|
6
|
+
const utils_1 = require("./utils");
|
|
7
|
+
/** Converts domain-level values like string ids/enums into their db equivalent. */
|
|
8
|
+
class ConditionBuilder {
|
|
9
|
+
/** Simple, single-column conditions, which will be AND-d together. */
|
|
10
|
+
conditions = [];
|
|
11
|
+
/** Complex expressions, which will also be AND-d together with `conditions`. */
|
|
12
|
+
expressions = [];
|
|
13
|
+
/** Accepts a raw user-facing DSL filter, and parses it into a `ParsedExpressionFilter`. */
|
|
14
|
+
maybeAddExpression(expression) {
|
|
15
|
+
const parsed = parseExpression(expression);
|
|
16
|
+
if (parsed)
|
|
17
|
+
this.expressions.push(parsed);
|
|
18
|
+
}
|
|
19
|
+
/** Adds an already-db-level condition to the simple conditions list. */
|
|
20
|
+
addSimpleCondition(condition) {
|
|
21
|
+
this.conditions.push(condition);
|
|
22
|
+
}
|
|
23
|
+
/** Adds an already-db-level condition to the simple conditions list. */
|
|
24
|
+
addRawCondition(condition) {
|
|
25
|
+
this.conditions.push({
|
|
26
|
+
kind: "raw",
|
|
27
|
+
bindings: [],
|
|
28
|
+
...condition,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/** Adds an already-db-level expression to the expressions list. */
|
|
32
|
+
addParsedExpression(parsed) {
|
|
33
|
+
this.expressions.push(parsed);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Adds a user-facing `ParsedValueFilter` to the inline conditions.
|
|
37
|
+
*
|
|
38
|
+
* Unless it's something like `in: [a1, null]`, in which case we split it into two `is-null` and `in` conditions.
|
|
39
|
+
*/
|
|
40
|
+
addValueFilter(alias, column, filter) {
|
|
41
|
+
if (filter.kind === "in" && filter.value.includes(null)) {
|
|
42
|
+
// If the filter contains a null, we need to split it into an `is-null` and `in` condition
|
|
43
|
+
const isNull = {
|
|
44
|
+
kind: "column",
|
|
45
|
+
alias,
|
|
46
|
+
column: column.columnName,
|
|
47
|
+
dbType: column.dbType,
|
|
48
|
+
cond: { kind: "is-null" },
|
|
49
|
+
};
|
|
50
|
+
const inValues = {
|
|
51
|
+
kind: "column",
|
|
52
|
+
alias,
|
|
53
|
+
column: column.columnName,
|
|
54
|
+
dbType: column.dbType,
|
|
55
|
+
cond: {
|
|
56
|
+
kind: "in",
|
|
57
|
+
// Filter out the nulls from the in condition
|
|
58
|
+
value: filter.value.filter((v) => v !== null).map((v) => column.mapToDb(v)),
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
// Now OR them back together
|
|
62
|
+
this.expressions.push({ kind: "exp", op: "or", conditions: [isNull, inValues] });
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
const cond = {
|
|
66
|
+
kind: "column",
|
|
67
|
+
alias,
|
|
68
|
+
column: column.columnName,
|
|
69
|
+
dbType: column.dbType,
|
|
70
|
+
// Rewrite the user-facing domain values to db values
|
|
71
|
+
cond: (0, QueryParser_1.mapToDb)(column, filter),
|
|
72
|
+
};
|
|
73
|
+
this.conditions.push(cond);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/** Combines our collected `conditions` & `expressions` into a single `ParsedExpressionFilter`. */
|
|
77
|
+
toExpressionFilter() {
|
|
78
|
+
const { expressions, conditions } = this;
|
|
79
|
+
if (conditions.length === 0 && expressions.length === 1) {
|
|
80
|
+
// If no inline conditions, and just 1 opt expression, just use that
|
|
81
|
+
return expressions[0];
|
|
82
|
+
}
|
|
83
|
+
else if (expressions.length === 1 && expressions[0].op === "and") {
|
|
84
|
+
// Merge the 1 `AND` expression with the other simple conditions
|
|
85
|
+
return { kind: "exp", op: "and", conditions: [...conditions, ...expressions[0].conditions] };
|
|
86
|
+
}
|
|
87
|
+
else if (conditions.length > 0 || expressions.length > 0) {
|
|
88
|
+
// Combine the conditions within the `em.find` join literal & the `conditions` as ANDs
|
|
89
|
+
return { kind: "exp", op: "and", conditions: [...conditions, ...expressions] };
|
|
90
|
+
}
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Finds `child.column.eq(...)` complex conditions that need pushed down into each lateral join.
|
|
95
|
+
*
|
|
96
|
+
* Once we find something like `{ column: "first_name", cond: { eq: "a1" } }`, we return it to the
|
|
97
|
+
* caller (for injection into the lateral join's `SELECT` clause), and replace it with a boolean
|
|
98
|
+
* expression that is basically "did any of my children match this condition?".
|
|
99
|
+
*
|
|
100
|
+
* We also assume that `findAndRewrite` is only called on the top-level/user-facing `ParsedFindQuery`,
|
|
101
|
+
* and not any intermediate `CteJoinTable` queries (which are allowed to have their own
|
|
102
|
+
* `ConditionBuilder`s for building their internal query, but it's not exposed to the user,
|
|
103
|
+
* so won't have any truly-complex conditions that should need rewritten).
|
|
104
|
+
*
|
|
105
|
+
* @param topLevelLateralJoin the outermost lateral join alias, as that will be the only alias
|
|
106
|
+
* that is visible to the rewritten condition, i.e. `_alias._whatever_condition_`.
|
|
107
|
+
* @param alias the alias being "hidden" in a lateral join, and so its columns/data won't be
|
|
108
|
+
* available for the top-level condition to directly AND/OR against.
|
|
109
|
+
*/
|
|
110
|
+
findAndRewrite(topLevelLateralJoin, alias) {
|
|
111
|
+
let j = 0;
|
|
112
|
+
const found = [];
|
|
113
|
+
const todo = [this.conditions];
|
|
114
|
+
for (const exp of this.expressions)
|
|
115
|
+
todo.push(exp.conditions);
|
|
116
|
+
while (todo.length > 0) {
|
|
117
|
+
const array = todo.pop();
|
|
118
|
+
array.forEach((cond, i) => {
|
|
119
|
+
if (cond.kind === "column") {
|
|
120
|
+
// Use startsWith to look for `_b0` / `_s0` base/subtype conditions
|
|
121
|
+
if (cond.alias === alias || cond.alias.startsWith(`${alias}_`)) {
|
|
122
|
+
if (cond.column === "_")
|
|
123
|
+
return; // Hack to skip rewriting `alias._ > 0`
|
|
124
|
+
const as = `_${alias}_${cond.column}_${j++}`;
|
|
125
|
+
array[i] = {
|
|
126
|
+
kind: "raw",
|
|
127
|
+
aliases: [topLevelLateralJoin],
|
|
128
|
+
condition: `${topLevelLateralJoin}.${as}`,
|
|
129
|
+
bindings: [],
|
|
130
|
+
pruneable: false,
|
|
131
|
+
...{ rewritten: true },
|
|
132
|
+
};
|
|
133
|
+
found.push({ cond, as });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
else if (cond.kind === "exp") {
|
|
137
|
+
todo.push(cond.conditions);
|
|
138
|
+
}
|
|
139
|
+
else if (cond.kind === "raw") {
|
|
140
|
+
// what would we do here?
|
|
141
|
+
if (cond.aliases.includes(alias)) {
|
|
142
|
+
// Look for a hacky hint that this is our own already-rewritten query; this is likely
|
|
143
|
+
// because `findAndRewrite` is mutating condition expressions that get passed into
|
|
144
|
+
// `parseFindQuery` multiple times, i.e. while batching/dataloading.
|
|
145
|
+
//
|
|
146
|
+
// ...although in theory parseExpression should already be making a copy of any user-facing
|
|
147
|
+
// `em.find` conditions. :thinking:
|
|
148
|
+
if ("rewritten" in cond)
|
|
149
|
+
return;
|
|
150
|
+
throw new Error("Joist doesn't support raw conditions in lateral joins yet");
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
(0, utils_1.assertNever)(cond);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
return found;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
exports.ConditionBuilder = ConditionBuilder;
|
|
162
|
+
/** Parses user-facing `{ and: ... }` or `{ or: ... }` into a `ParsedExpressionFilter`. */
|
|
163
|
+
function parseExpression(expression) {
|
|
164
|
+
// Look for `{ and: [...] }` or `{ or: [...] }`
|
|
165
|
+
const [op, expressions] = "and" in expression && expression.and
|
|
166
|
+
? ["and", expression.and]
|
|
167
|
+
: "or" in expression && expression.or
|
|
168
|
+
? ["or", expression.or]
|
|
169
|
+
: fail(`Invalid expression ${expression}`);
|
|
170
|
+
// Potentially recurse into nested expressions
|
|
171
|
+
const conditions = expressions.map((exp) => (exp && ("and" in exp || "or" in exp) ? parseExpression(exp) : exp));
|
|
172
|
+
const [skip, valid] = (0, utils_1.partition)(conditions, (cond) => cond === undefined || cond === QueryParser_1.skipCondition);
|
|
173
|
+
if ((skip.length > 0 && expression.pruneIfUndefined === "any") || valid.length === 0) {
|
|
174
|
+
return undefined;
|
|
175
|
+
}
|
|
176
|
+
return { kind: "exp", op, conditions: valid.filter(EntityManager_1.isDefined) };
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=ConditionBuilder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConditionBuilder.js","sourceRoot":"","sources":["../src/ConditionBuilder.ts"],"names":[],"mappings":"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"}
|
package/build/QueryParser.d.ts
CHANGED
|
@@ -30,8 +30,8 @@ export interface RawCondition {
|
|
|
30
30
|
condition: string;
|
|
31
31
|
/** The bindings within `condition`, i.e. `SUM(${alias}.amount) > ?`. */
|
|
32
32
|
bindings: any[];
|
|
33
|
-
/**
|
|
34
|
-
pruneable:
|
|
33
|
+
/** Used to mark system-added conditions (like `LATERAL JOIN` conditions), which can be ignored when pruning unused joins. */
|
|
34
|
+
pruneable: boolean;
|
|
35
35
|
}
|
|
36
36
|
/** A marker condition for alias methods to indicate they should be skipped/pruned. */
|
|
37
37
|
export declare const skipCondition: ColumnCondition;
|
|
@@ -48,15 +48,40 @@ export interface JoinTable {
|
|
|
48
48
|
col2: string;
|
|
49
49
|
distinct?: boolean;
|
|
50
50
|
}
|
|
51
|
-
export
|
|
51
|
+
export interface CrossJoinTable {
|
|
52
|
+
join: "cross";
|
|
53
|
+
alias: string;
|
|
54
|
+
table: string;
|
|
55
|
+
}
|
|
56
|
+
export interface LateralJoinTable {
|
|
57
|
+
join: "lateral";
|
|
58
|
+
alias: string;
|
|
59
|
+
/** Used for join dependency tracking. */
|
|
60
|
+
fromAlias: string;
|
|
61
|
+
/** Used more for bookkeeping/consistency with other join tables than the query itself. */
|
|
62
|
+
table: string;
|
|
63
|
+
/** The subquery that will look for/roll-up N children. */
|
|
64
|
+
query: ParsedFindQuery;
|
|
65
|
+
}
|
|
66
|
+
export type ParsedTable = PrimaryTable | JoinTable | CrossJoinTable | LateralJoinTable;
|
|
52
67
|
export interface ParsedOrderBy {
|
|
53
68
|
alias: string;
|
|
54
69
|
column: string;
|
|
55
70
|
order: OrderBy;
|
|
56
71
|
}
|
|
72
|
+
export interface ParsedGroupBy {
|
|
73
|
+
alias: string;
|
|
74
|
+
column: string;
|
|
75
|
+
}
|
|
76
|
+
type ParsedSelect = string | ParsedSelectWithBindings;
|
|
77
|
+
type ParsedSelectWithBindings = {
|
|
78
|
+
sql: string;
|
|
79
|
+
bindings: any[];
|
|
80
|
+
aliases: string[];
|
|
81
|
+
};
|
|
57
82
|
/** The result of parsing an `em.find` filter. */
|
|
58
83
|
export interface ParsedFindQuery {
|
|
59
|
-
selects:
|
|
84
|
+
selects: ParsedSelect[];
|
|
60
85
|
/** The primary table plus any joins. */
|
|
61
86
|
tables: ParsedTable[];
|
|
62
87
|
/** Any cross lateral joins, where the `joins: string[]` has the full join as raw SQL; currently only for preloading. */
|
|
@@ -66,6 +91,8 @@ export interface ParsedFindQuery {
|
|
|
66
91
|
};
|
|
67
92
|
/** The query's conditions. */
|
|
68
93
|
condition?: ParsedExpressionFilter;
|
|
94
|
+
/** Extremely optional group bys; we generally don't support adhoc/aggregate queries, but the auto-batching infra uses these. */
|
|
95
|
+
groupBys?: ParsedGroupBy[];
|
|
69
96
|
/** Any optional orders to add before the default 'order by id'. */
|
|
70
97
|
orderBys: ParsedOrderBy[];
|
|
71
98
|
/** Optional CTE to prefix to the query, i.e. for recursive relations. */
|
|
@@ -74,7 +101,7 @@ export interface ParsedFindQuery {
|
|
|
74
101
|
bindings: readonly any[];
|
|
75
102
|
};
|
|
76
103
|
}
|
|
77
|
-
/** Parses an `em.find` filter into a `ParsedFindQuery` for simpler execution. */
|
|
104
|
+
/** Parses an `em.find` filter into a `ParsedFindQuery` AST for simpler execution. */
|
|
78
105
|
export declare function parseFindQuery(meta: EntityMetadata, filter: any, opts?: {
|
|
79
106
|
conditions?: ExpressionFilter;
|
|
80
107
|
orderBy?: any;
|
|
@@ -82,6 +109,8 @@ export declare function parseFindQuery(meta: EntityMetadata, filter: any, opts?:
|
|
|
82
109
|
keepAliases?: string[];
|
|
83
110
|
softDeletes?: "include" | "exclude";
|
|
84
111
|
}): ParsedFindQuery;
|
|
112
|
+
/** Returns the `a` from `"a".*`. */
|
|
113
|
+
export declare function parseAlias(alias: string): string;
|
|
85
114
|
/** An ADT version of `EntityFilter`. */
|
|
86
115
|
export type ParsedEntityFilter = ParsedValueFilter<string | number> | {
|
|
87
116
|
kind: "join";
|
|
@@ -173,36 +202,13 @@ export type ParsedValueFilter<V> = {
|
|
|
173
202
|
*/
|
|
174
203
|
export declare function parseValueFilter<V>(filter: ValueFilter<V, any>): ParsedValueFilter<V>[];
|
|
175
204
|
/** Converts domain-level values like string ids/enums into their db equivalent. */
|
|
176
|
-
export declare class ConditionBuilder {
|
|
177
|
-
/** Simple, single-column conditions, which will be AND-d together. */
|
|
178
|
-
private conditions;
|
|
179
|
-
/** Complex expressions, which will also be AND-d together with `conditions`. */
|
|
180
|
-
private expressions;
|
|
181
|
-
/** Accepts a raw user-facing DSL filter, and parses it into a `ParsedExpressionFilter`. */
|
|
182
|
-
maybeAddExpression(expression: ExpressionFilter): void;
|
|
183
|
-
/** Adds an already-db-level condition to the simple conditions list. */
|
|
184
|
-
addSimpleCondition(condition: ColumnCondition): void;
|
|
185
|
-
/** Adds an already-db-level expression to the expressions list. */
|
|
186
|
-
addParsedExpression(parsed: ParsedExpressionFilter): void;
|
|
187
|
-
/**
|
|
188
|
-
* Adds a user-facing `ParsedValueFilter` to the inline conditions.
|
|
189
|
-
*
|
|
190
|
-
* Unless it's something like `in: [a1, null]`, in which case we split it into two `is-null` and `in` conditions.
|
|
191
|
-
*/
|
|
192
|
-
addValueFilter(alias: string, column: Column, filter: ParsedValueFilter<any>): void;
|
|
193
|
-
/** Combines our collected `conditions` & `expressions` into a single `ParsedExpressionFilter`. */
|
|
194
|
-
toExpressionFilter(): ParsedExpressionFilter | undefined;
|
|
195
|
-
}
|
|
196
|
-
/** Converts domain-level values like string ids/enums into their db equivalent. */
|
|
197
205
|
export declare function mapToDb(column: Column, filter: ParsedValueFilter<any>): ParsedValueFilter<any>;
|
|
198
206
|
/** Adds any user-configured default order, plus an "always order by id" for determinism. */
|
|
199
207
|
export declare function maybeAddOrderBy(query: ParsedFindQuery, meta: EntityMetadata, alias: string): void;
|
|
200
208
|
export declare function addTablePerClassJoinsAndClassTag(query: ParsedFindQuery, meta: EntityMetadata, alias: string, isPrimary: boolean): void;
|
|
201
209
|
export declare function maybeAddNotSoftDeleted(conditions: ColumnCondition[], meta: EntityMetadata, alias: string, softDeletes: "include" | "exclude"): void;
|
|
202
|
-
export declare function getTables(query: ParsedFindQuery): [PrimaryTable, JoinTable[]];
|
|
203
|
-
export declare function joinKeywords(join: JoinTable): string;
|
|
204
|
-
export declare function joinClause(join: JoinTable): string;
|
|
205
|
-
export declare function joinClauses(joins: ParsedTable[]): string[];
|
|
210
|
+
export declare function getTables(query: ParsedFindQuery): [PrimaryTable, JoinTable[], LateralJoinTable[], CrossJoinTable[]];
|
|
206
211
|
/** Converts a search term like `foo bar` into a SQL `like` pattern like `%foo%bar%`. */
|
|
207
212
|
export declare function makeLike(search: any | undefined): any;
|
|
213
|
+
export {};
|
|
208
214
|
//# sourceMappingURL=QueryParser.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryParser.d.ts","sourceRoot":"","sources":["../src/QueryParser.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,cAAc,EAAe,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"QueryParser.d.ts","sourceRoot":"","sources":["../src/QueryParser.ts"],"names":[],"mappings":"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"}
|
package/build/QueryParser.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.skipCondition = void 0;
|
|
4
4
|
exports.parseFindQuery = parseFindQuery;
|
|
5
|
+
exports.parseAlias = parseAlias;
|
|
5
6
|
exports.parseEntityFilter = parseEntityFilter;
|
|
6
7
|
exports.parseValueFilter = parseValueFilter;
|
|
7
8
|
exports.mapToDb = mapToDb;
|
|
@@ -9,14 +10,12 @@ exports.maybeAddOrderBy = maybeAddOrderBy;
|
|
|
9
10
|
exports.addTablePerClassJoinsAndClassTag = addTablePerClassJoinsAndClassTag;
|
|
10
11
|
exports.maybeAddNotSoftDeleted = maybeAddNotSoftDeleted;
|
|
11
12
|
exports.getTables = getTables;
|
|
12
|
-
exports.joinKeywords = joinKeywords;
|
|
13
|
-
exports.joinClause = joinClause;
|
|
14
|
-
exports.joinClauses = joinClauses;
|
|
15
13
|
exports.makeLike = makeLike;
|
|
16
14
|
const joist_utils_1 = require("joist-utils");
|
|
17
15
|
const Aliases_1 = require("./Aliases");
|
|
18
16
|
const Entity_1 = require("./Entity");
|
|
19
17
|
const EntityMetadata_1 = require("./EntityMetadata");
|
|
18
|
+
const QueryParser_pruning_1 = require("./QueryParser.pruning");
|
|
20
19
|
const QueryVisitor_1 = require("./QueryVisitor");
|
|
21
20
|
const configure_1 = require("./configure");
|
|
22
21
|
const index_1 = require("./index");
|
|
@@ -30,14 +29,14 @@ exports.skipCondition = {
|
|
|
30
29
|
dbType: "skip",
|
|
31
30
|
cond: undefined,
|
|
32
31
|
};
|
|
33
|
-
/** Parses an `em.find` filter into a `ParsedFindQuery` for simpler execution. */
|
|
32
|
+
/** Parses an `em.find` filter into a `ParsedFindQuery` AST for simpler execution. */
|
|
34
33
|
function parseFindQuery(meta, filter, opts = {}) {
|
|
35
34
|
const selects = [];
|
|
36
35
|
const tables = [];
|
|
37
36
|
const orderBys = [];
|
|
38
37
|
const query = { selects, tables, orderBys };
|
|
39
38
|
const { orderBy = undefined, conditions: optsExpression = undefined, softDeletes = "exclude", pruneJoins = true, keepAliases = [], } = opts;
|
|
40
|
-
const cb = new ConditionBuilder();
|
|
39
|
+
const cb = new index_1.ConditionBuilder();
|
|
41
40
|
const aliases = {};
|
|
42
41
|
function getAlias(tableName) {
|
|
43
42
|
const abbrev = (0, utils_1.abbreviation)(tableName);
|
|
@@ -92,6 +91,9 @@ function parseFindQuery(meta, filter, opts = {}) {
|
|
|
92
91
|
});
|
|
93
92
|
});
|
|
94
93
|
}
|
|
94
|
+
else if (join === "lateral" || join === "cross") {
|
|
95
|
+
(0, utils_1.fail)("Unexpected lateral join");
|
|
96
|
+
}
|
|
95
97
|
else {
|
|
96
98
|
tables.push({ alias, table: meta.tableName, join, col1, col2 });
|
|
97
99
|
// Maybe only do this if we're the primary, or have a field that needs it?
|
|
@@ -376,7 +378,7 @@ function parseFindQuery(meta, filter, opts = {}) {
|
|
|
376
378
|
}
|
|
377
379
|
maybeAddOrderBy(query, meta, alias);
|
|
378
380
|
if (pruneJoins) {
|
|
379
|
-
pruneUnusedJoins(query, keepAliases);
|
|
381
|
+
(0, QueryParser_pruning_1.pruneUnusedJoins)(query, keepAliases);
|
|
380
382
|
}
|
|
381
383
|
return query;
|
|
382
384
|
}
|
|
@@ -421,75 +423,6 @@ function maybeAddIdNotNulls(query) {
|
|
|
421
423
|
},
|
|
422
424
|
});
|
|
423
425
|
}
|
|
424
|
-
// Remove any joins that are not used in the select or conditions
|
|
425
|
-
function pruneUnusedJoins(parsed, keepAliases) {
|
|
426
|
-
// Mark all terminal usages
|
|
427
|
-
const used = new Set();
|
|
428
|
-
parsed.selects.forEach((s) => used.add(parseAlias(s)));
|
|
429
|
-
parsed.orderBys.forEach((o) => used.add(o.alias));
|
|
430
|
-
keepAliases.forEach((a) => used.add(a));
|
|
431
|
-
deepFindConditions(parsed.condition)
|
|
432
|
-
.filter((c) => !c.pruneable)
|
|
433
|
-
.forEach((c) => {
|
|
434
|
-
switch (c.kind) {
|
|
435
|
-
case "column":
|
|
436
|
-
used.add(c.alias);
|
|
437
|
-
break;
|
|
438
|
-
case "raw":
|
|
439
|
-
for (const alias of c.aliases) {
|
|
440
|
-
used.add(alias);
|
|
441
|
-
}
|
|
442
|
-
break;
|
|
443
|
-
default:
|
|
444
|
-
(0, utils_1.assertNever)(c);
|
|
445
|
-
}
|
|
446
|
-
});
|
|
447
|
-
// Mark all usages via joins
|
|
448
|
-
for (let i = 0; i < parsed.tables.length; i++) {
|
|
449
|
-
const t = parsed.tables[i];
|
|
450
|
-
if (t.join !== "primary") {
|
|
451
|
-
// If alias (col2) is required, ensure the col1 alias is also required
|
|
452
|
-
const a2 = t.alias;
|
|
453
|
-
const a1 = parseAlias(t.col1);
|
|
454
|
-
if (used.has(a2) && !used.has(a1)) {
|
|
455
|
-
used.add(a1);
|
|
456
|
-
// Restart at zero to find dependencies before us
|
|
457
|
-
i = 0;
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
// Now remove any unused joins
|
|
462
|
-
parsed.tables = parsed.tables.filter((t) => used.has(t.alias));
|
|
463
|
-
// And then remove any inline soft-delete conditions we don't need anymore
|
|
464
|
-
if (parsed.condition && parsed.condition.op === "and") {
|
|
465
|
-
parsed.condition.conditions = parsed.condition.conditions.filter((c) => {
|
|
466
|
-
if (c.kind === "column") {
|
|
467
|
-
const prune = c.pruneable && !parsed.tables.some((t) => t.alias === c.alias);
|
|
468
|
-
return !prune;
|
|
469
|
-
}
|
|
470
|
-
else {
|
|
471
|
-
return c;
|
|
472
|
-
}
|
|
473
|
-
});
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
/** Pulls out a flat list of all `ColumnCondition`s from a `ParsedExpressionFilter` tree. */
|
|
477
|
-
function deepFindConditions(condition) {
|
|
478
|
-
const todo = condition ? [condition] : [];
|
|
479
|
-
const result = [];
|
|
480
|
-
while (todo.length !== 0) {
|
|
481
|
-
const cc = todo.pop();
|
|
482
|
-
for (const c of cc.conditions) {
|
|
483
|
-
if (c.kind === "exp") {
|
|
484
|
-
todo.push(c);
|
|
485
|
-
}
|
|
486
|
-
else {
|
|
487
|
-
result.push(c);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
return result;
|
|
492
|
-
}
|
|
493
426
|
/** Returns the `a` from `"a".*`. */
|
|
494
427
|
function parseAlias(alias) {
|
|
495
428
|
return alias.split(".")[0].replaceAll(`"`, "");
|
|
@@ -705,82 +638,6 @@ function parseValueFilter(filter) {
|
|
|
705
638
|
}
|
|
706
639
|
}
|
|
707
640
|
/** Converts domain-level values like string ids/enums into their db equivalent. */
|
|
708
|
-
class ConditionBuilder {
|
|
709
|
-
/** Simple, single-column conditions, which will be AND-d together. */
|
|
710
|
-
conditions = [];
|
|
711
|
-
/** Complex expressions, which will also be AND-d together with `conditions`. */
|
|
712
|
-
expressions = [];
|
|
713
|
-
/** Accepts a raw user-facing DSL filter, and parses it into a `ParsedExpressionFilter`. */
|
|
714
|
-
maybeAddExpression(expression) {
|
|
715
|
-
const parsed = parseExpression(expression);
|
|
716
|
-
if (parsed)
|
|
717
|
-
this.expressions.push(parsed);
|
|
718
|
-
}
|
|
719
|
-
/** Adds an already-db-level condition to the simple conditions list. */
|
|
720
|
-
addSimpleCondition(condition) {
|
|
721
|
-
this.conditions.push(condition);
|
|
722
|
-
}
|
|
723
|
-
/** Adds an already-db-level expression to the expressions list. */
|
|
724
|
-
addParsedExpression(parsed) {
|
|
725
|
-
this.expressions.push(parsed);
|
|
726
|
-
}
|
|
727
|
-
/**
|
|
728
|
-
* Adds a user-facing `ParsedValueFilter` to the inline conditions.
|
|
729
|
-
*
|
|
730
|
-
* Unless it's something like `in: [a1, null]`, in which case we split it into two `is-null` and `in` conditions.
|
|
731
|
-
*/
|
|
732
|
-
addValueFilter(alias, column, filter) {
|
|
733
|
-
if (filter.kind === "in" && filter.value.includes(null)) {
|
|
734
|
-
// If the filter contains a null, we need to split it into an `is-null` and `in` condition
|
|
735
|
-
const isNull = {
|
|
736
|
-
kind: "column",
|
|
737
|
-
alias,
|
|
738
|
-
column: column.columnName,
|
|
739
|
-
dbType: column.dbType,
|
|
740
|
-
cond: { kind: "is-null" },
|
|
741
|
-
};
|
|
742
|
-
const inValues = {
|
|
743
|
-
kind: "column",
|
|
744
|
-
alias,
|
|
745
|
-
column: column.columnName,
|
|
746
|
-
dbType: column.dbType,
|
|
747
|
-
cond: {
|
|
748
|
-
kind: "in",
|
|
749
|
-
// Filter out the nulls from the in condition
|
|
750
|
-
value: filter.value.filter((v) => v !== null).map((v) => column.mapToDb(v)),
|
|
751
|
-
},
|
|
752
|
-
};
|
|
753
|
-
// Now OR them back together
|
|
754
|
-
this.expressions.push({ kind: "exp", op: "or", conditions: [isNull, inValues] });
|
|
755
|
-
}
|
|
756
|
-
else {
|
|
757
|
-
const cond = {
|
|
758
|
-
kind: "column",
|
|
759
|
-
alias,
|
|
760
|
-
column: column.columnName,
|
|
761
|
-
dbType: column.dbType,
|
|
762
|
-
// Rewrite the user-facing domain values to db values
|
|
763
|
-
cond: mapToDb(column, filter),
|
|
764
|
-
};
|
|
765
|
-
this.conditions.push(cond);
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
/** Combines our collected `conditions` & `expressions` into a single `ParsedExpressionFilter`. */
|
|
769
|
-
toExpressionFilter() {
|
|
770
|
-
const { expressions, conditions } = this;
|
|
771
|
-
if (conditions.length === 0 && expressions.length === 1) {
|
|
772
|
-
// If no inline conditions, and just 1 opt expression, just use that
|
|
773
|
-
return expressions[0];
|
|
774
|
-
}
|
|
775
|
-
else if (conditions.length > 0 || expressions.length > 0) {
|
|
776
|
-
// Combine the conditions within the `em.find` join literal & the `conditions` as ANDs
|
|
777
|
-
return { kind: "exp", op: "and", conditions: [...conditions, ...expressions] };
|
|
778
|
-
}
|
|
779
|
-
return undefined;
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
exports.ConditionBuilder = ConditionBuilder;
|
|
783
|
-
/** Converts domain-level values like string ids/enums into their db equivalent. */
|
|
784
641
|
function mapToDb(column, filter) {
|
|
785
642
|
// ...to teach this `mapToDb` function to handle/rewrite `in: [1, null]` handling, we'd need to:
|
|
786
643
|
// 1. return a maybe-simple/maybe-nested condition, so basically a `ParsedExpressionCondition`, because
|
|
@@ -938,40 +795,26 @@ function filterSoftDeletes(meta, softDeletes) {
|
|
|
938
795
|
// We don't support CTI subtype soft-delete filtering yet
|
|
939
796
|
(meta.inheritanceType !== "cti" || meta.baseTypes.length === 0));
|
|
940
797
|
}
|
|
941
|
-
function parseExpression(expression) {
|
|
942
|
-
const [op, expressions] = "and" in expression && expression.and
|
|
943
|
-
? ["and", expression.and]
|
|
944
|
-
: "or" in expression && expression.or
|
|
945
|
-
? ["or", expression.or]
|
|
946
|
-
: (0, utils_1.fail)(`Invalid expression ${expression}`);
|
|
947
|
-
const conditions = expressions.map((exp) => (exp && ("and" in exp || "or" in exp) ? parseExpression(exp) : exp));
|
|
948
|
-
const [skip, valid] = (0, utils_1.partition)(conditions, (cond) => cond === undefined || cond === exports.skipCondition);
|
|
949
|
-
if ((skip.length > 0 && expression.pruneIfUndefined === "any") || valid.length === 0) {
|
|
950
|
-
return undefined;
|
|
951
|
-
}
|
|
952
|
-
return { kind: "exp", op, conditions: valid.filter(index_1.isDefined) };
|
|
953
|
-
}
|
|
954
798
|
function getTables(query) {
|
|
955
799
|
let primary;
|
|
956
800
|
const joins = [];
|
|
801
|
+
const laterals = [];
|
|
802
|
+
const crosses = [];
|
|
957
803
|
for (const table of query.tables) {
|
|
958
804
|
if (table.join === "primary") {
|
|
959
805
|
primary = table;
|
|
960
806
|
}
|
|
807
|
+
else if (table.join === "lateral") {
|
|
808
|
+
laterals.push(table);
|
|
809
|
+
}
|
|
810
|
+
else if (table.join === "cross") {
|
|
811
|
+
crosses.push(table);
|
|
812
|
+
}
|
|
961
813
|
else {
|
|
962
814
|
joins.push(table);
|
|
963
815
|
}
|
|
964
816
|
}
|
|
965
|
-
return [primary, joins];
|
|
966
|
-
}
|
|
967
|
-
function joinKeywords(join) {
|
|
968
|
-
return join.join === "inner" ? "JOIN" : "LEFT OUTER JOIN";
|
|
969
|
-
}
|
|
970
|
-
function joinClause(join) {
|
|
971
|
-
return `${joinKeywords(join)} ${(0, keywords_1.kq)(join.table)} ${(0, keywords_1.kq)(join.alias)} ON ${join.col1} = ${join.col2}`;
|
|
972
|
-
}
|
|
973
|
-
function joinClauses(joins) {
|
|
974
|
-
return joins.map((t) => (t.join !== "primary" ? joinClause(t) : ""));
|
|
817
|
+
return [primary, joins, laterals, crosses];
|
|
975
818
|
}
|
|
976
819
|
function needsClassPerTableJoins(meta) {
|
|
977
820
|
return meta.inheritanceType === "cti" && (meta.subTypes.length > 0 || meta.baseTypes.length > 0);
|