mirror of
https://github.com/twentyhq/twenty.git
synced 2024-10-04 21:07:21 +03:00
Feat/complete filter order by types (#2943)
* Fixed orderBy bug * Fixed gitch select multiple record filter * Fixed RelationPicker search * Fixed OrderBy type * WIP * Finished RequestFilter typing * Finished RequestFilter type * Fixed missing import * Changed naming
This commit is contained in:
parent
8381869c7f
commit
2a4ab2ffd3
@ -1,4 +1,5 @@
|
||||
import { Note } from '@/activities/types/Note';
|
||||
import { OrderByField } from '@/object-metadata/types/OrderByField';
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
|
||||
import { ActivityTargetableEntity } from '../../types/ActivityTargetableEntity';
|
||||
@ -19,7 +20,7 @@ export const useNotes = (entity: ActivityTargetableEntity) => {
|
||||
};
|
||||
const orderBy = {
|
||||
createdAt: 'AscNullsFirst',
|
||||
} as any; // TODO: finish typing
|
||||
} as OrderByField;
|
||||
|
||||
const { records: notes } = useFindManyRecords({
|
||||
skip: !activityTargets?.length,
|
||||
|
@ -25,6 +25,7 @@ import {
|
||||
PaginatedRecordTypeResults,
|
||||
} from '../types/PaginatedRecordTypeResults';
|
||||
import { mapPaginatedRecordsToRecords } from '../utils/mapPaginatedRecordsToRecords';
|
||||
import { ObjectRecordFilter } from '@/object-record/types/ObjectRecordFilter';
|
||||
|
||||
export const useFindManyRecords = <
|
||||
RecordType extends { id: string } & Record<string, any>,
|
||||
@ -36,7 +37,7 @@ export const useFindManyRecords = <
|
||||
onCompleted,
|
||||
skip,
|
||||
}: ObjectMetadataItemIdentifier & {
|
||||
filter?: any;
|
||||
filter?: ObjectRecordFilter;
|
||||
orderBy?: OrderByField;
|
||||
limit?: number;
|
||||
onCompleted?: (data: PaginatedRecordTypeResults<RecordType>) => void;
|
||||
|
@ -1,104 +0,0 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { Company } from '@/companies/types/Company';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { turnFiltersIntoWhereClause } from '@/object-record/object-filter-dropdown/utils/turnFiltersIntoWhereClause';
|
||||
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
||||
import { useRecordBoardScopedStates } from '@/object-record/record-board/hooks/internal/useRecordBoardScopedStates';
|
||||
import { PaginatedRecordTypeResults } from '@/object-record/types/PaginatedRecordTypeResults';
|
||||
import { Opportunity } from '@/pipeline/types/Opportunity';
|
||||
import { PipelineStep } from '@/pipeline/types/PipelineStep';
|
||||
|
||||
import { useFindManyRecords } from './useFindManyRecords';
|
||||
|
||||
export const useObjectRecordBoard = () => {
|
||||
const objectNameSingular = 'opportunity';
|
||||
|
||||
const { objectMetadataItem: foundObjectMetadataItem } = useObjectMetadataItem(
|
||||
{
|
||||
objectNameSingular,
|
||||
},
|
||||
);
|
||||
|
||||
const {
|
||||
isBoardLoadedState,
|
||||
boardFiltersState,
|
||||
boardSortsState,
|
||||
savedCompaniesState,
|
||||
savedOpportunitiesState,
|
||||
savedPipelineStepsState,
|
||||
} = useRecordBoardScopedStates();
|
||||
|
||||
const setIsBoardLoaded = useSetRecoilState(isBoardLoadedState);
|
||||
|
||||
const boardFilters = useRecoilValue(boardFiltersState);
|
||||
const boardSorts = useRecoilValue(boardSortsState);
|
||||
|
||||
const setSavedCompanies = useSetRecoilState(savedCompaniesState);
|
||||
|
||||
const [savedOpportunities] = useRecoilState(savedOpportunitiesState);
|
||||
|
||||
const [savedPipelineSteps, setSavedPipelineSteps] = useRecoilState(
|
||||
savedPipelineStepsState,
|
||||
);
|
||||
|
||||
const filter = turnFiltersIntoWhereClause(
|
||||
boardFilters,
|
||||
foundObjectMetadataItem?.fields ?? [],
|
||||
);
|
||||
const orderBy = turnSortsIntoOrderBy(
|
||||
boardSorts,
|
||||
foundObjectMetadataItem?.fields ?? [],
|
||||
);
|
||||
|
||||
useFindManyRecords({
|
||||
objectNameSingular: 'pipelineStep',
|
||||
filter: {},
|
||||
onCompleted: useCallback(
|
||||
(data: PaginatedRecordTypeResults<PipelineStep>) => {
|
||||
setSavedPipelineSteps(data.edges.map((edge) => edge.node));
|
||||
},
|
||||
[setSavedPipelineSteps],
|
||||
),
|
||||
});
|
||||
|
||||
const {
|
||||
records: opportunities,
|
||||
loading,
|
||||
fetchMoreRecords: fetchMoreOpportunities,
|
||||
} = useFindManyRecords<Opportunity>({
|
||||
skip: !savedPipelineSteps.length,
|
||||
objectNameSingular: 'opportunity',
|
||||
filter: filter,
|
||||
orderBy: orderBy as any, // TODO: finish typing
|
||||
onCompleted: useCallback(() => {
|
||||
setIsBoardLoaded(true);
|
||||
}, [setIsBoardLoaded]),
|
||||
});
|
||||
|
||||
const { fetchMoreRecords: fetchMoreCompanies } = useFindManyRecords({
|
||||
skip: !savedOpportunities.length,
|
||||
objectNameSingular: 'company',
|
||||
filter: {
|
||||
id: {
|
||||
in: savedOpportunities.map(
|
||||
(opportunity) => opportunity.companyId || '',
|
||||
),
|
||||
},
|
||||
},
|
||||
onCompleted: useCallback(
|
||||
(data: PaginatedRecordTypeResults<Company>) => {
|
||||
setSavedCompanies(data.edges.map((edge) => edge.node));
|
||||
},
|
||||
[setSavedCompanies],
|
||||
),
|
||||
});
|
||||
|
||||
return {
|
||||
opportunities,
|
||||
loading,
|
||||
fetchMoreOpportunities,
|
||||
fetchMoreCompanies,
|
||||
};
|
||||
};
|
@ -3,7 +3,7 @@ import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { Company } from '@/companies/types/Company';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { turnFiltersIntoWhereClause } from '@/object-record/object-filter-dropdown/utils/turnFiltersIntoWhereClause';
|
||||
import { turnFiltersIntoObjectRecordFilters } from '@/object-record/utils/turnFiltersIntoWhereClause';
|
||||
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
||||
import { useRecordBoardScopedStates } from '@/object-record/record-board/hooks/internal/useRecordBoardScopedStates';
|
||||
import { PaginatedRecordTypeResults } from '@/object-record/types/PaginatedRecordTypeResults';
|
||||
@ -43,7 +43,7 @@ export const useObjectRecordBoard = () => {
|
||||
savedPipelineStepsState,
|
||||
);
|
||||
|
||||
const filter = turnFiltersIntoWhereClause(
|
||||
const filter = turnFiltersIntoObjectRecordFilters(
|
||||
boardFilters,
|
||||
foundObjectMetadataItem?.fields ?? [],
|
||||
);
|
||||
@ -70,8 +70,8 @@ export const useObjectRecordBoard = () => {
|
||||
} = useFindManyRecords<Opportunity>({
|
||||
skip: !savedPipelineSteps.length,
|
||||
objectNameSingular: 'opportunity',
|
||||
filter: filter,
|
||||
orderBy: orderBy as any, // TODO: finish typing
|
||||
filter,
|
||||
orderBy,
|
||||
onCompleted: useCallback(() => {
|
||||
setIsBoardLoaded(true);
|
||||
}, [setIsBoardLoaded]),
|
||||
|
@ -3,7 +3,7 @@ import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
||||
import { turnFiltersIntoWhereClause } from '@/object-record/object-filter-dropdown/utils/turnFiltersIntoWhereClause';
|
||||
import { turnFiltersIntoObjectRecordFilters } from '@/object-record/utils/turnFiltersIntoWhereClause';
|
||||
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
||||
import { useRecordTableScopedStates } from '@/object-record/record-table/hooks/internal/useRecordTableScopedStates';
|
||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||
@ -31,21 +31,20 @@ export const useObjectRecordTable = () => {
|
||||
const tableSorts = useRecoilValue(tableSortsState);
|
||||
const setLastRowVisible = useSetRecoilState(tableLastRowVisibleState);
|
||||
|
||||
const filter = turnFiltersIntoWhereClause(
|
||||
const requestFilters = turnFiltersIntoObjectRecordFilters(
|
||||
tableFilters,
|
||||
foundObjectMetadataItem?.fields ?? [],
|
||||
);
|
||||
|
||||
// TODO: finish typing
|
||||
const orderBy = turnSortsIntoOrderBy(
|
||||
tableSorts,
|
||||
foundObjectMetadataItem?.fields ?? [],
|
||||
) as any;
|
||||
);
|
||||
|
||||
const { records, loading, fetchMoreRecords, queryStateIdentifier } =
|
||||
useFindManyRecords({
|
||||
objectNameSingular,
|
||||
filter,
|
||||
filter: requestFilters,
|
||||
orderBy,
|
||||
onCompleted: () => {
|
||||
setLastRowVisible(false);
|
||||
|
@ -1,237 +0,0 @@
|
||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||
import { Field } from '~/generated/graphql';
|
||||
|
||||
import { Filter } from '../types/Filter';
|
||||
|
||||
type FilterToTurnIntoWhereClause = Omit<Filter, 'definition'> & {
|
||||
definition: {
|
||||
type: Filter['definition']['type'];
|
||||
};
|
||||
};
|
||||
|
||||
export const turnFiltersIntoWhereClause = (
|
||||
filters: FilterToTurnIntoWhereClause[],
|
||||
fields: Pick<Field, 'id' | 'name'>[],
|
||||
) => {
|
||||
const whereClause: any[] = [];
|
||||
|
||||
filters.forEach((filter) => {
|
||||
const correspondingField = fields.find(
|
||||
(field) => field.id === filter.fieldMetadataId,
|
||||
);
|
||||
if (!correspondingField) {
|
||||
throw new Error(
|
||||
`Could not find field ${filter.fieldMetadataId} in metadata object`,
|
||||
);
|
||||
}
|
||||
|
||||
switch (filter.definition.type) {
|
||||
case 'EMAIL':
|
||||
case 'PHONE':
|
||||
case 'TEXT':
|
||||
switch (filter.operand) {
|
||||
case ViewFilterOperand.Contains:
|
||||
whereClause.push({
|
||||
[correspondingField.name]: {
|
||||
ilike: `%${filter.value}%`,
|
||||
},
|
||||
});
|
||||
return;
|
||||
case ViewFilterOperand.DoesNotContain:
|
||||
whereClause.push({
|
||||
not: {
|
||||
[correspondingField.name]: {
|
||||
ilike: `%${filter.value}%`,
|
||||
},
|
||||
},
|
||||
});
|
||||
return;
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
||||
);
|
||||
}
|
||||
case 'DATE_TIME':
|
||||
switch (filter.operand) {
|
||||
case ViewFilterOperand.GreaterThan:
|
||||
whereClause.push({
|
||||
[correspondingField.name]: {
|
||||
gte: filter.value,
|
||||
},
|
||||
});
|
||||
return;
|
||||
case ViewFilterOperand.LessThan:
|
||||
whereClause.push({
|
||||
[correspondingField.name]: {
|
||||
lte: filter.value,
|
||||
},
|
||||
});
|
||||
return;
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
||||
);
|
||||
}
|
||||
case 'NUMBER':
|
||||
switch (filter.operand) {
|
||||
case ViewFilterOperand.GreaterThan:
|
||||
whereClause.push({
|
||||
[correspondingField.name]: {
|
||||
gte: parseFloat(filter.value),
|
||||
},
|
||||
});
|
||||
return;
|
||||
case ViewFilterOperand.LessThan:
|
||||
whereClause.push({
|
||||
[correspondingField.name]: {
|
||||
lte: parseFloat(filter.value),
|
||||
},
|
||||
});
|
||||
return;
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
||||
);
|
||||
}
|
||||
case 'RELATION':
|
||||
try {
|
||||
JSON.parse(filter.value);
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`Cannot parse filter value for RELATION filter : "${filter.value}"`,
|
||||
);
|
||||
}
|
||||
|
||||
const parsedRecordIds = JSON.parse(filter.value) as string[];
|
||||
|
||||
if (parsedRecordIds.length > 0) {
|
||||
switch (filter.operand) {
|
||||
case ViewFilterOperand.Is:
|
||||
whereClause.push({
|
||||
[correspondingField.name + 'Id']: {
|
||||
in: parsedRecordIds,
|
||||
},
|
||||
});
|
||||
return;
|
||||
case ViewFilterOperand.IsNot:
|
||||
whereClause.push({
|
||||
not: {
|
||||
[correspondingField.name + 'Id']: {
|
||||
in: parsedRecordIds,
|
||||
},
|
||||
},
|
||||
});
|
||||
return;
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'CURRENCY':
|
||||
switch (filter.operand) {
|
||||
case ViewFilterOperand.GreaterThan:
|
||||
whereClause.push({
|
||||
[correspondingField.name]: {
|
||||
amountMicros: { gte: parseFloat(filter.value) * 1000000 },
|
||||
},
|
||||
});
|
||||
return;
|
||||
case ViewFilterOperand.LessThan:
|
||||
whereClause.push({
|
||||
[correspondingField.name]: {
|
||||
amountMicros: { lte: parseFloat(filter.value) * 1000000 },
|
||||
},
|
||||
});
|
||||
return;
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
||||
);
|
||||
}
|
||||
case 'LINK':
|
||||
switch (filter.operand) {
|
||||
case ViewFilterOperand.Contains:
|
||||
whereClause.push({
|
||||
[correspondingField.name]: {
|
||||
url: {
|
||||
ilike: `%${filter.value}%`,
|
||||
},
|
||||
},
|
||||
});
|
||||
return;
|
||||
case ViewFilterOperand.DoesNotContain:
|
||||
whereClause.push({
|
||||
not: {
|
||||
[correspondingField.name]: {
|
||||
url: {
|
||||
ilike: `%${filter.value}%`,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
return;
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
||||
);
|
||||
}
|
||||
case 'FULL_NAME':
|
||||
switch (filter.operand) {
|
||||
case ViewFilterOperand.Contains:
|
||||
whereClause.push({
|
||||
or: [
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
firstName: {
|
||||
ilike: `%${filter.value}%`,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
firstName: {
|
||||
ilike: `%${filter.value}%`,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
return;
|
||||
case ViewFilterOperand.DoesNotContain:
|
||||
whereClause.push({
|
||||
and: [
|
||||
{
|
||||
not: {
|
||||
[correspondingField.name]: {
|
||||
firstName: {
|
||||
ilike: `%${filter.value}%`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
not: {
|
||||
[correspondingField.name]: {
|
||||
lastName: {
|
||||
ilike: `%${filter.value}%`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
return;
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
||||
);
|
||||
}
|
||||
default:
|
||||
throw new Error('Unknown filter type');
|
||||
}
|
||||
});
|
||||
|
||||
return { and: whereClause };
|
||||
};
|
@ -1,3 +1,4 @@
|
||||
import { OrderByField } from '@/object-metadata/types/OrderByField';
|
||||
import { Field } from '~/generated/graphql';
|
||||
|
||||
import { Sort } from '../types/Sort';
|
||||
@ -5,8 +6,9 @@ import { Sort } from '../types/Sort';
|
||||
export const turnSortsIntoOrderBy = (
|
||||
sorts: Sort[],
|
||||
fields: Pick<Field, 'id' | 'name'>[],
|
||||
) => {
|
||||
): OrderByField => {
|
||||
const sortsObject: Record<string, 'AscNullsFirst' | 'DescNullsLast'> = {};
|
||||
|
||||
if (!sorts.length) {
|
||||
const createdAtField = fields.find((field) => field.name === 'createdAt');
|
||||
if (createdAtField) {
|
||||
@ -23,6 +25,7 @@ export const turnSortsIntoOrderBy = (
|
||||
[fields[0].name]: 'DescNullsFirst',
|
||||
};
|
||||
}
|
||||
|
||||
sorts.forEach((sort) => {
|
||||
const correspondingField = fields.find(
|
||||
(field) => field.id === sort.fieldMetadataId,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
|
||||
import { useObjectRecordBoard } from '@/object-record/hooks/useObjectRecordBoard.1';
|
||||
import { useObjectRecordBoard } from '@/object-record/hooks/useObjectRecordBoard';
|
||||
import { useRecordBoardActionBarEntriesInternal } from '@/object-record/record-board/hooks/internal/useRecordBoardActionBarEntriesInternal';
|
||||
import { useRecordBoardContextMenuEntriesInternal } from '@/object-record/record-board/hooks/internal/useRecordBoardContextMenuEntriesInternal';
|
||||
import { useRecordBoardScopedStates } from '@/object-record/record-board/hooks/internal/useRecordBoardScopedStates';
|
||||
|
@ -0,0 +1,72 @@
|
||||
export type UUIDFilterValue = string;
|
||||
|
||||
export type IsFilter = 'NULL' | 'NOT_NULL';
|
||||
|
||||
export type UUIDFilter = {
|
||||
eq?: UUIDFilterValue;
|
||||
in?: UUIDFilterValue[];
|
||||
neq?: UUIDFilterValue;
|
||||
is?: IsFilter;
|
||||
};
|
||||
|
||||
export type StringFilter = {
|
||||
eq?: string;
|
||||
gt?: string;
|
||||
gte?: string;
|
||||
in?: string[];
|
||||
lt?: string;
|
||||
lte?: string;
|
||||
neq?: string;
|
||||
startsWith?: string;
|
||||
like?: string;
|
||||
ilike?: string;
|
||||
regex?: string;
|
||||
iregex?: string;
|
||||
is?: IsFilter;
|
||||
};
|
||||
|
||||
export type FloatFilter = {
|
||||
eq?: number;
|
||||
gt?: number;
|
||||
gte?: number;
|
||||
in?: number[];
|
||||
lt?: number;
|
||||
lte?: number;
|
||||
neq?: number;
|
||||
is?: IsFilter;
|
||||
};
|
||||
|
||||
|
||||
export type DateFilter = {
|
||||
eq?: string;
|
||||
gt?: string;
|
||||
gte?: string;
|
||||
in?: string[];
|
||||
lt?: string;
|
||||
lte?: string;
|
||||
neq?: string;
|
||||
is?: IsFilter;
|
||||
};
|
||||
|
||||
export type CurrencyFilter = {
|
||||
amountMicros?: FloatFilter;
|
||||
};
|
||||
|
||||
export type URLFilter = {
|
||||
url?: StringFilter;
|
||||
};
|
||||
|
||||
export type FullNameFilter = {
|
||||
firstName?: StringFilter;
|
||||
lastName?: StringFilter;
|
||||
};
|
||||
|
||||
export type LeafFilter = UUIDFilter | StringFilter | FloatFilter | DateFilter | CurrencyFilter | URLFilter | FullNameFilter
|
||||
|
||||
export type ObjectRecordFilter = {
|
||||
and?: ObjectRecordFilter[];
|
||||
or?: ObjectRecordFilter[];
|
||||
not?: ObjectRecordFilter;
|
||||
} | {
|
||||
[fieldName: string]: LeafFilter
|
||||
}
|
@ -0,0 +1,245 @@
|
||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||
import { Field } from '~/generated/graphql';
|
||||
|
||||
import { Filter } from '../object-filter-dropdown/types/Filter';
|
||||
import { CurrencyFilter, DateFilter, FloatFilter, FullNameFilter, ObjectRecordFilter, StringFilter, URLFilter } from '@/object-record/types/ObjectRecordFilter';
|
||||
|
||||
export type RawUIFilter = Omit<Filter, 'definition'> & {
|
||||
definition: {
|
||||
type: Filter['definition']['type'];
|
||||
};
|
||||
};
|
||||
|
||||
export const turnFiltersIntoObjectRecordFilters = (
|
||||
rawUIFilters: RawUIFilter[],
|
||||
fields: Pick<Field, 'id' | 'name'>[],
|
||||
): ObjectRecordFilter => {
|
||||
const objectRecordFilters: ObjectRecordFilter[] = [];
|
||||
|
||||
for(const rawUIFilter of rawUIFilters) {
|
||||
const correspondingField = fields.find(
|
||||
(field) => field.id === rawUIFilter.fieldMetadataId,
|
||||
);
|
||||
|
||||
if (!correspondingField) {
|
||||
throw new Error(
|
||||
`Could not find field ${rawUIFilter.fieldMetadataId} in metadata object`,
|
||||
);
|
||||
}
|
||||
|
||||
switch (rawUIFilter.definition.type) {
|
||||
case 'EMAIL':
|
||||
case 'PHONE':
|
||||
case 'TEXT':
|
||||
switch (rawUIFilter.operand) {
|
||||
case ViewFilterOperand.Contains:
|
||||
objectRecordFilters.push({
|
||||
[correspondingField.name]: {
|
||||
ilike: `%${rawUIFilter.value}%`,
|
||||
} as StringFilter,
|
||||
});
|
||||
break
|
||||
case ViewFilterOperand.DoesNotContain:
|
||||
objectRecordFilters.push({
|
||||
not: {
|
||||
[correspondingField.name]: {
|
||||
ilike: `%${rawUIFilter.value}%`,
|
||||
} as StringFilter,
|
||||
},
|
||||
});
|
||||
break
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${rawUIFilter.operand} for ${rawUIFilter.definition.type} filter`,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'DATE_TIME':
|
||||
switch (rawUIFilter.operand) {
|
||||
case ViewFilterOperand.GreaterThan:
|
||||
objectRecordFilters.push({
|
||||
[correspondingField.name]: {
|
||||
gte: rawUIFilter.value,
|
||||
} as DateFilter,
|
||||
});
|
||||
break;
|
||||
case ViewFilterOperand.LessThan:
|
||||
objectRecordFilters.push({
|
||||
[correspondingField.name]: {
|
||||
lte: rawUIFilter.value,
|
||||
} as DateFilter,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${rawUIFilter.operand} for ${rawUIFilter.definition.type} filter`,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'NUMBER':
|
||||
switch (rawUIFilter.operand) {
|
||||
case ViewFilterOperand.GreaterThan:
|
||||
objectRecordFilters.push({
|
||||
[correspondingField.name]: {
|
||||
gte: parseFloat(rawUIFilter.value),
|
||||
} as FloatFilter,
|
||||
});
|
||||
break;
|
||||
case ViewFilterOperand.LessThan:
|
||||
objectRecordFilters.push({
|
||||
[correspondingField.name]: {
|
||||
lte: parseFloat(rawUIFilter.value),
|
||||
} as FloatFilter,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${rawUIFilter.operand} for ${rawUIFilter.definition.type} filter`,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'RELATION':
|
||||
try {
|
||||
JSON.parse(rawUIFilter.value);
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`Cannot parse filter value for RELATION filter : "${rawUIFilter.value}"`,
|
||||
);
|
||||
}
|
||||
|
||||
const parsedRecordIds = JSON.parse(rawUIFilter.value) as string[];
|
||||
|
||||
if (parsedRecordIds.length > 0) {
|
||||
switch (rawUIFilter.operand) {
|
||||
case ViewFilterOperand.Is:
|
||||
objectRecordFilters.push({
|
||||
[correspondingField.name + 'Id']: {
|
||||
in: parsedRecordIds,
|
||||
} as StringFilter,
|
||||
});
|
||||
break;
|
||||
case ViewFilterOperand.IsNot:
|
||||
objectRecordFilters.push({
|
||||
not: {
|
||||
[correspondingField.name + 'Id']: {
|
||||
in: parsedRecordIds,
|
||||
} as StringFilter,
|
||||
},
|
||||
});
|
||||
break;
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${rawUIFilter.operand} for ${rawUIFilter.definition.type} filter`,
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'CURRENCY':
|
||||
switch (rawUIFilter.operand) {
|
||||
case ViewFilterOperand.GreaterThan:
|
||||
objectRecordFilters.push({
|
||||
[correspondingField.name]: {
|
||||
amountMicros: { gte: parseFloat(rawUIFilter.value) * 1000000 },
|
||||
} as CurrencyFilter,
|
||||
});
|
||||
break;
|
||||
case ViewFilterOperand.LessThan:
|
||||
objectRecordFilters.push({
|
||||
[correspondingField.name]: {
|
||||
amountMicros: { lte: parseFloat(rawUIFilter.value) * 1000000 },
|
||||
} as CurrencyFilter,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${rawUIFilter.operand} for ${rawUIFilter.definition.type} filter`,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'LINK':
|
||||
switch (rawUIFilter.operand) {
|
||||
case ViewFilterOperand.Contains:
|
||||
objectRecordFilters.push({
|
||||
[correspondingField.name]: {
|
||||
url: {
|
||||
ilike: `%${rawUIFilter.value}%`,
|
||||
},
|
||||
} as URLFilter,
|
||||
});
|
||||
break;
|
||||
case ViewFilterOperand.DoesNotContain:
|
||||
objectRecordFilters.push({
|
||||
not: {
|
||||
[correspondingField.name]: {
|
||||
url: {
|
||||
ilike: `%${rawUIFilter.value}%`,
|
||||
},
|
||||
} as URLFilter,
|
||||
},
|
||||
});
|
||||
break;
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${rawUIFilter.operand} for ${rawUIFilter.definition.type} filter`,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'FULL_NAME':
|
||||
switch (rawUIFilter.operand) {
|
||||
case ViewFilterOperand.Contains:
|
||||
objectRecordFilters.push({
|
||||
or: [
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
firstName: {
|
||||
ilike: `%${rawUIFilter.value}%`,
|
||||
},
|
||||
} as FullNameFilter,
|
||||
},
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
lastName: {
|
||||
ilike: `%${rawUIFilter.value}%`,
|
||||
},
|
||||
} as FullNameFilter,
|
||||
},
|
||||
],
|
||||
});
|
||||
break;
|
||||
case ViewFilterOperand.DoesNotContain:
|
||||
objectRecordFilters.push({
|
||||
and: [
|
||||
{
|
||||
not: {
|
||||
[correspondingField.name]: {
|
||||
firstName: {
|
||||
ilike: `%${rawUIFilter.value}%`,
|
||||
},
|
||||
} as FullNameFilter,
|
||||
},
|
||||
},
|
||||
{
|
||||
not: {
|
||||
[correspondingField.name]: {
|
||||
lastName: {
|
||||
ilike: `%${rawUIFilter.value}%`,
|
||||
},
|
||||
} as FullNameFilter,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
break;
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${rawUIFilter.operand} for ${rawUIFilter.definition.type} filter`,
|
||||
);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error('Unknown filter type');
|
||||
}
|
||||
}
|
||||
|
||||
return { and: objectRecordFilters };
|
||||
};
|
Loading…
Reference in New Issue
Block a user