Move union query application to applyQuery, fix where clause (#9494)

* Move union query application to applyQuery, fix where clause

Fixes #9228

* Handle case where union IDs length = 0

* Return modified db query

* Apply union last
This commit is contained in:
Rijk van Zanten
2021-11-04 18:55:10 -04:00
committed by GitHub
parent ae15f39091
commit dbe29554e7
2 changed files with 34 additions and 28 deletions

View File

@@ -69,24 +69,7 @@ export default async function runAST(
);
// The actual knex query builder instance. This is a promise that resolves with the raw items from the db
let dbQuery = getDBQuery(schema, knex, collection, fieldNodes, query);
if (query.union) {
const [field, keys] = query.union;
if (keys.length) {
const queries = keys.map((key) => {
return knex.select('*').from(
dbQuery
.clone()
.andWhere({ [field]: key })
.as('foo')
);
});
dbQuery = knex.unionAll(queries);
}
}
const dbQuery = getDBQuery(schema, knex, collection, fieldNodes, query);
const rawItems: Item | Item[] = await dbQuery;
@@ -230,9 +213,7 @@ function getDBQuery(
queryCopy.limit = typeof queryCopy.limit === 'number' ? queryCopy.limit : 100;
applyQuery(knex, table, dbQuery, queryCopy, schema);
return dbQuery;
return applyQuery(knex, table, dbQuery, queryCopy, schema);
}
function applyParentFilters(

View File

@@ -4,7 +4,7 @@ import { customAlphabet } from 'nanoid';
import validate from 'uuid-validate';
import { InvalidQueryException } from '../exceptions';
import { Relation, SchemaOverview } from '../types';
import { Aggregate, Filter, Query } from '@directus/shared/types';
import { Aggregate, Filter, LogicalFilterAND, Query } from '@directus/shared/types';
import { applyFunctionToColumnName } from './apply-function-to-column-name';
import { getColumn } from './get-column';
import { getRelationType } from './get-relation-type';
@@ -23,7 +23,7 @@ export default function applyQuery(
query: Query,
schema: SchemaOverview,
subQuery = false
): void {
): Knex.QueryBuilder {
if (query.sort) {
dbQuery.orderBy(
query.sort.map((sortField) => {
@@ -55,10 +55,6 @@ export default function applyQuery(
dbQuery.offset(query.limit * (query.page - 1));
}
if (query.filter) {
applyFilter(knex, schema, dbQuery, query.filter, collection, subQuery);
}
if (query.search) {
applySearch(schema, dbQuery, query.search, collection);
}
@@ -70,6 +66,33 @@ export default function applyQuery(
if (query.aggregate) {
applyAggregate(dbQuery, query.aggregate, collection);
}
if (query.union && query.union[1].length > 0) {
const [field, keys] = query.union as [string, (string | number)[]];
const queries = keys.map((key) => {
let filter = { [field]: { _eq: key } } as Filter;
if (query.filter) {
if ('_and' in query.filter) {
(query.filter as LogicalFilterAND)._and.push(filter);
filter = query.filter;
} else {
filter = {
_and: [query.filter, filter],
} as LogicalFilterAND;
}
}
return knex.select('*').from(applyFilter(knex, schema, dbQuery.clone(), filter, collection, subQuery).as('foo'));
});
dbQuery = knex.unionAll(queries);
} else if (query.filter) {
applyFilter(knex, schema, dbQuery, query.filter, collection, subQuery);
}
return dbQuery;
}
/**
@@ -118,7 +141,7 @@ export function applyFilter(
rootFilter: Filter,
collection: string,
subQuery = false
): void {
) {
const relations: Relation[] = schema.relations;
const aliasMap: Record<string, string> = {};
@@ -126,6 +149,8 @@ export function applyFilter(
addJoins(rootQuery, rootFilter, collection);
addWhereClauses(knex, rootQuery, rootFilter, collection);
return rootQuery;
function addJoins(dbQuery: Knex.QueryBuilder, filter: Filter, collection: string) {
for (const [key, value] of Object.entries(filter)) {
if (key === '_or' || key === '_and') {