Spaces:
Build error
Build error
twenty / packages /twenty-server /src /engine /workspace-manager /utils /get-ts-vector-column-expression.util.ts
| import { | |
| FieldMetadataType, | |
| compositeTypeDefinitions, | |
| } from 'twenty-shared/types'; | |
| import type { SearchableFieldType } from 'twenty-shared/utils'; | |
| import { | |
| computeColumnName, | |
| computeCompositeColumnName, | |
| } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util'; | |
| import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util'; | |
| import { isSearchableSubfield } from 'src/engine/workspace-manager/utils/is-searchable-subfield.util'; | |
| import { escapeIdentifier } from 'src/engine/workspace-manager/workspace-migration/utils/remove-sql-injection.util'; | |
| export type FieldTypeAndNameMetadata = { | |
| name: string; | |
| type: SearchableFieldType; | |
| }; | |
| export const getTsVectorColumnExpressionFromFields = ( | |
| fieldsUsedForSearch: FieldTypeAndNameMetadata[], | |
| ): string => { | |
| const columnExpressions = fieldsUsedForSearch.flatMap( | |
| getColumnExpressionsFromField, | |
| ); | |
| const concatenatedExpression = | |
| columnExpressions.length > 0 | |
| ? columnExpressions.join(" || ' ' || ") | |
| : 'NULL'; | |
| return `to_tsvector('simple', ${concatenatedExpression})`; | |
| }; | |
| const getColumnExpressionsFromField = ( | |
| fieldMetadataTypeAndName: FieldTypeAndNameMetadata, | |
| ): string[] => { | |
| if (isCompositeFieldMetadataType(fieldMetadataTypeAndName.type)) { | |
| const compositeType = compositeTypeDefinitions.get( | |
| fieldMetadataTypeAndName.type, | |
| ); | |
| if (!compositeType) { | |
| throw new Error( | |
| `Composite type not found for field metadata type: ${fieldMetadataTypeAndName.type}`, | |
| ); | |
| } | |
| const baseExpressions = compositeType.properties | |
| .filter((property) => | |
| isSearchableSubfield(compositeType.type, property.type, property.name), | |
| ) | |
| .map((property) => { | |
| const columnName = computeCompositeColumnName( | |
| fieldMetadataTypeAndName, | |
| property, | |
| ); | |
| return getColumnExpression(columnName, fieldMetadataTypeAndName.type); | |
| }); | |
| if (fieldMetadataTypeAndName.type === FieldMetadataType.PHONES) { | |
| const phoneNumberColumn = escapeIdentifier( | |
| `${fieldMetadataTypeAndName.name}PrimaryPhoneNumber`, | |
| ); | |
| const callingCodeColumn = escapeIdentifier( | |
| `${fieldMetadataTypeAndName.name}PrimaryPhoneCallingCode`, | |
| ); | |
| const additionalPhonesColumn = escapeIdentifier( | |
| `${fieldMetadataTypeAndName.name}AdditionalPhones`, | |
| ); | |
| const internationalFormats = [ | |
| `COALESCE(${callingCodeColumn} || ${phoneNumberColumn}, '')`, | |
| `COALESCE(REPLACE(${callingCodeColumn}, '+', '') || ${phoneNumberColumn}, '')`, | |
| `COALESCE('0' || ${phoneNumberColumn}, '')`, | |
| ]; | |
| const additionalPhonesExpression = `COALESCE(TRANSLATE(regexp_replace(${additionalPhonesColumn}::text, '"(number|countryCode|callingCode)"\\s*:\\s*', '', 'g'), '[]{}",:', ' '), '')`; | |
| return [ | |
| ...baseExpressions, | |
| ...internationalFormats, | |
| additionalPhonesExpression, | |
| ]; | |
| } | |
| if (fieldMetadataTypeAndName.type === FieldMetadataType.LINKS) { | |
| const secondaryLinksColumn = escapeIdentifier( | |
| `${fieldMetadataTypeAndName.name}SecondaryLinks`, | |
| ); | |
| const secondaryLinksExpression = `COALESCE(public.unaccent_immutable(TRANSLATE(regexp_replace(${secondaryLinksColumn}::text, '"(label|url)"\\s*:\\s*', '', 'g'), '[]{}",:', ' ')), '')`; | |
| return [...baseExpressions, secondaryLinksExpression]; | |
| } | |
| if (fieldMetadataTypeAndName.type === FieldMetadataType.EMAILS) { | |
| const additionalEmailsColumn = escapeIdentifier( | |
| `${fieldMetadataTypeAndName.name}AdditionalEmails`, | |
| ); | |
| const additionalEmailsExpression = `COALESCE(public.unaccent_immutable(TRANSLATE(${additionalEmailsColumn}::text, '[]",', ' ')), '') || ' ' || COALESCE(public.unaccent_immutable(TRANSLATE(REPLACE(${additionalEmailsColumn}::text, '@', ' '), '[]",', ' ')), '')`; | |
| return [...baseExpressions, additionalEmailsExpression]; | |
| } | |
| return baseExpressions; | |
| } | |
| const columnName = computeColumnName(fieldMetadataTypeAndName.name); | |
| return [getColumnExpression(columnName, fieldMetadataTypeAndName.type)]; | |
| }; | |
| const getColumnExpression = ( | |
| columnName: string, | |
| fieldType: FieldMetadataType, | |
| ): string => { | |
| const quotedColumnName = escapeIdentifier(columnName); | |
| switch (fieldType) { | |
| case FieldMetadataType.EMAILS: | |
| return ` | |
| COALESCE(public.unaccent_immutable(${quotedColumnName}), '') || ' ' || | |
| COALESCE(public.unaccent_immutable(SPLIT_PART(${quotedColumnName}, '@', 2)), '')`; | |
| case FieldMetadataType.PHONES: | |
| return `COALESCE(${quotedColumnName}, '')`; | |
| case FieldMetadataType.UUID: | |
| return `COALESCE(${quotedColumnName}::text, '')`; | |
| default: | |
| return `COALESCE(public.unaccent_immutable(${quotedColumnName}), '')`; | |
| } | |
| }; | |