Skip to content
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
40 changes: 40 additions & 0 deletions __tests__/bookmarks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1069,6 +1069,46 @@ describe('query searchBookmarksSuggestions', () => {
const res = await client.query(QUERY('p1'));
expect(res.data).toMatchSnapshot();
});

it('should handle special characters in search (C++)', async () => {
loggedUser = '1';
await con.getRepository(ArticlePost).save({
id: 'cpp-post',
title: 'Learn C++ programming',
shortId: 'cpp',
url: 'http://cpp.com',
sourceId: 'a',
visible: true,
});
await con.getRepository(Bookmark).save({
userId: loggedUser,
postId: 'cpp-post',
createdAt: now,
});
const res = await client.query(QUERY('c++'));
expect(res.data.searchBookmarksSuggestions.query).toBe('c++');
expect(res.data.searchBookmarksSuggestions.hits.length).toBeGreaterThan(0);
});

it('should handle special characters in search (C#)', async () => {
loggedUser = '1';
await con.getRepository(ArticlePost).save({
id: 'csharp-post',
title: 'Learn C# programming',
shortId: 'csharp',
url: 'http://csharp.com',
sourceId: 'a',
visible: true,
});
await con.getRepository(Bookmark).save({
userId: loggedUser,
postId: 'csharp-post',
createdAt: now,
});
const res = await client.query(QUERY('c#'));
expect(res.data.searchBookmarksSuggestions.query).toBe('c#');
expect(res.data.searchBookmarksSuggestions.hits.length).toBeGreaterThan(0);
});
});

describe('query searchBookmarks', () => {
Expand Down
44 changes: 44 additions & 0 deletions __tests__/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3440,6 +3440,50 @@ describe('query searchReadingHistorySuggestions', () => {
const res = await client.query(QUERY('p1'));
expect(res.data).toMatchSnapshot();
});

it('should handle special characters in search (C++)', async () => {
loggedUser = '1';
await con.getRepository(ArticlePost).save({
id: 'cpp-post',
title: 'Learn C++ programming',
shortId: 'cpp',
url: 'http://cpp.com',
sourceId: 'a',
visible: true,
});
await con.getRepository(View).save({
userId: loggedUser,
timestamp: now,
postId: 'cpp-post',
});
const res = await client.query(QUERY('c++'));
expect(res.data.searchReadingHistorySuggestions.query).toBe('c++');
expect(
res.data.searchReadingHistorySuggestions.hits.length,
).toBeGreaterThan(0);
});

it('should handle special characters in search (C#)', async () => {
loggedUser = '1';
await con.getRepository(ArticlePost).save({
id: 'csharp-post',
title: 'Learn C# programming',
shortId: 'csharp',
url: 'http://csharp.com',
sourceId: 'a',
visible: true,
});
await con.getRepository(View).save({
userId: loggedUser,
timestamp: now,
postId: 'csharp-post',
});
const res = await client.query(QUERY('c#'));
expect(res.data.searchReadingHistorySuggestions.query).toBe('c#');
expect(
res.data.searchReadingHistorySuggestions.hits.length,
).toBeGreaterThan(0);
});
});

describe('query search reading history', () => {
Expand Down
19 changes: 17 additions & 2 deletions src/schema/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,23 @@ export interface PageGenerator<
export const getSearchQuery = (param: string): string =>
`SELECT to_tsquery('english', ${param}) AS query`;

export const processSearchQuery = (query: string): string =>
query.trim().split(' ').join(' & ') + ':*';
export const processSearchQuery = (query: string): string => {
const trimmed = query.trim();

// Check if query contains special characters that should be preserved
// Common programming language patterns: c#, c++, f#, .net, node.js, etc.
const hasSpecialChars = /[#+.\-]/.test(trimmed);

if (hasSpecialChars) {
// For queries with special characters, use phrase search to preserve them
// Replace single quotes with double single quotes to escape them
const escaped = trimmed.replace(/'/g, "''");
return `'${escaped}':*`;
}

// For regular queries, use the original AND logic with prefix matching
return trimmed.split(' ').join(' & ') + ':*';
};

export const mimirOffsetGenerator = <
TReturn extends { id: string },
Expand Down
Loading