postgres short circuit empty find results

This commit is contained in:
Dan Ribbens
2023-09-09 17:26:38 -04:00
parent 754efe00f6
commit af6b7592a1
5 changed files with 80 additions and 49 deletions

View File

@@ -13,7 +13,6 @@ export const create: Create = async function create({
adapter: this,
data,
fields: collection.fields,
locale: req.locale,
operation: 'create',
tableName: toSnakeCase(collectionSlug),
});

View File

@@ -49,7 +49,7 @@ export const find: Find = async function find(
const selectFields: Record<string, GenericColumn> = {
id: table.id,
};
if (orderBy) {
if (orderBy.column) {
selectFields.sort = orderBy.column;
}
@@ -79,13 +79,30 @@ export const find: Find = async function find(
const result = await selectQuery
.offset((page - 1) * limit)
.limit(limit === 0 ? undefined : limit);
if (result.length === 0) {
return {
docs: [],
totalDocs: 0,
limit,
totalPages: 0,
page: 1,
pagingCounter: 0,
hasPrevPage: false,
hasNextPage: false,
prevPage: null,
nextPage: null,
};
}
// set the id in an object for sorting later
result.forEach(({ id }, i) => {
orderedIDMap[id as (number | string)] = i;
});
findManyArgs.where = inArray(this.tables[tableName].id, Object.keys(orderedIDMap));
} else {
findManyArgs.where = where;
if (where) {
findManyArgs.where = where;
}
// orderBy will only be set if a complex sort is needed on a relation
if (sort) {
if (sort[0] === '-') {

View File

@@ -143,10 +143,11 @@ export const getTableColumnFromPath = ({
case 'relationship':
case 'upload': {
newTableName = `${toSnakeCase(tableName)}_relationships`;
let relationshipFields;
if (typeof field.relationTo === 'string') {
relationshipFields = adapter.payload.collections[field.relationTo];
newTableName = `${toSnakeCase(field.relationTo)}`;
joins[newTableName] = eq(adapter.tables[newTableName].id, adapter.tables[`${toSnakeCase(tableName)}_relationships`][`${toSnakeCase(field.relationTo)}ID`]);
relationshipFields = adapter.payload.collections[field.relationTo].config.fields;
if (locale && field.localized && adapter.payload.config.localization) {
joins[newTableName] = and(
eq(adapter.tables[tableName].id, adapter.tables[newTableName]._parentID),
@@ -162,7 +163,7 @@ export const getTableColumnFromPath = ({
adapter,
collectionPath: pathSegments.slice(1)
.join('.'),
fields: relationshipFields as Field[],
fields: relationshipFields,
joins,
locale,
pathSegments: pathSegments.slice(1),

View File

@@ -1,4 +1,4 @@
import { and, eq, gt, gte, inArray, isNotNull, lt, lte, ne, notInArray, or } from 'drizzle-orm';
import { and, eq, gt, gte, ilike, inArray, isNotNull, lt, lte, ne, notInArray, or } from 'drizzle-orm';
export const operatorMap = {
greater_than_equal: gte,
@@ -6,6 +6,7 @@ export const operatorMap = {
less_than: lt,
greater_than: gt,
in: inArray,
like: ilike,
// TODO:
// all: all,
not_in: notInArray,

View File

@@ -19,6 +19,7 @@ type Args = {
tableName: string,
fields: Field[]
}
export async function parseParams({
joins,
where,
@@ -30,49 +31,57 @@ export async function parseParams({
let result: SQL;
const constraints: SQL[] = [];
if (typeof where === 'object') {
if (typeof where === 'object' && Object.keys(where).length > 0) {
// We need to determine if the whereKey is an AND, OR, or a schema path
for (const relationOrPath of Object.keys(where)) {
const condition = where[relationOrPath];
let conditionOperator: 'and' | 'or';
if (relationOrPath.toLowerCase() === 'and') {
conditionOperator = 'and';
} else if (relationOrPath.toLowerCase() === 'or') {
conditionOperator = 'or';
}
if (Array.isArray(condition)) {
const builtConditions = await buildAndOrConditions({
joins,
fields,
adapter,
locale,
tableName,
where: condition,
});
if (builtConditions.length > 0) result = operatorMap[conditionOperator](result, ...builtConditions);
} else {
// It's a path - and there can be multiple comparisons on a single path.
// For example - title like 'test' and title not equal to 'tester'
// So we need to loop on keys again here to handle each operator independently
const pathOperators = where[relationOrPath];
if (typeof pathOperators === 'object') {
for (const operator of Object.keys(pathOperators)) {
if (validOperators.includes(operator as Operator)) {
const tableColumn = getTableColumnFromPath({
adapter,
collectionPath: relationOrPath,
fields,
joins,
locale,
pathSegments: relationOrPath.split('.'),
tableName,
});
const queryValue = sanitizeQueryValue({
field: tableColumn.field,
operator,
val: where[relationOrPath][operator],
});
constraints.push(operatorMap[operator](tableColumn.table[tableColumn.columnName], queryValue));
if (relationOrPath) {
const condition = where[relationOrPath];
let conditionOperator: 'and' | 'or';
if (relationOrPath.toLowerCase() === 'and') {
conditionOperator = 'and';
} else if (relationOrPath.toLowerCase() === 'or') {
conditionOperator = 'or';
}
if (Array.isArray(condition)) {
const builtConditions = await buildAndOrConditions({
joins,
fields,
adapter,
locale,
tableName,
where: condition,
});
if (builtConditions.length > 0) {
if (result) {
result = operatorMap[conditionOperator](result, ...builtConditions);
} else {
result = operatorMap[conditionOperator](...builtConditions);
}
}
} else {
// It's a path - and there can be multiple comparisons on a single path.
// For example - title like 'test' and title not equal to 'tester'
// So we need to loop on keys again here to handle each operator independently
const pathOperators = where[relationOrPath];
if (typeof pathOperators === 'object') {
for (const operator of Object.keys(pathOperators)) {
if (validOperators.includes(operator as Operator)) {
const tableColumn = getTableColumnFromPath({
adapter,
collectionPath: relationOrPath,
fields,
joins,
locale,
pathSegments: relationOrPath.split('.'),
tableName,
});
const queryValue = sanitizeQueryValue({
field: tableColumn.field,
operator,
val: where[relationOrPath][operator],
});
constraints.push(operatorMap[operator](tableColumn.table[tableColumn.columnName], queryValue));
}
}
}
}
@@ -80,7 +89,11 @@ export async function parseParams({
}
}
if (constraints.length > 0) {
result = and(result, ...constraints);
if (result) {
result = and(result, ...constraints);
} else {
result = and(...constraints);
}
}