Browse Source

Добавлена возможность задавать префикс "%" для поискового значения.
Данный префикс позволяет вести поиск по группе подстрок, разделенных пробелами

Book Pauk 8 months ago
parent
commit
57cd9be637

+ 4 - 0
CHANGELOG.md

@@ -1,3 +1,7 @@
+1.6.0 / 2024-??-??
+
+- Добавлена возможность задавать префикс "%" для поискового значения. Данный префикс позволяет вести поиск по группе подстрок, разделенных пробелами
+
 1.5.7 / 2024-04-04
 
 - В параметр bookReadLink конфига добавлен вариант замены DOWNLOAD_URI на uri из ссылки для скачивания книги (#29)

+ 17 - 4
client/components/Search/BaseList.js

@@ -387,21 +387,34 @@ export default class BaseList {
                 searchValue = searchValue.toLowerCase();
 
             //особая обработка префиксов
-            if (searchValue[0] == '=') {
+            if (searchValue[0] === '=') {
 
                 searchValue = searchValue.substring(1);
                 return bookValue.localeCompare(searchValue) == 0;
-            } else if (searchValue[0] == '*') {
+            } else if (searchValue[0] === '%') {
+
+                searchValue = searchValue.substring(1);
+
+                const words = searchValue.split(' ').filter(a => a);
+                if (!words.length)
+                    words.push('');
+
+                for (const w of words)
+                    if (bookValue !== emptyFieldValue && bookValue.indexOf(w) >= 0)
+                        return true;
+
+                return false;
+            } else if (searchValue[0] === '*') {
 
                 searchValue = searchValue.substring(1);
                 return bookValue !== emptyFieldValue && bookValue.indexOf(searchValue) >= 0;
-            } else if (searchValue[0] == '#') {
+            } else if (searchValue[0] === '#') {
 
                 searchValue = searchValue.substring(1);
                 if (!bookValue)
                     return false;
                 return bookValue !== emptyFieldValue && !enru.has(bookValue[0]) && bookValue.indexOf(searchValue) >= 0;
-            } else if (searchValue[0] == '~') {//RegExp
+            } else if (searchValue[0] === '~') {//RegExp
 
                 searchValue = searchValue.substring(1);
                 const re = new RegExp(searchValue, 'i');

+ 7 - 2
client/components/Search/Search.vue

@@ -846,8 +846,13 @@ class Search {
         </li>
         <br>
         <li>
-            "*" поиск подстроки в строке. Например, для "*Александр" в поле автора, будут найдены
-            все авторы, имя которых содержит "Александр"
+            "%" поиск по группе подстрок, разделенных пробелами. Например, для "%Александр Пушкин" в поле автора, будут найдены
+            все авторы, имя которых содержит и "Александр", и "Пушкин" одновременно
+        </li>
+        <br>
+        <li>
+            "*" поиск подстроки в строке вместе с пробелами. Например, для "*Александр Сергеевич" в поле автора, будут найдены
+            все авторы, имя которых содержит "Александр Сергеевич"
         </li>
         <br>
         <li>

+ 4 - 1
client/components/Search/SelectExtSearchDialog/SelectExtSearchDialog.vue

@@ -155,7 +155,10 @@ class SelectExtSearchDialog {
             префикс "=": поиск по точному совпадению
         </li>
         <li>
-            префикс "*": поиск подстроки в строке
+            префикс "%": поиск по группе подстрок, разделенных пробелами
+        </li>
+        <li>
+            префикс "*": поиск подстроки в строке (вместе с пробелами)
         </li>
         <li>
             префикс "#": поиск подстроки в строке, но только среди начинающихся не с латинского или кириллического символа

+ 31 - 9
server/core/DbSearcher.js

@@ -54,13 +54,24 @@ class DbSearcher {
         let where;
 
         //особая обработка префиксов
-        if (a[0] == '=') {
+        if (a[0] === '=') {
             a = a.substring(1);
             where = `@dirtyIndexLR('value', ${db.esc(a)}, ${db.esc(a)})`;
-        } else if (a[0] == '*') {
+        } else if (a[0] === '%') {
+            a = a.substring(1);
+            const ands = [];
+            const words = a.split(' ').filter(a => a);
+            if (!words.length)
+                words.push('');
+
+            for (const w of words)
+                ands.push(`v.indexOf(${db.esc(w)}) >= 0`);
+
+            where = `@indexIter('value', (v) => (v !== ${db.esc(emptyFieldValue)} && (${ands.join('&&')})) )`;
+        } else if (a[0] === '*') {
             a = a.substring(1);
             where = `@indexIter('value', (v) => (v !== ${db.esc(emptyFieldValue)} && v.indexOf(${db.esc(a)}) >= 0) )`;
-        } else if (a[0] == '#') {
+        } else if (a[0] === '#') {
             a = a.substring(1);
             where = `@indexIter('value', (v) => {
                 const enru = new Set(${db.esc(enruArr)});
@@ -68,7 +79,7 @@ class DbSearcher {
                     return false;
                 return v !== ${db.esc(emptyFieldValue)} && !enru.has(v[0]) && v.indexOf(${db.esc(a)}) >= 0;
             })`;
-        } else if (a[0] == '~') {//RegExp
+        } else if (a[0] === '~') {//RegExp
             a = a.substring(1);
             where = `
                 await (async() => {
@@ -595,21 +606,32 @@ class DbSearcher {
             const filterBySearch = (bookField, searchValue) => {
                 searchValue = searchValue.toLowerCase();
                 //особая обработка префиксов
-                if (searchValue == emptyFieldValue) {
+                if (searchValue === emptyFieldValue) {
                     return `(row.${bookField} === '' || row.${bookField}.indexOf(${db.esc(emptyFieldValue)}) === 0)`;
-                } else if (searchValue[0] == '=') {
+                } else if (searchValue[0] === '=') {
 
                     searchValue = searchValue.substring(1);
                     return `(row.${bookField}.toLowerCase().localeCompare(${db.esc(searchValue)}) === 0)`;
-                } else if (searchValue[0] == '*') {
+                } else if (searchValue[0] === '%') {
+                    searchValue = searchValue.substring(1);
+                    const ands = [];
+                    const words = searchValue.split(' ').filter(a => a);
+                    if (!words.length)
+                        words.push('');
+
+                    for (const w of words)
+                        ands.push(`row.${bookField}.toLowerCase().indexOf(${db.esc(w)}) >= 0`);
+
+                    return `(row.${bookField} && (${ands.join('&&')}))`;
+                } else if (searchValue[0] === '*') {
 
                     searchValue = searchValue.substring(1);
                     return `(row.${bookField} && row.${bookField}.toLowerCase().indexOf(${db.esc(searchValue)}) >= 0)`;
-                } else if (searchValue[0] == '#') {
+                } else if (searchValue[0] === '#') {
 
                     searchValue = searchValue.substring(1);
                     return `(row.${bookField} === '' || (!enru.has(row.${bookField}.toLowerCase()[0]) && row.${bookField}.toLowerCase().indexOf(${db.esc(searchValue)}) >= 0))`;
-                } else if (searchValue[0] == '~') {//RegExp
+                } else if (searchValue[0] === '~') {//RegExp
                     searchValue = searchValue.substring(1);
 
                     return `

+ 17 - 4
server/core/opds/BasePage.js

@@ -247,21 +247,34 @@ class BasePage {
                 searchValue = searchValue.toLowerCase();
 
             //особая обработка префиксов
-            if (searchValue[0] == '=') {
+            if (searchValue[0] === '=') {
 
                 searchValue = searchValue.substring(1);
                 return bookValue.localeCompare(searchValue) == 0;
-            } else if (searchValue[0] == '*') {
+            } else if (searchValue[0] === '%') {
+
+                searchValue = searchValue.substring(1);
+
+                const words = searchValue.split(' ').filter(a => a);
+                if (!words.length)
+                    words.push('');
+
+                for (const w of words)
+                    if (bookValue !== emptyFieldValue && bookValue.indexOf(w) >= 0)
+                        return true;
+
+                return false;
+            } else if (searchValue[0] === '*') {
 
                 searchValue = searchValue.substring(1);
                 return bookValue !== emptyFieldValue && bookValue.indexOf(searchValue) >= 0;
-            } else if (searchValue[0] == '#') {
+            } else if (searchValue[0] === '#') {
 
                 searchValue = searchValue.substring(1);
                 if (!bookValue)
                     return false;
                 return bookValue !== emptyFieldValue && !enru.has(bookValue[0]) && bookValue.indexOf(searchValue) >= 0;
-            } else if (searchValue[0] == '~') {//RegExp
+            } else if (searchValue[0] === '~') {//RegExp
 
                 searchValue = searchValue.substring(1);
                 const re = new RegExp(searchValue, 'i');

+ 4 - 1
server/core/opds/SearchHelpPage.js

@@ -24,7 +24,10 @@ class SearchHelpPage extends BasePage {
         префикс "=": поиск по точному совпадению
     </li>
     <li>
-        префикс "*": поиск подстроки в строке
+        префикс "%": поиск по группе подстрок, разделенных пробелами
+    </li>
+    <li>
+        префикс "*": поиск подстроки в строке (вместе с пробелами)
     </li>
     <li>
         префикс "#": поиск подстроки в строке, но только среди значений, начинающихся не с латинского или кириллического символа