Skip to content

Commit

Permalink
Move union query application to applyQuery, fix where clause (directu…
Browse files Browse the repository at this point in the history
…s#9494)

* Move union query application to applyQuery, fix where clause

Fixes directus#9228

* Handle case where union IDs length = 0

* Return modified db query

* Apply union last
  • Loading branch information
rijkvanzanten authored and Armen Danielyan committed Nov 9, 2021
1 parent 3153f2c commit 3835533
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 28 deletions.
23 changes: 2 additions & 21 deletions api/src/database/run-ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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(
Expand Down
39 changes: 32 additions & 7 deletions api/src/utils/apply-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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) => {
Expand Down Expand Up @@ -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);
}
Expand All @@ -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;
}

/**
Expand Down Expand Up @@ -118,14 +141,16 @@ export function applyFilter(
rootFilter: Filter,
collection: string,
subQuery = false
): void {
) {
const relations: Relation[] = schema.relations;

const aliasMap: Record<string, string> = {};

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') {
Expand Down

0 comments on commit 3835533

Please sign in to comment.