Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V1.19 rc #779

Merged
merged 8 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions hrm-domain/hrm-core/case/caseReindexService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,14 @@ export const reindexCasesStream = async (
});

this.push(
`${new Date().toISOString()},${accountSid},contad id: ${
`${new Date().toISOString()}, ${accountSid}, case id: ${
caseObj.id
} Success, MessageId ${MessageId}
\n`,
);
} catch (err) {
this.push(
`${new Date().toISOString()},${accountSid},contad id: ${caseObj.id} Error: ${
`${new Date().toISOString()}, ${accountSid}, case id: ${caseObj.id} Error: ${
err.message?.replace('"', '""') || String(err)
}\n`,
);
Expand Down
13 changes: 9 additions & 4 deletions hrm-domain/hrm-core/contact/canPerformContactAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,11 @@ export const canPerformViewContactAction = canPerformActionOnContact(
);

const canRemoveFromCase = async (
originalCaseId: string,
originalCaseId: number,
{ can, user, hrmAccountId, permissions },
): Promise<boolean> => {
if (originalCaseId) {
const originalCaseObj = await getCase(parseInt(originalCaseId), hrmAccountId, {
const originalCaseObj = await getCase(originalCaseId, hrmAccountId, {
can,
user,
permissions,
Expand All @@ -190,11 +190,16 @@ const canConnectContact = canPerformActionOnContact(
{ can, user, hrmAccountId, body: { caseId: targetCaseId }, permissions },
) => {
if (
!(await canRemoveFromCase(originalCaseId, { can, user, hrmAccountId, permissions }))
!(await canRemoveFromCase(originalCaseId, {
can,
user,
hrmAccountId,
permissions,
}))
) {
return false;
}
const targetCaseObj = await getCase(parseInt(targetCaseId), hrmAccountId, {
const targetCaseObj = await getCase(parseInt(targetCaseId, 10), hrmAccountId, {
can,
user,
permissions,
Expand Down
8 changes: 4 additions & 4 deletions hrm-domain/hrm-core/contact/contactsReindexService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,16 @@ export const reindexContactsStream = async (
});

this.push(
`${new Date().toISOString()},${accountSid},contad id: ${
`${new Date().toISOString()}, ${accountSid}, contact id: ${
contact.id
} Success, MessageId ${MessageId}
\n`,
);
} catch (err) {
this.push(
`${new Date().toISOString()},${accountSid},contad id: ${contact.id} Error: ${
err.message?.replace('"', '""') || String(err)
}\n`,
`${new Date().toISOString()}, ${accountSid}, contact id: ${
contact.id
} Error: ${err.message?.replace('"', '""') || String(err)}\n`,
);
}
callback();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ describe('canDisconnectContact', () => {
let contact = new ContactBuilder().withFinalizedAt(BASELINE_DATE).build();
beforeEach(() => {
mockGetContactById.mockResolvedValue(contact);
contact.caseId = '123';
contact.caseId = 123;
});
test('can returns true to permit & case id not set on contact - permits', async () => {
delete contact.caseId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ const generatePayloadFromContact = (
...(ps[HRM_CASES_INDEX_TYPE] ?? []),
{
...m,
documentId: parseInt(m.message.contact.caseId, 10),
documentId: m.message.contact.caseId,
payload: { ...m.message, transcript: m.transcript },
indexHandler: 'updateScript',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export const convertContactToContactDocument = ({

const contactDocument: ContactDocument = {
accountSid,
id,
id: id.toString(),
createdAt,
updatedAt,
createdBy,
Expand Down Expand Up @@ -115,7 +115,7 @@ const convertCaseToCaseDocument = ({

const caseDocument: CaseDocument = {
accountSid,
id,
id: id.toString(),
createdAt,
updatedAt,
createdBy,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const convertContactToCaseScriptUpdate = (
const contactDocument = convertContactToContactDocument(payload);

const documentUpdate: CreateIndexConvertedDocument<CaseDocument> = {
id: parseInt(caseId!, 10),
id: caseId!.toString(),
accountSid,
contacts: [contactDocument],
};
Expand Down Expand Up @@ -66,9 +66,9 @@ const convertContactToCaseScriptUpdate = (
case 'remove': {
const scriptUpdate: Script = {
source:
'def removeContact(int contactId, List contacts) { contacts.removeIf(contact -> contact.id == contactId); } removeContact(params.contactId, ctx._source.contacts);',
'def removeContact(String contactId, List contacts) { contacts.removeIf(contact -> contact.id == contactId); } removeContact(params.contactId, ctx._source.contacts);',
params: {
contactId: payload.contact.id,
contactId: payload.contact.id.toString(),
},
};

Expand Down
153 changes: 68 additions & 85 deletions hrm-domain/packages/hrm-search-config/generateElasticsearchQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ const BOOST_FACTORS = {
case: 3,
};
const MIN_SCORE = 0.1;
const MAX_INT = 2147483648 - 1; // 2^31 - 1, the max integer allowed by ElasticSearch integer type

export const FILTER_ALL_CLAUSE: QueryDslQueryContainer[][] = [
[
Expand Down Expand Up @@ -61,21 +60,36 @@ export type DocumentTypeQueryParams = {
[DocumentType.Case]: GenerateTDocQueryParams<DocumentType.Case>;
};

type GenerateTermQueryParams = {
type NestableQueryParams = {
parentPath?: string;
};

type GenerateTermQueryParams<TDoc extends DocumentType> = {
type: 'term';
term: string | boolean | number;
field: keyof DocumentTypeToDocument[TDoc];
boost?: number;
};
type GenerateRangeQueryParams = {
} & NestableQueryParams;
type GenerateRangeQueryParams<TDoc extends DocumentType> = {
type: 'range';
field: keyof DocumentTypeToDocument[TDoc];
ranges: { lt?: string; lte?: string; gt?: string; gte?: string };
};
type GenerateQueryStringQuery = { type: 'queryString'; query: string; boost?: number };
type GenerateSimpleQueryStringQuery = {
type: 'simpleQueryString';
} & NestableQueryParams;
type GenerateQueryStringQuery<TDoc extends DocumentType> = {
type: 'queryString';
query: string;
field: keyof DocumentTypeToDocument[TDoc];
boost?: number;
};
} & NestableQueryParams;
type SimpleQueryStringFields<TDoc extends DocumentType> = {
field: keyof DocumentTypeToDocument[TDoc];
boost?: number;
}[];
type GenerateSimpleQueryStringQuery<TDoc extends DocumentType> = {
type: 'simpleQueryString';
query: string;
fields: SimpleQueryStringFields<TDoc>;
} & NestableQueryParams;
type GenerateMustNotQueryParams<TDoc extends DocumentType> = {
type: 'mustNot';
innerQuery: DocumentTypeQueryParams[TDoc];
Expand All @@ -98,12 +112,12 @@ type GenerateNestedQueryParams<TDoc extends DocumentType> = {
}[keyof NestedDocumentsQueryParams[TDoc]];

type GenerateQueryParams<TDoc extends DocumentType> =
| ({ field: keyof DocumentTypeToDocument[TDoc]; parentPath?: string } & (
| GenerateTermQueryParams
| GenerateRangeQueryParams
| GenerateQueryStringQuery
| GenerateSimpleQueryStringQuery
))
| (
| GenerateTermQueryParams<TDoc>
| GenerateRangeQueryParams<TDoc>
| GenerateQueryStringQuery<TDoc>
| GenerateSimpleQueryStringQuery<TDoc>
)
| GenerateMustNotQueryParams<TDoc>
| GenerateNestedQueryParams<TDoc>;

Expand All @@ -113,6 +127,14 @@ const getFieldName = <T extends {}>(p: { field: keyof T; parentPath?: string })
return `${prefix}${String(p.field)}`;
};

const getSimpleQueryStringFields = <TDoc extends DocumentType>(
p: GenerateSimpleQueryStringQuery<TDoc>,
) => {
const prefix = p.parentPath ? `${p.parentPath}.` : '';

return p.fields.map(f => `${prefix}${String(f.field)}${f.boost ? `^${f.boost}` : ''}`);
};

/** Utility function that creates a filter based on a more human-readable representation */
export const generateESQuery = <TDoc extends DocumentType>(
p: DocumentTypeQueryParams[TDoc],
Expand Down Expand Up @@ -144,10 +166,9 @@ export const generateESQuery = <TDoc extends DocumentType>(
case 'simpleQueryString': {
return {
simple_query_string: {
fields: [getFieldName(p)],
fields: getSimpleQueryStringFields(p as GenerateSimpleQueryStringQuery<TDoc>), // typecast to conform TS, only valid parameters should be accept
query: p.query,
flags: 'FUZZY|NEAR|PHRASE|WHITESPACE',
...(p.boost && { boost: p.boost }),
},
};
}
Expand Down Expand Up @@ -193,73 +214,28 @@ type SearchParametersContact = {
};
} & SearchPagination;

const generateQueriesFromId = <TDoc extends DocumentType>({
searchTerm,
documentType,
parentPath,
boostFactor,
queryWrapper = p => p,
}: {
searchTerm: string;
boostFactor: number;
queryWrapper?: (
p: DocumentTypeQueryParams[DocumentType],
) => DocumentTypeQueryParams[DocumentType];
} & {
documentType: TDoc;
parentPath?: string;
}): QueryDslQueryContainer[] => {
const terms = searchTerm.split(' ');

if (terms.length > 1) {
return [];
}

const parsed = Number.parseInt(searchTerm, 10);
// Ignore terms that are not entirely a number or greater than max int, as that breaks term queries against integer fields
if (Number.isNaN(parsed) || !Number.isInteger(parsed) || parsed > MAX_INT) {
return [];
}

return [
generateESQuery(
queryWrapper({
documentType,
type: 'term',
term: parsed,
boost: boostFactor * BOOST_FACTORS.id,
field: 'id' as any, // typecast to conform TS, only valid parameters should be accept
parentPath,
}),
),
];
};

const generateQueryFromSearchTerms = <TDoc extends DocumentType>({
searchTerm,
documentType,
field,
fields,
parentPath,
boostFactor,
queryWrapper = p => p,
}: {
searchTerm: string;
boostFactor: number;
queryWrapper?: (
p: DocumentTypeQueryParams[DocumentType],
) => DocumentTypeQueryParams[DocumentType];
} & {
documentType: TDoc;
field: keyof DocumentTypeToDocument[TDoc];
fields: SimpleQueryStringFields<TDoc>;
parentPath?: string;
}): QueryDslQueryContainer => {
const query = generateESQuery(
queryWrapper({
documentType,
type: 'simpleQueryString',
query: searchTerm,
boost: boostFactor,
field: field as any, // typecast to conform TS, only valid parameters should be accept
fields: fields as any, // typecast to conform TS, only valid parameters should be accept
parentPath,
}),
);
Expand All @@ -282,10 +258,9 @@ const generateTranscriptQueriesFromFilters = ({
}): QueryDslQueryContainer[] => {
const query = generateQueryFromSearchTerms({
documentType: DocumentType.Contact,
field: 'transcript',
fields: [{ field: 'transcript', boost: BOOST_FACTORS.transcript }],
searchTerm: searchParameters.searchTerm,
parentPath: buildParams.parentPath,
boostFactor: BOOST_FACTORS.transcript,
queryWrapper,
});

Expand Down Expand Up @@ -331,17 +306,18 @@ const generateContactsQueriesFromFilters = ({
const queries = [
generateQueryFromSearchTerms({
documentType: DocumentType.Contact,
field: 'content',
searchTerm: searchParameters.searchTerm,
parentPath: buildParams.parentPath,
boostFactor: BOOST_FACTORS.contact,
queryWrapper,
}),
...generateQueriesFromId({
documentType: DocumentType.Contact,
fields: [
{
field: 'content',
boost: BOOST_FACTORS.contact,
},
{
field: 'id',
boost: BOOST_FACTORS.id * BOOST_FACTORS.contact,
},
],
searchTerm: searchParameters.searchTerm,
parentPath: buildParams.parentPath,
boostFactor: BOOST_FACTORS.contact,
queryWrapper,
}),
];
Expand Down Expand Up @@ -434,22 +410,29 @@ const generateCasesQueriesFromFilters = ({
const queries = [
generateQueryFromSearchTerms({
documentType: DocumentType.Case,
field: 'content',
searchTerm: searchParameters.searchTerm,
boostFactor: BOOST_FACTORS.case,
}),
...generateQueriesFromId({
documentType: DocumentType.Case,
fields: [
{
field: 'content',
boost: BOOST_FACTORS.case,
},
{
field: 'id',
boost: BOOST_FACTORS.id * BOOST_FACTORS.case,
},
],
searchTerm: searchParameters.searchTerm,
boostFactor: BOOST_FACTORS.case,
}),
];

const sectionsQuery = generateQueryFromSearchTerms({
documentType: DocumentType.CaseSection,
field: 'content',
fields: [
{
field: 'content',
boost: BOOST_FACTORS.case,
},
],
searchTerm: searchParameters.searchTerm,
boostFactor: BOOST_FACTORS.case,
queryWrapper: p => ({
documentType: DocumentType.Case,
type: 'nested',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const commonProperties = {
// Properties shared by both types of documents, cases and contacts
const rootProperties = {
id: {
type: 'integer',
type: 'keyword',
},
twilioWorkerId: {
type: 'keyword',
Expand Down
Loading
Loading