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.
Files changed (35) hide show
  1. package/build/ConditionBuilder.d.ts +50 -0
  2. package/build/ConditionBuilder.d.ts.map +1 -0
  3. package/build/ConditionBuilder.js +178 -0
  4. package/build/ConditionBuilder.js.map +1 -0
  5. package/build/QueryParser.d.ts +36 -30
  6. package/build/QueryParser.d.ts.map +1 -1
  7. package/build/QueryParser.js +18 -175
  8. package/build/QueryParser.js.map +1 -1
  9. package/build/QueryParser.pruning.d.ts +5 -0
  10. package/build/QueryParser.pruning.d.ts.map +1 -0
  11. package/build/QueryParser.pruning.js +118 -0
  12. package/build/QueryParser.pruning.js.map +1 -0
  13. package/build/QueryVisitor.d.ts +3 -2
  14. package/build/QueryVisitor.d.ts.map +1 -1
  15. package/build/QueryVisitor.js +37 -9
  16. package/build/QueryVisitor.js.map +1 -1
  17. package/build/dataloaders/findCountDataLoader.d.ts.map +1 -1
  18. package/build/dataloaders/findCountDataLoader.js +32 -25
  19. package/build/dataloaders/findCountDataLoader.js.map +1 -1
  20. package/build/dataloaders/findDataLoader.d.ts +7 -14
  21. package/build/dataloaders/findDataLoader.d.ts.map +1 -1
  22. package/build/dataloaders/findDataLoader.js +70 -88
  23. package/build/dataloaders/findDataLoader.js.map +1 -1
  24. package/build/drivers/buildRawQuery.d.ts.map +1 -1
  25. package/build/drivers/buildRawQuery.js +20 -7
  26. package/build/drivers/buildRawQuery.js.map +1 -1
  27. package/build/drivers/buildUtils.js +1 -4
  28. package/build/drivers/buildUtils.js.map +1 -1
  29. package/build/index.d.ts +1 -0
  30. package/build/index.d.ts.map +1 -1
  31. package/build/index.js +4 -2
  32. package/build/index.js.map +1 -1
  33. package/build/plugins/PreloadPlugin.d.ts +2 -4
  34. package/build/plugins/PreloadPlugin.d.ts.map +1 -1
  35. 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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"}
@@ -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
- /** We assume raw conditions are never system-added, so can't be pruned. */
34
- pruneable: false;
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 type ParsedTable = PrimaryTable | JoinTable;
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: string[];
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":"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"}
1
+ {"version":3,"file":"QueryParser.d.ts","sourceRoot":"","sources":["../src/QueryParser.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ConditionBuilder = exports.skipCondition = void 0;
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);