Improve multi word filtering (#5034)

improve multi word search

closes #4212 
closes #3386
This commit is contained in:
martmull
2024-04-18 15:46:59 +02:00
committed by GitHub
parent 88c14b7e52
commit 1c1a055c94
54 changed files with 212 additions and 146 deletions

View File

@ -24,7 +24,7 @@ import { isFieldDateTime } from '../types/guards/isFieldDateTime';
import { isFieldEmail } from '../types/guards/isFieldEmail';
import { isFieldFullName } from '../types/guards/isFieldFullName';
import { isFieldLink } from '../types/guards/isFieldLink';
import { isFieldMultiSelect } from '../types/guards/isFieldMultiSelect.ts';
import { isFieldMultiSelect } from '../types/guards/isFieldMultiSelect';
import { isFieldNumber } from '../types/guards/isFieldNumber';
import { isFieldPhone } from '../types/guards/isFieldPhone';
import { isFieldRawJson } from '../types/guards/isFieldRawJson';

View File

@ -9,7 +9,7 @@ import { SelectFieldInput } from '@/object-record/record-field/meta-types/input/
import { RecordFieldInputScope } from '@/object-record/record-field/scopes/RecordFieldInputScope';
import { isFieldDate } from '@/object-record/record-field/types/guards/isFieldDate';
import { isFieldFullName } from '@/object-record/record-field/types/guards/isFieldFullName';
import { isFieldMultiSelect } from '@/object-record/record-field/types/guards/isFieldMultiSelect.ts';
import { isFieldMultiSelect } from '@/object-record/record-field/types/guards/isFieldMultiSelect';
import { isFieldRawJson } from '@/object-record/record-field/types/guards/isFieldRawJson';
import { isFieldSelect } from '@/object-record/record-field/types/guards/isFieldSelect';
import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId';

View File

@ -7,8 +7,8 @@ import { isFieldDate } from '@/object-record/record-field/types/guards/isFieldDa
import { isFieldDateValue } from '@/object-record/record-field/types/guards/isFieldDateValue';
import { isFieldFullName } from '@/object-record/record-field/types/guards/isFieldFullName';
import { isFieldFullNameValue } from '@/object-record/record-field/types/guards/isFieldFullNameValue';
import { isFieldMultiSelect } from '@/object-record/record-field/types/guards/isFieldMultiSelect.ts';
import { isFieldMultiSelectValue } from '@/object-record/record-field/types/guards/isFieldMultiSelectValue.ts';
import { isFieldMultiSelect } from '@/object-record/record-field/types/guards/isFieldMultiSelect';
import { isFieldMultiSelectValue } from '@/object-record/record-field/types/guards/isFieldMultiSelectValue';
import { isFieldRawJson } from '@/object-record/record-field/types/guards/isFieldRawJson';
import { isFieldRawJsonValue } from '@/object-record/record-field/types/guards/isFieldRawJsonValue';
import { isFieldSelect } from '@/object-record/record-field/types/guards/isFieldSelect';

View File

@ -1,6 +1,6 @@
import styled from '@emotion/styled';
import { useMultiSelectField } from '@/object-record/record-field/meta-types/hooks/useMultiSelectField.ts';
import { useMultiSelectField } from '@/object-record/record-field/meta-types/hooks/useMultiSelectField';
import { Tag } from '@/ui/display/tag/components/Tag';
const StyledTagContainer = styled.div`

View File

@ -1,14 +1,14 @@
import { useContext } from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext.ts';
import { usePersistField } from '@/object-record/record-field/hooks/usePersistField.ts';
import { useRecordFieldInput } from '@/object-record/record-field/hooks/useRecordFieldInput.ts';
import { FieldMultiSelectValue } from '@/object-record/record-field/types/FieldMetadata.ts';
import { assertFieldMetadata } from '@/object-record/record-field/types/guards/assertFieldMetadata.ts';
import { isFieldMultiSelect } from '@/object-record/record-field/types/guards/isFieldMultiSelect.ts';
import { isFieldMultiSelectValue } from '@/object-record/record-field/types/guards/isFieldMultiSelectValue.ts';
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector.ts';
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
import { usePersistField } from '@/object-record/record-field/hooks/usePersistField';
import { useRecordFieldInput } from '@/object-record/record-field/hooks/useRecordFieldInput';
import { FieldMultiSelectValue } from '@/object-record/record-field/types/FieldMetadata';
import { assertFieldMetadata } from '@/object-record/record-field/types/guards/assertFieldMetadata';
import { isFieldMultiSelect } from '@/object-record/record-field/types/guards/isFieldMultiSelect';
import { isFieldMultiSelectValue } from '@/object-record/record-field/types/guards/isFieldMultiSelectValue';
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
import { FieldMetadataType } from '~/generated/graphql.tsx';
export const useMultiSelectField = () => {

View File

@ -1,7 +1,7 @@
import { useRef, useState } from 'react';
import styled from '@emotion/styled';
import { useMultiSelectField } from '@/object-record/record-field/meta-types/hooks/useMultiSelectField.ts';
import { useMultiSelectField } from '@/object-record/record-field/meta-types/hooks/useMultiSelectField';
import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';

View File

@ -1,4 +1,4 @@
import { FieldMetadataType } from '~/generated-metadata/graphql.ts';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { FieldDefinition } from '../FieldDefinition';
import { FieldAddressMetadata, FieldMetadata } from '../FieldMetadata';

View File

@ -1,4 +1,4 @@
import { FieldMetadataType } from '~/generated-metadata/graphql.ts';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { FieldDefinition } from '../FieldDefinition';
import { FieldBooleanMetadata, FieldMetadata } from '../FieldMetadata';

View File

@ -1,4 +1,4 @@
import { FieldMetadataType } from '~/generated-metadata/graphql.ts';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { FieldDefinition } from '../FieldDefinition';
import { FieldCurrencyMetadata, FieldMetadata } from '../FieldMetadata';

View File

@ -1,4 +1,4 @@
import { FieldMetadataType } from '~/generated-metadata/graphql.ts';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { FieldDefinition } from '../FieldDefinition';
import { FieldDateTimeMetadata, FieldMetadata } from '../FieldMetadata';

View File

@ -1,4 +1,4 @@
import { FieldMetadataType } from '~/generated-metadata/graphql.ts';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { FieldDefinition } from '../FieldDefinition';
import { FieldEmailMetadata, FieldMetadata } from '../FieldMetadata';

View File

@ -1,4 +1,4 @@
import { FieldMetadataType } from '~/generated-metadata/graphql.ts';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { FieldDefinition } from '../FieldDefinition';
import { FieldFullNameMetadata, FieldMetadata } from '../FieldMetadata';

View File

@ -1,4 +1,4 @@
import { FieldMetadataType } from '~/generated-metadata/graphql.ts';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { FieldDefinition } from '../FieldDefinition';
import { FieldLinkMetadata, FieldMetadata } from '../FieldMetadata';

View File

@ -1,9 +1,9 @@
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition.ts';
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
import {
FieldMetadata,
FieldMultiSelectMetadata,
} from '@/object-record/record-field/types/FieldMetadata.ts';
import { FieldMetadataType } from '~/generated-metadata/graphql.ts';
} from '@/object-record/record-field/types/FieldMetadata';
import { FieldMetadataType } from '~/generated-metadata/graphql';
export const isFieldMultiSelect = (
field: Pick<FieldDefinition<FieldMetadata>, 'type'>,

View File

@ -1,5 +1,5 @@
import { FieldMultiSelectValue } from '@/object-record/record-field/types/FieldMetadata.ts';
import { multiSelectFieldValueSchema } from '@/object-record/record-field/validation-schemas/multiSelectFieldValueSchema.ts';
import { FieldMultiSelectValue } from '@/object-record/record-field/types/FieldMetadata';
import { multiSelectFieldValueSchema } from '@/object-record/record-field/validation-schemas/multiSelectFieldValueSchema';
export const isFieldMultiSelectValue = (
fieldValue: unknown,

View File

@ -1,4 +1,4 @@
import { FieldMetadataType } from '~/generated-metadata/graphql.ts';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { FieldDefinition } from '../FieldDefinition';
import { FieldMetadata, FieldNumberMetadata } from '../FieldMetadata';

View File

@ -1,4 +1,4 @@
import { FieldMetadataType } from '~/generated-metadata/graphql.ts';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { FieldDefinition } from '../FieldDefinition';
import { FieldMetadata, FieldPhoneMetadata } from '../FieldMetadata';

View File

@ -1,4 +1,4 @@
import { FieldMetadataType } from '~/generated-metadata/graphql.ts';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { FieldDefinition } from '../FieldDefinition';
import { FieldMetadata, FieldRawJsonMetadata } from '../FieldMetadata';

View File

@ -1,4 +1,4 @@
import { FieldMetadataType } from '~/generated-metadata/graphql.ts';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { FieldDefinition } from '../FieldDefinition';
import { FieldMetadata, FieldRelationMetadata } from '../FieldMetadata';

View File

@ -1,4 +1,4 @@
import { FieldMetadataType } from '~/generated-metadata/graphql.ts';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { FieldDefinition } from '../FieldDefinition';
import { FieldMetadata, FieldTextMetadata } from '../FieldMetadata';

View File

@ -1,4 +1,4 @@
import { FieldMetadataType } from '~/generated-metadata/graphql.ts';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { FieldDefinition } from '../FieldDefinition';
import { FieldMetadata, FieldUuidMetadata } from '../FieldMetadata';

View File

@ -12,8 +12,8 @@ import { isFieldFullName } from '@/object-record/record-field/types/guards/isFie
import { isFieldFullNameValue } from '@/object-record/record-field/types/guards/isFieldFullNameValue';
import { isFieldLink } from '@/object-record/record-field/types/guards/isFieldLink';
import { isFieldLinkValue } from '@/object-record/record-field/types/guards/isFieldLinkValue';
import { isFieldMultiSelect } from '@/object-record/record-field/types/guards/isFieldMultiSelect.ts';
import { isFieldMultiSelectValue } from '@/object-record/record-field/types/guards/isFieldMultiSelectValue.ts';
import { isFieldMultiSelect } from '@/object-record/record-field/types/guards/isFieldMultiSelect';
import { isFieldMultiSelectValue } from '@/object-record/record-field/types/guards/isFieldMultiSelectValue';
import { isFieldNumber } from '@/object-record/record-field/types/guards/isFieldNumber';
import { isFieldRating } from '@/object-record/record-field/types/guards/isFieldRating';
import { isFieldRawJson } from '@/object-record/record-field/types/guards/isFieldRawJson';

View File

@ -5,7 +5,6 @@ import {
CurrencyFilter,
DateFilter,
FloatFilter,
FullNameFilter,
ObjectRecordQueryFilter,
StringFilter,
URLFilter,
@ -14,6 +13,7 @@ import {
import { makeAndFilterVariables } from '@/object-record/utils/makeAndFilterVariables';
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
import { Field } from '~/generated/graphql';
import { generateILikeFiltersForCompositeFields } from '~/utils/array/generateILikeFiltersForCompositeFields';
import { isDefined } from '~/utils/isDefined';
import { Filter } from '../../object-filter-dropdown/types/Filter';
@ -203,50 +203,25 @@ export const turnObjectDropdownFilterIntoQueryFilter = (
);
}
break;
case 'FULL_NAME':
case 'FULL_NAME': {
const fullNameFilters = generateILikeFiltersForCompositeFields(
rawUIFilter.value,
correspondingField.name,
['firstName', 'lastName'],
);
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,
},
],
or: fullNameFilters,
});
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,
},
},
],
and: fullNameFilters.map((filter) => {
return {
not: filter,
};
}),
});
break;
default:
@ -255,6 +230,7 @@ export const turnObjectDropdownFilterIntoQueryFilter = (
);
}
break;
}
case 'ADDRESS':
switch (rawUIFilter.operand) {
case ViewFilterOperand.Contains:

View File

@ -1,6 +1,6 @@
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState.ts';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';

View File

@ -9,7 +9,7 @@ import {
} from 'twenty-ui';
import { RECORD_INDEX_OPTIONS_DROPDOWN_ID } from '@/object-record/record-index/options/constants/RecordIndexOptionsDropdownId';
import { useExportTableData } from '@/object-record/record-index/options/hooks/useExportTableData.ts';
import { useExportTableData } from '@/object-record/record-index/options/hooks/useExportTableData';
import { useRecordIndexOptionsForBoard } from '@/object-record/record-index/options/hooks/useRecordIndexOptionsForBoard';
import { useRecordIndexOptionsForTable } from '@/object-record/record-index/options/hooks/useRecordIndexOptionsForTable';
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';

View File

@ -14,7 +14,7 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
import { RecordChip } from '@/object-record/components/RecordChip';
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord.ts';
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
import { useLazyFindOneRecord } from '@/object-record/hooks/useLazyFindOneRecord';
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
import {

View File

@ -5,6 +5,7 @@ import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/get
import { ObjectRecordQueryFilter } from '@/object-record/record-filter/types/ObjectRecordQueryFilter';
import { makeOrFilterVariables } from '@/object-record/utils/makeOrFilterVariables';
import { FieldMetadataType } from '~/generated/graphql';
import { generateILikeFiltersForCompositeFields } from '~/utils/array/generateILikeFiltersForCompositeFields';
import { isDefined } from '~/utils/isDefined';
export const useSearchFilterPerMetadataItem = ({
@ -29,25 +30,16 @@ export const useSearchFilterPerMetadataItem = ({
switch (labelIdentifierFieldMetadataItem.type) {
case FieldMetadataType.FullName: {
if (isNonEmptyString(searchFilterValue)) {
const fullNameFilter = makeOrFilterVariables([
{
[labelIdentifierFieldMetadataItem.name]: {
firstName: {
ilike: `%${searchFilterValue}%`,
},
},
},
{
[labelIdentifierFieldMetadataItem.name]: {
lastName: {
ilike: `%${searchFilterValue}%`,
},
},
},
]);
const compositeFilter = makeOrFilterVariables(
generateILikeFiltersForCompositeFields(
searchFilterValue,
labelIdentifierFieldMetadataItem.name,
['firstName', 'lastName'],
),
);
if (isDefined(fullNameFilter)) {
searchFilter = fullNameFilter;
if (isDefined(compositeFilter)) {
searchFilter = compositeFilter;
}
}
break;