Skip to content

Commit 2d8823c

Browse files
fix: preserve special characters in search queries (#3441)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Chris Bongers <rebelchris@users.noreply.github.com>
1 parent 40e8fc4 commit 2d8823c

3 files changed

Lines changed: 101 additions & 2 deletions

File tree

__tests__/bookmarks.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,6 +1069,46 @@ describe('query searchBookmarksSuggestions', () => {
10691069
const res = await client.query(QUERY('p1'));
10701070
expect(res.data).toMatchSnapshot();
10711071
});
1072+
1073+
it('should handle special characters in search (C++)', async () => {
1074+
loggedUser = '1';
1075+
await con.getRepository(ArticlePost).save({
1076+
id: 'cpp-post',
1077+
title: 'Learn C++ programming',
1078+
shortId: 'cpp',
1079+
url: 'http://cpp.com',
1080+
sourceId: 'a',
1081+
visible: true,
1082+
});
1083+
await con.getRepository(Bookmark).save({
1084+
userId: loggedUser,
1085+
postId: 'cpp-post',
1086+
createdAt: now,
1087+
});
1088+
const res = await client.query(QUERY('c++'));
1089+
expect(res.data.searchBookmarksSuggestions.query).toBe('c++');
1090+
expect(res.data.searchBookmarksSuggestions.hits.length).toBeGreaterThan(0);
1091+
});
1092+
1093+
it('should handle special characters in search (C#)', async () => {
1094+
loggedUser = '1';
1095+
await con.getRepository(ArticlePost).save({
1096+
id: 'csharp-post',
1097+
title: 'Learn C# programming',
1098+
shortId: 'csharp',
1099+
url: 'http://csharp.com',
1100+
sourceId: 'a',
1101+
visible: true,
1102+
});
1103+
await con.getRepository(Bookmark).save({
1104+
userId: loggedUser,
1105+
postId: 'csharp-post',
1106+
createdAt: now,
1107+
});
1108+
const res = await client.query(QUERY('c#'));
1109+
expect(res.data.searchBookmarksSuggestions.query).toBe('c#');
1110+
expect(res.data.searchBookmarksSuggestions.hits.length).toBeGreaterThan(0);
1111+
});
10721112
});
10731113

10741114
describe('query searchBookmarks', () => {

__tests__/users.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3440,6 +3440,50 @@ describe('query searchReadingHistorySuggestions', () => {
34403440
const res = await client.query(QUERY('p1'));
34413441
expect(res.data).toMatchSnapshot();
34423442
});
3443+
3444+
it('should handle special characters in search (C++)', async () => {
3445+
loggedUser = '1';
3446+
await con.getRepository(ArticlePost).save({
3447+
id: 'cpp-post',
3448+
title: 'Learn C++ programming',
3449+
shortId: 'cpp',
3450+
url: 'http://cpp.com',
3451+
sourceId: 'a',
3452+
visible: true,
3453+
});
3454+
await con.getRepository(View).save({
3455+
userId: loggedUser,
3456+
timestamp: now,
3457+
postId: 'cpp-post',
3458+
});
3459+
const res = await client.query(QUERY('c++'));
3460+
expect(res.data.searchReadingHistorySuggestions.query).toBe('c++');
3461+
expect(
3462+
res.data.searchReadingHistorySuggestions.hits.length,
3463+
).toBeGreaterThan(0);
3464+
});
3465+
3466+
it('should handle special characters in search (C#)', async () => {
3467+
loggedUser = '1';
3468+
await con.getRepository(ArticlePost).save({
3469+
id: 'csharp-post',
3470+
title: 'Learn C# programming',
3471+
shortId: 'csharp',
3472+
url: 'http://csharp.com',
3473+
sourceId: 'a',
3474+
visible: true,
3475+
});
3476+
await con.getRepository(View).save({
3477+
userId: loggedUser,
3478+
timestamp: now,
3479+
postId: 'csharp-post',
3480+
});
3481+
const res = await client.query(QUERY('c#'));
3482+
expect(res.data.searchReadingHistorySuggestions.query).toBe('c#');
3483+
expect(
3484+
res.data.searchReadingHistorySuggestions.hits.length,
3485+
).toBeGreaterThan(0);
3486+
});
34433487
});
34443488

34453489
describe('query search reading history', () => {

src/schema/common.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,23 @@ export interface PageGenerator<
190190
export const getSearchQuery = (param: string): string =>
191191
`SELECT to_tsquery('english', ${param}) AS query`;
192192

193-
export const processSearchQuery = (query: string): string =>
194-
query.trim().split(' ').join(' & ') + ':*';
193+
export const processSearchQuery = (query: string): string => {
194+
const trimmed = query.trim();
195+
196+
// Check if query contains special characters that should be preserved
197+
// Common programming language patterns: c#, c++, f#, .net, node.js, etc.
198+
const hasSpecialChars = /[#+.\-]/.test(trimmed);
199+
200+
if (hasSpecialChars) {
201+
// For queries with special characters, use phrase search to preserve them
202+
// Replace single quotes with double single quotes to escape them
203+
const escaped = trimmed.replace(/'/g, "''");
204+
return `'${escaped}':*`;
205+
}
206+
207+
// For regular queries, use the original AND logic with prefix matching
208+
return trimmed.split(' ').join(' & ') + ':*';
209+
};
195210

196211
export const mimirOffsetGenerator = <
197212
TReturn extends { id: string },

0 commit comments

Comments
 (0)