twenty / packages /twenty-server /src /engine /workspace-manager /utils /get-ts-vector-column-expression.util.ts
Jules
Initial clean CRM deployment with prebuilt assets
d9494a5
Raw
History Blame Contribute Delete
4.88 kB
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}), '')`;
}
};