@undefineds.co/drizzle-solid 0.2.10 → 0.2.13
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/README.md +255 -439
- package/dist/core/expressions.d.ts +4 -0
- package/dist/core/expressions.d.ts.map +1 -1
- package/dist/core/expressions.js +8 -1
- package/dist/core/expressions.js.map +1 -1
- package/dist/core/order-by.d.ts +9 -0
- package/dist/core/order-by.d.ts.map +1 -0
- package/dist/core/order-by.js +20 -0
- package/dist/core/order-by.js.map +1 -0
- package/dist/core/pod-database.d.ts +6 -0
- package/dist/core/pod-database.d.ts.map +1 -1
- package/dist/core/pod-database.js +121 -31
- package/dist/core/pod-database.js.map +1 -1
- package/dist/core/pod-dialect.d.ts +10 -1
- package/dist/core/pod-dialect.d.ts.map +1 -1
- package/dist/core/pod-dialect.js +81 -2
- package/dist/core/pod-dialect.js.map +1 -1
- package/dist/core/query-builders/delete-query-builder.d.ts +7 -12
- package/dist/core/query-builders/delete-query-builder.d.ts.map +1 -1
- package/dist/core/query-builders/delete-query-builder.js +47 -20
- package/dist/core/query-builders/delete-query-builder.js.map +1 -1
- package/dist/core/query-builders/helpers.d.ts +7 -0
- package/dist/core/query-builders/helpers.d.ts.map +1 -1
- package/dist/core/query-builders/helpers.js +169 -0
- package/dist/core/query-builders/helpers.js.map +1 -1
- package/dist/core/query-builders/insert-query-builder.d.ts +10 -3
- package/dist/core/query-builders/insert-query-builder.d.ts.map +1 -1
- package/dist/core/query-builders/insert-query-builder.js +50 -6
- package/dist/core/query-builders/insert-query-builder.js.map +1 -1
- package/dist/core/query-builders/select-query-builder.d.ts +29 -1
- package/dist/core/query-builders/select-query-builder.d.ts.map +1 -1
- package/dist/core/query-builders/select-query-builder.js +405 -85
- package/dist/core/query-builders/select-query-builder.js.map +1 -1
- package/dist/core/query-builders/types.d.ts +5 -3
- package/dist/core/query-builders/types.d.ts.map +1 -1
- package/dist/core/query-builders/update-query-builder.d.ts +8 -12
- package/dist/core/query-builders/update-query-builder.d.ts.map +1 -1
- package/dist/core/query-builders/update-query-builder.js +63 -21
- package/dist/core/query-builders/update-query-builder.js.map +1 -1
- package/dist/core/query-conditions.d.ts +17 -16
- package/dist/core/query-conditions.d.ts.map +1 -1
- package/dist/core/query-conditions.js.map +1 -1
- package/dist/core/resource-resolver/base-resolver.d.ts +8 -4
- package/dist/core/resource-resolver/base-resolver.d.ts.map +1 -1
- package/dist/core/resource-resolver/base-resolver.js +39 -36
- package/dist/core/resource-resolver/base-resolver.js.map +1 -1
- package/dist/core/resource-resolver/document-resolver.d.ts.map +1 -1
- package/dist/core/resource-resolver/document-resolver.js +75 -69
- package/dist/core/resource-resolver/document-resolver.js.map +1 -1
- package/dist/core/schema/pod-table.d.ts +1 -0
- package/dist/core/schema/pod-table.d.ts.map +1 -1
- package/dist/core/schema/pod-table.js +67 -0
- package/dist/core/schema/pod-table.js.map +1 -1
- package/dist/core/select-plan.d.ts +6 -3
- package/dist/core/select-plan.d.ts.map +1 -1
- package/dist/core/sparql/builder/expression-builder.d.ts +10 -0
- package/dist/core/sparql/builder/expression-builder.d.ts.map +1 -1
- package/dist/core/sparql/builder/expression-builder.js +27 -4
- package/dist/core/sparql/builder/expression-builder.js.map +1 -1
- package/dist/core/sparql/builder/select-builder.d.ts +9 -0
- package/dist/core/sparql/builder/select-builder.d.ts.map +1 -1
- package/dist/core/sparql/builder/select-builder.js +147 -2
- package/dist/core/sparql/builder/select-builder.js.map +1 -1
- package/dist/core/utils/debug-logger.d.ts +19 -0
- package/dist/core/utils/debug-logger.d.ts.map +1 -0
- package/dist/core/utils/debug-logger.js +59 -0
- package/dist/core/utils/debug-logger.js.map +1 -0
- package/dist/driver.d.ts +4 -0
- package/dist/driver.d.ts.map +1 -1
- package/dist/driver.js +1 -0
- package/dist/driver.js.map +1 -1
- package/dist/esm/core/expressions.d.ts +4 -0
- package/dist/esm/core/expressions.d.ts.map +1 -1
- package/dist/esm/core/expressions.js +6 -0
- package/dist/esm/core/expressions.js.map +1 -1
- package/dist/esm/core/order-by.d.ts +9 -0
- package/dist/esm/core/order-by.d.ts.map +1 -0
- package/dist/esm/core/order-by.js +15 -0
- package/dist/esm/core/order-by.js.map +1 -0
- package/dist/esm/core/pod-database.d.ts +6 -0
- package/dist/esm/core/pod-database.d.ts.map +1 -1
- package/dist/esm/core/pod-database.js +122 -32
- package/dist/esm/core/pod-database.js.map +1 -1
- package/dist/esm/core/pod-dialect.d.ts +10 -1
- package/dist/esm/core/pod-dialect.d.ts.map +1 -1
- package/dist/esm/core/pod-dialect.js +81 -2
- package/dist/esm/core/pod-dialect.js.map +1 -1
- package/dist/esm/core/query-builders/delete-query-builder.d.ts +7 -12
- package/dist/esm/core/query-builders/delete-query-builder.d.ts.map +1 -1
- package/dist/esm/core/query-builders/delete-query-builder.js +48 -21
- package/dist/esm/core/query-builders/delete-query-builder.js.map +1 -1
- package/dist/esm/core/query-builders/helpers.d.ts +7 -0
- package/dist/esm/core/query-builders/helpers.d.ts.map +1 -1
- package/dist/esm/core/query-builders/helpers.js +164 -0
- package/dist/esm/core/query-builders/helpers.js.map +1 -1
- package/dist/esm/core/query-builders/insert-query-builder.d.ts +10 -3
- package/dist/esm/core/query-builders/insert-query-builder.d.ts.map +1 -1
- package/dist/esm/core/query-builders/insert-query-builder.js +50 -6
- package/dist/esm/core/query-builders/insert-query-builder.js.map +1 -1
- package/dist/esm/core/query-builders/select-query-builder.d.ts +29 -1
- package/dist/esm/core/query-builders/select-query-builder.d.ts.map +1 -1
- package/dist/esm/core/query-builders/select-query-builder.js +407 -87
- package/dist/esm/core/query-builders/select-query-builder.js.map +1 -1
- package/dist/esm/core/query-builders/types.d.ts +5 -3
- package/dist/esm/core/query-builders/types.d.ts.map +1 -1
- package/dist/esm/core/query-builders/update-query-builder.d.ts +8 -12
- package/dist/esm/core/query-builders/update-query-builder.d.ts.map +1 -1
- package/dist/esm/core/query-builders/update-query-builder.js +64 -22
- package/dist/esm/core/query-builders/update-query-builder.js.map +1 -1
- package/dist/esm/core/query-conditions.d.ts +17 -16
- package/dist/esm/core/query-conditions.d.ts.map +1 -1
- package/dist/esm/core/query-conditions.js.map +1 -1
- package/dist/esm/core/resource-resolver/base-resolver.d.ts +8 -4
- package/dist/esm/core/resource-resolver/base-resolver.d.ts.map +1 -1
- package/dist/esm/core/resource-resolver/base-resolver.js +39 -36
- package/dist/esm/core/resource-resolver/base-resolver.js.map +1 -1
- package/dist/esm/core/resource-resolver/document-resolver.d.ts.map +1 -1
- package/dist/esm/core/resource-resolver/document-resolver.js +75 -69
- package/dist/esm/core/resource-resolver/document-resolver.js.map +1 -1
- package/dist/esm/core/schema/pod-table.d.ts +1 -0
- package/dist/esm/core/schema/pod-table.d.ts.map +1 -1
- package/dist/esm/core/schema/pod-table.js +66 -0
- package/dist/esm/core/schema/pod-table.js.map +1 -1
- package/dist/esm/core/select-plan.d.ts +6 -3
- package/dist/esm/core/select-plan.d.ts.map +1 -1
- package/dist/esm/core/sparql/builder/expression-builder.d.ts +10 -0
- package/dist/esm/core/sparql/builder/expression-builder.d.ts.map +1 -1
- package/dist/esm/core/sparql/builder/expression-builder.js +27 -4
- package/dist/esm/core/sparql/builder/expression-builder.js.map +1 -1
- package/dist/esm/core/sparql/builder/select-builder.d.ts +9 -0
- package/dist/esm/core/sparql/builder/select-builder.d.ts.map +1 -1
- package/dist/esm/core/sparql/builder/select-builder.js +148 -3
- package/dist/esm/core/sparql/builder/select-builder.js.map +1 -1
- package/dist/esm/core/utils/debug-logger.d.ts +19 -0
- package/dist/esm/core/utils/debug-logger.d.ts.map +1 -0
- package/dist/esm/core/utils/debug-logger.js +53 -0
- package/dist/esm/core/utils/debug-logger.js.map +1 -0
- package/dist/esm/driver.d.ts +4 -0
- package/dist/esm/driver.d.ts.map +1 -1
- package/dist/esm/driver.js +1 -0
- package/dist/esm/driver.js.map +1 -1
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +3 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/package.json +17 -6
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
var _a;
|
|
2
2
|
import { entityKind, SQL } from 'drizzle-orm';
|
|
3
|
-
import { PodColumnBase } from '../schema';
|
|
3
|
+
import { PodTable, PodColumnBase } from '../schema';
|
|
4
4
|
import { inArray } from '../query-conditions';
|
|
5
5
|
import { isAggregateExpression } from '../aggregates';
|
|
6
|
-
import { createLiteralCondition, buildConditionTreeFromObject } from './helpers';
|
|
6
|
+
import { createLiteralCondition, buildConditionTreeFromObject, inferSPARQLQueryType } from './helpers';
|
|
7
7
|
import { UriResolverImpl } from '../uri';
|
|
8
|
+
import { isOrderByExpression } from '../order-by';
|
|
9
|
+
import { SelectionAliasExpression } from '../expressions';
|
|
8
10
|
export class SelectQueryBuilder {
|
|
9
11
|
constructor(session, fields) {
|
|
10
12
|
this.session = session;
|
|
@@ -129,17 +131,35 @@ export class SelectQueryBuilder {
|
|
|
129
131
|
fullJoin(table, condition) {
|
|
130
132
|
return this.addJoin('fullJoin', table, condition);
|
|
131
133
|
}
|
|
134
|
+
crossJoin(table) {
|
|
135
|
+
return this.addJoin('crossJoin', table);
|
|
136
|
+
}
|
|
132
137
|
groupBy(...fields) {
|
|
133
138
|
const refs = fields.map((field) => this.resolveColumnReference(field));
|
|
134
139
|
this.groupByColumns.push(...refs);
|
|
135
140
|
return this;
|
|
136
141
|
}
|
|
142
|
+
having(condition) {
|
|
143
|
+
this.havingCondition = typeof condition === 'function'
|
|
144
|
+
? condition(this.createSelectedFieldAliases())
|
|
145
|
+
: condition;
|
|
146
|
+
return this;
|
|
147
|
+
}
|
|
148
|
+
createSelectedFieldAliases() {
|
|
149
|
+
const aliases = {};
|
|
150
|
+
for (const alias of Object.keys(this.selectedFields ?? {})) {
|
|
151
|
+
aliases[alias] = new SelectionAliasExpression(alias);
|
|
152
|
+
}
|
|
153
|
+
return aliases;
|
|
154
|
+
}
|
|
137
155
|
addJoin(type, table, condition) {
|
|
138
156
|
if (type === 'rightJoin' || type === 'fullJoin') {
|
|
139
157
|
throw new Error(`${type} is not yet supported in Solid dialect`);
|
|
140
158
|
}
|
|
141
159
|
const alias = this.ensureAliasForTable(table);
|
|
142
|
-
const resolvedConditions =
|
|
160
|
+
const resolvedConditions = type === 'crossJoin'
|
|
161
|
+
? undefined
|
|
162
|
+
: this.resolveJoinConditions(condition, alias);
|
|
143
163
|
this.joins.push({
|
|
144
164
|
type,
|
|
145
165
|
table,
|
|
@@ -164,8 +184,11 @@ export class SelectQueryBuilder {
|
|
|
164
184
|
return alias;
|
|
165
185
|
}
|
|
166
186
|
resolveJoinConditions(condition, joinAlias) {
|
|
187
|
+
if (this.isQueryCondition(condition)) {
|
|
188
|
+
return this.resolveJoinConditionExpression(condition, joinAlias);
|
|
189
|
+
}
|
|
167
190
|
if (!condition || typeof condition !== 'object') {
|
|
168
|
-
throw new Error('JOIN condition must be an
|
|
191
|
+
throw new Error('JOIN condition must be an equality expression or column mapping');
|
|
169
192
|
}
|
|
170
193
|
const entries = Object.entries(condition);
|
|
171
194
|
if (entries.length === 0) {
|
|
@@ -180,6 +203,44 @@ export class SelectQueryBuilder {
|
|
|
180
203
|
return { left: leftRef, right: rightRef };
|
|
181
204
|
});
|
|
182
205
|
}
|
|
206
|
+
resolveJoinConditionExpression(condition, joinAlias) {
|
|
207
|
+
if (condition.type === 'logical_expr') {
|
|
208
|
+
const operator = (condition.operator ?? '').toUpperCase();
|
|
209
|
+
const expressions = (condition.expressions ?? []);
|
|
210
|
+
if (operator !== 'AND' || expressions.length === 0) {
|
|
211
|
+
throw new Error('JOIN condition only supports equality expressions combined with AND');
|
|
212
|
+
}
|
|
213
|
+
return expressions.flatMap((expression) => this.resolveJoinConditionExpression(expression, joinAlias));
|
|
214
|
+
}
|
|
215
|
+
if (condition.type !== 'binary_expr' || condition.operator !== '=') {
|
|
216
|
+
throw new Error('JOIN condition only supports equality expressions');
|
|
217
|
+
}
|
|
218
|
+
const leftRef = this.getConditionColumnReference(condition.left);
|
|
219
|
+
const rightRef = this.getConditionColumnReference(condition.right);
|
|
220
|
+
if (!leftRef || !rightRef) {
|
|
221
|
+
throw new Error('JOIN equality must compare two table columns');
|
|
222
|
+
}
|
|
223
|
+
if (leftRef.alias !== joinAlias && rightRef.alias !== joinAlias) {
|
|
224
|
+
throw new Error('JOIN condition must reference the joined table in at least one side');
|
|
225
|
+
}
|
|
226
|
+
return [{ left: leftRef, right: rightRef }];
|
|
227
|
+
}
|
|
228
|
+
getConditionColumnReference(field, fallbackAlias) {
|
|
229
|
+
if (field instanceof PodColumnBase) {
|
|
230
|
+
return this.resolveColumnReference(field, fallbackAlias);
|
|
231
|
+
}
|
|
232
|
+
if (typeof field === 'string') {
|
|
233
|
+
if (field.includes('.')) {
|
|
234
|
+
return this.resolveColumnReference(field, fallbackAlias);
|
|
235
|
+
}
|
|
236
|
+
const alias = fallbackAlias ?? this.primaryAlias;
|
|
237
|
+
const table = alias ? this.aliasToTable.get(alias) : undefined;
|
|
238
|
+
if (table && field in (table.columns ?? {})) {
|
|
239
|
+
return this.resolveColumnReference(field, fallbackAlias);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return undefined;
|
|
243
|
+
}
|
|
183
244
|
resolveColumnReference(field, fallbackAlias) {
|
|
184
245
|
if (field instanceof PodColumnBase) {
|
|
185
246
|
const table = field.table;
|
|
@@ -274,6 +335,7 @@ export class SelectQueryBuilder {
|
|
|
274
335
|
joins: planJoins.length > 0 ? planJoins : undefined,
|
|
275
336
|
joinFilters: this.joinFilters.length > 0 ? [...this.joinFilters] : undefined,
|
|
276
337
|
groupBy: this.groupByColumns.length > 0 ? [...this.groupByColumns] : undefined,
|
|
338
|
+
having: this.havingCondition,
|
|
277
339
|
orderBy: this.orderByClauses.length > 0
|
|
278
340
|
? this.orderByClauses.map((clause) => ({
|
|
279
341
|
rawColumn: clause.column,
|
|
@@ -301,49 +363,115 @@ export class SelectQueryBuilder {
|
|
|
301
363
|
this.offsetCount = count;
|
|
302
364
|
return this;
|
|
303
365
|
}
|
|
304
|
-
|
|
366
|
+
addOrderByClause(column, direction = 'asc') {
|
|
305
367
|
const columnName = typeof column === 'string' ? column : column.name;
|
|
306
368
|
if (!columnName) {
|
|
307
369
|
throw new Error('ORDER BY requires a valid column name');
|
|
308
370
|
}
|
|
309
371
|
this.orderByClauses.push({ column: columnName, direction });
|
|
372
|
+
}
|
|
373
|
+
orderBy(...args) {
|
|
374
|
+
if (args.length === 0) {
|
|
375
|
+
throw new Error('ORDER BY requires at least one column or expression');
|
|
376
|
+
}
|
|
377
|
+
if (args.length === 2
|
|
378
|
+
&& (args[0] instanceof PodColumnBase || typeof args[0] === 'string')
|
|
379
|
+
&& (args[1] === 'asc' || args[1] === 'desc')) {
|
|
380
|
+
this.addOrderByClause(args[0], args[1]);
|
|
381
|
+
return this;
|
|
382
|
+
}
|
|
383
|
+
for (const arg of args) {
|
|
384
|
+
if (isOrderByExpression(arg)) {
|
|
385
|
+
this.addOrderByClause(arg.column, arg.direction);
|
|
386
|
+
continue;
|
|
387
|
+
}
|
|
388
|
+
if (arg instanceof PodColumnBase || typeof arg === 'string') {
|
|
389
|
+
this.addOrderByClause(arg, 'asc');
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
392
|
+
throw new Error('ORDER BY received an unsupported argument');
|
|
393
|
+
}
|
|
310
394
|
return this;
|
|
311
395
|
}
|
|
312
396
|
distinct(enable = true) {
|
|
313
397
|
this.isDistinct = enable;
|
|
314
398
|
return this;
|
|
315
399
|
}
|
|
400
|
+
buildSPARQLQuery(methodName = 'toSPARQL()') {
|
|
401
|
+
if (this.sql) {
|
|
402
|
+
const query = this.sql.queryChunks.join('');
|
|
403
|
+
const type = inferSPARQLQueryType(query);
|
|
404
|
+
if (!type) {
|
|
405
|
+
throw new Error(`${methodName} could not infer SPARQL query type from raw AST input`);
|
|
406
|
+
}
|
|
407
|
+
return { type, query, prefixes: {} };
|
|
408
|
+
}
|
|
409
|
+
if (!this.selectedTable) {
|
|
410
|
+
throw new Error('No table specified for SELECT query');
|
|
411
|
+
}
|
|
412
|
+
if (this.joins.length > 0) {
|
|
413
|
+
throw new Error(`${methodName} is not yet supported for JOIN queries in Solid dialect`);
|
|
414
|
+
}
|
|
415
|
+
if (this.shouldUseProjectionFallback()) {
|
|
416
|
+
throw new Error(`${methodName} does not support structured selections in Solid dialect`);
|
|
417
|
+
}
|
|
418
|
+
const converter = this.session.getDialect().getSPARQLConverter?.();
|
|
419
|
+
if (!converter) {
|
|
420
|
+
throw new Error(`${methodName} requires dialect SPARQL converter support`);
|
|
421
|
+
}
|
|
422
|
+
return converter.convertSelectPlan(this.toIR());
|
|
423
|
+
}
|
|
424
|
+
toSPARQL() {
|
|
425
|
+
return this.buildSPARQLQuery('toSPARQL()');
|
|
426
|
+
}
|
|
427
|
+
toSparql() {
|
|
428
|
+
return this.toSPARQL();
|
|
429
|
+
}
|
|
316
430
|
async execute() {
|
|
317
431
|
if (!this.selectedTable) {
|
|
318
432
|
throw new Error('No table specified for SELECT query');
|
|
319
433
|
}
|
|
434
|
+
if (this.limitCount === 0) {
|
|
435
|
+
return [];
|
|
436
|
+
}
|
|
320
437
|
if (this.sql) {
|
|
321
438
|
return await this.session.executeSql(this.sql, this.selectedTable);
|
|
322
439
|
}
|
|
323
440
|
else {
|
|
324
441
|
const plan = this.toIR();
|
|
325
442
|
const wherePayload = plan.conditionTree;
|
|
443
|
+
const hasJoins = this.joins.length > 0;
|
|
444
|
+
const useAggregateFallback = this.shouldUseAggregateFallback();
|
|
445
|
+
const useProjectionFallback = this.shouldUseProjectionFallback();
|
|
446
|
+
const shouldDeferQueryModifiers = hasJoins || useAggregateFallback;
|
|
447
|
+
if (hasJoins || useAggregateFallback || useProjectionFallback) {
|
|
448
|
+
plan.select = undefined;
|
|
449
|
+
plan.selectAll = true;
|
|
450
|
+
}
|
|
451
|
+
const executionPlan = shouldDeferQueryModifiers
|
|
452
|
+
? {
|
|
453
|
+
...plan,
|
|
454
|
+
limit: undefined,
|
|
455
|
+
offset: undefined,
|
|
456
|
+
orderBy: undefined,
|
|
457
|
+
...(useAggregateFallback ? { groupBy: undefined, having: undefined } : {}),
|
|
458
|
+
}
|
|
459
|
+
: plan;
|
|
326
460
|
const operation = {
|
|
327
461
|
type: 'select',
|
|
328
462
|
table: this.selectedTable,
|
|
329
463
|
where: wherePayload,
|
|
330
|
-
limit: this.limitCount,
|
|
331
|
-
offset: this.offsetCount,
|
|
332
|
-
orderBy: this.orderByClauses.length
|
|
464
|
+
limit: shouldDeferQueryModifiers ? undefined : this.limitCount,
|
|
465
|
+
offset: shouldDeferQueryModifiers ? undefined : this.offsetCount,
|
|
466
|
+
orderBy: shouldDeferQueryModifiers || this.orderByClauses.length === 0 ? undefined : this.orderByClauses,
|
|
333
467
|
distinct: this.isDistinct || undefined
|
|
334
468
|
};
|
|
335
|
-
|
|
336
|
-
const useAggregateFallback = this.shouldUseAggregateFallback();
|
|
337
|
-
if (hasJoins || useAggregateFallback) {
|
|
338
|
-
plan.select = undefined;
|
|
339
|
-
plan.selectAll = true;
|
|
340
|
-
}
|
|
341
|
-
operation.plan = plan;
|
|
469
|
+
operation.plan = executionPlan;
|
|
342
470
|
if (this.groupByColumns.length === 0 && this.hasMixedAggregateSelection()) {
|
|
343
471
|
throw new Error('Mixed aggregate and non-aggregate selections require groupBy columns');
|
|
344
472
|
}
|
|
345
473
|
let intermediateRows;
|
|
346
|
-
if (!hasJoins && !useAggregateFallback) {
|
|
474
|
+
if (!hasJoins && !useAggregateFallback && !useProjectionFallback) {
|
|
347
475
|
if (this.selectedFields) {
|
|
348
476
|
operation.select = this.selectedFields;
|
|
349
477
|
}
|
|
@@ -354,7 +482,7 @@ export class SelectQueryBuilder {
|
|
|
354
482
|
if (hasJoins) {
|
|
355
483
|
operation.select = undefined;
|
|
356
484
|
}
|
|
357
|
-
else if (!useAggregateFallback) {
|
|
485
|
+
else if (!useAggregateFallback && !useProjectionFallback) {
|
|
358
486
|
operation.select = this.selectedFields;
|
|
359
487
|
}
|
|
360
488
|
else {
|
|
@@ -371,51 +499,141 @@ export class SelectQueryBuilder {
|
|
|
371
499
|
}
|
|
372
500
|
}
|
|
373
501
|
if (useAggregateFallback) {
|
|
374
|
-
|
|
502
|
+
let aggregateRows = this.handleAggregateFallback(intermediateRows);
|
|
503
|
+
aggregateRows = this.applyHavingFilter(aggregateRows);
|
|
504
|
+
if (shouldDeferQueryModifiers) {
|
|
505
|
+
aggregateRows = this.applyDeferredOrderBy(aggregateRows);
|
|
506
|
+
aggregateRows = this.applyDeferredOffsetAndLimit(aggregateRows);
|
|
507
|
+
}
|
|
508
|
+
return aggregateRows;
|
|
375
509
|
}
|
|
376
510
|
let finalRows = intermediateRows;
|
|
377
511
|
if (!hasJoins) {
|
|
378
512
|
finalRows = this.mergeRowsBySubject(finalRows);
|
|
379
513
|
}
|
|
380
514
|
if (this.selectedTable) {
|
|
381
|
-
finalRows = await this.hydrateInlineColumns(finalRows, this.selectedTable);
|
|
515
|
+
finalRows = await this.hydrateInlineColumns(finalRows, this.selectedTable, !hasJoins);
|
|
382
516
|
// 处理引用字段:将 URI 转换回 ID
|
|
383
517
|
finalRows = this.resolveReferenceIds(finalRows, this.selectedTable);
|
|
384
518
|
}
|
|
519
|
+
if (hasJoins) {
|
|
520
|
+
finalRows = this.applyDeferredOrderBy(finalRows);
|
|
521
|
+
}
|
|
385
522
|
if (this.selectedFields) {
|
|
386
523
|
finalRows = finalRows.map((row) => this.projectSelectedRow(row));
|
|
387
524
|
}
|
|
388
|
-
finalRows = this.
|
|
525
|
+
finalRows = this.applyDistinctRows(finalRows);
|
|
526
|
+
if (!hasJoins) {
|
|
527
|
+
finalRows = this.mergeRowsBySubject(finalRows);
|
|
528
|
+
}
|
|
529
|
+
if (hasJoins) {
|
|
530
|
+
finalRows = this.applyDeferredOffsetAndLimit(finalRows);
|
|
531
|
+
}
|
|
389
532
|
return finalRows;
|
|
390
533
|
}
|
|
391
534
|
}
|
|
392
535
|
projectSelectedRow(row) {
|
|
393
|
-
const projected = {};
|
|
394
536
|
if (!this.selectedFields) {
|
|
395
537
|
return row;
|
|
396
538
|
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
539
|
+
return this.projectFieldMap(row, this.selectedFields);
|
|
540
|
+
}
|
|
541
|
+
projectFieldMap(row, fields, allowAliasFallback = true) {
|
|
542
|
+
const projected = {};
|
|
543
|
+
for (const [key, field] of Object.entries(fields)) {
|
|
544
|
+
projected[key] = this.projectFieldValue(row, key, field, allowAliasFallback);
|
|
545
|
+
}
|
|
546
|
+
return projected;
|
|
547
|
+
}
|
|
548
|
+
projectFieldValue(row, alias, field, allowAliasFallback = true) {
|
|
549
|
+
if (isAggregateExpression(field)) {
|
|
550
|
+
return allowAliasFallback ? row[alias] : undefined;
|
|
551
|
+
}
|
|
552
|
+
if (field instanceof PodTable) {
|
|
553
|
+
return this.projectTableValue(row, field);
|
|
554
|
+
}
|
|
555
|
+
if (this.isSelectFieldMap(field)) {
|
|
556
|
+
const aliases = this.collectSelectionAliases(field);
|
|
557
|
+
const isJoinedOnlySelection = aliases.size === 1 && !aliases.has(this.primaryAlias ?? '');
|
|
558
|
+
const projected = this.projectFieldMap(row, field, !isJoinedOnlySelection);
|
|
559
|
+
if (aliases.size === 1) {
|
|
560
|
+
const [targetAlias] = Array.from(aliases);
|
|
561
|
+
if (targetAlias && targetAlias !== this.primaryAlias && this.isProjectedValueEmpty(projected)) {
|
|
562
|
+
return null;
|
|
409
563
|
}
|
|
410
564
|
}
|
|
411
|
-
|
|
412
|
-
|
|
565
|
+
return projected;
|
|
566
|
+
}
|
|
567
|
+
for (const candidate of this.resolveFieldBindingCandidates(alias, field)) {
|
|
568
|
+
if (row[candidate] !== undefined) {
|
|
569
|
+
return row[candidate];
|
|
413
570
|
}
|
|
414
571
|
}
|
|
572
|
+
return allowAliasFallback ? row[alias] : undefined;
|
|
573
|
+
}
|
|
574
|
+
projectTableValue(row, table) {
|
|
575
|
+
const alias = this.tableAliases.get(table) ?? table.config.name;
|
|
576
|
+
const projected = {};
|
|
577
|
+
let hasValue = false;
|
|
578
|
+
for (const columnName of Object.keys(table.columns)) {
|
|
579
|
+
const candidates = alias === this.primaryAlias
|
|
580
|
+
? [columnName, `${alias}.${columnName}`]
|
|
581
|
+
: [`${alias}.${columnName}`];
|
|
582
|
+
const match = candidates.find((candidate) => row[candidate] !== undefined);
|
|
583
|
+
projected[columnName] = match ? row[match] : undefined;
|
|
584
|
+
if (projected[columnName] !== undefined) {
|
|
585
|
+
hasValue = true;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
if (alias !== this.primaryAlias && !hasValue) {
|
|
589
|
+
return null;
|
|
590
|
+
}
|
|
415
591
|
return projected;
|
|
416
592
|
}
|
|
593
|
+
isSelectFieldMap(field) {
|
|
594
|
+
return !!field
|
|
595
|
+
&& typeof field === 'object'
|
|
596
|
+
&& !(field instanceof PodColumnBase)
|
|
597
|
+
&& !(field instanceof PodTable)
|
|
598
|
+
&& !isAggregateExpression(field);
|
|
599
|
+
}
|
|
600
|
+
collectSelectionAliases(field) {
|
|
601
|
+
if (typeof field === 'string') {
|
|
602
|
+
const { alias } = this.parseColumnReferenceString(field);
|
|
603
|
+
return new Set(alias ? [alias] : this.primaryAlias ? [this.primaryAlias] : []);
|
|
604
|
+
}
|
|
605
|
+
if (field instanceof PodColumnBase) {
|
|
606
|
+
return new Set([this.resolveColumnReference(field).alias]);
|
|
607
|
+
}
|
|
608
|
+
if (field instanceof PodTable) {
|
|
609
|
+
return new Set([this.tableAliases.get(field) ?? field.config.name]);
|
|
610
|
+
}
|
|
611
|
+
if (!this.isSelectFieldMap(field)) {
|
|
612
|
+
return new Set();
|
|
613
|
+
}
|
|
614
|
+
const aliases = new Set();
|
|
615
|
+
for (const child of Object.values(field)) {
|
|
616
|
+
for (const alias of this.collectSelectionAliases(child)) {
|
|
617
|
+
aliases.add(alias);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
return aliases;
|
|
621
|
+
}
|
|
622
|
+
isProjectedValueEmpty(value) {
|
|
623
|
+
if (value === undefined || value === null) {
|
|
624
|
+
return true;
|
|
625
|
+
}
|
|
626
|
+
if (Array.isArray(value)) {
|
|
627
|
+
return value.length === 0;
|
|
628
|
+
}
|
|
629
|
+
if (typeof value === 'object') {
|
|
630
|
+
const entries = Object.values(value);
|
|
631
|
+
return entries.length > 0 && entries.every((entry) => this.isProjectedValueEmpty(entry));
|
|
632
|
+
}
|
|
633
|
+
return false;
|
|
634
|
+
}
|
|
417
635
|
resolveFieldBindingCandidates(alias, field) {
|
|
418
|
-
const candidates = new Set(
|
|
636
|
+
const candidates = new Set();
|
|
419
637
|
if (typeof field === 'string') {
|
|
420
638
|
const { alias: refAlias, column } = this.parseColumnReferenceString(field);
|
|
421
639
|
candidates.add(field);
|
|
@@ -426,8 +644,10 @@ export class SelectQueryBuilder {
|
|
|
426
644
|
}
|
|
427
645
|
else if (field instanceof PodColumnBase) {
|
|
428
646
|
const columnRef = this.resolveColumnReference(field);
|
|
429
|
-
candidates.add(field.name);
|
|
430
647
|
candidates.add(`${columnRef.alias}.${columnRef.column}`);
|
|
648
|
+
if (!columnRef.alias || columnRef.alias === this.primaryAlias) {
|
|
649
|
+
candidates.add(field.name);
|
|
650
|
+
}
|
|
431
651
|
}
|
|
432
652
|
else if (field && typeof field === 'object') {
|
|
433
653
|
const candidateName = field.name;
|
|
@@ -437,13 +657,31 @@ export class SelectQueryBuilder {
|
|
|
437
657
|
}
|
|
438
658
|
return Array.from(candidates);
|
|
439
659
|
}
|
|
660
|
+
shouldUseProjectionFallback() {
|
|
661
|
+
if (!this.selectedFields) {
|
|
662
|
+
return false;
|
|
663
|
+
}
|
|
664
|
+
const containsStructuredField = (field) => {
|
|
665
|
+
if (field instanceof PodTable) {
|
|
666
|
+
return true;
|
|
667
|
+
}
|
|
668
|
+
if (this.isSelectFieldMap(field)) {
|
|
669
|
+
return true;
|
|
670
|
+
}
|
|
671
|
+
return false;
|
|
672
|
+
};
|
|
673
|
+
return Object.values(this.selectedFields).some((field) => containsStructuredField(field));
|
|
674
|
+
}
|
|
440
675
|
shouldUseAggregateFallback() {
|
|
441
|
-
|
|
676
|
+
if (this.havingCondition) {
|
|
677
|
+
return true;
|
|
678
|
+
}
|
|
679
|
+
if (this.joins.length > 0) {
|
|
680
|
+
return this.groupByColumns.length > 0 || this.hasAggregateSelection();
|
|
681
|
+
}
|
|
442
682
|
if (this.groupByColumns.length > 0) {
|
|
443
683
|
return false;
|
|
444
684
|
}
|
|
445
|
-
// For pure aggregate queries (no GROUP BY), Comunica seems to have issues with multiple aggregates
|
|
446
|
-
// So we use JS fallback for these cases
|
|
447
685
|
if (!this.selectedFields) {
|
|
448
686
|
return false;
|
|
449
687
|
}
|
|
@@ -654,6 +892,12 @@ export class SelectQueryBuilder {
|
|
|
654
892
|
}
|
|
655
893
|
return undefined;
|
|
656
894
|
}
|
|
895
|
+
hasAggregateSelection() {
|
|
896
|
+
if (!this.selectedFields) {
|
|
897
|
+
return false;
|
|
898
|
+
}
|
|
899
|
+
return Object.values(this.selectedFields).some((field) => isAggregateExpression(field));
|
|
900
|
+
}
|
|
657
901
|
hasMixedAggregateSelection() {
|
|
658
902
|
if (!this.selectedFields) {
|
|
659
903
|
return false;
|
|
@@ -718,15 +962,17 @@ export class SelectQueryBuilder {
|
|
|
718
962
|
return result;
|
|
719
963
|
});
|
|
720
964
|
}
|
|
721
|
-
async hydrateInlineColumns(rows, table) {
|
|
965
|
+
async hydrateInlineColumns(rows, table, mergeRows = true) {
|
|
722
966
|
if (!rows.length) {
|
|
723
967
|
return rows;
|
|
724
968
|
}
|
|
725
|
-
rows = this.mergeRowsBySubject(rows);
|
|
726
969
|
const inlineColumns = Object.values(table.columns ?? {}).filter((col) => this.isInlineObjectColumn(col));
|
|
727
970
|
if (inlineColumns.length === 0) {
|
|
728
971
|
return rows;
|
|
729
972
|
}
|
|
973
|
+
if (mergeRows) {
|
|
974
|
+
rows = this.mergeRowsBySubject(rows);
|
|
975
|
+
}
|
|
730
976
|
const predicateToColumn = new Map();
|
|
731
977
|
inlineColumns.forEach((col) => {
|
|
732
978
|
const predicate = col.getPredicate(table.config.namespace);
|
|
@@ -779,7 +1025,7 @@ export class SelectQueryBuilder {
|
|
|
779
1025
|
if (!childIri || !pred)
|
|
780
1026
|
return;
|
|
781
1027
|
const child = childMap.get(childIri) ?? { '@id': childIri, id: this.extractIdFromSubject(childIri, table) };
|
|
782
|
-
const key =
|
|
1028
|
+
const key = this.normalizeInlinePredicateKey(pred, inlineNamespace);
|
|
783
1029
|
if (obj === undefined) {
|
|
784
1030
|
childMap.set(childIri, child);
|
|
785
1031
|
return;
|
|
@@ -865,6 +1111,20 @@ export class SelectQueryBuilder {
|
|
|
865
1111
|
return result;
|
|
866
1112
|
});
|
|
867
1113
|
}
|
|
1114
|
+
normalizeInlinePredicateKey(predicate, inlineNamespace) {
|
|
1115
|
+
if (inlineNamespace && predicate.startsWith(inlineNamespace)) {
|
|
1116
|
+
return predicate.slice(inlineNamespace.length);
|
|
1117
|
+
}
|
|
1118
|
+
const hashIndex = predicate.lastIndexOf('#');
|
|
1119
|
+
if (hashIndex !== -1 && hashIndex < predicate.length - 1) {
|
|
1120
|
+
return predicate.slice(hashIndex + 1);
|
|
1121
|
+
}
|
|
1122
|
+
const slashIndex = predicate.lastIndexOf('/');
|
|
1123
|
+
if (slashIndex !== -1 && slashIndex < predicate.length - 1) {
|
|
1124
|
+
return predicate.slice(slashIndex + 1);
|
|
1125
|
+
}
|
|
1126
|
+
return predicate;
|
|
1127
|
+
}
|
|
868
1128
|
normalizeInlineObjectValue(value) {
|
|
869
1129
|
if (value === null || value === undefined)
|
|
870
1130
|
return undefined;
|
|
@@ -887,6 +1147,73 @@ export class SelectQueryBuilder {
|
|
|
887
1147
|
return value.value;
|
|
888
1148
|
return undefined;
|
|
889
1149
|
}
|
|
1150
|
+
applyDeferredOrderBy(rows) {
|
|
1151
|
+
if (this.orderByClauses.length === 0 || rows.length < 2) {
|
|
1152
|
+
return rows;
|
|
1153
|
+
}
|
|
1154
|
+
const sorted = [...rows];
|
|
1155
|
+
sorted.sort((leftRow, rightRow) => {
|
|
1156
|
+
for (const clause of this.orderByClauses) {
|
|
1157
|
+
const leftValue = this.getOrderByValue(leftRow, clause.column);
|
|
1158
|
+
const rightValue = this.getOrderByValue(rightRow, clause.column);
|
|
1159
|
+
const comparison = this.compareOrderByValues(leftValue, rightValue);
|
|
1160
|
+
if (comparison !== 0) {
|
|
1161
|
+
return clause.direction === 'desc' ? -comparison : comparison;
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
return 0;
|
|
1165
|
+
});
|
|
1166
|
+
return sorted;
|
|
1167
|
+
}
|
|
1168
|
+
applyDistinctRows(rows) {
|
|
1169
|
+
if (!this.isDistinct || rows.length < 2) {
|
|
1170
|
+
return rows;
|
|
1171
|
+
}
|
|
1172
|
+
const seen = new Set();
|
|
1173
|
+
const deduped = [];
|
|
1174
|
+
for (const row of rows) {
|
|
1175
|
+
const key = this.serializeValueForKey(row);
|
|
1176
|
+
if (seen.has(key)) {
|
|
1177
|
+
continue;
|
|
1178
|
+
}
|
|
1179
|
+
seen.add(key);
|
|
1180
|
+
deduped.push(row);
|
|
1181
|
+
}
|
|
1182
|
+
return deduped;
|
|
1183
|
+
}
|
|
1184
|
+
applyDeferredOffsetAndLimit(rows) {
|
|
1185
|
+
const offset = this.offsetCount ?? 0;
|
|
1186
|
+
const offsetRows = offset > 0 ? rows.slice(offset) : rows;
|
|
1187
|
+
if (this.limitCount === undefined) {
|
|
1188
|
+
return offsetRows;
|
|
1189
|
+
}
|
|
1190
|
+
return offsetRows.slice(0, this.limitCount);
|
|
1191
|
+
}
|
|
1192
|
+
getOrderByValue(row, columnName) {
|
|
1193
|
+
if (columnName in row) {
|
|
1194
|
+
return row[columnName];
|
|
1195
|
+
}
|
|
1196
|
+
const aliasKey = Object.keys(row).find((key) => key.endsWith(`.${columnName}`));
|
|
1197
|
+
if (aliasKey) {
|
|
1198
|
+
return row[aliasKey];
|
|
1199
|
+
}
|
|
1200
|
+
return undefined;
|
|
1201
|
+
}
|
|
1202
|
+
compareOrderByValues(left, right) {
|
|
1203
|
+
if (left === right) {
|
|
1204
|
+
return 0;
|
|
1205
|
+
}
|
|
1206
|
+
if (left === undefined || left === null) {
|
|
1207
|
+
return 1;
|
|
1208
|
+
}
|
|
1209
|
+
if (right === undefined || right === null) {
|
|
1210
|
+
return -1;
|
|
1211
|
+
}
|
|
1212
|
+
if (typeof left === 'number' && typeof right === 'number') {
|
|
1213
|
+
return left - right;
|
|
1214
|
+
}
|
|
1215
|
+
return String(left).localeCompare(String(right));
|
|
1216
|
+
}
|
|
890
1217
|
mergeRowsBySubject(rows) {
|
|
891
1218
|
const merged = new Map();
|
|
892
1219
|
const order = [];
|
|
@@ -984,11 +1311,11 @@ export class SelectQueryBuilder {
|
|
|
984
1311
|
isInlineObjectColumn(column) {
|
|
985
1312
|
if (!column)
|
|
986
1313
|
return false;
|
|
987
|
-
if (column.dataType === 'object')
|
|
1314
|
+
if (column.dataType === 'object' || column.dataType === 'json')
|
|
988
1315
|
return true;
|
|
989
1316
|
if (column.dataType === 'array') {
|
|
990
1317
|
const elementType = column.elementType ?? column.options?.baseType;
|
|
991
|
-
return elementType === 'object';
|
|
1318
|
+
return elementType === 'object' || elementType === 'json';
|
|
992
1319
|
}
|
|
993
1320
|
return false;
|
|
994
1321
|
}
|
|
@@ -1001,6 +1328,10 @@ export class SelectQueryBuilder {
|
|
|
1001
1328
|
return combinedRows;
|
|
1002
1329
|
}
|
|
1003
1330
|
async fetchJoinRows(join, baseRows) {
|
|
1331
|
+
if (join.type === 'crossJoin') {
|
|
1332
|
+
const joinRows = await this.session.select().from(join.table);
|
|
1333
|
+
return this.normalizeJoinRows(join, joinRows);
|
|
1334
|
+
}
|
|
1004
1335
|
const conditions = join.resolvedConditions ?? [];
|
|
1005
1336
|
if (conditions.length === 0) {
|
|
1006
1337
|
return [];
|
|
@@ -1054,6 +1385,18 @@ export class SelectQueryBuilder {
|
|
|
1054
1385
|
});
|
|
1055
1386
|
}
|
|
1056
1387
|
mergeRowsWithJoin(baseRows, join, joinRows) {
|
|
1388
|
+
if (join.type === 'crossJoin') {
|
|
1389
|
+
if (baseRows.length === 0 || joinRows.length === 0) {
|
|
1390
|
+
return [];
|
|
1391
|
+
}
|
|
1392
|
+
const merged = [];
|
|
1393
|
+
for (const baseRow of baseRows) {
|
|
1394
|
+
for (const joinRow of joinRows) {
|
|
1395
|
+
merged.push({ ...baseRow, ...joinRow });
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
return merged;
|
|
1399
|
+
}
|
|
1057
1400
|
const conditions = join.resolvedConditions ?? [];
|
|
1058
1401
|
if (conditions.length === 0) {
|
|
1059
1402
|
return baseRows;
|
|
@@ -1106,6 +1449,12 @@ export class SelectQueryBuilder {
|
|
|
1106
1449
|
}
|
|
1107
1450
|
return rows.filter((row) => this.joinFilters.every((condition) => this.evaluateCondition(row, condition)));
|
|
1108
1451
|
}
|
|
1452
|
+
applyHavingFilter(rows) {
|
|
1453
|
+
if (!this.havingCondition) {
|
|
1454
|
+
return rows;
|
|
1455
|
+
}
|
|
1456
|
+
return rows.filter((row) => this.evaluateCondition(row, this.havingCondition));
|
|
1457
|
+
}
|
|
1109
1458
|
evaluateCondition(row, condition) {
|
|
1110
1459
|
switch (condition.type) {
|
|
1111
1460
|
case 'binary_expr':
|
|
@@ -1125,27 +1474,8 @@ export class SelectQueryBuilder {
|
|
|
1125
1474
|
if (!left) {
|
|
1126
1475
|
return true;
|
|
1127
1476
|
}
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
let tableAlias;
|
|
1131
|
-
if (typeof left === 'string') {
|
|
1132
|
-
if (left.includes('.')) {
|
|
1133
|
-
[tableAlias, colName] = left.split('.');
|
|
1134
|
-
}
|
|
1135
|
-
else {
|
|
1136
|
-
colName = left;
|
|
1137
|
-
}
|
|
1138
|
-
}
|
|
1139
|
-
else if (left && typeof left === 'object') {
|
|
1140
|
-
colName = left.name;
|
|
1141
|
-
tableAlias = left.table;
|
|
1142
|
-
}
|
|
1143
|
-
else {
|
|
1144
|
-
return true;
|
|
1145
|
-
}
|
|
1146
|
-
const columnRef = this.resolveColumnReference(`${tableAlias ?? this.primaryAlias}.${colName}`);
|
|
1147
|
-
const value = this.getRowValueForColumn(row, columnRef);
|
|
1148
|
-
const target = right;
|
|
1477
|
+
const value = this.resolveConditionOperandValue(row, left, this.primaryAlias);
|
|
1478
|
+
const target = this.resolveConditionOperandValue(row, right);
|
|
1149
1479
|
switch (op.toUpperCase()) {
|
|
1150
1480
|
case '=':
|
|
1151
1481
|
return value === target;
|
|
@@ -1173,33 +1503,13 @@ export class SelectQueryBuilder {
|
|
|
1173
1503
|
evaluateUnaryCondition(row, condition) {
|
|
1174
1504
|
const op = condition.operator;
|
|
1175
1505
|
const val = condition.value;
|
|
1176
|
-
// For NOT operator, value is another condition
|
|
1177
1506
|
if (op.toUpperCase() === 'NOT') {
|
|
1178
1507
|
return !this.evaluateCondition(row, val);
|
|
1179
1508
|
}
|
|
1180
|
-
// For IS NULL / IS NOT NULL, value is the column reference
|
|
1181
1509
|
if (!val) {
|
|
1182
1510
|
return true;
|
|
1183
1511
|
}
|
|
1184
|
-
|
|
1185
|
-
let tableAlias;
|
|
1186
|
-
if (typeof val === 'string') {
|
|
1187
|
-
if (val.includes('.')) {
|
|
1188
|
-
[tableAlias, colName] = val.split('.');
|
|
1189
|
-
}
|
|
1190
|
-
else {
|
|
1191
|
-
colName = val;
|
|
1192
|
-
}
|
|
1193
|
-
}
|
|
1194
|
-
else if (val && typeof val === 'object' && 'name' in val) {
|
|
1195
|
-
colName = val.name;
|
|
1196
|
-
tableAlias = val.table;
|
|
1197
|
-
}
|
|
1198
|
-
else {
|
|
1199
|
-
return true;
|
|
1200
|
-
}
|
|
1201
|
-
const columnRef = this.resolveColumnReference(`${tableAlias ?? this.primaryAlias}.${colName}`);
|
|
1202
|
-
const rowValue = this.getRowValueForColumn(row, columnRef);
|
|
1512
|
+
const rowValue = this.resolveConditionOperandValue(row, val, this.primaryAlias);
|
|
1203
1513
|
switch (op.toUpperCase()) {
|
|
1204
1514
|
case 'IS NULL':
|
|
1205
1515
|
return rowValue === null || rowValue === undefined;
|
|
@@ -1220,6 +1530,16 @@ export class SelectQueryBuilder {
|
|
|
1220
1530
|
}
|
|
1221
1531
|
return true;
|
|
1222
1532
|
}
|
|
1533
|
+
resolveConditionOperandValue(row, operand, fallbackAlias) {
|
|
1534
|
+
if (operand instanceof SelectionAliasExpression) {
|
|
1535
|
+
return row[operand.alias];
|
|
1536
|
+
}
|
|
1537
|
+
const columnRef = this.getConditionColumnReference(operand, fallbackAlias);
|
|
1538
|
+
if (columnRef) {
|
|
1539
|
+
return this.getRowValueForColumn(row, columnRef);
|
|
1540
|
+
}
|
|
1541
|
+
return operand;
|
|
1542
|
+
}
|
|
1223
1543
|
getColumnKeyCandidates(column) {
|
|
1224
1544
|
const candidates = [];
|
|
1225
1545
|
const baseAlias = this.primaryAlias;
|