From b7e5828adc7bc6602da7992b073b005b30aa896f Mon Sep 17 00:00:00 2001 From: Elliot DeNolf Date: Tue, 6 Sep 2022 16:47:57 -0400 Subject: [PATCH] feat: cyrillic like query support (#1078) --- src/mongoose/sanitizeFormattedValue.ts | 2 +- src/utilities/wordBoundariesRegex.ts | 7 ++++++- test/collections-rest/int.spec.ts | 16 ++++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/mongoose/sanitizeFormattedValue.ts b/src/mongoose/sanitizeFormattedValue.ts index 2bd9ba5869..d538a472e2 100644 --- a/src/mongoose/sanitizeFormattedValue.ts +++ b/src/mongoose/sanitizeFormattedValue.ts @@ -97,7 +97,7 @@ export const sanitizeQueryValue = (schemaType: SchemaType, path: string, operato } if (operator === 'like' && typeof formattedValue === 'string') { - const $regex = wordBoundariesRegex(formattedValue) + const $regex = wordBoundariesRegex(formattedValue); formattedValue = { $regex }; } } diff --git a/src/utilities/wordBoundariesRegex.ts b/src/utilities/wordBoundariesRegex.ts index ff6d7cee5a..a5d8d38450 100644 --- a/src/utilities/wordBoundariesRegex.ts +++ b/src/utilities/wordBoundariesRegex.ts @@ -1,7 +1,12 @@ export default (input: string): RegExp => { const words = input.split(' '); + + // Regex word boundaries that work for cyrillic characters - https://stackoverflow.com/a/47062016/1717697 + const wordBoundaryBefore = '(?:(?<=[^\\p{L}\\p{N}])|^)'; + const wordBoundaryAfter = '(?=[^\\p{L}\\p{N}]|$)'; + const regex = words.reduce((pattern, word, i) => { - return `${pattern}(?=.*\\b${word}.*\\b)${i + 1 === words.length ? '.+' : ''}`; + return `${pattern}(?=.*${wordBoundaryBefore}${word}.*${wordBoundaryAfter})${i + 1 === words.length ? '.+' : ''}`; }, ''); return new RegExp(regex, 'i'); }; diff --git a/test/collections-rest/int.spec.ts b/test/collections-rest/int.spec.ts index 65a3f37568..32ae8493ec 100644 --- a/test/collections-rest/int.spec.ts +++ b/test/collections-rest/int.spec.ts @@ -373,6 +373,22 @@ describe('collections-rest', () => { expect(result.totalDocs).toEqual(1); }); + it('like - cyrillic characters', async () => { + const post1 = await createPost({ title: 'Тест' }); + + const { status, result } = await client.find({ + query: { + title: { + like: 'Тест', + }, + }, + }); + + expect(status).toEqual(200); + expect(result.docs).toEqual([post1]); + expect(result.totalDocs).toEqual(1); + }); + it('like - partial word match', async () => { const post = await createPost({ title: 'separate words should partially match' });