From 084554eaa82662ff61d14f503cbe0de656863a25 Mon Sep 17 00:00:00 2001 From: Weiko Date: Thu, 27 Feb 2025 11:05:53 +0100 Subject: [PATCH] Fix filter rest api (#10537) ## Context Rest API is now using cache metadata but the change was not done everywhere which was breaking the API Screenshot 2025-02-27 at 10 48 31 --- .../factories/get-variables.factory.ts | 13 +++- .../__tests__/check-fields.utils.spec.ts | 53 ++++++++++++-- .../__tests__/get-field-type.utils.spec.ts | 38 +++++++++- .../query-builder/utils/check-fields.utils.ts | 9 +-- .../utils/check-order-by.utils.ts | 8 +- .../check-filter-enum-values.spec.ts | 32 +++++++- .../__tests__/parse-filter.utils.spec.ts | 55 ++++++++++++-- .../filter-utils/check-filter-enum-values.ts | 8 +- .../utils/filter-utils/parse-filter.utils.ts | 13 ++-- .../utils/get-field-type.utils.ts | 6 +- .../__tests__/filter-input.factory.spec.ts | 73 ++++++++++++++++++- .../input-factories/filter-input.factory.ts | 12 ++- 12 files changed, 269 insertions(+), 51 deletions(-) diff --git a/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/get-variables.factory.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/get-variables.factory.ts index 5af552d48..fe5331a72 100644 --- a/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/get-variables.factory.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/get-variables.factory.ts @@ -2,12 +2,14 @@ import { Injectable } from '@nestjs/common'; import { Request } from 'express'; -import { LimitInputFactory } from 'src/engine/api/rest/input-factories/limit-input.factory'; -import { OrderByInputFactory } from 'src/engine/api/rest/input-factories/order-by-input.factory'; -import { FilterInputFactory } from 'src/engine/api/rest/input-factories/filter-input.factory'; import { QueryVariables } from 'src/engine/api/rest/core/types/query-variables.type'; import { EndingBeforeInputFactory } from 'src/engine/api/rest/input-factories/ending-before-input.factory'; +import { FilterInputFactory } from 'src/engine/api/rest/input-factories/filter-input.factory'; +import { LimitInputFactory } from 'src/engine/api/rest/input-factories/limit-input.factory'; +import { OrderByInputFactory } from 'src/engine/api/rest/input-factories/order-by-input.factory'; import { StartingAfterInputFactory } from 'src/engine/api/rest/input-factories/starting-after-input.factory'; +import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps'; +import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps'; @Injectable() export class GetVariablesFactory { @@ -22,7 +24,10 @@ export class GetVariablesFactory { create( id: string | undefined, request: Request, - objectMetadata, + objectMetadata: { + objectMetadataMaps: ObjectMetadataMaps; + objectMetadataMapItem: ObjectMetadataItemWithFieldMaps; + }, ): QueryVariables { if (id) { return { filter: { id: { eq: id } } }; diff --git a/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/__tests__/check-fields.utils.spec.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/__tests__/check-fields.utils.spec.ts index 865eac4bc..623f047ee 100644 --- a/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/__tests__/check-fields.utils.spec.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/__tests__/check-fields.utils.spec.ts @@ -1,31 +1,70 @@ -import { objectMetadataItemMock } from 'src/engine/api/__mocks__/object-metadata-item.mock'; +import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface'; + +import { + fieldNumberMock, + objectMetadataItemMock, +} from 'src/engine/api/__mocks__/object-metadata-item.mock'; import { checkFields } from 'src/engine/api/rest/core/query-builder/utils/check-fields.utils'; import { checkArrayFields } from 'src/engine/api/rest/core/query-builder/utils/check-order-by.utils'; +import { FieldMetadataMap } from 'src/engine/metadata-modules/types/field-metadata-map'; describe('checkFields', () => { + const completeFieldNumberMock: FieldMetadataInterface = { + id: 'field-number-id', + type: fieldNumberMock.type, + name: fieldNumberMock.name, + label: 'Field Number', + objectMetadataId: 'object-metadata-id', + isNullable: fieldNumberMock.isNullable, + defaultValue: fieldNumberMock.defaultValue, + }; + + const fieldsById: FieldMetadataMap = { + 'field-number-id': completeFieldNumberMock, + }; + + const fieldsByName: FieldMetadataMap = { + [completeFieldNumberMock.name]: completeFieldNumberMock, + }; + + const mockObjectMetadataWithFieldMaps = { + ...objectMetadataItemMock, + fieldsById, + fieldsByName, + }; + it('should check field types', () => { expect(() => - checkFields(objectMetadataItemMock, ['fieldNumber']), + checkFields(mockObjectMetadataWithFieldMaps, ['fieldNumber']), ).not.toThrow(); - expect(() => checkFields(objectMetadataItemMock, ['wrongField'])).toThrow(); + expect(() => + checkFields(mockObjectMetadataWithFieldMaps, ['wrongField']), + ).toThrow(); expect(() => - checkFields(objectMetadataItemMock, ['fieldNumber', 'wrongField']), + checkFields(mockObjectMetadataWithFieldMaps, [ + 'fieldNumber', + 'wrongField', + ]), ).toThrow(); }); it('should check field types from array of fields', () => { expect(() => - checkArrayFields(objectMetadataItemMock, [{ fieldNumber: undefined }]), + checkArrayFields(mockObjectMetadataWithFieldMaps, [ + { fieldNumber: undefined }, + ]), ).not.toThrow(); expect(() => - checkArrayFields(objectMetadataItemMock, [{ wrongField: undefined }]), + checkArrayFields(mockObjectMetadataWithFieldMaps, [ + { wrongField: undefined }, + ]), ).toThrow(); expect(() => - checkArrayFields(objectMetadataItemMock, [ + checkArrayFields(mockObjectMetadataWithFieldMaps, [ { fieldNumber: undefined }, { wrongField: undefined }, ]), diff --git a/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/__tests__/get-field-type.utils.spec.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/__tests__/get-field-type.utils.spec.ts index 8a23abca6..48658961a 100644 --- a/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/__tests__/get-field-type.utils.spec.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/__tests__/get-field-type.utils.spec.ts @@ -1,12 +1,42 @@ import { FieldMetadataType } from 'twenty-shared'; -import { objectMetadataItemMock } from 'src/engine/api/__mocks__/object-metadata-item.mock'; +import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface'; + +import { + fieldNumberMock, + objectMetadataItemMock, +} from 'src/engine/api/__mocks__/object-metadata-item.mock'; import { getFieldType } from 'src/engine/api/rest/core/query-builder/utils/get-field-type.utils'; +import { FieldMetadataMap } from 'src/engine/metadata-modules/types/field-metadata-map'; describe('getFieldType', () => { + const completeFieldNumberMock: FieldMetadataInterface = { + id: 'field-number-id', + type: fieldNumberMock.type, + name: fieldNumberMock.name, + label: 'Field Number', + objectMetadataId: 'object-metadata-id', + isNullable: fieldNumberMock.isNullable, + defaultValue: fieldNumberMock.defaultValue, + }; + + const fieldsById: FieldMetadataMap = { + 'field-number-id': completeFieldNumberMock, + }; + + const fieldsByName: FieldMetadataMap = { + [completeFieldNumberMock.name]: completeFieldNumberMock, + }; + + const mockObjectMetadataWithFieldMaps = { + ...objectMetadataItemMock, + fieldsById, + fieldsByName, + }; + it('should get field type', () => { - expect(getFieldType(objectMetadataItemMock, 'fieldNumber')).toEqual( - FieldMetadataType.NUMBER, - ); + expect( + getFieldType(mockObjectMetadataWithFieldMaps, 'fieldNumber'), + ).toEqual(FieldMetadataType.NUMBER); }); }); diff --git a/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/check-fields.utils.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/check-fields.utils.ts index df9141b99..e9a10d105 100644 --- a/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/check-fields.utils.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/check-fields.utils.ts @@ -1,16 +1,15 @@ import { BadRequestException } from '@nestjs/common'; -import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface'; - import { compositeTypeDefinitions } from 'src/engine/metadata-modules/field-metadata/composite-types'; import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util'; +import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps'; import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; export const checkFields = ( - objectMetadata: ObjectMetadataInterface, + objectMetadataItem: ObjectMetadataItemWithFieldMaps, fieldNames: string[], ): void => { - const fieldMetadataNames = objectMetadata.fields + const fieldMetadataNames = objectMetadataItem.fields .map((field) => { if (isCompositeFieldMetadataType(field.type)) { const compositeType = compositeTypeDefinitions.get(field.type); @@ -38,7 +37,7 @@ export const checkFields = ( if (!fieldMetadataNames.includes(fieldName)) { throw new BadRequestException( `field '${fieldName}' does not exist in '${computeObjectTargetTable( - objectMetadata, + objectMetadataItem, )}' object`, ); } diff --git a/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/check-order-by.utils.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/check-order-by.utils.ts index 55f929791..b128ad11b 100644 --- a/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/check-order-by.utils.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/check-order-by.utils.ts @@ -1,17 +1,17 @@ import { BadRequestException } from '@nestjs/common'; import { ObjectRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface'; -import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface'; import { compositeTypeDefinitions } from 'src/engine/metadata-modules/field-metadata/composite-types'; import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util'; +import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps'; import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; export const checkArrayFields = ( - objectMetadata: ObjectMetadataInterface, + objectMetadataItem: ObjectMetadataItemWithFieldMaps, fields: Array>, ): void => { - const fieldMetadataNames = objectMetadata.fields + const fieldMetadataNames = objectMetadataItem.fields .map((field) => { if (isCompositeFieldMetadataType(field.type)) { const compositeType = compositeTypeDefinitions.get(field.type); @@ -39,7 +39,7 @@ export const checkArrayFields = ( if (!fieldMetadataNames.includes(fieldName)) { throw new BadRequestException( `field '${fieldName}' does not exist in '${computeObjectTargetTable( - objectMetadata, + objectMetadataItem, )}' object`, ); } diff --git a/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/check-filter-enum-values.spec.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/check-filter-enum-values.spec.ts index ee0a8c6e0..c75e8c7a2 100644 --- a/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/check-filter-enum-values.spec.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/check-filter-enum-values.spec.ts @@ -1,19 +1,47 @@ import { FieldMetadataType } from 'twenty-shared'; +import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface'; + import { fieldSelectMock, objectMetadataItemMock, } from 'src/engine/api/__mocks__/object-metadata-item.mock'; import { checkFilterEnumValues } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/check-filter-enum-values'; +import { FieldMetadataMap } from 'src/engine/metadata-modules/types/field-metadata-map'; describe('checkFilterEnumValues', () => { + const completeFieldSelectMock: FieldMetadataInterface = { + id: 'field-select-id', + type: fieldSelectMock.type, + name: fieldSelectMock.name, + label: 'Field Select', + objectMetadataId: 'object-metadata-id', + isNullable: fieldSelectMock.isNullable, + defaultValue: fieldSelectMock.defaultValue, + options: fieldSelectMock.options, + }; + + const fieldsById: FieldMetadataMap = { + 'field-select-id': completeFieldSelectMock, + }; + + const fieldsByName: FieldMetadataMap = { + [completeFieldSelectMock.name]: completeFieldSelectMock, + }; + + const mockObjectMetadataWithFieldMaps = { + ...objectMetadataItemMock, + fieldsById, + fieldsByName, + }; + it('should check properly', () => { expect(() => checkFilterEnumValues( FieldMetadataType.SELECT, fieldSelectMock.name, 'OPTION_1', - objectMetadataItemMock, + mockObjectMetadataWithFieldMaps, ), ).not.toThrow(); @@ -22,7 +50,7 @@ describe('checkFilterEnumValues', () => { FieldMetadataType.SELECT, fieldSelectMock.name, 'MISSING_OPTION', - objectMetadataItemMock, + mockObjectMetadataWithFieldMaps, ), ).toThrow( `'filter' enum value 'MISSING_OPTION' not available in '${fieldSelectMock.name}' enum. Available enum values are ['OPTION_1', 'OPTION_2']`, diff --git a/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/parse-filter.utils.spec.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/parse-filter.utils.spec.ts index b92b09c96..8376ab61b 100644 --- a/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/parse-filter.utils.spec.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/parse-filter.utils.spec.ts @@ -1,12 +1,55 @@ -import { objectMetadataItemMock } from 'src/engine/api/__mocks__/object-metadata-item.mock'; +import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface'; + +import { + fieldNumberMock, + fieldTextMock, + objectMetadataItemMock, +} from 'src/engine/api/__mocks__/object-metadata-item.mock'; import { parseFilter } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/parse-filter.utils'; +import { FieldMetadataMap } from 'src/engine/metadata-modules/types/field-metadata-map'; describe('parseFilter', () => { + const completeFieldNumberMock: FieldMetadataInterface = { + id: 'field-number-id', + type: fieldNumberMock.type, + name: fieldNumberMock.name, + label: 'Field Number', + objectMetadataId: 'object-metadata-id', + isNullable: fieldNumberMock.isNullable, + defaultValue: fieldNumberMock.defaultValue, + }; + + const completeFieldTextMock: FieldMetadataInterface = { + id: 'field-text-id', + type: fieldTextMock.type, + name: fieldTextMock.name, + label: 'Field Text', + objectMetadataId: 'object-metadata-id', + isNullable: fieldTextMock.isNullable, + defaultValue: fieldTextMock.defaultValue, + }; + + const fieldsById: FieldMetadataMap = { + 'field-number-id': completeFieldNumberMock, + 'field-text-id': completeFieldTextMock, + }; + + const fieldsByName: FieldMetadataMap = { + [completeFieldNumberMock.name]: completeFieldNumberMock, + [completeFieldTextMock.name]: completeFieldTextMock, + }; + + const mockObjectMetadataWithFieldMaps = { + ...objectMetadataItemMock, + fieldsById, + fieldsByName, + }; + it('should parse string filter test 1', () => { expect( parseFilter( 'and(fieldNumber[eq]:1,fieldNumber[eq]:2)', - objectMetadataItemMock, + mockObjectMetadataWithFieldMaps, ), ).toEqual({ and: [{ fieldNumber: { eq: 1 } }, { fieldNumber: { eq: 2 } }], @@ -17,7 +60,7 @@ describe('parseFilter', () => { expect( parseFilter( 'and(fieldNumber[eq]:1,or(fieldNumber[eq]:2,fieldNumber[eq]:3))', - objectMetadataItemMock, + mockObjectMetadataWithFieldMaps, ), ).toEqual({ and: [ @@ -31,7 +74,7 @@ describe('parseFilter', () => { expect( parseFilter( 'and(fieldNumber[eq]:1,or(fieldNumber[eq]:2,fieldNumber[eq]:3,and(fieldNumber[eq]:6,fieldNumber[eq]:7)),or(fieldNumber[eq]:4,fieldNumber[eq]:5))', - objectMetadataItemMock, + mockObjectMetadataWithFieldMaps, ), ).toEqual({ and: [ @@ -52,7 +95,7 @@ describe('parseFilter', () => { expect( parseFilter( 'and(fieldText[gt]:"val,ue",or(fieldNumber[is]:NOT_NULL,not(fieldText[startsWith]:"val"),and(fieldNumber[eq]:6,fieldText[ilike]:"%val%")),or(fieldNumber[eq]:4,fieldText[is]:NULL))', - objectMetadataItemMock, + mockObjectMetadataWithFieldMaps, ), ).toEqual({ and: [ @@ -78,7 +121,7 @@ describe('parseFilter', () => { expect( parseFilter( 'and(fieldNumber[eq]:1,not(fieldNumber[eq]:2))', - objectMetadataItemMock, + mockObjectMetadataWithFieldMaps, ), ).toEqual({ and: [ diff --git a/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/check-filter-enum-values.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/check-filter-enum-values.ts index 9565a087f..1c75f4417 100644 --- a/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/check-filter-enum-values.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/check-filter-enum-values.ts @@ -2,13 +2,13 @@ import { BadRequestException } from '@nestjs/common'; import { FieldMetadataType } from 'twenty-shared'; -import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface'; +import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps'; export const checkFilterEnumValues = ( fieldType: FieldMetadataType | undefined, fieldName: string, value: string, - objectMetadataItem: ObjectMetadataInterface, + objectMetadataItem: ObjectMetadataItemWithFieldMaps, ): void => { if ( !fieldType || @@ -18,9 +18,7 @@ export const checkFilterEnumValues = ( ) { return; } - const field = objectMetadataItem.fields.find( - (field) => field.name === fieldName, - ); + const field = objectMetadataItem.fieldsByName[fieldName]; const values = /^\[.*\]$/.test(value) ? value.slice(1, -1).split(',') diff --git a/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/parse-filter.utils.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/parse-filter.utils.ts index 0f8a043b3..8587f56b6 100644 --- a/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/parse-filter.utils.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/parse-filter.utils.ts @@ -1,14 +1,13 @@ import { BadRequestException } from '@nestjs/common'; -import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface'; - -import { parseFilterContent } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/parse-filter-content.utils'; -import { parseBaseFilter } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/parse-base-filter.utils'; import { checkFields } from 'src/engine/api/rest/core/query-builder/utils/check-fields.utils'; -import { formatFieldValue } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/format-field-values.utils'; -import { FieldValue } from 'src/engine/api/rest/core/types/field-value.type'; import { checkFilterEnumValues } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/check-filter-enum-values'; +import { formatFieldValue } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/format-field-values.utils'; +import { parseBaseFilter } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/parse-base-filter.utils'; +import { parseFilterContent } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/parse-filter-content.utils'; import { getFieldType } from 'src/engine/api/rest/core/query-builder/utils/get-field-type.utils'; +import { FieldValue } from 'src/engine/api/rest/core/types/field-value.type'; +import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps'; export enum Conjunctions { or = 'or', @@ -18,7 +17,7 @@ export enum Conjunctions { export const parseFilter = ( filterQuery: string, - objectMetadataItem: ObjectMetadataInterface, + objectMetadataItem: ObjectMetadataItemWithFieldMaps, ): Record => { const result = {}; const match = filterQuery.match( diff --git a/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/get-field-type.utils.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/get-field-type.utils.ts index b118344e2..04e3bdd90 100644 --- a/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/get-field-type.utils.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/get-field-type.utils.ts @@ -1,10 +1,10 @@ import { FieldMetadataType } from 'twenty-shared'; -import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface'; +import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps'; export const getFieldType = ( - objectMetadata: ObjectMetadataInterface, + objectMetadataItem: ObjectMetadataItemWithFieldMaps, fieldName: string, ): FieldMetadataType | undefined => { - return objectMetadata.fields.find((field) => field.name === fieldName)?.type; + return objectMetadataItem.fieldsByName[fieldName]?.type; }; diff --git a/packages/twenty-server/src/engine/api/rest/input-factories/__tests__/filter-input.factory.spec.ts b/packages/twenty-server/src/engine/api/rest/input-factories/__tests__/filter-input.factory.spec.ts index 0ccf816d1..6ced8c6a2 100644 --- a/packages/twenty-server/src/engine/api/rest/input-factories/__tests__/filter-input.factory.spec.ts +++ b/packages/twenty-server/src/engine/api/rest/input-factories/__tests__/filter-input.factory.spec.ts @@ -1,10 +1,79 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { objectMetadataItemMock } from 'src/engine/api/__mocks__/object-metadata-item.mock'; +import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface'; + +import { + fieldCurrencyMock, + fieldNumberMock, + fieldTextMock, + objectMetadataItemMock, +} from 'src/engine/api/__mocks__/object-metadata-item.mock'; import { FilterInputFactory } from 'src/engine/api/rest/input-factories/filter-input.factory'; +import { FieldMetadataMap } from 'src/engine/metadata-modules/types/field-metadata-map'; describe('FilterInputFactory', () => { - const objectMetadata = { objectMetadataItem: objectMetadataItemMock }; + const completeFieldNumberMock: FieldMetadataInterface = { + id: 'field-number-id', + type: fieldNumberMock.type, + name: fieldNumberMock.name, + label: 'Field Number', + objectMetadataId: 'object-metadata-id', + isNullable: fieldNumberMock.isNullable, + defaultValue: fieldNumberMock.defaultValue, + }; + + const completeFieldTextMock: FieldMetadataInterface = { + id: 'field-text-id', + type: fieldTextMock.type, + name: fieldTextMock.name, + label: 'Field Text', + objectMetadataId: 'object-metadata-id', + isNullable: fieldTextMock.isNullable, + defaultValue: fieldTextMock.defaultValue, + }; + + const completeFieldCurrencyMock: FieldMetadataInterface = { + id: 'field-currency-id', + type: fieldCurrencyMock.type, + name: fieldCurrencyMock.name, + label: 'Field Currency', + objectMetadataId: 'object-metadata-id', + isNullable: fieldCurrencyMock.isNullable, + defaultValue: fieldCurrencyMock.defaultValue, + }; + + const fieldsById: FieldMetadataMap = { + 'field-number-id': completeFieldNumberMock, + 'field-text-id': completeFieldTextMock, + 'field-currency-id': completeFieldCurrencyMock, + }; + + const fieldsByName: FieldMetadataMap = { + [completeFieldNumberMock.name]: completeFieldNumberMock, + [completeFieldTextMock.name]: completeFieldTextMock, + [completeFieldCurrencyMock.name]: completeFieldCurrencyMock, + }; + + const objectMetadataMapItem = { + ...objectMetadataItemMock, + fieldsById, + fieldsByName, + }; + + const objectMetadataMaps = { + byId: { + [objectMetadataItemMock.id || 'mock-id']: objectMetadataMapItem, + }, + idByNameSingular: { + [objectMetadataItemMock.nameSingular]: + objectMetadataItemMock.id || 'mock-id', + }, + }; + + const objectMetadata = { + objectMetadataMaps, + objectMetadataMapItem, + }; let service: FilterInputFactory; diff --git a/packages/twenty-server/src/engine/api/rest/input-factories/filter-input.factory.ts b/packages/twenty-server/src/engine/api/rest/input-factories/filter-input.factory.ts index 93ed93d51..382878664 100644 --- a/packages/twenty-server/src/engine/api/rest/input-factories/filter-input.factory.ts +++ b/packages/twenty-server/src/engine/api/rest/input-factories/filter-input.factory.ts @@ -6,10 +6,18 @@ import { addDefaultConjunctionIfMissing } from 'src/engine/api/rest/core/query-b import { checkFilterQuery } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/check-filter-query.utils'; import { parseFilter } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/parse-filter.utils'; import { FieldValue } from 'src/engine/api/rest/core/types/field-value.type'; +import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps'; +import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps'; @Injectable() export class FilterInputFactory { - create(request: Request, objectMetadata): Record { + create( + request: Request, + objectMetadata: { + objectMetadataMaps: ObjectMetadataMaps; + objectMetadataMapItem: ObjectMetadataItemWithFieldMaps; + }, + ): Record { let filterQuery = request.query.filter; if (typeof filterQuery !== 'string') { @@ -20,6 +28,6 @@ export class FilterInputFactory { filterQuery = addDefaultConjunctionIfMissing(filterQuery); - return parseFilter(filterQuery, objectMetadata.objectMetadataItem); + return parseFilter(filterQuery, objectMetadata.objectMetadataMapItem); } }