From 57cd9be637b406359b46f9c069cb8989bc3e0fc1 Mon Sep 17 00:00:00 2001 From: Book Pauk Date: Thu, 29 Aug 2024 17:45:35 +0700 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D1=8C=20=D0=B7=D0=B0=D0=B4=D0=B0=D0=B2=D0=B0=D1=82?= =?UTF-8?q?=D1=8C=20=D0=BF=D1=80=D0=B5=D1=84=D0=B8=D0=BA=D1=81=20"%"=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=BF=D0=BE=D0=B8=D1=81=D0=BA=D0=BE=D0=B2?= =?UTF-8?q?=D0=BE=D0=B3=D0=BE=20=D0=B7=D0=BD=D0=B0=D1=87=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F.=20=D0=94=D0=B0=D0=BD=D0=BD=D1=8B=D0=B9=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B5=D1=84=D0=B8=D0=BA=D1=81=20=D0=BF=D0=BE=D0=B7=D0=B2=D0=BE?= =?UTF-8?q?=D0=BB=D1=8F=D0=B5=D1=82=20=D0=B2=D0=B5=D1=81=D1=82=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=B8=D1=81=D0=BA=20=D0=BF=D0=BE=20=D0=B3=D1=80?= =?UTF-8?q?=D1=83=D0=BF=D0=BF=D0=B5=20=D0=BF=D0=BE=D0=B4=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=BE=D0=BA,=20=D1=80=D0=B0=D0=B7=D0=B4=D0=B5=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=BD=D1=8B=D1=85=20=D0=BF=D1=80=D0=BE=D0=B1=D0=B5=D0=BB?= =?UTF-8?q?=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 4 ++ client/components/Search/BaseList.js | 21 ++++++++-- client/components/Search/Search.vue | 9 ++++- .../SelectExtSearchDialog.vue | 5 ++- server/core/DbSearcher.js | 40 ++++++++++++++----- server/core/opds/BasePage.js | 21 ++++++++-- server/core/opds/SearchHelpPage.js | 5 ++- 7 files changed, 84 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a677d0..5f36909 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +1.6.0 / 2024-??-?? + +- Добавлена возможность задавать префикс "%" для поискового значения. Данный префикс позволяет вести поиск по группе подстрок, разделенных пробелами + 1.5.7 / 2024-04-04 - В параметр bookReadLink конфига добавлен вариант замены DOWNLOAD_URI на uri из ссылки для скачивания книги (#29) diff --git a/client/components/Search/BaseList.js b/client/components/Search/BaseList.js index f8f7a34..71c1b25 100644 --- a/client/components/Search/BaseList.js +++ b/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'); diff --git a/client/components/Search/Search.vue b/client/components/Search/Search.vue index 3d09034..b940592 100644 --- a/client/components/Search/Search.vue +++ b/client/components/Search/Search.vue @@ -846,8 +846,13 @@ class Search {
  • - "*" поиск подстроки в строке. Например, для "*Александр" в поле автора, будут найдены - все авторы, имя которых содержит "Александр" + "%" поиск по группе подстрок, разделенных пробелами. Например, для "%Александр Пушкин" в поле автора, будут найдены + все авторы, имя которых содержит и "Александр", и "Пушкин" одновременно +
  • +
    +
  • + "*" поиск подстроки в строке вместе с пробелами. Например, для "*Александр Сергеевич" в поле автора, будут найдены + все авторы, имя которых содержит "Александр Сергеевич"

  • diff --git a/client/components/Search/SelectExtSearchDialog/SelectExtSearchDialog.vue b/client/components/Search/SelectExtSearchDialog/SelectExtSearchDialog.vue index f4d5a8d..c24fa33 100644 --- a/client/components/Search/SelectExtSearchDialog/SelectExtSearchDialog.vue +++ b/client/components/Search/SelectExtSearchDialog/SelectExtSearchDialog.vue @@ -155,7 +155,10 @@ class SelectExtSearchDialog { префикс "=": поиск по точному совпадению
  • - префикс "*": поиск подстроки в строке + префикс "%": поиск по группе подстрок, разделенных пробелами +
  • +
  • + префикс "*": поиск подстроки в строке (вместе с пробелами)
  • префикс "#": поиск подстроки в строке, но только среди начинающихся не с латинского или кириллического символа diff --git a/server/core/DbSearcher.js b/server/core/DbSearcher.js index 0b2d7a5..d18c7de 100644 --- a/server/core/DbSearcher.js +++ b/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 ` diff --git a/server/core/opds/BasePage.js b/server/core/opds/BasePage.js index 83695a9..9003efa 100644 --- a/server/core/opds/BasePage.js +++ b/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'); diff --git a/server/core/opds/SearchHelpPage.js b/server/core/opds/SearchHelpPage.js index 246f499..23c3c31 100644 --- a/server/core/opds/SearchHelpPage.js +++ b/server/core/opds/SearchHelpPage.js @@ -24,7 +24,10 @@ class SearchHelpPage extends BasePage { префикс "=": поиск по точному совпадению
  • - префикс "*": поиск подстроки в строке + префикс "%": поиск по группе подстрок, разделенных пробелами +
  • +
  • + префикс "*": поиск подстроки в строке (вместе с пробелами)
  • префикс "#": поиск подстроки в строке, но только среди значений, начинающихся не с латинского или кириллического символа