Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca0f04923c | ||
|
|
be3b3c95f1 | ||
|
|
ff2f86848c | ||
|
|
f1ce22db97 | ||
|
|
90ea800f16 | ||
|
|
ee4fe62a13 | ||
|
|
95b64f2eda | ||
|
|
11e408a3da | ||
|
|
eaccc68ca1 |
+4
-3
@@ -9,6 +9,7 @@ import { contextStoreFilterGroupsComponentState } from '@/context-store/states/c
|
||||
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters';
|
||||
import { fieldMetadataItemByIdMapSelector } from '@/object-metadata/states/fieldMetadataItemByIdMapSelector';
|
||||
import { objectMetadataItemsSelector } from '@/object-metadata/states/objectMetadataItemsSelector';
|
||||
import { type EnrichedObjectMetadataItem } from '@/object-metadata/types/EnrichedObjectMetadataItem';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
@@ -89,8 +90,8 @@ export const buildHeadlessCommandContextApi = ({
|
||||
? (currentWorkspaceMember?.timeZone ?? systemTimeZone)
|
||||
: systemTimeZone;
|
||||
|
||||
const flattenedFieldMetadataItems = objectMetadataItems.flatMap(
|
||||
(objectMetadataItem) => objectMetadataItem.fields,
|
||||
const fieldMetadataItemByIdMap = store.get(
|
||||
fieldMetadataItemByIdMapSelector.atom,
|
||||
);
|
||||
|
||||
const graphqlFilter = isDefined(objectMetadataItem)
|
||||
@@ -99,7 +100,7 @@ export const buildHeadlessCommandContextApi = ({
|
||||
contextStoreFilters: filters,
|
||||
contextStoreFilterGroups: filterGroups,
|
||||
objectMetadataItem,
|
||||
flattenedFieldMetadataItems,
|
||||
findFieldMetadataItemById: (id) => fieldMetadataItemByIdMap.get(id),
|
||||
filterValueDependencies: {
|
||||
currentWorkspaceMemberId: currentWorkspaceMember?.id,
|
||||
timeZone: userTimezone,
|
||||
|
||||
+9
-16
@@ -5,7 +5,7 @@ import { contextStoreFiltersComponentState } from '@/context-store/states/contex
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters';
|
||||
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
||||
import { objectMetadataItemsSelector } from '@/object-metadata/states/objectMetadataItemsSelector';
|
||||
import { fieldMetadataItemByIdMapSelector } from '@/object-metadata/states/fieldMetadataItemByIdMapSelector';
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||
@@ -50,29 +50,22 @@ export const useFindManyRecordsSelectedInContextStore = ({
|
||||
|
||||
const { filterValueDependencies } = useFilterValueDependencies();
|
||||
|
||||
const objectMetadataItems = useAtomStateValue(objectMetadataItemsSelector);
|
||||
|
||||
const allFieldMetadataItems = objectMetadataItems.flatMap(
|
||||
(objectMetadataItem) => objectMetadataItem.fields,
|
||||
const fieldMetadataItemByIdMap = useAtomStateValue(
|
||||
fieldMetadataItemByIdMapSelector,
|
||||
);
|
||||
|
||||
const isSoftDeleteFilterActive = contextStoreFilters.some((filter) => {
|
||||
const foundFieldMetadataItem = allFieldMetadataItems.find(
|
||||
(fieldMetadataItem) => fieldMetadataItem.id === filter.fieldMetadataId,
|
||||
);
|
||||
|
||||
return (
|
||||
foundFieldMetadataItem?.name === 'deletedAt' &&
|
||||
filter.operand === RecordFilterOperand.IS_NOT_EMPTY
|
||||
);
|
||||
});
|
||||
const isSoftDeleteFilterActive = contextStoreFilters.some(
|
||||
(filter) =>
|
||||
fieldMetadataItemByIdMap.get(filter.fieldMetadataId)?.name ===
|
||||
'deletedAt' && filter.operand === RecordFilterOperand.IS_NOT_EMPTY,
|
||||
);
|
||||
|
||||
const queryFilter = computeContextStoreFilters({
|
||||
contextStoreTargetedRecordsRule,
|
||||
contextStoreFilters,
|
||||
contextStoreFilterGroups,
|
||||
objectMetadataItem,
|
||||
flattenedFieldMetadataItems: allFieldMetadataItems,
|
||||
findFieldMetadataItemById: (id) => fieldMetadataItemByIdMap.get(id),
|
||||
filterValueDependencies,
|
||||
contextStoreAnyFieldFilterValue,
|
||||
});
|
||||
|
||||
+4
-2
@@ -29,7 +29,8 @@ describe('computeContextStoreFilters', () => {
|
||||
contextStoreFilters: [],
|
||||
contextStoreFilterGroups: [],
|
||||
objectMetadataItem: personObjectMetadataItem,
|
||||
flattenedFieldMetadataItems: personObjectMetadataItem.fields,
|
||||
findFieldMetadataItemById: (id) =>
|
||||
personObjectMetadataItem.fields.find((field) => field.id === id),
|
||||
filterValueDependencies: mockFilterValueDependencies,
|
||||
contextStoreAnyFieldFilterValue: '',
|
||||
});
|
||||
@@ -74,7 +75,8 @@ describe('computeContextStoreFilters', () => {
|
||||
contextStoreFilters,
|
||||
contextStoreFilterGroups: [],
|
||||
objectMetadataItem: personObjectMetadataItem,
|
||||
flattenedFieldMetadataItems: personObjectMetadataItem.fields,
|
||||
findFieldMetadataItemById: (id) =>
|
||||
personObjectMetadataItem.fields.find((field) => field.id === id),
|
||||
filterValueDependencies: mockFilterValueDependencies,
|
||||
contextStoreAnyFieldFilterValue: '',
|
||||
});
|
||||
|
||||
+5
-12
@@ -1,9 +1,7 @@
|
||||
import { type ContextStoreTargetedRecordsRule } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { type EnrichedObjectMetadataItem } from '@/object-metadata/types/EnrichedObjectMetadataItem';
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { augmentFieldsWithRelationTargets } from '@/object-record/record-filter/utils/augmentFieldsWithRelationTargets';
|
||||
import { makeAndFilterVariables } from '@/object-record/utils/makeAndFilterVariables';
|
||||
import {
|
||||
type RecordFilterValueDependencies,
|
||||
@@ -11,6 +9,7 @@ import {
|
||||
} from 'twenty-shared/types';
|
||||
import {
|
||||
computeRecordGqlOperationFilter,
|
||||
type FindFieldMetadataItemById,
|
||||
turnAnyFieldFilterIntoRecordGqlFilter,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
@@ -19,7 +18,7 @@ type ComputeContextStoreFiltersProps = {
|
||||
contextStoreFilters: RecordFilter[];
|
||||
contextStoreFilterGroups: RecordFilterGroup[];
|
||||
objectMetadataItem: EnrichedObjectMetadataItem;
|
||||
flattenedFieldMetadataItems: FieldMetadataItem[];
|
||||
findFieldMetadataItemById: FindFieldMetadataItemById;
|
||||
filterValueDependencies: RecordFilterValueDependencies;
|
||||
contextStoreAnyFieldFilterValue: string;
|
||||
};
|
||||
@@ -29,7 +28,7 @@ export const computeContextStoreFilters = ({
|
||||
contextStoreFilters,
|
||||
contextStoreFilterGroups,
|
||||
objectMetadataItem,
|
||||
flattenedFieldMetadataItems,
|
||||
findFieldMetadataItemById,
|
||||
filterValueDependencies,
|
||||
contextStoreAnyFieldFilterValue,
|
||||
}: ComputeContextStoreFiltersProps) => {
|
||||
@@ -41,18 +40,12 @@ export const computeContextStoreFilters = ({
|
||||
fields: objectMetadataItem.fields,
|
||||
});
|
||||
|
||||
const fields = augmentFieldsWithRelationTargets({
|
||||
baseFields: objectMetadataItem?.fields ?? [],
|
||||
recordFilters: contextStoreFilters,
|
||||
allFieldMetadataItems: flattenedFieldMetadataItems,
|
||||
});
|
||||
|
||||
if (contextStoreTargetedRecordsRule.mode === 'exclusion') {
|
||||
queryFilter = makeAndFilterVariables([
|
||||
recordGqlFilterForAnyFieldFilter,
|
||||
computeRecordGqlOperationFilter({
|
||||
filterValueDependencies,
|
||||
fields,
|
||||
findFieldMetadataItemById,
|
||||
recordFilters: contextStoreFilters,
|
||||
recordFilterGroups: contextStoreFilterGroups,
|
||||
}),
|
||||
@@ -81,7 +74,7 @@ export const computeContextStoreFilters = ({
|
||||
},
|
||||
computeRecordGqlOperationFilter({
|
||||
filterValueDependencies,
|
||||
fields,
|
||||
findFieldMetadataItemById,
|
||||
recordFilters: contextStoreFilters,
|
||||
recordFilterGroups: contextStoreFilterGroups,
|
||||
}),
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
import { flattenedFieldMetadataItemsSelector } from '@/object-metadata/states/flattenedFieldMetadataItemsSelector';
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { createAtomSelector } from '@/ui/utilities/state/jotai/utils/createAtomSelector';
|
||||
|
||||
export const fieldMetadataItemByIdMapSelector = createAtomSelector<
|
||||
Map<string, FieldMetadataItem>
|
||||
>({
|
||||
key: 'fieldMetadataItemByIdMapSelector',
|
||||
get: ({ get }) =>
|
||||
new Map(
|
||||
get(flattenedFieldMetadataItemsSelector).map((field) => [
|
||||
field.id,
|
||||
field,
|
||||
]),
|
||||
),
|
||||
});
|
||||
+4
-9
@@ -1,4 +1,4 @@
|
||||
import { flattenedFieldMetadataItemsSelector } from '@/object-metadata/states/flattenedFieldMetadataItemsSelector';
|
||||
import { fieldMetadataItemByIdMapSelector } from '@/object-metadata/states/fieldMetadataItemByIdMapSelector';
|
||||
import { useRecordCalendarContextOrThrow } from '@/object-record/record-calendar/contexts/RecordCalendarContext';
|
||||
import { useRecordCalendarMonthDaysRange } from '@/object-record/record-calendar/month/hooks/useRecordCalendarMonthDaysRange';
|
||||
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
|
||||
@@ -7,7 +7,6 @@ import { anyFieldFilterValueComponentState } from '@/object-record/record-filter
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||
import { augmentFieldsWithRelationTargets } from '@/object-record/record-filter/utils/augmentFieldsWithRelationTargets';
|
||||
import { useUserTimezone } from '@/ui/input/components/internal/date/hooks/useUserTimezone';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
@@ -49,8 +48,8 @@ export const useRecordCalendarQueryDateRangeFilter = (
|
||||
|
||||
const { filterValueDependencies } = useFilterValueDependencies();
|
||||
|
||||
const flattenedFieldMetadataItems = useAtomStateValue(
|
||||
flattenedFieldMetadataItemsSelector,
|
||||
const fieldMetadataItemByIdMap = useAtomStateValue(
|
||||
fieldMetadataItemByIdMapSelector,
|
||||
);
|
||||
|
||||
const anyFieldFilterValue = useAtomComponentStateValue(
|
||||
@@ -111,11 +110,7 @@ export const useRecordCalendarQueryDateRangeFilter = (
|
||||
filterValueDependencies,
|
||||
recordFilters: calendarRecordFilters,
|
||||
recordFilterGroups: currentRecordFilterGroups,
|
||||
fields: augmentFieldsWithRelationTargets({
|
||||
baseFields: objectMetadataItem.fields,
|
||||
recordFilters: calendarRecordFilters,
|
||||
allFieldMetadataItems: flattenedFieldMetadataItems,
|
||||
}),
|
||||
findFieldMetadataItemById: (id) => fieldMetadataItemByIdMap.get(id),
|
||||
});
|
||||
|
||||
const { recordGqlOperationFilter: anyFieldFilter } =
|
||||
|
||||
+20
-11
@@ -22,6 +22,15 @@ const petMockObjectMetadataItem = getMockObjectMetadataItemOrThrow('pet');
|
||||
|
||||
const personMockObjectMetadataItem = getMockObjectMetadataItemOrThrow('person');
|
||||
|
||||
const findCompanyFieldById = (id: string) =>
|
||||
companyMockObjectMetadataItem.fields.find((field) => field.id === id);
|
||||
|
||||
const findPersonFieldById = (id: string) =>
|
||||
personMockObjectMetadataItem.fields.find((field) => field.id === id);
|
||||
|
||||
const findPetFieldById = (id: string) =>
|
||||
petMockObjectMetadataItem.fields.find((field) => field.id === id);
|
||||
|
||||
const mockFilterValueDependencies: RecordFilterValueDependencies = {
|
||||
currentWorkspaceMemberId: '32219445-f587-4c40-b2b1-6d3205ed96da',
|
||||
timeZone: 'Europe/Paris',
|
||||
@@ -54,7 +63,7 @@ describe('computeViewRecordGqlOperationFilter', () => {
|
||||
filterValueDependencies: mockFilterValueDependencies,
|
||||
recordFilters: [nameFilter],
|
||||
recordFilterGroups: [],
|
||||
fields: companyMockObjectMetadataItem.fields,
|
||||
findFieldMetadataItemById: findCompanyFieldById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
@@ -107,7 +116,7 @@ describe('computeViewRecordGqlOperationFilter', () => {
|
||||
filterValueDependencies: mockFilterValueDependencies,
|
||||
recordFilters: [nameFilter, employeesFilter],
|
||||
recordFilterGroups: [],
|
||||
fields: companyMockObjectMetadataItem.fields,
|
||||
findFieldMetadataItemById: findCompanyFieldById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
@@ -187,7 +196,7 @@ describe('should work as expected for the different field types', () => {
|
||||
addressFilterIsNotEmpty,
|
||||
],
|
||||
recordFilterGroups: [],
|
||||
fields: companyMockObjectMetadataItem.fields,
|
||||
findFieldMetadataItemById: findCompanyFieldById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
@@ -651,7 +660,7 @@ describe('should work as expected for the different field types', () => {
|
||||
phonesFilterIsNotEmpty,
|
||||
],
|
||||
recordFilterGroups: [],
|
||||
fields: personMockObjectMetadataItem.fields,
|
||||
findFieldMetadataItemById: findPersonFieldById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
@@ -848,7 +857,7 @@ describe('should work as expected for the different field types', () => {
|
||||
emailsFilterIsNotEmpty,
|
||||
],
|
||||
recordFilterGroups: [],
|
||||
fields: personMockObjectMetadataItem.fields,
|
||||
findFieldMetadataItemById: findPersonFieldById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
@@ -1060,7 +1069,7 @@ describe('should work as expected for the different field types', () => {
|
||||
dateFilterIsNotEmpty,
|
||||
],
|
||||
recordFilterGroups: [],
|
||||
fields: companyMockObjectMetadataItem.fields,
|
||||
findFieldMetadataItemById: findCompanyFieldById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
@@ -1162,7 +1171,7 @@ describe('should work as expected for the different field types', () => {
|
||||
employeesFilterIsNotEmpty,
|
||||
],
|
||||
recordFilterGroups: [],
|
||||
fields: companyMockObjectMetadataItem.fields,
|
||||
findFieldMetadataItemById: findCompanyFieldById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
@@ -1264,7 +1273,7 @@ describe('should work as expected for the different field types', () => {
|
||||
ARRFilterIsNot,
|
||||
],
|
||||
recordFilterGroups: [],
|
||||
fields: companyMockObjectMetadataItem.fields,
|
||||
findFieldMetadataItemById: findCompanyFieldById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
@@ -1341,7 +1350,7 @@ describe('should work as expected for the different field types', () => {
|
||||
filterValueDependencies: mockFilterValueDependencies,
|
||||
recordFilters: [ARRFilterIn, ARRFilterNotIn],
|
||||
recordFilterGroups: [],
|
||||
fields: companyMockObjectMetadataItem.fields,
|
||||
findFieldMetadataItemById: findCompanyFieldById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
@@ -1401,7 +1410,7 @@ describe('should work as expected for the different field types', () => {
|
||||
filterValueDependencies: mockFilterValueDependencies,
|
||||
recordFilters: [selectFilterIs, selectFilterIsNot],
|
||||
recordFilterGroups: [],
|
||||
fields: petMockObjectMetadataItem.fields,
|
||||
findFieldMetadataItemById: findPetFieldById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
@@ -1474,7 +1483,7 @@ describe('should work as expected for the different field types', () => {
|
||||
multiSelectFilterDoesNotContain,
|
||||
],
|
||||
recordFilterGroups: [],
|
||||
fields: companyMockObjectMetadataItem.fields,
|
||||
findFieldMetadataItemById: findCompanyFieldById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
|
||||
-41
@@ -1,41 +0,0 @@
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
// Relation-traversal filters reference target fields that live on a
|
||||
// different object than the one being queried, so they aren't in the
|
||||
// source object's own field list. The shared GraphQL filter dispatcher
|
||||
// looks the target up by id in `fieldMetadataItems` and drops the filter
|
||||
// when it can't find it — this helper merges the resolved target fields
|
||||
// in from the workspace-wide flat list so callers don't silently lose
|
||||
// relation-traversal filters.
|
||||
export const augmentFieldsWithRelationTargets = ({
|
||||
baseFields,
|
||||
recordFilters,
|
||||
allFieldMetadataItems,
|
||||
}: {
|
||||
baseFields: FieldMetadataItem[];
|
||||
recordFilters: Pick<RecordFilter, 'relationTargetFieldMetadataId'>[];
|
||||
allFieldMetadataItems: FieldMetadataItem[];
|
||||
}): FieldMetadataItem[] => {
|
||||
const targetFieldIds = new Set(
|
||||
recordFilters
|
||||
.map((filter) => filter.relationTargetFieldMetadataId)
|
||||
.filter(isDefined),
|
||||
);
|
||||
|
||||
if (targetFieldIds.size === 0) {
|
||||
return baseFields;
|
||||
}
|
||||
|
||||
const baseFieldIds = new Set(baseFields.map((field) => field.id));
|
||||
const additionalTargetFields = allFieldMetadataItems.filter(
|
||||
(field) => targetFieldIds.has(field.id) && !baseFieldIds.has(field.id),
|
||||
);
|
||||
|
||||
if (additionalTargetFields.length === 0) {
|
||||
return baseFields;
|
||||
}
|
||||
|
||||
return [...baseFields, ...additionalTargetFields];
|
||||
};
|
||||
+4
-4
@@ -6,7 +6,7 @@ import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/s
|
||||
import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
||||
import { flattenedFieldMetadataItemsSelector } from '@/object-metadata/states/flattenedFieldMetadataItemsSelector';
|
||||
import { fieldMetadataItemByIdMapSelector } from '@/object-metadata/states/fieldMetadataItemByIdMapSelector';
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
@@ -54,8 +54,8 @@ export const RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect =
|
||||
|
||||
const { filterValueDependencies } = useFilterValueDependencies();
|
||||
|
||||
const flattenedFieldMetadataItems = useAtomStateValue(
|
||||
flattenedFieldMetadataItemsSelector,
|
||||
const fieldMetadataItemByIdMap = useAtomStateValue(
|
||||
fieldMetadataItemByIdMapSelector,
|
||||
);
|
||||
|
||||
const computedFilter = computeContextStoreFilters({
|
||||
@@ -63,7 +63,7 @@ export const RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect =
|
||||
contextStoreFilters,
|
||||
contextStoreFilterGroups,
|
||||
objectMetadataItem,
|
||||
flattenedFieldMetadataItems,
|
||||
findFieldMetadataItemById: (id) => fieldMetadataItemByIdMap.get(id),
|
||||
filterValueDependencies,
|
||||
contextStoreAnyFieldFilterValue,
|
||||
});
|
||||
|
||||
+4
-4
@@ -7,7 +7,7 @@ import { contextStoreFilterGroupsComponentState } from '@/context-store/states/c
|
||||
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters';
|
||||
import { flattenedFieldMetadataItemsSelector } from '@/object-metadata/states/flattenedFieldMetadataItemsSelector';
|
||||
import { fieldMetadataItemByIdMapSelector } from '@/object-metadata/states/fieldMetadataItemByIdMapSelector';
|
||||
import { type EnrichedObjectMetadataItem } from '@/object-metadata/types/EnrichedObjectMetadataItem';
|
||||
import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRecords';
|
||||
import { EXPORT_TABLE_DATA_DEFAULT_PAGE_SIZE } from '@/object-record/object-options-dropdown/constants/ExportTableDataDefaultPageSize';
|
||||
@@ -89,8 +89,8 @@ export const useRecordIndexLazyFetchRecords = ({
|
||||
|
||||
const { filterValueDependencies } = useFilterValueDependencies();
|
||||
|
||||
const flattenedFieldMetadataItems = useAtomStateValue(
|
||||
flattenedFieldMetadataItemsSelector,
|
||||
const fieldMetadataItemByIdMap = useAtomStateValue(
|
||||
fieldMetadataItemByIdMapSelector,
|
||||
);
|
||||
|
||||
const findManyRecordsParams = useFindManyRecordIndexTableParams(
|
||||
@@ -107,7 +107,7 @@ export const useRecordIndexLazyFetchRecords = ({
|
||||
contextStoreFilters,
|
||||
contextStoreFilterGroups,
|
||||
objectMetadataItem,
|
||||
flattenedFieldMetadataItems,
|
||||
findFieldMetadataItemById: (id) => fieldMetadataItemByIdMap.get(id),
|
||||
filterValueDependencies,
|
||||
contextStoreAnyFieldFilterValue,
|
||||
});
|
||||
|
||||
+4
-9
@@ -1,12 +1,11 @@
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { flattenedFieldMetadataItemsSelector } from '@/object-metadata/states/flattenedFieldMetadataItemsSelector';
|
||||
import { fieldMetadataItemByIdMapSelector } from '@/object-metadata/states/fieldMetadataItemByIdMapSelector';
|
||||
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
||||
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
|
||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||
import { anyFieldFilterValueComponentState } from '@/object-record/record-filter/states/anyFieldFilterValueComponentState';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { augmentFieldsWithRelationTargets } from '@/object-record/record-filter/utils/augmentFieldsWithRelationTargets';
|
||||
import { useCurrentRecordGroupDefinition } from '@/object-record/record-group/hooks/useCurrentRecordGroupDefinition';
|
||||
import { useRecordGroupFilter } from '@/object-record/record-group/hooks/useRecordGroupFilter';
|
||||
import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState';
|
||||
@@ -50,16 +49,12 @@ export const useFindManyRecordIndexTableParams = (
|
||||
|
||||
const { filterValueDependencies } = useFilterValueDependencies();
|
||||
|
||||
const flattenedFieldMetadataItems = useAtomStateValue(
|
||||
flattenedFieldMetadataItemsSelector,
|
||||
const fieldMetadataItemByIdMap = useAtomStateValue(
|
||||
fieldMetadataItemByIdMapSelector,
|
||||
);
|
||||
|
||||
const currentFilters = computeRecordGqlOperationFilter({
|
||||
fields: augmentFieldsWithRelationTargets({
|
||||
baseFields: objectMetadataItem?.fields ?? [],
|
||||
recordFilters: currentRecordFilters,
|
||||
allFieldMetadataItems: flattenedFieldMetadataItems,
|
||||
}),
|
||||
findFieldMetadataItemById: (id) => fieldMetadataItemByIdMap.get(id),
|
||||
recordFilterGroups: currentRecordFilterGroups,
|
||||
recordFilters: currentRecordFilters,
|
||||
filterValueDependencies,
|
||||
|
||||
+4
-9
@@ -1,12 +1,11 @@
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { flattenedFieldMetadataItemsSelector } from '@/object-metadata/states/flattenedFieldMetadataItemsSelector';
|
||||
import { fieldMetadataItemByIdMapSelector } from '@/object-metadata/states/fieldMetadataItemByIdMapSelector';
|
||||
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
||||
import { useRelevantRecordsGqlFields } from '@/object-record/record-field/hooks/useRelevantRecordsGqlFields';
|
||||
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
|
||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||
import { anyFieldFilterValueComponentState } from '@/object-record/record-filter/states/anyFieldFilterValueComponentState';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { augmentFieldsWithRelationTargets } from '@/object-record/record-filter/utils/augmentFieldsWithRelationTargets';
|
||||
import { recordGroupDefinitionsComponentSelector } from '@/object-record/record-group/states/selectors/recordGroupDefinitionsComponentSelector';
|
||||
import { computeRecordGroupOptionsFilter } from '@/object-record/record-group/utils/computeRecordGroupOptionsFilter';
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
@@ -39,19 +38,15 @@ export const useRecordIndexGroupCommonQueryVariables = () => {
|
||||
|
||||
const { filterValueDependencies } = useFilterValueDependencies();
|
||||
|
||||
const flattenedFieldMetadataItems = useAtomStateValue(
|
||||
flattenedFieldMetadataItemsSelector,
|
||||
const fieldMetadataItemByIdMap = useAtomStateValue(
|
||||
fieldMetadataItemByIdMapSelector,
|
||||
);
|
||||
|
||||
const requestFilters = computeRecordGqlOperationFilter({
|
||||
filterValueDependencies,
|
||||
recordFilters: currentRecordFilters,
|
||||
recordFilterGroups: currentRecordFilterGroups,
|
||||
fields: augmentFieldsWithRelationTargets({
|
||||
baseFields: objectMetadataItem.fields,
|
||||
recordFilters: currentRecordFilters,
|
||||
allFieldMetadataItems: flattenedFieldMetadataItems,
|
||||
}),
|
||||
findFieldMetadataItemById: (id) => fieldMetadataItemByIdMap.get(id),
|
||||
});
|
||||
|
||||
const anyFieldFilterValue = useAtomComponentStateValue(
|
||||
|
||||
+4
-9
@@ -1,5 +1,5 @@
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { flattenedFieldMetadataItemsSelector } from '@/object-metadata/states/flattenedFieldMetadataItemsSelector';
|
||||
import { fieldMetadataItemByIdMapSelector } from '@/object-metadata/states/fieldMetadataItemByIdMapSelector';
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { type EnrichedObjectMetadataItem } from '@/object-metadata/types/EnrichedObjectMetadataItem';
|
||||
import { EMPTY_QUERY } from '@/object-record/constants/EmptyQuery';
|
||||
@@ -9,7 +9,6 @@ import { currentRecordFilterGroupsComponentState } from '@/object-record/record-
|
||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||
import { anyFieldFilterValueComponentState } from '@/object-record/record-filter/states/anyFieldFilterValueComponentState';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { augmentFieldsWithRelationTargets } from '@/object-record/record-filter/utils/augmentFieldsWithRelationTargets';
|
||||
import { useAggregateGqlFieldsFromRecordIndexGroupAggregates } from '@/object-record/record-index/hooks/useAggregateGqlFieldsFromRecordIndexGroupAggregates';
|
||||
import { type ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations';
|
||||
import { buildGroupByFieldObject } from '@/page-layout/widgets/graph/utils/buildGroupByFieldObject';
|
||||
@@ -49,19 +48,15 @@ export const useRecordIndexGroupsAggregatesGroupBy = ({
|
||||
|
||||
const { filterValueDependencies } = useFilterValueDependencies();
|
||||
|
||||
const flattenedFieldMetadataItems = useAtomStateValue(
|
||||
flattenedFieldMetadataItemsSelector,
|
||||
const fieldMetadataItemByIdMap = useAtomStateValue(
|
||||
fieldMetadataItemByIdMapSelector,
|
||||
);
|
||||
|
||||
const requestFilters = computeRecordGqlOperationFilter({
|
||||
filterValueDependencies,
|
||||
recordFilters: currentRecordFilters,
|
||||
recordFilterGroups: currentRecordFilterGroups,
|
||||
fields: augmentFieldsWithRelationTargets({
|
||||
baseFields: objectMetadataItem.fields,
|
||||
recordFilters: currentRecordFilters,
|
||||
allFieldMetadataItems: flattenedFieldMetadataItems,
|
||||
}),
|
||||
findFieldMetadataItemById: (id) => fieldMetadataItemByIdMap.get(id),
|
||||
});
|
||||
|
||||
const { recordAggregateGqlField } =
|
||||
|
||||
+5
-10
@@ -1,11 +1,10 @@
|
||||
import { useListenToObjectRecordOperationBrowserEvent } from '@/browser-event/hooks/useListenToObjectRecordOperationBrowserEvent';
|
||||
import { type ObjectRecordOperationBrowserEventDetail } from '@/browser-event/types/ObjectRecordOperationBrowserEventDetail';
|
||||
import { flattenedFieldMetadataItemsSelector } from '@/object-metadata/states/flattenedFieldMetadataItemsSelector';
|
||||
import { fieldMetadataItemByIdMapSelector } from '@/object-metadata/states/fieldMetadataItemByIdMapSelector';
|
||||
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
||||
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
|
||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { augmentFieldsWithRelationTargets } from '@/object-record/record-filter/utils/augmentFieldsWithRelationTargets';
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { recordIndexHasRecordsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexHasRecordsComponentSelector';
|
||||
import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState';
|
||||
@@ -41,8 +40,8 @@ export const RecordTableEmptyHasNewRecordEffect = () => {
|
||||
|
||||
const { filterValueDependencies } = useFilterValueDependencies();
|
||||
|
||||
const flattenedFieldMetadataItems = useAtomStateValue(
|
||||
flattenedFieldMetadataItemsSelector,
|
||||
const fieldMetadataItemByIdMap = useAtomStateValue(
|
||||
fieldMetadataItemByIdMapSelector,
|
||||
);
|
||||
|
||||
const currentRecordFilters = useAtomComponentStateValue(
|
||||
@@ -64,11 +63,7 @@ export const RecordTableEmptyHasNewRecordEffect = () => {
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
variables: {
|
||||
filter: computeRecordGqlOperationFilter({
|
||||
fields: augmentFieldsWithRelationTargets({
|
||||
baseFields: objectMetadataItem.fields,
|
||||
recordFilters: currentRecordFilters,
|
||||
allFieldMetadataItems: flattenedFieldMetadataItems,
|
||||
}),
|
||||
findFieldMetadataItemById: (id) => fieldMetadataItemByIdMap.get(id),
|
||||
recordFilters: currentRecordFilters,
|
||||
recordFilterGroups: currentRecordFilterGroups,
|
||||
filterValueDependencies,
|
||||
@@ -82,7 +77,7 @@ export const RecordTableEmptyHasNewRecordEffect = () => {
|
||||
currentRecordFilterGroups,
|
||||
filterValueDependencies,
|
||||
currentRecordSorts,
|
||||
flattenedFieldMetadataItems,
|
||||
fieldMetadataItemByIdMap,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
+4
-9
@@ -1,4 +1,4 @@
|
||||
import { flattenedFieldMetadataItemsSelector } from '@/object-metadata/states/flattenedFieldMetadataItemsSelector';
|
||||
import { fieldMetadataItemByIdMapSelector } from '@/object-metadata/states/fieldMetadataItemByIdMapSelector';
|
||||
import { useAggregateRecords } from '@/object-record/hooks/useAggregateRecords';
|
||||
import { transformAggregateRawValueIntoAggregateDisplayValue } from '@/object-record/record-aggregate/utils/transformAggregateRawValueIntoAggregateDisplayValue';
|
||||
import { getAggregateOperationLabel } from '@/object-record/record-board/record-board-column/utils/getAggregateOperationLabel';
|
||||
@@ -7,7 +7,6 @@ import { currentRecordFilterGroupsComponentState } from '@/object-record/record-
|
||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||
import { anyFieldFilterValueComponentState } from '@/object-record/record-filter/states/anyFieldFilterValueComponentState';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { augmentFieldsWithRelationTargets } from '@/object-record/record-filter/utils/augmentFieldsWithRelationTargets';
|
||||
import { useRecordGroupFilter } from '@/object-record/record-group/hooks/useRecordGroupFilter';
|
||||
import { getRecordAggregateDisplayLabel } from '@/object-record/record-index/utils/getRecordndexAggregateDisplayLabel';
|
||||
import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations';
|
||||
@@ -47,18 +46,14 @@ export const useAggregateRecordsForRecordTableColumnFooter = (
|
||||
|
||||
const dateLocale = useAtomStateValue(dateLocaleState);
|
||||
|
||||
const flattenedFieldMetadataItems = useAtomStateValue(
|
||||
flattenedFieldMetadataItemsSelector,
|
||||
const fieldMetadataItemByIdMap = useAtomStateValue(
|
||||
fieldMetadataItemByIdMapSelector,
|
||||
);
|
||||
|
||||
const { filterValueDependencies } = useFilterValueDependencies();
|
||||
|
||||
const requestFilters = computeRecordGqlOperationFilter({
|
||||
fields: augmentFieldsWithRelationTargets({
|
||||
baseFields: objectMetadataItem.fields,
|
||||
recordFilters: currentRecordFilters,
|
||||
allFieldMetadataItems: flattenedFieldMetadataItems,
|
||||
}),
|
||||
findFieldMetadataItemById: (id) => fieldMetadataItemByIdMap.get(id),
|
||||
filterValueDependencies,
|
||||
recordFilterGroups: currentRecordFilterGroups,
|
||||
recordFilters: currentRecordFilters,
|
||||
|
||||
+5
-10
@@ -1,11 +1,10 @@
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { flattenedFieldMetadataItemsSelector } from '@/object-metadata/states/flattenedFieldMetadataItemsSelector';
|
||||
import { fieldMetadataItemByIdMapSelector } from '@/object-metadata/states/fieldMetadataItemByIdMapSelector';
|
||||
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
||||
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
|
||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { augmentFieldsWithRelationTargets } from '@/object-record/record-filter/utils/augmentFieldsWithRelationTargets';
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState';
|
||||
import { useListenToEventsForQuery } from '@/sse-db-event/hooks/useListenToEventsForQuery';
|
||||
@@ -17,8 +16,8 @@ export const RecordTableVirtualizedSSESubscribeEffect = () => {
|
||||
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||
const { filterValueDependencies } = useFilterValueDependencies();
|
||||
|
||||
const flattenedFieldMetadataItems = useAtomStateValue(
|
||||
flattenedFieldMetadataItemsSelector,
|
||||
const fieldMetadataItemByIdMap = useAtomStateValue(
|
||||
fieldMetadataItemByIdMapSelector,
|
||||
);
|
||||
|
||||
const currentRecordFilters = useAtomComponentStateValue(
|
||||
@@ -40,11 +39,7 @@ export const RecordTableVirtualizedSSESubscribeEffect = () => {
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
variables: {
|
||||
filter: computeRecordGqlOperationFilter({
|
||||
fields: augmentFieldsWithRelationTargets({
|
||||
baseFields: objectMetadataItem.fields,
|
||||
recordFilters: currentRecordFilters,
|
||||
allFieldMetadataItems: flattenedFieldMetadataItems,
|
||||
}),
|
||||
findFieldMetadataItemById: (id) => fieldMetadataItemByIdMap.get(id),
|
||||
recordFilters: currentRecordFilters,
|
||||
recordFilterGroups: currentRecordFilterGroups,
|
||||
filterValueDependencies,
|
||||
@@ -58,7 +53,7 @@ export const RecordTableVirtualizedSSESubscribeEffect = () => {
|
||||
currentRecordFilterGroups,
|
||||
filterValueDependencies,
|
||||
currentRecordSorts,
|
||||
flattenedFieldMetadataItems,
|
||||
fieldMetadataItemByIdMap,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
+4
-4
@@ -4,7 +4,7 @@ import { contextStoreFilterGroupsComponentState } from '@/context-store/states/c
|
||||
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters';
|
||||
import { flattenedFieldMetadataItemsSelector } from '@/object-metadata/states/flattenedFieldMetadataItemsSelector';
|
||||
import { fieldMetadataItemByIdMapSelector } from '@/object-metadata/states/fieldMetadataItemByIdMapSelector';
|
||||
import { useIncrementalUpdateManyRecords } from '@/object-record/hooks/useIncrementalUpdateManyRecords';
|
||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
@@ -45,8 +45,8 @@ export const useUpdateMultipleRecordsActions = ({
|
||||
|
||||
const { filterValueDependencies } = useFilterValueDependencies();
|
||||
|
||||
const flattenedFieldMetadataItems = useAtomStateValue(
|
||||
flattenedFieldMetadataItemsSelector,
|
||||
const fieldMetadataItemByIdMap = useAtomStateValue(
|
||||
fieldMetadataItemByIdMapSelector,
|
||||
);
|
||||
|
||||
const graphqlFilter = computeContextStoreFilters({
|
||||
@@ -54,7 +54,7 @@ export const useUpdateMultipleRecordsActions = ({
|
||||
contextStoreFilters,
|
||||
contextStoreFilterGroups,
|
||||
objectMetadataItem,
|
||||
flattenedFieldMetadataItems,
|
||||
findFieldMetadataItemById: (id) => fieldMetadataItemByIdMap.get(id),
|
||||
filterValueDependencies,
|
||||
contextStoreAnyFieldFilterValue,
|
||||
});
|
||||
|
||||
+4
-9
@@ -1,7 +1,6 @@
|
||||
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
||||
import { flattenedFieldMetadataItemsSelector } from '@/object-metadata/states/flattenedFieldMetadataItemsSelector';
|
||||
import { fieldMetadataItemByIdMapSelector } from '@/object-metadata/states/fieldMetadataItemByIdMapSelector';
|
||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||
import { augmentFieldsWithRelationTargets } from '@/object-record/record-filter/utils/augmentFieldsWithRelationTargets';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import {
|
||||
computeRecordGqlOperationFilter,
|
||||
@@ -41,18 +40,14 @@ export const useGraphWidgetQueryCommon = ({
|
||||
|
||||
const { filterValueDependencies } = useFilterValueDependencies();
|
||||
|
||||
const flattenedFieldMetadataItems = useAtomStateValue(
|
||||
flattenedFieldMetadataItemsSelector,
|
||||
const fieldMetadataItemByIdMap = useAtomStateValue(
|
||||
fieldMetadataItemByIdMapSelector,
|
||||
);
|
||||
|
||||
const widgetRecordFilters = configuration.filter?.recordFilters ?? [];
|
||||
|
||||
const gqlOperationFilter = computeRecordGqlOperationFilter({
|
||||
fields: augmentFieldsWithRelationTargets({
|
||||
baseFields: objectMetadataItem.fields,
|
||||
recordFilters: widgetRecordFilters,
|
||||
allFieldMetadataItems: flattenedFieldMetadataItems,
|
||||
}),
|
||||
findFieldMetadataItemById: (id) => fieldMetadataItemByIdMap.get(id),
|
||||
filterValueDependencies,
|
||||
recordFilters: widgetRecordFilters,
|
||||
recordFilterGroups: configuration.filter?.recordFilterGroups ?? [],
|
||||
|
||||
+4
-9
@@ -1,11 +1,10 @@
|
||||
import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow';
|
||||
import { flattenedFieldMetadataItemsSelector } from '@/object-metadata/states/flattenedFieldMetadataItemsSelector';
|
||||
import { fieldMetadataItemByIdMapSelector } from '@/object-metadata/states/fieldMetadataItemByIdMapSelector';
|
||||
import { useAggregateRecords } from '@/object-record/hooks/useAggregateRecords';
|
||||
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
|
||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||
import { anyFieldFilterValueComponentState } from '@/object-record/record-filter/states/anyFieldFilterValueComponentState';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { augmentFieldsWithRelationTargets } from '@/object-record/record-filter/utils/augmentFieldsWithRelationTargets';
|
||||
import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
@@ -28,8 +27,8 @@ export const useGetRecordIndexTotalCount = () => {
|
||||
|
||||
const { filterValueDependencies } = useFilterValueDependencies();
|
||||
|
||||
const flattenedFieldMetadataItems = useAtomStateValue(
|
||||
flattenedFieldMetadataItemsSelector,
|
||||
const fieldMetadataItemByIdMap = useAtomStateValue(
|
||||
fieldMetadataItemByIdMapSelector,
|
||||
);
|
||||
|
||||
const recordGroupsVisibilityFilter = useGetViewGroupsFilters();
|
||||
@@ -38,11 +37,7 @@ export const useGetRecordIndexTotalCount = () => {
|
||||
filterValueDependencies,
|
||||
recordFilters: [...currentRecordFilters, ...recordGroupsVisibilityFilter],
|
||||
recordFilterGroups: currentRecordFilterGroups,
|
||||
fields: augmentFieldsWithRelationTargets({
|
||||
baseFields: objectMetadataItem.fields,
|
||||
recordFilters: [...currentRecordFilters, ...recordGroupsVisibilityFilter],
|
||||
allFieldMetadataItems: flattenedFieldMetadataItems,
|
||||
}),
|
||||
findFieldMetadataItemById: (id) => fieldMetadataItemByIdMap.get(id),
|
||||
});
|
||||
|
||||
const anyFieldFilterValue = useAtomComponentStateValue(
|
||||
|
||||
@@ -213,6 +213,8 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
||||
viewFilterGroupId: viewFilter.viewFilterGroupId,
|
||||
positionInViewFilterGroup: viewFilter.positionInViewFilterGroup,
|
||||
subFieldName: viewFilter.subFieldName ?? null,
|
||||
relationTargetFieldMetadataId:
|
||||
viewFilter.relationTargetFieldMetadataId ?? null,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||
import { contextStoreRecordShowParentViewComponentState } from '@/context-store/states/contextStoreRecordShowParentViewComponentState';
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { flattenedFieldMetadataItemsSelector } from '@/object-metadata/states/flattenedFieldMetadataItemsSelector';
|
||||
import { fieldMetadataItemByIdMapSelector } from '@/object-metadata/states/fieldMetadataItemByIdMapSelector';
|
||||
import { type EnrichedObjectMetadataItem } from '@/object-metadata/types/EnrichedObjectMetadataItem';
|
||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
@@ -15,8 +15,8 @@ export const useQueryVariablesFromParentView = ({
|
||||
}) => {
|
||||
const { objectMetadataItems } = useObjectMetadataItems();
|
||||
|
||||
const flattenedFieldMetadataItems = useAtomStateValue(
|
||||
flattenedFieldMetadataItemsSelector,
|
||||
const fieldMetadataItemByIdMap = useAtomStateValue(
|
||||
fieldMetadataItemByIdMapSelector,
|
||||
);
|
||||
|
||||
const contextStoreRecordShowParentView = useAtomComponentStateValue(
|
||||
@@ -33,7 +33,7 @@ export const useQueryVariablesFromParentView = ({
|
||||
recordSorts: contextStoreRecordShowParentView?.parentViewSorts ?? [],
|
||||
objectMetadataItem,
|
||||
objectMetadataItems,
|
||||
flattenedFieldMetadataItems,
|
||||
findFieldMetadataItemById: (id) => fieldMetadataItemByIdMap.get(id),
|
||||
filterValueDependencies,
|
||||
});
|
||||
|
||||
|
||||
+7
-10
@@ -1,12 +1,13 @@
|
||||
import { type EnrichedObjectMetadataItem } from '@/object-metadata/types/EnrichedObjectMetadataItem';
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
||||
import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { augmentFieldsWithRelationTargets } from '@/object-record/record-filter/utils/augmentFieldsWithRelationTargets';
|
||||
import { type RecordSort } from '@/object-record/record-sort/types/RecordSort';
|
||||
import { type RecordFilterValueDependencies } from 'twenty-shared/types';
|
||||
import { computeRecordGqlOperationFilter } from 'twenty-shared/utils';
|
||||
import {
|
||||
computeRecordGqlOperationFilter,
|
||||
type FindFieldMetadataItemById,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
export const getQueryVariablesFromFiltersAndSorts = ({
|
||||
recordFilterGroups,
|
||||
@@ -14,7 +15,7 @@ export const getQueryVariablesFromFiltersAndSorts = ({
|
||||
recordSorts,
|
||||
objectMetadataItem,
|
||||
objectMetadataItems = [],
|
||||
flattenedFieldMetadataItems,
|
||||
findFieldMetadataItemById,
|
||||
filterValueDependencies,
|
||||
}: {
|
||||
recordFilterGroups: RecordFilterGroup[];
|
||||
@@ -22,15 +23,11 @@ export const getQueryVariablesFromFiltersAndSorts = ({
|
||||
recordSorts: RecordSort[];
|
||||
objectMetadataItem: EnrichedObjectMetadataItem;
|
||||
objectMetadataItems?: EnrichedObjectMetadataItem[];
|
||||
flattenedFieldMetadataItems: FieldMetadataItem[];
|
||||
findFieldMetadataItemById: FindFieldMetadataItemById;
|
||||
filterValueDependencies: RecordFilterValueDependencies;
|
||||
}) => {
|
||||
const filter = computeRecordGqlOperationFilter({
|
||||
fields: augmentFieldsWithRelationTargets({
|
||||
baseFields: objectMetadataItem?.fields ?? [],
|
||||
recordFilters,
|
||||
allFieldMetadataItems: flattenedFieldMetadataItems,
|
||||
}),
|
||||
findFieldMetadataItemById,
|
||||
filterValueDependencies,
|
||||
recordFilterGroups,
|
||||
recordFilters,
|
||||
|
||||
+5
-28
@@ -256,37 +256,14 @@ export class CommonGroupByQueryRunnerService extends CommonBaseQueryRunnerServic
|
||||
options: field.options as PartialFieldMetadataItemOption[],
|
||||
}));
|
||||
|
||||
// Relation-traversal filters reference target fields on related objects
|
||||
// that aren't in the source object's field list above. Resolve and add
|
||||
// them so the shared dispatcher can look them up by id.
|
||||
const relationTargetFieldsFromFilters = recordFilters
|
||||
.map((filter) => filter.relationTargetFieldMetadataId)
|
||||
.filter(isDefined)
|
||||
.filter((id) => !fields.some((field) => field.id === id))
|
||||
.map((id) => {
|
||||
const field = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: id,
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
if (!field) return null;
|
||||
|
||||
return {
|
||||
id: field.id,
|
||||
name: field.name,
|
||||
type: field.type,
|
||||
label: field.label,
|
||||
options: field.options as PartialFieldMetadataItemOption[],
|
||||
};
|
||||
})
|
||||
.filter(isDefined);
|
||||
|
||||
fields.push(...relationTargetFieldsFromFilters);
|
||||
|
||||
const filtersFromView = computeRecordGqlOperationFilter({
|
||||
recordFilters,
|
||||
recordFilterGroups: recordFilterGroups,
|
||||
fields,
|
||||
findFieldMetadataItemById: (id) =>
|
||||
findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: id,
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
}),
|
||||
filterValueDependencies: {
|
||||
timeZone: 'UTC', // TODO: see if we use workspace member timezone here
|
||||
},
|
||||
|
||||
+5
-32
@@ -107,39 +107,12 @@ export class ViewQueryParamsService {
|
||||
: RecordFilterGroupLogicalOperator.AND,
|
||||
}));
|
||||
|
||||
const filterFieldMetadataIds = recordFilters.flatMap((filter) =>
|
||||
isDefined(filter.relationTargetFieldMetadataId)
|
||||
? [filter.fieldMetadataId, filter.relationTargetFieldMetadataId]
|
||||
: [filter.fieldMetadataId],
|
||||
);
|
||||
|
||||
const fields = filterFieldMetadataIds
|
||||
.map((fieldMetadataId) => {
|
||||
const field = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: fieldMetadataId,
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
if (!field) return null;
|
||||
|
||||
return {
|
||||
id: field.id,
|
||||
name: field.name,
|
||||
type: field.type,
|
||||
label: field.label,
|
||||
options: field.options?.map((opt) => ({
|
||||
id: opt.id ?? '',
|
||||
label: opt.label,
|
||||
value: opt.value,
|
||||
color: 'color' in opt ? opt.color : undefined,
|
||||
position: opt.position,
|
||||
})),
|
||||
};
|
||||
})
|
||||
.filter(isDefined);
|
||||
|
||||
const filter = computeRecordGqlOperationFilter({
|
||||
fields,
|
||||
findFieldMetadataItemById: (id) =>
|
||||
findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: id,
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
}),
|
||||
recordFilters,
|
||||
recordFilterGroups,
|
||||
filterValueDependencies: { currentWorkspaceMemberId, timeZone },
|
||||
|
||||
+5
-18
@@ -5,7 +5,6 @@ import {
|
||||
RecordFilterGroupLogicalOperator,
|
||||
RowLevelPermissionPredicateGroupLogicalOperator,
|
||||
type CompositeFieldSubFieldName,
|
||||
type PartialFieldMetadataItemOption,
|
||||
type RecordGqlOperationFilter,
|
||||
type RowLevelPermissionPredicateValue,
|
||||
} from 'twenty-shared/types';
|
||||
@@ -216,26 +215,14 @@ export const buildRowLevelPermissionRecordFilter = ({
|
||||
predicateGroup.parentRowLevelPermissionPredicateGroupId,
|
||||
}));
|
||||
|
||||
const fieldMetadataItems = predicates
|
||||
.map((predicate) =>
|
||||
findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: predicate.fieldMetadataId,
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
}),
|
||||
)
|
||||
.filter(isDefined)
|
||||
.map((field) => ({
|
||||
id: field.id,
|
||||
name: field.name,
|
||||
type: field.type,
|
||||
label: field.label,
|
||||
options: field.options as PartialFieldMetadataItemOption[],
|
||||
}));
|
||||
|
||||
return computeRecordGqlOperationFilter({
|
||||
recordFilters,
|
||||
recordFilterGroups,
|
||||
fields: fieldMetadataItems,
|
||||
findFieldMetadataItemById: (id) =>
|
||||
findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: id,
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
}),
|
||||
filterValueDependencies: {
|
||||
currentWorkspaceMemberId: workspaceMember?.id,
|
||||
},
|
||||
|
||||
-1
@@ -93,7 +93,6 @@ export class ChartDataQueryService {
|
||||
}: ExecuteGroupByQueryParams): Promise<GroupByRawResult[]> {
|
||||
const gqlOperationFilter = convertChartFilterToGqlOperationFilter({
|
||||
filter,
|
||||
flatObjectMetadata,
|
||||
flatFieldMetadataMaps,
|
||||
userTimezone,
|
||||
});
|
||||
|
||||
+7
-33
@@ -2,7 +2,6 @@ import {
|
||||
type ChartFilter,
|
||||
type CompositeFieldSubFieldName,
|
||||
type FilterableAndTSVectorFieldType,
|
||||
type PartialFieldMetadataItem,
|
||||
type RecordFilterGroupLogicalOperator,
|
||||
type ViewFilterOperand,
|
||||
} from 'twenty-shared/types';
|
||||
@@ -18,18 +17,15 @@ import { type ObjectRecordFilter } from 'src/engine/api/graphql/workspace-query-
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
|
||||
type ConvertChartFilterToGqlOperationFilterParams = {
|
||||
filter: ChartFilter | undefined;
|
||||
flatObjectMetadata: FlatObjectMetadata;
|
||||
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
|
||||
userTimezone: string;
|
||||
};
|
||||
|
||||
export const convertChartFilterToGqlOperationFilter = ({
|
||||
filter,
|
||||
flatObjectMetadata,
|
||||
flatFieldMetadataMaps,
|
||||
userTimezone,
|
||||
}: ConvertChartFilterToGqlOperationFilterParams): ObjectRecordFilter => {
|
||||
@@ -44,34 +40,6 @@ export const convertChartFilterToGqlOperationFilter = ({
|
||||
return {};
|
||||
}
|
||||
|
||||
const fieldIds = flatObjectMetadata.fieldIds ?? [];
|
||||
const fields: PartialFieldMetadataItem[] = fieldIds
|
||||
.map((fieldId: string) => {
|
||||
const field = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: fieldId,
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(field)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
id: field.id,
|
||||
name: field.name,
|
||||
type: field.type,
|
||||
label: field.label,
|
||||
options: field.options?.map((opt) => ({
|
||||
id: opt.id ?? '',
|
||||
label: opt.label,
|
||||
value: opt.value,
|
||||
color: 'color' in opt ? opt.color : undefined,
|
||||
position: opt.position,
|
||||
})),
|
||||
};
|
||||
})
|
||||
.filter(isDefined);
|
||||
|
||||
const convertedRecordFilters: Omit<RecordFilter, 'id'>[] = recordFilters.map(
|
||||
(recordFilter) => {
|
||||
const field = findFlatEntityByIdInFlatEntityMaps({
|
||||
@@ -90,6 +58,8 @@ export const convertChartFilterToGqlOperationFilter = ({
|
||||
subFieldName: (recordFilter.subFieldName ?? undefined) as
|
||||
| CompositeFieldSubFieldName
|
||||
| undefined,
|
||||
relationTargetFieldMetadataId:
|
||||
recordFilter.relationTargetFieldMetadataId ?? null,
|
||||
};
|
||||
},
|
||||
);
|
||||
@@ -104,7 +74,11 @@ export const convertChartFilterToGqlOperationFilter = ({
|
||||
}));
|
||||
|
||||
return computeRecordGqlOperationFilter({
|
||||
fields,
|
||||
findFieldMetadataItemById: (id) =>
|
||||
findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: id,
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
}),
|
||||
recordFilters: convertedRecordFilters,
|
||||
recordFilterGroups: convertedRecordFilterGroups,
|
||||
filterValueDependencies: {
|
||||
|
||||
+6
-33
@@ -1,12 +1,7 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import {
|
||||
type FieldMetadataComplexOption,
|
||||
type FieldMetadataDefaultOption,
|
||||
} from 'twenty-shared/types';
|
||||
import {
|
||||
computeRecordGqlOperationFilter,
|
||||
isDefined,
|
||||
isRecordFilterValueValid,
|
||||
resolveInput,
|
||||
} from 'twenty-shared/utils';
|
||||
@@ -63,38 +58,12 @@ export class FindRecordsWorkflowAction implements WorkflowAction {
|
||||
const executionContext =
|
||||
await this.workflowExecutionContextService.getExecutionContext(runInfo);
|
||||
|
||||
const { flatObjectMetadata, flatFieldMetadataMaps } =
|
||||
const { flatFieldMetadataMaps } =
|
||||
await this.workflowCommonWorkspaceService.getObjectMetadataInfo(
|
||||
workflowActionInput.objectName,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
const fields = flatObjectMetadata.fieldIds
|
||||
.map((fieldId) => {
|
||||
const field = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: fieldId,
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
if (!field) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
id: field.id,
|
||||
name: field.name,
|
||||
type: field.type,
|
||||
label: field.label,
|
||||
// Note: force cast is required until we deprecate the CreateFieldInput and UpdateFieldInput
|
||||
// type derivation from the FieldMetadataDto
|
||||
options: field.options as
|
||||
| (FieldMetadataDefaultOption & { id: string })[]
|
||||
| (FieldMetadataComplexOption & { id: string })[]
|
||||
| null,
|
||||
};
|
||||
})
|
||||
.filter(isDefined);
|
||||
|
||||
if (workflowActionInput.filter?.recordFilters) {
|
||||
for (const filter of workflowActionInput.filter.recordFilters) {
|
||||
if (!isRecordFilterValueValid(filter)) {
|
||||
@@ -110,7 +79,11 @@ export class FindRecordsWorkflowAction implements WorkflowAction {
|
||||
workflowActionInput.filter?.recordFilters &&
|
||||
workflowActionInput.filter?.recordFilterGroups
|
||||
? computeRecordGqlOperationFilter({
|
||||
fields,
|
||||
findFieldMetadataItemById: (id) =>
|
||||
findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: id,
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
}),
|
||||
recordFilters: workflowActionInput.filter.recordFilters,
|
||||
recordFilterGroups: workflowActionInput.filter.recordFilterGroups,
|
||||
filterValueDependencies: {
|
||||
|
||||
+230
@@ -0,0 +1,230 @@
|
||||
import gql from 'graphql-tag';
|
||||
import request from 'supertest';
|
||||
import { createManyOperationFactory } from 'test/integration/graphql/utils/create-many-operation-factory.util';
|
||||
import { deleteManyOperationFactory } from 'test/integration/graphql/utils/delete-many-operation-factory.util';
|
||||
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
||||
import { makeMetadataAPIRequest } from 'test/integration/metadata/suites/utils/make-metadata-api-request.util';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
const client = request(`http://localhost:${APP_PORT}`);
|
||||
|
||||
const TEST_COMPANY_AIRBNB_ID = '20202020-aaaa-4000-8000-000000000001';
|
||||
const TEST_COMPANY_STRIPE_ID = '20202020-aaaa-4000-8000-000000000002';
|
||||
const TEST_PERSON_AIRBNB_1_ID = '20202020-bbbb-4000-8000-000000000001';
|
||||
const TEST_PERSON_AIRBNB_2_ID = '20202020-bbbb-4000-8000-000000000002';
|
||||
const TEST_PERSON_STRIPE_1_ID = '20202020-bbbb-4000-8000-000000000003';
|
||||
const SHARED_JOB_TITLE = 'chart-test-relation-traversal';
|
||||
const ALL_TEST_PERSON_IDS = [
|
||||
TEST_PERSON_AIRBNB_1_ID,
|
||||
TEST_PERSON_AIRBNB_2_ID,
|
||||
TEST_PERSON_STRIPE_1_ID,
|
||||
];
|
||||
const ALL_TEST_COMPANY_IDS = [TEST_COMPANY_AIRBNB_ID, TEST_COMPANY_STRIPE_ID];
|
||||
|
||||
describe('BarChartData with relation-traversal filter (e2e)', () => {
|
||||
let personObjectMetadataId: string | null = null;
|
||||
let personIdFieldMetadataId: string | null = null;
|
||||
let personJobTitleFieldMetadataId: string | null = null;
|
||||
let personCompanyFieldMetadataId: string | null = null;
|
||||
let companyNameFieldMetadataId: string | null = null;
|
||||
|
||||
const lookupMetadataIds = async () => {
|
||||
const objectsResponse = await makeMetadataAPIRequest({
|
||||
query: gql`
|
||||
query Objects($filter: ObjectFilter!, $paging: CursorPaging!) {
|
||||
objects(filter: $filter, paging: $paging) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
nameSingular
|
||||
fieldsList {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: { paging: { first: 1000 }, filter: {} },
|
||||
});
|
||||
|
||||
expect(objectsResponse.body.errors).toBeUndefined();
|
||||
|
||||
const objects: Array<{
|
||||
id: string;
|
||||
nameSingular: string;
|
||||
fieldsList: Array<{ id: string; name: string }>;
|
||||
}> = objectsResponse.body.data.objects.edges.map(
|
||||
(edge: { node: unknown }) => edge.node,
|
||||
);
|
||||
|
||||
const personObject = objects.find((o) => o.nameSingular === 'person');
|
||||
const companyObject = objects.find((o) => o.nameSingular === 'company');
|
||||
|
||||
personObjectMetadataId = personObject?.id ?? null;
|
||||
personIdFieldMetadataId =
|
||||
personObject?.fieldsList.find((f) => f.name === 'id')?.id ?? null;
|
||||
personJobTitleFieldMetadataId =
|
||||
personObject?.fieldsList.find((f) => f.name === 'jobTitle')?.id ?? null;
|
||||
personCompanyFieldMetadataId =
|
||||
personObject?.fieldsList.find((f) => f.name === 'company')?.id ?? null;
|
||||
companyNameFieldMetadataId =
|
||||
companyObject?.fieldsList.find((f) => f.name === 'name')?.id ?? null;
|
||||
|
||||
if (
|
||||
!personObjectMetadataId ||
|
||||
!personIdFieldMetadataId ||
|
||||
!personJobTitleFieldMetadataId ||
|
||||
!personCompanyFieldMetadataId ||
|
||||
!companyNameFieldMetadataId
|
||||
) {
|
||||
throw new Error('Failed to resolve required metadata ids for chart test');
|
||||
}
|
||||
};
|
||||
|
||||
const seedTestRecords = async () => {
|
||||
await makeGraphqlAPIRequest(
|
||||
createManyOperationFactory({
|
||||
objectMetadataSingularName: 'company',
|
||||
objectMetadataPluralName: 'companies',
|
||||
gqlFields: 'id',
|
||||
data: [
|
||||
{ id: TEST_COMPANY_AIRBNB_ID, name: 'AirbnbChartTest' },
|
||||
{ id: TEST_COMPANY_STRIPE_ID, name: 'StripeChartTest' },
|
||||
],
|
||||
upsert: true,
|
||||
}),
|
||||
);
|
||||
|
||||
await makeGraphqlAPIRequest(
|
||||
createManyOperationFactory({
|
||||
objectMetadataSingularName: 'person',
|
||||
objectMetadataPluralName: 'people',
|
||||
gqlFields: 'id',
|
||||
data: [
|
||||
{
|
||||
id: TEST_PERSON_AIRBNB_1_ID,
|
||||
companyId: TEST_COMPANY_AIRBNB_ID,
|
||||
jobTitle: SHARED_JOB_TITLE,
|
||||
},
|
||||
{
|
||||
id: TEST_PERSON_AIRBNB_2_ID,
|
||||
companyId: TEST_COMPANY_AIRBNB_ID,
|
||||
jobTitle: SHARED_JOB_TITLE,
|
||||
},
|
||||
{
|
||||
id: TEST_PERSON_STRIPE_1_ID,
|
||||
companyId: TEST_COMPANY_STRIPE_ID,
|
||||
jobTitle: SHARED_JOB_TITLE,
|
||||
},
|
||||
],
|
||||
upsert: true,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const queryBarChartCount = async (extraRecordFilters: object[] = []) => {
|
||||
const filterGroupId = uuidv4();
|
||||
const allRecordFilters = [
|
||||
{
|
||||
id: uuidv4(),
|
||||
type: 'TEXT',
|
||||
operand: 'CONTAINS',
|
||||
value: SHARED_JOB_TITLE,
|
||||
fieldMetadataId: personJobTitleFieldMetadataId,
|
||||
recordFilterGroupId: filterGroupId,
|
||||
},
|
||||
...extraRecordFilters.map((filter) => ({
|
||||
...filter,
|
||||
recordFilterGroupId: filterGroupId,
|
||||
})),
|
||||
];
|
||||
|
||||
const response = await client
|
||||
.post('/metadata')
|
||||
.set('Authorization', `Bearer ${APPLE_JANE_ADMIN_ACCESS_TOKEN}`)
|
||||
.send({
|
||||
query: `
|
||||
query BarChartData($input: BarChartDataInput!) {
|
||||
barChartData(input: $input) {
|
||||
data
|
||||
indexBy
|
||||
keys
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
input: {
|
||||
objectMetadataId: personObjectMetadataId,
|
||||
configuration: {
|
||||
configurationType: 'BAR_CHART',
|
||||
layout: 'VERTICAL',
|
||||
aggregateFieldMetadataId: personIdFieldMetadataId,
|
||||
aggregateOperation: 'COUNT',
|
||||
primaryAxisGroupByFieldMetadataId: personJobTitleFieldMetadataId,
|
||||
primaryAxisOrderBy: 'VALUE_DESC',
|
||||
filter: {
|
||||
recordFilters: allRecordFilters,
|
||||
recordFilterGroups: [
|
||||
{ id: filterGroupId, logicalOperator: 'AND' },
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(response.body.errors).toBeUndefined();
|
||||
const data: Array<Record<string, string | number>> =
|
||||
response.body.data.barChartData.data;
|
||||
const row = data.find((entry) => entry.jobTitle === SHARED_JOB_TITLE);
|
||||
|
||||
return typeof row?.id === 'number' ? row.id : 0;
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
await lookupMetadataIds();
|
||||
await seedTestRecords();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await makeGraphqlAPIRequest(
|
||||
deleteManyOperationFactory({
|
||||
objectMetadataSingularName: 'person',
|
||||
objectMetadataPluralName: 'people',
|
||||
gqlFields: 'id',
|
||||
filter: { id: { in: ALL_TEST_PERSON_IDS } },
|
||||
}),
|
||||
);
|
||||
await makeGraphqlAPIRequest(
|
||||
deleteManyOperationFactory({
|
||||
objectMetadataSingularName: 'company',
|
||||
objectMetadataPluralName: 'companies',
|
||||
gqlFields: 'id',
|
||||
filter: { id: { in: ALL_TEST_COMPANY_IDS } },
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should count all 3 test people without a relation-traversal filter', async () => {
|
||||
const count = await queryBarChartCount();
|
||||
|
||||
expect(count).toBe(3);
|
||||
});
|
||||
|
||||
it('should apply a one-hop relation-traversal filter and only count Airbnb people', async () => {
|
||||
const count = await queryBarChartCount([
|
||||
{
|
||||
id: uuidv4(),
|
||||
type: 'TEXT',
|
||||
operand: 'CONTAINS',
|
||||
value: 'AirbnbChartTest',
|
||||
fieldMetadataId: personCompanyFieldMetadataId,
|
||||
relationTargetFieldMetadataId: companyNameFieldMetadataId,
|
||||
},
|
||||
]);
|
||||
|
||||
expect(count).toBe(2);
|
||||
});
|
||||
});
|
||||
+348
@@ -0,0 +1,348 @@
|
||||
import gql from 'graphql-tag';
|
||||
import request from 'supertest';
|
||||
import { createManyOperationFactory } from 'test/integration/graphql/utils/create-many-operation-factory.util';
|
||||
import { deleteManyOperationFactory } from 'test/integration/graphql/utils/delete-many-operation-factory.util';
|
||||
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
||||
import {
|
||||
destroyWorkflowRun,
|
||||
runWorkflowVersion,
|
||||
waitForWorkflowCompletion,
|
||||
} from 'test/integration/graphql/suites/workflow/utils/workflow-run-test.util';
|
||||
import { makeMetadataAPIRequest } from 'test/integration/metadata/suites/utils/make-metadata-api-request.util';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
const client = request(`http://localhost:${APP_PORT}`);
|
||||
|
||||
const TEST_COMPANY_AIRBNB_ID = '20202020-eeee-4000-8000-000000000001';
|
||||
const TEST_COMPANY_STRIPE_ID = '20202020-eeee-4000-8000-000000000002';
|
||||
const TEST_PERSON_AIRBNB_1_ID = '20202020-ffff-4000-8000-000000000001';
|
||||
const TEST_PERSON_AIRBNB_2_ID = '20202020-ffff-4000-8000-000000000002';
|
||||
const TEST_PERSON_STRIPE_1_ID = '20202020-ffff-4000-8000-000000000003';
|
||||
const ALL_TEST_PERSON_IDS = [
|
||||
TEST_PERSON_AIRBNB_1_ID,
|
||||
TEST_PERSON_AIRBNB_2_ID,
|
||||
TEST_PERSON_STRIPE_1_ID,
|
||||
];
|
||||
const ALL_TEST_COMPANY_IDS = [TEST_COMPANY_AIRBNB_ID, TEST_COMPANY_STRIPE_ID];
|
||||
|
||||
describe('FindRecords workflow action with relation-traversal filter (e2e)', () => {
|
||||
let createdWorkflowId: string | null = null;
|
||||
let createdWorkflowVersionId: string | null = null;
|
||||
let findRecordsStepId: string | null = null;
|
||||
let createdWorkflowRunId: string | null = null;
|
||||
let personCompanyFieldMetadataId: string | null = null;
|
||||
let companyNameFieldMetadataId: string | null = null;
|
||||
|
||||
const lookupFieldMetadataIds = async () => {
|
||||
const objectsResponse = await makeMetadataAPIRequest({
|
||||
query: gql`
|
||||
query Objects($filter: ObjectFilter!, $paging: CursorPaging!) {
|
||||
objects(filter: $filter, paging: $paging) {
|
||||
edges {
|
||||
node {
|
||||
nameSingular
|
||||
fieldsList {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: { paging: { first: 1000 }, filter: {} },
|
||||
});
|
||||
|
||||
expect(objectsResponse.body.errors).toBeUndefined();
|
||||
|
||||
const objects: Array<{
|
||||
nameSingular: string;
|
||||
fieldsList: Array<{ id: string; name: string }>;
|
||||
}> = objectsResponse.body.data.objects.edges.map(
|
||||
(edge: { node: unknown }) => edge.node,
|
||||
);
|
||||
|
||||
const personObject = objects.find((o) => o.nameSingular === 'person');
|
||||
const companyObject = objects.find((o) => o.nameSingular === 'company');
|
||||
|
||||
personCompanyFieldMetadataId =
|
||||
personObject?.fieldsList.find((f) => f.name === 'company')?.id ?? null;
|
||||
companyNameFieldMetadataId =
|
||||
companyObject?.fieldsList.find((f) => f.name === 'name')?.id ?? null;
|
||||
|
||||
if (!personCompanyFieldMetadataId || !companyNameFieldMetadataId) {
|
||||
throw new Error(
|
||||
`Could not resolve required field metadata ids — person.company=${personCompanyFieldMetadataId}, company.name=${companyNameFieldMetadataId}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const seedTestRecords = async () => {
|
||||
await makeGraphqlAPIRequest(
|
||||
createManyOperationFactory({
|
||||
objectMetadataSingularName: 'company',
|
||||
objectMetadataPluralName: 'companies',
|
||||
gqlFields: 'id',
|
||||
data: [
|
||||
{ id: TEST_COMPANY_AIRBNB_ID, name: 'AirbnbWorkflowTest' },
|
||||
{ id: TEST_COMPANY_STRIPE_ID, name: 'StripeWorkflowTest' },
|
||||
],
|
||||
upsert: true,
|
||||
}),
|
||||
);
|
||||
|
||||
await makeGraphqlAPIRequest(
|
||||
createManyOperationFactory({
|
||||
objectMetadataSingularName: 'person',
|
||||
objectMetadataPluralName: 'people',
|
||||
gqlFields: 'id',
|
||||
data: [
|
||||
{
|
||||
id: TEST_PERSON_AIRBNB_1_ID,
|
||||
companyId: TEST_COMPANY_AIRBNB_ID,
|
||||
jobTitle: 'workflow-test-airbnb-1',
|
||||
},
|
||||
{
|
||||
id: TEST_PERSON_AIRBNB_2_ID,
|
||||
companyId: TEST_COMPANY_AIRBNB_ID,
|
||||
jobTitle: 'workflow-test-airbnb-2',
|
||||
},
|
||||
{
|
||||
id: TEST_PERSON_STRIPE_1_ID,
|
||||
companyId: TEST_COMPANY_STRIPE_ID,
|
||||
jobTitle: 'workflow-test-stripe-1',
|
||||
},
|
||||
],
|
||||
upsert: true,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const buildWorkflow = async () => {
|
||||
const createWorkflowResponse = await client
|
||||
.post('/graphql')
|
||||
.set('Authorization', `Bearer ${APPLE_JANE_ADMIN_ACCESS_TOKEN}`)
|
||||
.send({
|
||||
query: `
|
||||
mutation CreateWorkflow {
|
||||
createWorkflow(data: { name: "Relation Traversal Find Records Test" }) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
expect(createWorkflowResponse.body.errors).toBeUndefined();
|
||||
createdWorkflowId = createWorkflowResponse.body.data.createWorkflow.id;
|
||||
|
||||
const getWorkflowResponse = await client
|
||||
.post('/graphql')
|
||||
.set('Authorization', `Bearer ${APPLE_JANE_ADMIN_ACCESS_TOKEN}`)
|
||||
.send({
|
||||
query: `
|
||||
query GetWorkflow($id: UUID!) {
|
||||
workflow(filter: { id: { eq: $id } }) {
|
||||
id
|
||||
versions { edges { node { id } } }
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: { id: createdWorkflowId },
|
||||
});
|
||||
|
||||
createdWorkflowVersionId =
|
||||
getWorkflowResponse.body.data.workflow.versions.edges[0].node.id;
|
||||
|
||||
await client
|
||||
.post('/graphql')
|
||||
.set('Authorization', `Bearer ${APPLE_JANE_ADMIN_ACCESS_TOKEN}`)
|
||||
.send({
|
||||
query: `
|
||||
mutation UpdateWorkflowVersion($id: UUID!, $data: WorkflowVersionUpdateInput!) {
|
||||
updateWorkflowVersion(id: $id, data: $data) { id }
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
id: createdWorkflowVersionId,
|
||||
data: {
|
||||
trigger: {
|
||||
name: 'Manual Trigger',
|
||||
type: 'MANUAL',
|
||||
settings: { outputSchema: {} },
|
||||
nextStepIds: [],
|
||||
position: { x: 0, y: 0 },
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const createStepResponse = await client
|
||||
.post('/graphql')
|
||||
.set('Authorization', `Bearer ${APPLE_JANE_ADMIN_ACCESS_TOKEN}`)
|
||||
.send({
|
||||
query: `
|
||||
mutation CreateWorkflowVersionStep($input: CreateWorkflowVersionStepInput!) {
|
||||
createWorkflowVersionStep(input: $input) { stepsDiff }
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
input: {
|
||||
workflowVersionId: createdWorkflowVersionId,
|
||||
stepType: 'FIND_RECORDS',
|
||||
parentStepId: 'trigger',
|
||||
position: { x: 200, y: 0 },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(createStepResponse.body.errors).toBeUndefined();
|
||||
|
||||
const getVersionResponse = await client
|
||||
.post('/graphql')
|
||||
.set('Authorization', `Bearer ${APPLE_JANE_ADMIN_ACCESS_TOKEN}`)
|
||||
.send({
|
||||
query: `
|
||||
query GetWorkflowVersion($id: UUID!) {
|
||||
workflowVersion(filter: { id: { eq: $id } }) { steps }
|
||||
}
|
||||
`,
|
||||
variables: { id: createdWorkflowVersionId },
|
||||
});
|
||||
|
||||
const steps = getVersionResponse.body.data.workflowVersion.steps;
|
||||
const findRecordsStep = steps.find(
|
||||
(step: { type: string }) => step.type === 'FIND_RECORDS',
|
||||
);
|
||||
|
||||
expect(findRecordsStep).toBeDefined();
|
||||
findRecordsStepId = findRecordsStep.id;
|
||||
|
||||
const filterGroupId = uuidv4();
|
||||
const filterId = uuidv4();
|
||||
|
||||
const updateStepResponse = await client
|
||||
.post('/graphql')
|
||||
.set('Authorization', `Bearer ${APPLE_JANE_ADMIN_ACCESS_TOKEN}`)
|
||||
.send({
|
||||
query: `
|
||||
mutation UpdateWorkflowVersionStep($input: UpdateWorkflowVersionStepInput!) {
|
||||
updateWorkflowVersionStep(input: $input) { id }
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
input: {
|
||||
workflowVersionId: createdWorkflowVersionId,
|
||||
step: {
|
||||
...findRecordsStep,
|
||||
settings: {
|
||||
...findRecordsStep.settings,
|
||||
input: {
|
||||
...findRecordsStep.settings.input,
|
||||
objectName: 'person',
|
||||
limit: 25,
|
||||
filter: {
|
||||
recordFilters: [
|
||||
{
|
||||
id: filterId,
|
||||
type: 'TEXT',
|
||||
label: 'Company → Name',
|
||||
value: 'AirbnbWorkflowTest',
|
||||
operand: 'CONTAINS',
|
||||
displayValue: 'AirbnbWorkflowTest',
|
||||
fieldMetadataId: personCompanyFieldMetadataId,
|
||||
relationTargetFieldMetadataId:
|
||||
companyNameFieldMetadataId,
|
||||
recordFilterGroupId: filterGroupId,
|
||||
},
|
||||
],
|
||||
recordFilterGroups: [
|
||||
{ id: filterGroupId, logicalOperator: 'AND' },
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(updateStepResponse.body.errors).toBeUndefined();
|
||||
|
||||
const activateResponse = await client
|
||||
.post('/graphql')
|
||||
.set('Authorization', `Bearer ${APPLE_JANE_ADMIN_ACCESS_TOKEN}`)
|
||||
.send({
|
||||
query: `
|
||||
mutation ActivateWorkflowVersion($workflowVersionId: UUID!) {
|
||||
activateWorkflowVersion(workflowVersionId: $workflowVersionId)
|
||||
}
|
||||
`,
|
||||
variables: { workflowVersionId: createdWorkflowVersionId },
|
||||
});
|
||||
|
||||
expect(activateResponse.body.errors).toBeUndefined();
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
await lookupFieldMetadataIds();
|
||||
await seedTestRecords();
|
||||
await buildWorkflow();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
if (createdWorkflowRunId) {
|
||||
await destroyWorkflowRun(createdWorkflowRunId);
|
||||
}
|
||||
if (createdWorkflowId) {
|
||||
await client
|
||||
.post('/graphql')
|
||||
.set('Authorization', `Bearer ${APPLE_JANE_ADMIN_ACCESS_TOKEN}`)
|
||||
.send({
|
||||
query: `mutation DestroyWorkflow($id: ID!) { destroyWorkflow(id: $id) { id } }`,
|
||||
variables: { id: createdWorkflowId },
|
||||
});
|
||||
}
|
||||
await makeGraphqlAPIRequest(
|
||||
deleteManyOperationFactory({
|
||||
objectMetadataSingularName: 'person',
|
||||
objectMetadataPluralName: 'people',
|
||||
gqlFields: 'id',
|
||||
filter: { id: { in: ALL_TEST_PERSON_IDS } },
|
||||
}),
|
||||
);
|
||||
await makeGraphqlAPIRequest(
|
||||
deleteManyOperationFactory({
|
||||
objectMetadataSingularName: 'company',
|
||||
objectMetadataPluralName: 'companies',
|
||||
gqlFields: 'id',
|
||||
filter: { id: { in: ALL_TEST_COMPANY_IDS } },
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should apply a one-hop relation-traversal filter and return only matching records', async () => {
|
||||
const workflowRunId = await runWorkflowVersion({
|
||||
workflowVersionId: createdWorkflowVersionId!,
|
||||
});
|
||||
|
||||
createdWorkflowRunId = workflowRunId;
|
||||
|
||||
const workflowRun = await waitForWorkflowCompletion(workflowRunId);
|
||||
|
||||
expect(workflowRun?.status).toBe('COMPLETED');
|
||||
expect(workflowRun?.state?.stepInfos?.[findRecordsStepId!]?.status).toBe(
|
||||
'SUCCESS',
|
||||
);
|
||||
|
||||
const result = workflowRun?.state?.stepInfos?.[findRecordsStepId!]
|
||||
?.result as
|
||||
| { all?: Array<{ id: string }>; totalCount?: number }
|
||||
| undefined;
|
||||
|
||||
const returnedIds = (result?.all ?? []).map((record) => record.id);
|
||||
|
||||
expect(returnedIds).toContain(TEST_PERSON_AIRBNB_1_ID);
|
||||
expect(returnedIds).toContain(TEST_PERSON_AIRBNB_2_ID);
|
||||
expect(returnedIds).not.toContain(TEST_PERSON_STRIPE_1_ID);
|
||||
});
|
||||
});
|
||||
@@ -8,6 +8,7 @@ export type ChartRecordFilter = {
|
||||
type?: string;
|
||||
recordFilterGroupId?: string | null;
|
||||
subFieldName?: string | null;
|
||||
relationTargetFieldMetadataId?: SerializedRelation | null;
|
||||
};
|
||||
|
||||
export type ChartRecordFilterGroup = {
|
||||
|
||||
+2
-1
@@ -27,7 +27,8 @@ describe('computeRecordGqlOperationFilter', () => {
|
||||
];
|
||||
|
||||
const filter = computeRecordGqlOperationFilter({
|
||||
fields: [companyIdField],
|
||||
findFieldMetadataItemById: (id) =>
|
||||
id === companyIdField.id ? companyIdField : undefined,
|
||||
recordFilters,
|
||||
recordFilterGroups: [],
|
||||
filterValueDependencies: {
|
||||
|
||||
+7
-4
@@ -21,11 +21,14 @@ describe('turnRecordFilterGroupsIntoGqlOperationFilter', () => {
|
||||
},
|
||||
];
|
||||
|
||||
const fieldById = new Map(fields.map((field) => [field.id, field]));
|
||||
const findFieldMetadataItemById = (id: string) => fieldById.get(id);
|
||||
|
||||
it('should return undefined when group is not found', () => {
|
||||
const result = turnRecordFilterGroupsIntoGqlOperationFilter({
|
||||
filterValueDependencies: {},
|
||||
filters: [],
|
||||
fields,
|
||||
findFieldMetadataItemById,
|
||||
recordFilterGroups: [],
|
||||
currentRecordFilterGroupId: 'nonexistent',
|
||||
});
|
||||
@@ -45,7 +48,7 @@ describe('turnRecordFilterGroupsIntoGqlOperationFilter', () => {
|
||||
recordFilterGroupId: 'group1',
|
||||
},
|
||||
],
|
||||
fields,
|
||||
findFieldMetadataItemById,
|
||||
recordFilterGroups: [
|
||||
{
|
||||
id: 'group1',
|
||||
@@ -70,7 +73,7 @@ describe('turnRecordFilterGroupsIntoGqlOperationFilter', () => {
|
||||
recordFilterGroupId: 'group1',
|
||||
},
|
||||
],
|
||||
fields,
|
||||
findFieldMetadataItemById,
|
||||
recordFilterGroups: [
|
||||
{
|
||||
id: 'group1',
|
||||
@@ -95,7 +98,7 @@ describe('turnRecordFilterGroupsIntoGqlOperationFilter', () => {
|
||||
recordFilterGroupId: 'subgroup1',
|
||||
},
|
||||
],
|
||||
fields,
|
||||
findFieldMetadataItemById,
|
||||
recordFilterGroups: [
|
||||
{
|
||||
id: 'group1',
|
||||
|
||||
+59
-56
@@ -131,6 +131,9 @@ const fields = [
|
||||
|
||||
const filterValueDependencies = { timeZone: 'UTC' };
|
||||
|
||||
const fieldById = new Map(fields.map((field) => [field.id, field]));
|
||||
const findFieldMetadataItemById = (id: string) => fieldById.get(id);
|
||||
|
||||
const makeFilter = (
|
||||
fieldMetadataId: string,
|
||||
operand: RecordFilterOperand,
|
||||
@@ -156,7 +159,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.CONTAINS,
|
||||
'x',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
@@ -166,7 +169,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
const result = turnRecordFilterIntoRecordGqlOperationFilter({
|
||||
filterValueDependencies,
|
||||
recordFilter: makeFilter('f-text', RecordFilterOperand.CONTAINS, ''),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
@@ -181,7 +184,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.CONTAINS,
|
||||
'test',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({ name: { ilike: '%test%' } });
|
||||
@@ -195,7 +198,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.DOES_NOT_CONTAIN,
|
||||
'test',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({ not: { name: { ilike: '%test%' } } });
|
||||
@@ -207,7 +210,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
const result = turnRecordFilterIntoRecordGqlOperationFilter({
|
||||
filterValueDependencies,
|
||||
recordFilter: makeFilter('f-number', RecordFilterOperand.IS, '42'),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({ amount: { eq: 42 } });
|
||||
@@ -217,7 +220,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
const result = turnRecordFilterIntoRecordGqlOperationFilter({
|
||||
filterValueDependencies,
|
||||
recordFilter: makeFilter('f-number', RecordFilterOperand.IS_NOT, '42'),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({ not: { amount: { eq: 42 } } });
|
||||
@@ -231,7 +234,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.GREATER_THAN_OR_EQUAL,
|
||||
'10',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({ amount: { gte: 10 } });
|
||||
@@ -245,7 +248,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.LESS_THAN_OR_EQUAL,
|
||||
'100',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({ amount: { lte: 100 } });
|
||||
@@ -261,7 +264,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.IS_AFTER,
|
||||
'2024-03-15',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({ createdAt: { gte: '2024-03-15' } });
|
||||
@@ -275,7 +278,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.IS_BEFORE,
|
||||
'2024-03-15',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({ createdAt: { lt: '2024-03-15' } });
|
||||
@@ -289,7 +292,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.IS,
|
||||
'2024-03-15',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({ createdAt: { eq: '2024-03-15' } });
|
||||
@@ -299,7 +302,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
const result = turnRecordFilterIntoRecordGqlOperationFilter({
|
||||
filterValueDependencies,
|
||||
recordFilter: makeFilter('f-date', RecordFilterOperand.IS_IN_PAST, ''),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('createdAt.lt');
|
||||
@@ -313,7 +316,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.IS_IN_FUTURE,
|
||||
'',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('createdAt.gte');
|
||||
@@ -323,7 +326,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
const result = turnRecordFilterIntoRecordGqlOperationFilter({
|
||||
filterValueDependencies,
|
||||
recordFilter: makeFilter('f-date', RecordFilterOperand.IS_TODAY, ''),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('createdAt.eq');
|
||||
@@ -337,7 +340,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.IS_RELATIVE,
|
||||
'PAST_7_DAY',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('and');
|
||||
@@ -353,7 +356,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.IS_AFTER,
|
||||
'2024-03-15T10:00:00Z',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('updatedAt.gte');
|
||||
@@ -367,7 +370,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.IS_BEFORE,
|
||||
'2024-03-15T10:00:00Z',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('updatedAt.lt');
|
||||
@@ -381,7 +384,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.IS,
|
||||
'2024-03-15T10:00:00Z',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('and');
|
||||
@@ -395,7 +398,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.IS_IN_PAST,
|
||||
'',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('updatedAt.lt');
|
||||
@@ -409,7 +412,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.IS_IN_FUTURE,
|
||||
'',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('updatedAt.gt');
|
||||
@@ -423,7 +426,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.IS_TODAY,
|
||||
'',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('and');
|
||||
@@ -437,7 +440,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.IS_RELATIVE,
|
||||
`PAST_7_DAY;;UTC;;`,
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('and');
|
||||
@@ -449,7 +452,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
const result = turnRecordFilterIntoRecordGqlOperationFilter({
|
||||
filterValueDependencies,
|
||||
recordFilter: makeFilter('f-rating', RecordFilterOperand.IS, '3'),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('rating.eq');
|
||||
@@ -463,7 +466,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.GREATER_THAN_OR_EQUAL,
|
||||
'3',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('rating.in');
|
||||
@@ -477,7 +480,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.LESS_THAN_OR_EQUAL,
|
||||
'3',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('rating.in');
|
||||
@@ -489,7 +492,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
const result = turnRecordFilterIntoRecordGqlOperationFilter({
|
||||
filterValueDependencies,
|
||||
recordFilter: makeFilter('f-bool', RecordFilterOperand.IS, 'true'),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({ isActive: { eq: true } });
|
||||
@@ -499,7 +502,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
const result = turnRecordFilterIntoRecordGqlOperationFilter({
|
||||
filterValueDependencies,
|
||||
recordFilter: makeFilter('f-bool', RecordFilterOperand.IS, 'false'),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({ isActive: { eq: false } });
|
||||
@@ -515,7 +518,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.IS,
|
||||
'["ACTIVE","PENDING"]',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('status.in');
|
||||
@@ -529,7 +532,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.IS_NOT,
|
||||
'["ACTIVE"]',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('not');
|
||||
@@ -545,7 +548,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.CONTAINS,
|
||||
'["TAG1","TAG2"]',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('tags.containsAny');
|
||||
@@ -559,7 +562,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.DOES_NOT_CONTAIN,
|
||||
'["TAG1"]',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('or');
|
||||
@@ -575,7 +578,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.IS,
|
||||
'["550e8400-e29b-41d4-a716-446655440000"]',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('companyId.in');
|
||||
@@ -589,7 +592,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.IS_NOT,
|
||||
'["550e8400-e29b-41d4-a716-446655440000"]',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('or');
|
||||
@@ -605,7 +608,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.CONTAINS,
|
||||
'test',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({ metadata: { like: '%test%' } });
|
||||
@@ -619,7 +622,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.DOES_NOT_CONTAIN,
|
||||
'test',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({ not: { metadata: { like: '%test%' } } });
|
||||
@@ -635,7 +638,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.CONTAINS,
|
||||
'doc',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({ attachments: { like: '%doc%' } });
|
||||
@@ -651,7 +654,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.VECTOR_SEARCH,
|
||||
'hello world',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({ search: { search: 'hello world' } });
|
||||
@@ -669,7 +672,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
'CURRENCY',
|
||||
'amountMicros',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('revenue');
|
||||
@@ -685,7 +688,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.CONTAINS,
|
||||
'John',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('or');
|
||||
@@ -701,7 +704,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.CONTAINS,
|
||||
'Paris',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('or');
|
||||
@@ -717,7 +720,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.CONTAINS,
|
||||
'api',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
@@ -744,7 +747,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.CONTAINS,
|
||||
'xyz123',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
@@ -769,7 +772,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.DOES_NOT_CONTAIN,
|
||||
'api',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
@@ -800,7 +803,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.DOES_NOT_CONTAIN,
|
||||
'xyz123',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
@@ -831,7 +834,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
'PHONES',
|
||||
'primaryPhoneNumber',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toBeDefined();
|
||||
@@ -849,7 +852,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
'EMAILS',
|
||||
'primaryEmail',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toBeDefined();
|
||||
@@ -867,7 +870,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
'LINKS',
|
||||
'primaryLinkUrl',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toBeDefined();
|
||||
@@ -883,7 +886,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.CONTAINS,
|
||||
'["item1"]',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toBeDefined();
|
||||
@@ -897,7 +900,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.DOES_NOT_CONTAIN,
|
||||
'["item1"]',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('not');
|
||||
@@ -913,7 +916,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.IS,
|
||||
'["550e8400-e29b-41d4-a716-446655440000"]',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('recordId.in');
|
||||
@@ -931,13 +934,13 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
...makeFilter('f-relation', RecordFilterOperand.CONTAINS, 'Acme'),
|
||||
relationTargetFieldMetadataId: 'f-text',
|
||||
} as RecordFilter,
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({ company: { name: { ilike: '%Acme%' } } });
|
||||
});
|
||||
|
||||
// If the target field is no longer in fieldMetadataItems (e.g. it was
|
||||
// If the target field is no longer resolvable (e.g. it was
|
||||
// deleted from the workspace), dropping the filter is the safe path —
|
||||
// the alternative would silently interpret the text value as a UUID
|
||||
// list against the relation FK.
|
||||
@@ -948,7 +951,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
...makeFilter('f-relation', RecordFilterOperand.CONTAINS, 'Acme'),
|
||||
relationTargetFieldMetadataId: 'nonexistent-target',
|
||||
} as RecordFilter,
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
@@ -963,7 +966,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
...makeFilter('f-relation', RecordFilterOperand.IS_EMPTY, ''),
|
||||
relationTargetFieldMetadataId: 'f-text',
|
||||
} as RecordFilter,
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
// Without traversal, the RELATION case would have produced a filter
|
||||
@@ -984,7 +987,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
...makeFilter('f-relation', RecordFilterOperand.IS, '["ACTIVE"]'),
|
||||
relationTargetFieldMetadataId: 'f-select',
|
||||
} as RecordFilter,
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toEqual({ company: { status: { in: ['ACTIVE'] } } });
|
||||
@@ -1001,7 +1004,7 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
|
||||
RecordFilterOperand.IS,
|
||||
'["550e8400-e29b-41d4-a716-446655440000"]',
|
||||
),
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('companyId.in');
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {
|
||||
type PartialFieldMetadataItem,
|
||||
type RecordFilterValueDependencies,
|
||||
type RecordGqlOperationFilter,
|
||||
} from '@/types';
|
||||
@@ -8,17 +7,20 @@ import {
|
||||
type RecordFilter,
|
||||
type RecordFilterGroup,
|
||||
} from '@/utils/filter/turnRecordFilterGroupIntoGqlOperationFilter';
|
||||
import { turnRecordFilterIntoRecordGqlOperationFilter } from '@/utils/filter/turnRecordFilterIntoGqlOperationFilter';
|
||||
import {
|
||||
type FindFieldMetadataItemById,
|
||||
turnRecordFilterIntoRecordGqlOperationFilter,
|
||||
} from '@/utils/filter/turnRecordFilterIntoGqlOperationFilter';
|
||||
import { isDefined } from '@/utils/validation/isDefined';
|
||||
|
||||
export const computeRecordGqlOperationFilter = ({
|
||||
fields,
|
||||
findFieldMetadataItemById,
|
||||
recordFilters,
|
||||
recordFilterGroups,
|
||||
filterValueDependencies,
|
||||
}: {
|
||||
recordFilters: Omit<RecordFilter, 'id'>[];
|
||||
fields: PartialFieldMetadataItem[];
|
||||
findFieldMetadataItemById: FindFieldMetadataItemById;
|
||||
recordFilterGroups: RecordFilterGroup[];
|
||||
filterValueDependencies: RecordFilterValueDependencies;
|
||||
}): RecordGqlOperationFilter => {
|
||||
@@ -28,7 +30,7 @@ export const computeRecordGqlOperationFilter = ({
|
||||
.map((regularFilter) => {
|
||||
return turnRecordFilterIntoRecordGqlOperationFilter({
|
||||
recordFilter: regularFilter,
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
filterValueDependencies,
|
||||
});
|
||||
})
|
||||
@@ -42,7 +44,7 @@ export const computeRecordGqlOperationFilter = ({
|
||||
turnRecordFilterGroupsIntoGqlOperationFilter({
|
||||
filterValueDependencies,
|
||||
filters: recordFilters,
|
||||
fields,
|
||||
findFieldMetadataItemById,
|
||||
recordFilterGroups,
|
||||
currentRecordFilterGroupId: outermostFilterGroupId,
|
||||
});
|
||||
|
||||
@@ -221,11 +221,13 @@ export const turnAnyFieldFilterIntoRecordGqlFilter = ({
|
||||
}
|
||||
}
|
||||
|
||||
const fieldById = new Map(fields.map((field) => [field.id, field]));
|
||||
|
||||
const baseRecordGqlOperationFilters = anyFieldRecordFilters
|
||||
.map((recordFilter) =>
|
||||
turnRecordFilterIntoRecordGqlOperationFilter({
|
||||
filterValueDependencies: {},
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById: (id) => fieldById.get(id),
|
||||
recordFilter,
|
||||
}),
|
||||
)
|
||||
|
||||
+8
-6
@@ -1,7 +1,6 @@
|
||||
import {
|
||||
type CompositeFieldSubFieldName,
|
||||
type FilterableAndTSVectorFieldType,
|
||||
type PartialFieldMetadataItem,
|
||||
RecordFilterGroupLogicalOperator,
|
||||
type RecordFilterValueDependencies,
|
||||
type RecordGqlOperationFilter,
|
||||
@@ -9,7 +8,10 @@ import {
|
||||
} from '@/types';
|
||||
|
||||
import { isDefined } from '@/utils';
|
||||
import { turnRecordFilterIntoRecordGqlOperationFilter } from '@/utils/filter/turnRecordFilterIntoGqlOperationFilter';
|
||||
import {
|
||||
type FindFieldMetadataItemById,
|
||||
turnRecordFilterIntoRecordGqlOperationFilter,
|
||||
} from '@/utils/filter/turnRecordFilterIntoGqlOperationFilter';
|
||||
|
||||
export type RecordFilter = {
|
||||
id: string;
|
||||
@@ -31,13 +33,13 @@ export type RecordFilterGroup = {
|
||||
export const turnRecordFilterGroupsIntoGqlOperationFilter = ({
|
||||
filterValueDependencies,
|
||||
filters,
|
||||
fields,
|
||||
findFieldMetadataItemById,
|
||||
recordFilterGroups,
|
||||
currentRecordFilterGroupId,
|
||||
}: {
|
||||
filterValueDependencies: RecordFilterValueDependencies;
|
||||
filters: Omit<RecordFilter, 'id'>[];
|
||||
fields: PartialFieldMetadataItem[];
|
||||
findFieldMetadataItemById: FindFieldMetadataItemById;
|
||||
recordFilterGroups: RecordFilterGroup[];
|
||||
currentRecordFilterGroupId?: string;
|
||||
}): RecordGqlOperationFilter | undefined => {
|
||||
@@ -58,7 +60,7 @@ export const turnRecordFilterGroupsIntoGqlOperationFilter = ({
|
||||
turnRecordFilterIntoRecordGqlOperationFilter({
|
||||
filterValueDependencies,
|
||||
recordFilter: recordFilter,
|
||||
fieldMetadataItems: fields,
|
||||
findFieldMetadataItemById,
|
||||
}),
|
||||
)
|
||||
.filter(isDefined);
|
||||
@@ -73,7 +75,7 @@ export const turnRecordFilterGroupsIntoGqlOperationFilter = ({
|
||||
turnRecordFilterGroupsIntoGqlOperationFilter({
|
||||
filterValueDependencies,
|
||||
filters,
|
||||
fields,
|
||||
findFieldMetadataItemById,
|
||||
recordFilterGroups,
|
||||
currentRecordFilterGroupId: subRecordFilterGroup.id,
|
||||
}),
|
||||
|
||||
@@ -62,21 +62,23 @@ type FieldShared = {
|
||||
label: string;
|
||||
};
|
||||
|
||||
export type FindFieldMetadataItemById = (id: string) => FieldShared | undefined;
|
||||
|
||||
type TurnRecordFilterIntoRecordGqlOperationFilterParams = {
|
||||
filterValueDependencies: RecordFilterValueDependencies;
|
||||
recordFilter: Omit<RecordFilter, 'id'>;
|
||||
fieldMetadataItems: FieldShared[];
|
||||
findFieldMetadataItemById: FindFieldMetadataItemById;
|
||||
};
|
||||
|
||||
export const turnRecordFilterIntoRecordGqlOperationFilter = ({
|
||||
recordFilter,
|
||||
fieldMetadataItems,
|
||||
findFieldMetadataItemById,
|
||||
filterValueDependencies,
|
||||
}: TurnRecordFilterIntoRecordGqlOperationFilterParams):
|
||||
| RecordGqlOperationFilter
|
||||
| undefined => {
|
||||
const sourceFieldMetadataItem = fieldMetadataItems.find(
|
||||
(field) => field.id === recordFilter.fieldMetadataId,
|
||||
const sourceFieldMetadataItem = findFieldMetadataItemById(
|
||||
recordFilter.fieldMetadataId,
|
||||
);
|
||||
|
||||
if (!isDefined(sourceFieldMetadataItem)) {
|
||||
@@ -91,8 +93,8 @@ export const turnRecordFilterIntoRecordGqlOperationFilter = ({
|
||||
sourceFieldMetadataItem.type === FieldMetadataType.RELATION &&
|
||||
isDefined(recordFilter.relationTargetFieldMetadataId)
|
||||
) {
|
||||
const targetFieldMetadataItem = fieldMetadataItems.find(
|
||||
(field) => field.id === recordFilter.relationTargetFieldMetadataId,
|
||||
const targetFieldMetadataItem = findFieldMetadataItemById(
|
||||
recordFilter.relationTargetFieldMetadataId,
|
||||
);
|
||||
|
||||
if (!isDefined(targetFieldMetadataItem)) {
|
||||
|
||||
@@ -104,6 +104,7 @@ export type {
|
||||
RecordFilterGroup,
|
||||
} from './filter/turnRecordFilterGroupIntoGqlOperationFilter';
|
||||
export { turnRecordFilterGroupsIntoGqlOperationFilter } from './filter/turnRecordFilterGroupIntoGqlOperationFilter';
|
||||
export type { FindFieldMetadataItemById } from './filter/turnRecordFilterIntoGqlOperationFilter';
|
||||
export { turnRecordFilterIntoRecordGqlOperationFilter } from './filter/turnRecordFilterIntoGqlOperationFilter';
|
||||
export { combineFilters } from './filter/utils/combineFilters';
|
||||
export { convertViewFilterOperandToCoreOperand } from './filter/utils/convert-view-filter-operand-to-core-operand.util';
|
||||
|
||||
Reference in New Issue
Block a user