From c3898a6fcce6669b508d574cd0d5823302339906 Mon Sep 17 00:00:00 2001 From: Michael Bromley Date: Tue, 28 Jan 2020 20:21:46 +0100 Subject: [PATCH] fix(core): Fix "contains" list filter operator for postgres --- .../list-query-builder/get-column-metadata.ts | 18 +++++++++ .../list-query-builder/parse-filter-params.ts | 40 ++++++++++--------- .../parse-sort-params.spec.ts | 5 ++- .../list-query-builder/parse-sort-params.ts | 17 ++------ 4 files changed, 46 insertions(+), 34 deletions(-) create mode 100644 packages/core/src/service/helpers/list-query-builder/get-column-metadata.ts diff --git a/packages/core/src/service/helpers/list-query-builder/get-column-metadata.ts b/packages/core/src/service/helpers/list-query-builder/get-column-metadata.ts new file mode 100644 index 0000000000..03e1e71298 --- /dev/null +++ b/packages/core/src/service/helpers/list-query-builder/get-column-metadata.ts @@ -0,0 +1,18 @@ +import { Type } from '@vendure/common/lib/shared-types'; +import { Connection } from 'typeorm'; +import { ColumnMetadata } from 'typeorm/metadata/ColumnMetadata'; + +export function getColumnMetadata(connection: Connection, entity: Type) { + const metadata = connection.getMetadata(entity); + const columns = metadata.columns; + let translationColumns: ColumnMetadata[] = []; + const relations = metadata.relations; + + const translationRelation = relations.find(r => r.propertyName === 'translations'); + if (translationRelation) { + const translationMetadata = connection.getMetadata(translationRelation.type); + translationColumns = columns.concat(translationMetadata.columns.filter(c => !c.relationMetadata)); + } + const alias = metadata.name.toLowerCase(); + return { columns, translationColumns, alias }; +} diff --git a/packages/core/src/service/helpers/list-query-builder/parse-filter-params.ts b/packages/core/src/service/helpers/list-query-builder/parse-filter-params.ts index bdd049d53f..98bf91ed08 100644 --- a/packages/core/src/service/helpers/list-query-builder/parse-filter-params.ts +++ b/packages/core/src/service/helpers/list-query-builder/parse-filter-params.ts @@ -1,7 +1,6 @@ import { Type } from '@vendure/common/lib/shared-types'; import { assertNever } from '@vendure/common/lib/shared-utils'; -import { Connection } from 'typeorm'; -import { ColumnMetadata } from 'typeorm/metadata/ColumnMetadata'; +import { Connection, ConnectionOptions } from 'typeorm'; import { UserInputError } from '../../../common/error/errors'; import { @@ -14,6 +13,8 @@ import { } from '../../../common/types/common-types'; import { VendureEntity } from '../../../entity/base/base.entity'; +import { getColumnMetadata } from './get-column-metadata'; + export interface WhereCondition { clause: string; parameters: { [param: string]: string | number }; @@ -30,21 +31,9 @@ export function parseFilterParams( if (!filterParams) { return []; } - - const metadata = connection.getMetadata(entity); - const columns = metadata.columns; - let translationColumns: ColumnMetadata[] = []; - const relations = metadata.relations; - - const translationRelation = relations.find(r => r.propertyName === 'translations'); - if (translationRelation) { - const translationMetadata = connection.getMetadata(translationRelation.type); - translationColumns = columns.concat(translationMetadata.columns.filter(c => !c.relationMetadata)); - } - + const { columns, translationColumns, alias } = getColumnMetadata(connection, entity); const output: WhereCondition[] = []; - const alias = metadata.name.toLowerCase(); - + const dbType = connection.options.type; let argIndex = 1; for (const [key, operation] of Object.entries(filterParams)) { if (operation) { @@ -57,7 +46,13 @@ export function parseFilterParams( } else { throw new UserInputError('error.invalid-filter-field'); } - const condition = buildWhereCondition(fieldName, operator as Operator, operand, argIndex); + const condition = buildWhereCondition( + fieldName, + operator as Operator, + operand, + argIndex, + dbType, + ); output.push(condition); argIndex++; } @@ -67,7 +62,13 @@ export function parseFilterParams( return output; } -function buildWhereCondition(fieldName: string, operator: Operator, operand: any, argIndex: number): WhereCondition { +function buildWhereCondition( + fieldName: string, + operator: Operator, + operand: any, + argIndex: number, + dbType: ConnectionOptions['type'], +): WhereCondition { switch (operator) { case 'eq': return { @@ -75,8 +76,9 @@ function buildWhereCondition(fieldName: string, operator: Operator, operand: any parameters: { [`arg${argIndex}`]: operand }, }; case 'contains': + const LIKE = dbType === 'postgres' ? 'ILIKE' : 'LIKE'; return { - clause: `${fieldName} LIKE :arg${argIndex}`, + clause: `${fieldName} ${LIKE} :arg${argIndex}`, parameters: { [`arg${argIndex}`]: `%${operand.trim()}%` }, }; case 'lt': diff --git a/packages/core/src/service/helpers/list-query-builder/parse-sort-params.spec.ts b/packages/core/src/service/helpers/list-query-builder/parse-sort-params.spec.ts index 787e33711b..09f8155b6b 100644 --- a/packages/core/src/service/helpers/list-query-builder/parse-sort-params.spec.ts +++ b/packages/core/src/service/helpers/list-query-builder/parse-sort-params.spec.ts @@ -145,5 +145,8 @@ export class MockConnection { columns: this.columnsMap.get(entity) || [], relations: this.relationsMap.get(entity) || [], }; - } + }; + readonly options = { + type: 'sqljs', + }; } diff --git a/packages/core/src/service/helpers/list-query-builder/parse-sort-params.ts b/packages/core/src/service/helpers/list-query-builder/parse-sort-params.ts index cf888a6053..dc5a60863b 100644 --- a/packages/core/src/service/helpers/list-query-builder/parse-sort-params.ts +++ b/packages/core/src/service/helpers/list-query-builder/parse-sort-params.ts @@ -7,6 +7,8 @@ import { UserInputError } from '../../../common/error/errors'; import { NullOptionals, SortParameter } from '../../../common/types/common-types'; import { VendureEntity } from '../../../entity/base/base.entity'; +import { getColumnMetadata } from './get-column-metadata'; + /** * Parses the provided SortParameter array against the metadata of the given entity, ensuring that only * valid fields are being sorted against. The output assumes @@ -22,21 +24,8 @@ export function parseSortParams( if (!sortParams || Object.keys(sortParams).length === 0) { return {}; } - - const metadata = connection.getMetadata(entity); - const columns = metadata.columns; - let translationColumns: ColumnMetadata[] = []; - const relations = metadata.relations; - - const translationRelation = relations.find(r => r.propertyName === 'translations'); - if (translationRelation) { - const translationMetadata = connection.getMetadata(translationRelation.type); - translationColumns = columns.concat(translationMetadata.columns.filter(c => !c.relationMetadata)); - } - + const { columns, translationColumns, alias } = getColumnMetadata(connection, entity); const output: OrderByCondition = {}; - const alias = metadata.name.toLowerCase(); - for (const [key, order] of Object.entries(sortParams)) { if (columns.find(c => c.propertyName === key)) { output[`${alias}.${key}`] = order as any;