Skip to content

Commit a283cc1

Browse files
fix(search-service): fix global search issue
fix global search issue GH-2553
1 parent f5ecddf commit a283cc1

2 files changed

Lines changed: 51 additions & 6 deletions

File tree

services/search-service/src/__tests__/unit/psql/query.builder.unit.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,49 @@ import {buildTestsRunner} from '../runner';
66
import {PsqlQueryBuilder} from '../../../classes';
77
import {expect} from '@loopback/testlab';
88
import {testModelList, testModelListWithIdentifier} from '../..';
9+
import {AnyObject} from '@loopback/repository';
910

1011
describe('PostgreSQL QueryBuilder', () => {
1112
const queryPart =
1213
" from public.TestSearchedCustom where to_tsvector(public.f_concat_ws(' ', about, identifier)) @@ to_tsquery($1))";
14+
15+
describe('_formatAndSanitize', () => {
16+
it('should preserve dots in search terms', () => {
17+
const builder = new PsqlQueryBuilder({match: 'Deal 10.1'});
18+
const result = (builder as AnyObject)._formatAndSanitize('Deal 10.1');
19+
expect(result).to.equal('Deal:*<->10.1:*');
20+
});
21+
22+
it('should handle project names with dots', () => {
23+
const builder = new PsqlQueryBuilder({match: 'test'});
24+
const result = (builder as AnyObject)._formatAndSanitize('testlift.QA');
25+
expect(result).to.equal('testlift.QA:*');
26+
});
27+
28+
it('should handle multiple dots in different positions', () => {
29+
const builder = new PsqlQueryBuilder({match: 'test'});
30+
const result = (builder as AnyObject)._formatAndSanitize(
31+
'Project.Alpha.Beta',
32+
);
33+
expect(result).to.equal('Project.Alpha.Beta:*');
34+
});
35+
36+
it('should handle mix of dots and special characters', () => {
37+
const builder = new PsqlQueryBuilder({match: 'test'});
38+
const result = (builder as AnyObject)._formatAndSanitize(
39+
'Deal.10 & Test.1.5',
40+
);
41+
expect(result).to.equal('Deal.10:*<->Test.1.5:*');
42+
});
43+
44+
it('should handle complex search with dots and spaces', () => {
45+
const builder = new PsqlQueryBuilder({match: 'test'});
46+
const result = (builder as AnyObject)._formatAndSanitize(
47+
'Version 2.5 (Release)',
48+
);
49+
expect(result).to.equal('Version:*<->2.5:*<->Release:*');
50+
});
51+
});
1352
describe(
1453
'with match parameter',
1554
buildTestsRunner(

services/search-service/src/classes/psql/query.builder.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,17 @@ export class PsqlQueryBuilder<T extends Model> extends SearchQueryBuilder<T> {
7878
}
7979

8080
_formatAndSanitize(param: string) {
81-
return param
82-
.replace(/[^A-Za-z\s0-9]/g, ' ')
83-
.split(' ')
84-
.filter(p => p)
85-
.map(p => `${p}:*`)
86-
.join('<->');
81+
let result = param;
82+
while (result.endsWith('.')) {
83+
result = result.slice(0, -1);
84+
}
85+
86+
return result
87+
.replace(/[!&|<>():'"]/g, ' ') // Remove PostgreSQL tsquery special chars
88+
.replace(/[^A-Za-z0-9.\s]/g, ' ') // Keep dots, remove other symbols
89+
.split(/\s+/) // Split on any whitespace (not just spaces)
90+
.filter(p => p && p !== '.') // Filter empty and standalone dots
91+
.map(p => `${p}:*`) // Add prefix match operator
92+
.join('<->'); // Join with followed-by operator
8793
}
8894
}

0 commit comments

Comments
 (0)