From 4be152e73c1787c6449a3139e5d4051d4692b4d0 Mon Sep 17 00:00:00 2001 From: Chi Kai Lam Date: Wed, 24 Sep 2025 12:29:30 +0100 Subject: [PATCH 01/15] #1463: Fix Proposal Table View Query Err --- apps/backend/src/datasources/stfc/StfcProposalDataSource.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/backend/src/datasources/stfc/StfcProposalDataSource.ts b/apps/backend/src/datasources/stfc/StfcProposalDataSource.ts index 9e1e62c369..3ddd67b31f 100644 --- a/apps/backend/src/datasources/stfc/StfcProposalDataSource.ts +++ b/apps/backend/src/datasources/stfc/StfcProposalDataSource.ts @@ -120,6 +120,7 @@ export default class StfcProposalDataSource extends PostgresProposalDataSource { .orderBy('proposal_pk', 'desc') .modify((query) => { if (filter?.text) { + const jsonPath = `$[*].name ? (@.type() == "string" && @ like_regex "${filter.text}" flag "i")`; query.where(function () { this.where('title', 'ilike', `%${filter.text}%`) .orWhere('proposal_id', 'ilike', `%${filter.text}%`) @@ -129,10 +130,7 @@ export default class StfcProposalDataSource extends PostgresProposalDataSource { .orWhere('users.lastname', 'ilike', `%${filter.text}%`) .orWhere('principal_investigator', 'in', stfcUserIds) // NOTE: Using jsonpath we check the jsonb (instruments) field if it contains object with name equal to searchText case insensitive - .orWhereRaw( - 'jsonb_path_exists(instruments, \'$[*].name \\? (@.type() == "string" && @ like_regex :searchText: flag "i")\')', - { searchText: filter.text } - ); + .orWhereRaw('jsonb_path_exists(instruments, ?)', [jsonPath]); }); } if (filter?.reviewer === ReviewerFilter.ME) { From a7706b8441ba07f02e9bd3cdc3bfc02ab5946649 Mon Sep 17 00:00:00 2001 From: Chi Kai Lam Date: Wed, 8 Oct 2025 11:46:42 +0100 Subject: [PATCH 02/15] Add generic special character escaping for json column. --- apps/backend/src/customTypes/index.d.ts | 10 +++++++ .../postgres/databaseExtensions.ts | 26 +++++++++++++++++++ .../stfc/StfcProposalDataSource.ts | 4 +-- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/apps/backend/src/customTypes/index.d.ts b/apps/backend/src/customTypes/index.d.ts index 66322d7c4d..d4ded24e82 100644 --- a/apps/backend/src/customTypes/index.d.ts +++ b/apps/backend/src/customTypes/index.d.ts @@ -34,6 +34,16 @@ declare module 'knex' { query: string, userInput: string ): QueryBuilder; + + whereJsonbPathLike( + column: string, + userInput: string + ) : QueryBuilder; + + orWhereJsonbPathLike( + column: string, + userInput: string + ) : QueryBuilder; } } } diff --git a/apps/backend/src/datasources/postgres/databaseExtensions.ts b/apps/backend/src/datasources/postgres/databaseExtensions.ts index b4c3d8990c..ad0d00f8c2 100644 --- a/apps/backend/src/datasources/postgres/databaseExtensions.ts +++ b/apps/backend/src/datasources/postgres/databaseExtensions.ts @@ -3,6 +3,14 @@ import Knex from 'knex'; const escapeLike = (s: string) => s.replace(/\\/g, '\\\\').replace(/[%_]/g, '\\$&'); +function safeJsonPath(input: string): string { + return input + .replace(/[\\]/g, '\\\\') + .replace(/"/g, '\\"') + .replace(/\./g, ' ') + .trim(); +} + const addExtensions = () => { // Add the custom methods Knex.QueryBuilder.extend( @@ -23,6 +31,24 @@ const addExtensions = () => { return this.orWhereILike(column, finalQuery); } ); + Knex.QueryBuilder.extend( + 'whereJsonbPathLike', + function (column: string, userInput: string) { + const escapedInput = safeJsonPath(userInput); + const jsonPath = `$[*].name ? (@ like_regex "${escapedInput}" flag "i")`; + + return this.orWhereRaw('jsonb_path_exists(??, ?)', [column, jsonPath]); + } + ); + Knex.QueryBuilder.extend( + 'orWhereJsonbPathLike', + function (column: string, userInput: string) { + const escapedInput = safeJsonPath(userInput); + const jsonPath = `$[*].name ? (@ like_regex "${escapedInput}" flag "i")`; + + return this.orWhereRaw('jsonb_path_exists(??, ?)', [column, jsonPath]); + } + ); }; export default addExtensions; diff --git a/apps/backend/src/datasources/stfc/StfcProposalDataSource.ts b/apps/backend/src/datasources/stfc/StfcProposalDataSource.ts index cc3afc7366..993c09e3bf 100644 --- a/apps/backend/src/datasources/stfc/StfcProposalDataSource.ts +++ b/apps/backend/src/datasources/stfc/StfcProposalDataSource.ts @@ -121,7 +121,6 @@ export default class StfcProposalDataSource extends PostgresProposalDataSource { .orderBy('proposal_pk', 'desc') .modify((query) => { if (filter?.text) { - const jsonPath = `$[*].name ? (@.type() == "string" && @ like_regex "${filter.text}" flag "i")`; query.where(function () { this.where('title', 'ilike', `%${filter.text}%`) .orWhere('proposal_id', 'ilike', `%${filter.text}%`) @@ -130,8 +129,7 @@ export default class StfcProposalDataSource extends PostgresProposalDataSource { .orWhere('users.firstname', 'ilike', `%${filter.text}%`) .orWhere('users.lastname', 'ilike', `%${filter.text}%`) .orWhere('principal_investigator', 'in', stfcUserIds) - // NOTE: Using jsonpath we check the jsonb (instruments) field if it contains object with name equal to searchText case insensitive - .orWhereRaw('jsonb_path_exists(instruments, ?)', [jsonPath]); + .orWhereJsonbPathLike('instruments', `%${filter.text}%`); }); } if (filter?.reviewer === ReviewerFilter.ME) { From c8d003584056951b7e46aa1891af2cb77797f801 Mon Sep 17 00:00:00 2001 From: Chi Kai Lam <114708346+bashanlam@users.noreply.github.com> Date: Wed, 8 Oct 2025 14:47:40 +0100 Subject: [PATCH 03/15] Update apps/backend/src/datasources/postgres/databaseExtensions.ts Reviewed Co-authored-by: Yoganandan Pandiyan <132274772+yoganandaness@users.noreply.github.com> --- apps/backend/src/datasources/postgres/databaseExtensions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/backend/src/datasources/postgres/databaseExtensions.ts b/apps/backend/src/datasources/postgres/databaseExtensions.ts index ad0d00f8c2..02759e5306 100644 --- a/apps/backend/src/datasources/postgres/databaseExtensions.ts +++ b/apps/backend/src/datasources/postgres/databaseExtensions.ts @@ -37,7 +37,7 @@ const addExtensions = () => { const escapedInput = safeJsonPath(userInput); const jsonPath = `$[*].name ? (@ like_regex "${escapedInput}" flag "i")`; - return this.orWhereRaw('jsonb_path_exists(??, ?)', [column, jsonPath]); + return this.whereRaw('jsonb_path_exists(??, ?)', [column, jsonPath]); } ); Knex.QueryBuilder.extend( From a33df8532886f88c2051adf0973e8a2627684a2e Mon Sep 17 00:00:00 2001 From: Chi Kai Lam Date: Fri, 10 Oct 2025 15:36:38 +0100 Subject: [PATCH 04/15] Update PostgresProposalDataSource to use whereJsonbPathLike or orWhereJsonbPathLike function. --- .../postgres/ProposalDataSource.ts | 19 ++----------------- .../postgres/databaseExtensions.ts | 6 +----- 2 files changed, 3 insertions(+), 22 deletions(-) diff --git a/apps/backend/src/datasources/postgres/ProposalDataSource.ts b/apps/backend/src/datasources/postgres/ProposalDataSource.ts index 42af7bc8d3..399e4d12e3 100644 --- a/apps/backend/src/datasources/postgres/ProposalDataSource.ts +++ b/apps/backend/src/datasources/postgres/ProposalDataSource.ts @@ -377,11 +377,6 @@ export default class PostgresProposalDataSource implements ProposalDataSource { return query; } - safeEscapeRegexExpression(expression: string): string { - const escaped = expression.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - - return escaped; - } async getProposalsFromView( filter?: ProposalsFilter, first?: number, @@ -442,10 +437,6 @@ export default class PostgresProposalDataSource implements ProposalDataSource { searchText !== null && searchText !== undefined ) { - const regexLiteral = this.safeEscapeRegexExpression(searchText); - // NOTE: Using jsonpath we check the jsonb (instruments) field if it contains object with name equal to searchText case insensitive - const jsonPathPattern = `$[*] ? (@.name.type() == "string" && @.name like_regex "${regexLiteral}" flag "i")`; - query.andWhere((qb) => qb .orWhereRaw('proposal_id ILIKE ?', [`%${searchText}%`]) @@ -455,9 +446,7 @@ export default class PostgresProposalDataSource implements ProposalDataSource { .orWhere('users.firstname', 'ilike', `%${searchText}%`) .orWhere('users.lastname', 'ilike', `%${searchText}%`) .orWhere('principal_investigator', 'in', principalInvestigator) - .orWhereRaw('jsonb_path_exists(instruments, ?)', [ - jsonPathPattern, - ]) + .orWhereJsonbPathLike('instruments', `%${searchText}%`) ); } @@ -634,11 +623,7 @@ export default class PostgresProposalDataSource implements ProposalDataSource { .orWhereRaw('users.email ILIKE ?', `%${filter.text}%`) .orWhereRaw('users.firstname ILIKE ?', `%${filter.text}%`) .orWhereRaw('users.lastname ILIKE ?', `%${filter.text}%`) - // NOTE: Using jsonpath we check the jsonb (instruments) field if it contains object with name equal to searchText case insensitive - .orWhereRaw( - 'jsonb_path_exists(instruments, \'$[*].name \\? (@.type() == "string" && @ like_regex :searchText: flag "i")\')', - { searchText: filter.text } - ) + .orWhereJsonbPathLike('instruments', `%${filter.text}%`) ); } if (filter?.callId) { diff --git a/apps/backend/src/datasources/postgres/databaseExtensions.ts b/apps/backend/src/datasources/postgres/databaseExtensions.ts index 02759e5306..e886dc4e07 100644 --- a/apps/backend/src/datasources/postgres/databaseExtensions.ts +++ b/apps/backend/src/datasources/postgres/databaseExtensions.ts @@ -4,11 +4,7 @@ const escapeLike = (s: string) => s.replace(/\\/g, '\\\\').replace(/[%_]/g, '\\$&'); function safeJsonPath(input: string): string { - return input - .replace(/[\\]/g, '\\\\') - .replace(/"/g, '\\"') - .replace(/\./g, ' ') - .trim(); + return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').trim(); } const addExtensions = () => { From 4bb8deb0a73ad25dcef396fa2e8c9b41c73c9153 Mon Sep 17 00:00:00 2001 From: Chi Kai Lam <114708346+bashanlam@users.noreply.github.com> Date: Mon, 13 Oct 2025 09:44:45 +0100 Subject: [PATCH 05/15] Update apps/backend/src/datasources/postgres/databaseExtensions.ts Co-authored-by: Simon Fernandes --- apps/backend/src/datasources/postgres/databaseExtensions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/backend/src/datasources/postgres/databaseExtensions.ts b/apps/backend/src/datasources/postgres/databaseExtensions.ts index e886dc4e07..3095efad8b 100644 --- a/apps/backend/src/datasources/postgres/databaseExtensions.ts +++ b/apps/backend/src/datasources/postgres/databaseExtensions.ts @@ -4,7 +4,7 @@ const escapeLike = (s: string) => s.replace(/\\/g, '\\\\').replace(/[%_]/g, '\\$&'); function safeJsonPath(input: string): string { - return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').trim(); + return input.replace(/[.*+?^${}()|[\]\\"]/g, '\\$&').trim(); } const addExtensions = () => { From cb2db836095e6390f9a7bc482f08e21f2bec315d Mon Sep 17 00:00:00 2001 From: Chi Kai Lam <114708346+bashanlam@users.noreply.github.com> Date: Tue, 14 Oct 2025 13:32:34 +0100 Subject: [PATCH 06/15] Search field as input parameter Co-authored-by: Yoganandan Pandiyan <132274772+yoganandaness@users.noreply.github.com> --- apps/backend/src/datasources/postgres/databaseExtensions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/backend/src/datasources/postgres/databaseExtensions.ts b/apps/backend/src/datasources/postgres/databaseExtensions.ts index 3095efad8b..eca1fdaf7f 100644 --- a/apps/backend/src/datasources/postgres/databaseExtensions.ts +++ b/apps/backend/src/datasources/postgres/databaseExtensions.ts @@ -28,7 +28,7 @@ const addExtensions = () => { } ); Knex.QueryBuilder.extend( - 'whereJsonbPathLike', + 'whereJsonFieldLikeEscaped', function (column: string, userInput: string) { const escapedInput = safeJsonPath(userInput); const jsonPath = `$[*].name ? (@ like_regex "${escapedInput}" flag "i")`; From 37e86b87effeeb84a9fdc663f46dee7c7611590b Mon Sep 17 00:00:00 2001 From: Chi Kai Lam <114708346+bashanlam@users.noreply.github.com> Date: Tue, 14 Oct 2025 13:32:45 +0100 Subject: [PATCH 07/15] Search field as input parameter Co-authored-by: Yoganandan Pandiyan <132274772+yoganandaness@users.noreply.github.com> --- apps/backend/src/datasources/postgres/databaseExtensions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/backend/src/datasources/postgres/databaseExtensions.ts b/apps/backend/src/datasources/postgres/databaseExtensions.ts index eca1fdaf7f..b4be6e7e7b 100644 --- a/apps/backend/src/datasources/postgres/databaseExtensions.ts +++ b/apps/backend/src/datasources/postgres/databaseExtensions.ts @@ -37,7 +37,7 @@ const addExtensions = () => { } ); Knex.QueryBuilder.extend( - 'orWhereJsonbPathLike', + 'orWhereJsonFieldLikeEscaped', function (column: string, userInput: string) { const escapedInput = safeJsonPath(userInput); const jsonPath = `$[*].name ? (@ like_regex "${escapedInput}" flag "i")`; From 215a397985c215351e6f1f59d8bb80a98608b10e Mon Sep 17 00:00:00 2001 From: Chi Kai Lam <114708346+bashanlam@users.noreply.github.com> Date: Tue, 14 Oct 2025 13:33:00 +0100 Subject: [PATCH 08/15] Search field as input parameter Co-authored-by: Yoganandan Pandiyan <132274772+yoganandaness@users.noreply.github.com> --- apps/backend/src/datasources/postgres/databaseExtensions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/backend/src/datasources/postgres/databaseExtensions.ts b/apps/backend/src/datasources/postgres/databaseExtensions.ts index b4be6e7e7b..3f0ee48277 100644 --- a/apps/backend/src/datasources/postgres/databaseExtensions.ts +++ b/apps/backend/src/datasources/postgres/databaseExtensions.ts @@ -29,7 +29,7 @@ const addExtensions = () => { ); Knex.QueryBuilder.extend( 'whereJsonFieldLikeEscaped', - function (column: string, userInput: string) { + function (column: string, field: string, userInput: string) { const escapedInput = safeJsonPath(userInput); const jsonPath = `$[*].name ? (@ like_regex "${escapedInput}" flag "i")`; From 1f201499e00fa90f1a1532e4bce0c2948ef5c65a Mon Sep 17 00:00:00 2001 From: Chi Kai Lam <114708346+bashanlam@users.noreply.github.com> Date: Tue, 14 Oct 2025 13:33:16 +0100 Subject: [PATCH 09/15] Search field as input parameter Co-authored-by: Yoganandan Pandiyan <132274772+yoganandaness@users.noreply.github.com> --- apps/backend/src/datasources/postgres/databaseExtensions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/backend/src/datasources/postgres/databaseExtensions.ts b/apps/backend/src/datasources/postgres/databaseExtensions.ts index 3f0ee48277..995948a3a7 100644 --- a/apps/backend/src/datasources/postgres/databaseExtensions.ts +++ b/apps/backend/src/datasources/postgres/databaseExtensions.ts @@ -31,7 +31,7 @@ const addExtensions = () => { 'whereJsonFieldLikeEscaped', function (column: string, field: string, userInput: string) { const escapedInput = safeJsonPath(userInput); - const jsonPath = `$[*].name ? (@ like_regex "${escapedInput}" flag "i")`; + const jsonPath = `$[*].${field}? (@ like_regex "${escapedInput}" flag "i")`; return this.whereRaw('jsonb_path_exists(??, ?)', [column, jsonPath]); } From 14c4cb598f84840878479d05007e12a3698acbf4 Mon Sep 17 00:00:00 2001 From: Chi Kai Lam <114708346+bashanlam@users.noreply.github.com> Date: Tue, 14 Oct 2025 13:33:32 +0100 Subject: [PATCH 10/15] Search field as input parameter Co-authored-by: Yoganandan Pandiyan <132274772+yoganandaness@users.noreply.github.com> --- apps/backend/src/datasources/postgres/databaseExtensions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/backend/src/datasources/postgres/databaseExtensions.ts b/apps/backend/src/datasources/postgres/databaseExtensions.ts index 995948a3a7..ba071a71c3 100644 --- a/apps/backend/src/datasources/postgres/databaseExtensions.ts +++ b/apps/backend/src/datasources/postgres/databaseExtensions.ts @@ -38,7 +38,7 @@ const addExtensions = () => { ); Knex.QueryBuilder.extend( 'orWhereJsonFieldLikeEscaped', - function (column: string, userInput: string) { + function (column: string, field: string, userInput: string) { const escapedInput = safeJsonPath(userInput); const jsonPath = `$[*].name ? (@ like_regex "${escapedInput}" flag "i")`; From 15230b5e806e78901042b8fd69f30ed8a2198b57 Mon Sep 17 00:00:00 2001 From: Chi Kai Lam <114708346+bashanlam@users.noreply.github.com> Date: Tue, 14 Oct 2025 13:33:42 +0100 Subject: [PATCH 11/15] Search field as input parameter Co-authored-by: Yoganandan Pandiyan <132274772+yoganandaness@users.noreply.github.com> --- apps/backend/src/datasources/stfc/StfcProposalDataSource.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/backend/src/datasources/stfc/StfcProposalDataSource.ts b/apps/backend/src/datasources/stfc/StfcProposalDataSource.ts index 993c09e3bf..970345d999 100644 --- a/apps/backend/src/datasources/stfc/StfcProposalDataSource.ts +++ b/apps/backend/src/datasources/stfc/StfcProposalDataSource.ts @@ -129,7 +129,7 @@ export default class StfcProposalDataSource extends PostgresProposalDataSource { .orWhere('users.firstname', 'ilike', `%${filter.text}%`) .orWhere('users.lastname', 'ilike', `%${filter.text}%`) .orWhere('principal_investigator', 'in', stfcUserIds) - .orWhereJsonbPathLike('instruments', `%${filter.text}%`); + .orWhereJsonFieldLike('instruments', 'name', `%${filter.text}%`); }); } if (filter?.reviewer === ReviewerFilter.ME) { From e00b02dcc153d9bc40edcf5b6a8927042f1ba51b Mon Sep 17 00:00:00 2001 From: Chi Kai Lam <114708346+bashanlam@users.noreply.github.com> Date: Tue, 14 Oct 2025 13:33:55 +0100 Subject: [PATCH 12/15] Search field as input parameter Co-authored-by: Yoganandan Pandiyan <132274772+yoganandaness@users.noreply.github.com> --- apps/backend/src/datasources/postgres/databaseExtensions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/backend/src/datasources/postgres/databaseExtensions.ts b/apps/backend/src/datasources/postgres/databaseExtensions.ts index ba071a71c3..2957a1ebc9 100644 --- a/apps/backend/src/datasources/postgres/databaseExtensions.ts +++ b/apps/backend/src/datasources/postgres/databaseExtensions.ts @@ -40,7 +40,7 @@ const addExtensions = () => { 'orWhereJsonFieldLikeEscaped', function (column: string, field: string, userInput: string) { const escapedInput = safeJsonPath(userInput); - const jsonPath = `$[*].name ? (@ like_regex "${escapedInput}" flag "i")`; + const jsonPath = `$[*].${field}? (@ like_regex "${escapedInput}" flag "i")`; return this.orWhereRaw('jsonb_path_exists(??, ?)', [column, jsonPath]); } From 80de0a6592c18f8d723375a85d74075d47ee8075 Mon Sep 17 00:00:00 2001 From: Chi Kai Lam <114708346+bashanlam@users.noreply.github.com> Date: Tue, 14 Oct 2025 13:34:04 +0100 Subject: [PATCH 13/15] Search field as input parameter Co-authored-by: Yoganandan Pandiyan <132274772+yoganandaness@users.noreply.github.com> --- apps/backend/src/datasources/postgres/ProposalDataSource.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/backend/src/datasources/postgres/ProposalDataSource.ts b/apps/backend/src/datasources/postgres/ProposalDataSource.ts index 399e4d12e3..41934ee61b 100644 --- a/apps/backend/src/datasources/postgres/ProposalDataSource.ts +++ b/apps/backend/src/datasources/postgres/ProposalDataSource.ts @@ -623,7 +623,8 @@ export default class PostgresProposalDataSource implements ProposalDataSource { .orWhereRaw('users.email ILIKE ?', `%${filter.text}%`) .orWhereRaw('users.firstname ILIKE ?', `%${filter.text}%`) .orWhereRaw('users.lastname ILIKE ?', `%${filter.text}%`) - .orWhereJsonbPathLike('instruments', `%${filter.text}%`) + . orWhereJsonFieldLikeEscaped('instruments', 'name', `%${filter.text}%`) + ); } if (filter?.callId) { From 5cff8411b9b09001e9c0c85e90e6abc9f86a48b2 Mon Sep 17 00:00:00 2001 From: Chi Kai Lam Date: Tue, 14 Oct 2025 14:16:16 +0100 Subject: [PATCH 14/15] Fix local site error. --- apps/backend/src/customTypes/index.d.ts | 6 ++++-- .../src/datasources/postgres/ProposalDataSource.ts | 13 ++++++++++--- .../src/datasources/stfc/StfcProposalDataSource.ts | 6 +++++- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/apps/backend/src/customTypes/index.d.ts b/apps/backend/src/customTypes/index.d.ts index d4ded24e82..7b4a2ead3e 100644 --- a/apps/backend/src/customTypes/index.d.ts +++ b/apps/backend/src/customTypes/index.d.ts @@ -35,13 +35,15 @@ declare module 'knex' { userInput: string ): QueryBuilder; - whereJsonbPathLike( + whereJsonFieldLikeEscaped( column: string, + field: string, userInput: string ) : QueryBuilder; - orWhereJsonbPathLike( + orWhereJsonFieldLikeEscaped( column: string, + field: string, userInput: string ) : QueryBuilder; } diff --git a/apps/backend/src/datasources/postgres/ProposalDataSource.ts b/apps/backend/src/datasources/postgres/ProposalDataSource.ts index 41934ee61b..0154dca1a3 100644 --- a/apps/backend/src/datasources/postgres/ProposalDataSource.ts +++ b/apps/backend/src/datasources/postgres/ProposalDataSource.ts @@ -446,7 +446,11 @@ export default class PostgresProposalDataSource implements ProposalDataSource { .orWhere('users.firstname', 'ilike', `%${searchText}%`) .orWhere('users.lastname', 'ilike', `%${searchText}%`) .orWhere('principal_investigator', 'in', principalInvestigator) - .orWhereJsonbPathLike('instruments', `%${searchText}%`) + .orWhereJsonFieldLikeEscaped( + 'instruments', + 'name', + `%${searchText}%` + ) ); } @@ -623,8 +627,11 @@ export default class PostgresProposalDataSource implements ProposalDataSource { .orWhereRaw('users.email ILIKE ?', `%${filter.text}%`) .orWhereRaw('users.firstname ILIKE ?', `%${filter.text}%`) .orWhereRaw('users.lastname ILIKE ?', `%${filter.text}%`) - . orWhereJsonFieldLikeEscaped('instruments', 'name', `%${filter.text}%`) - + .orWhereJsonFieldLikeEscaped( + 'instruments', + 'name', + `%${filter.text}%` + ) ); } if (filter?.callId) { diff --git a/apps/backend/src/datasources/stfc/StfcProposalDataSource.ts b/apps/backend/src/datasources/stfc/StfcProposalDataSource.ts index 970345d999..2570be61c4 100644 --- a/apps/backend/src/datasources/stfc/StfcProposalDataSource.ts +++ b/apps/backend/src/datasources/stfc/StfcProposalDataSource.ts @@ -129,7 +129,11 @@ export default class StfcProposalDataSource extends PostgresProposalDataSource { .orWhere('users.firstname', 'ilike', `%${filter.text}%`) .orWhere('users.lastname', 'ilike', `%${filter.text}%`) .orWhere('principal_investigator', 'in', stfcUserIds) - .orWhereJsonFieldLike('instruments', 'name', `%${filter.text}%`); + .orWhereJsonFieldLikeEscaped( + 'instruments', + 'name', + `%${filter.text}%` + ); }); } if (filter?.reviewer === ReviewerFilter.ME) { From 957ff8c6bd59175ec212041b91e353dc130e6edf Mon Sep 17 00:00:00 2001 From: Chi Kai Lam Date: Tue, 14 Oct 2025 15:37:15 +0100 Subject: [PATCH 15/15] Remove unnecessary %. --- apps/backend/src/datasources/postgres/ProposalDataSource.ts | 4 ++-- apps/backend/src/datasources/stfc/StfcProposalDataSource.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/backend/src/datasources/postgres/ProposalDataSource.ts b/apps/backend/src/datasources/postgres/ProposalDataSource.ts index 0154dca1a3..e1609b21f0 100644 --- a/apps/backend/src/datasources/postgres/ProposalDataSource.ts +++ b/apps/backend/src/datasources/postgres/ProposalDataSource.ts @@ -449,7 +449,7 @@ export default class PostgresProposalDataSource implements ProposalDataSource { .orWhereJsonFieldLikeEscaped( 'instruments', 'name', - `%${searchText}%` + `${searchText}` ) ); } @@ -630,7 +630,7 @@ export default class PostgresProposalDataSource implements ProposalDataSource { .orWhereJsonFieldLikeEscaped( 'instruments', 'name', - `%${filter.text}%` + `${filter.text}` ) ); } diff --git a/apps/backend/src/datasources/stfc/StfcProposalDataSource.ts b/apps/backend/src/datasources/stfc/StfcProposalDataSource.ts index 2570be61c4..0303aa7b6e 100644 --- a/apps/backend/src/datasources/stfc/StfcProposalDataSource.ts +++ b/apps/backend/src/datasources/stfc/StfcProposalDataSource.ts @@ -132,7 +132,7 @@ export default class StfcProposalDataSource extends PostgresProposalDataSource { .orWhereJsonFieldLikeEscaped( 'instruments', 'name', - `%${filter.text}%` + `${filter.text}` ); }); }