Работа над поиском по дате поступления и оценке
This commit is contained in:
@@ -402,12 +402,28 @@ export default class BaseList {
|
||||
langFound = searchLang.has(book.lang || emptyFieldValue);
|
||||
}
|
||||
|
||||
//date
|
||||
let dateFound = !s.date;
|
||||
if (!dateFound) {
|
||||
let [from = '0000-00-00', to = '9999-99-99'] = s.date.split(',');
|
||||
dateFound = (book.date >= from && book.date <= to);
|
||||
}
|
||||
|
||||
//librate
|
||||
let librateFound = !s.librate;
|
||||
if (!librateFound) {
|
||||
const searchLibrate = new Set(s.librate.split(',').map(n => parseInt(n, 10)).filter(n => !isNaN(n)));
|
||||
librateFound = searchLibrate.has(book.librate);
|
||||
}
|
||||
|
||||
return (this.showDeleted || !book.del)
|
||||
&& authorFound
|
||||
&& filterBySearch(book.series, s.series)
|
||||
&& filterBySearch(book.title, s.title)
|
||||
&& genreFound
|
||||
&& langFound
|
||||
&& dateFound
|
||||
&& librateFound
|
||||
;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="root column fit" style="position: relative">
|
||||
<div ref="scroller" class="col fit column no-wrap" style="overflow: auto; position: relative" @scroll="onScroll">
|
||||
<div ref="toolPanel" class="tool-panel column bg-cyan-2" style="position: sticky; top: 0; z-index: 10;">
|
||||
<div ref="toolPanel" class="tool-panel q-pb-xs column bg-cyan-2" style="position: sticky; top: 0; z-index: 10;">
|
||||
<div class="header q-mx-md q-mb-xs q-mt-sm row items-center">
|
||||
<a :href="newSearchLink" style="height: 33px">
|
||||
<img src="./assets/logo.png" />
|
||||
@@ -46,7 +46,7 @@
|
||||
{{ projectName }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-mx-md q-mb-sm items-center">
|
||||
<div class="row q-mx-md q-mb-xs items-center">
|
||||
<q-input
|
||||
ref="authorInput" v-model="search.author" :maxlength="5000" :debounce="inputDebounce"
|
||||
class="q-mt-xs" :bg-color="inputBgColor('author')" style="width: 200px;" label="Автор" stack-label outlined dense clearable
|
||||
@@ -79,6 +79,10 @@
|
||||
class="q-mt-xs" :bg-color="inputBgColor()" input-style="cursor: pointer" style="width: 80px;" label="Язык" stack-label outlined dense clearable readonly
|
||||
@click="selectLang"
|
||||
>
|
||||
<template v-if="search.lang" #append>
|
||||
<q-icon name="la la-times-circle" class="q-field__focusable-action" @click.stop.prevent="search.lang = ''" />
|
||||
</template>
|
||||
|
||||
<q-tooltip v-if="search.lang && showTooltips" :delay="500" anchor="bottom middle" content-style="font-size: 80%" max-width="400px">
|
||||
{{ search.lang }}
|
||||
</q-tooltip>
|
||||
@@ -95,10 +99,10 @@
|
||||
</q-tooltip>
|
||||
</DivBtn>
|
||||
</div>
|
||||
<div v-show="extendedParams" class="row q-mx-md q-mb-sm items-center">
|
||||
<div v-show="extendedParams" class="row q-mx-md q-mb-xs items-center">
|
||||
<q-input
|
||||
v-model="genreNames" :maxlength="inputMaxLength" :debounce="inputDebounce"
|
||||
:bg-color="inputBgColor()" input-style="cursor: pointer" style="width: 200px;" label="Жанр" stack-label outlined dense clearable readonly
|
||||
class="q-mt-xs" :bg-color="inputBgColor()" input-style="cursor: pointer" style="width: 200px;" label="Жанр" stack-label outlined dense clearable readonly
|
||||
@click="selectGenre"
|
||||
>
|
||||
<template v-if="genreNames" #append>
|
||||
@@ -109,6 +113,30 @@
|
||||
{{ genreNames }}
|
||||
</q-tooltip>
|
||||
</q-input>
|
||||
|
||||
<div class="q-mx-xs" />
|
||||
<q-input
|
||||
v-model="search.date" :maxlength="inputMaxLength" :debounce="inputDebounce"
|
||||
class="q-mt-xs" :bg-color="inputBgColor()" input-style="cursor: pointer" style="width: 200px;" label="Дата поступления" stack-label outlined dense clearable
|
||||
>
|
||||
<q-tooltip v-if="search.date && showTooltips" :delay="500" anchor="bottom middle" content-style="font-size: 80%" max-width="400px">
|
||||
{{ search.date }}
|
||||
</q-tooltip>
|
||||
</q-input>
|
||||
|
||||
<div class="q-mx-xs" />
|
||||
<q-input
|
||||
v-model="search.librate" :maxlength="inputMaxLength" :debounce="inputDebounce"
|
||||
class="q-mt-xs" :bg-color="inputBgColor()" input-style="cursor: pointer" style="width: 180px;" label="Оценка" stack-label outlined dense clearable
|
||||
>
|
||||
<template v-if="search.librate" #append>
|
||||
<q-icon name="la la-times-circle" class="q-field__focusable-action" @click.stop.prevent="search.librate = ''" />
|
||||
</template>
|
||||
|
||||
<q-tooltip v-if="search.librate && showTooltips" :delay="500" anchor="bottom middle" content-style="font-size: 80%" max-width="400px">
|
||||
{{ search.librate }}
|
||||
</q-tooltip>
|
||||
</q-input>
|
||||
</div>
|
||||
<div v-show="!extendedParams && extendedParamsMessage" class="row q-mx-md q-mb-sm items-center clickable" @click="extendedParams = true">
|
||||
+{{ extendedParamsMessage }}
|
||||
@@ -325,6 +353,8 @@ class Search {
|
||||
title: search.title || '',
|
||||
genre: search.genre || '',
|
||||
lang: search.lang || '',
|
||||
date: search.date || '',
|
||||
librate: search.librate || '',
|
||||
page: search.page || 1,
|
||||
limit: search.limit || 50,
|
||||
});
|
||||
@@ -776,6 +806,8 @@ class Search {
|
||||
title: query.title,
|
||||
genre: query.genre,
|
||||
lang: (typeof(query.lang) == 'string' ? query.lang : this.langDefault),
|
||||
date: query.date,
|
||||
librate: query.librate,
|
||||
page: parseInt(query.page, 10),
|
||||
limit: parseInt(query.limit, 10) || this.search.limit,
|
||||
})
|
||||
@@ -793,6 +825,7 @@ class Search {
|
||||
try {
|
||||
const oldQuery = this.$route.query;
|
||||
const cloned = _.cloneDeep(this.search);
|
||||
|
||||
delete cloned.setDefaults;
|
||||
|
||||
const query = _.pickBy(cloned);
|
||||
|
||||
@@ -60,6 +60,10 @@ class DbCreator {
|
||||
let langArr = [];
|
||||
let delMap = new Map();//удаленные
|
||||
let delArr = [];
|
||||
let dateMap = new Map();//дата поступления
|
||||
let dateArr = [];
|
||||
let librateMap = new Map();//оценка
|
||||
let librateArr = [];
|
||||
|
||||
//stats
|
||||
let authorCount = 0;
|
||||
@@ -393,6 +397,12 @@ class DbCreator {
|
||||
|
||||
//удаленные
|
||||
parseField(rec.del, delMap, delArr, authorIds);
|
||||
|
||||
//дата поступления
|
||||
parseField(rec.date, dateMap, dateArr, authorIds);
|
||||
|
||||
//оценка
|
||||
parseField(rec.librate, librateMap, librateArr, authorIds);
|
||||
};
|
||||
|
||||
callback({job: 'search tables create', jobMessage: 'Создание поисковых таблиц', jobStep: 4, progress: 0});
|
||||
@@ -448,6 +458,8 @@ class DbCreator {
|
||||
genreMap = null;
|
||||
langMap = null;
|
||||
delMap = null;
|
||||
dateMap = null;
|
||||
librateMap = null;
|
||||
|
||||
utils.freeMemory();
|
||||
|
||||
@@ -553,13 +565,19 @@ class DbCreator {
|
||||
callback({job: 'genre save', jobMessage: 'Сохранение индекса жанров', jobStep: 9, progress: 0});
|
||||
await saveTable('genre', genreArr, () => {genreArr = null}, true);
|
||||
|
||||
callback({job: 'others save', jobMessage: 'Сохранение остальных индексов', jobStep: 10, progress: 0});
|
||||
//lang
|
||||
callback({job: 'lang save', jobMessage: 'Сохранение индекса языков', jobStep: 10, progress: 0});
|
||||
await saveTable('lang', langArr, () => {langArr = null}, true);
|
||||
|
||||
//del
|
||||
await saveTable('del', delArr, () => {delArr = null}, true, false, 'number');
|
||||
|
||||
//date
|
||||
await saveTable('date', dateArr, () => {dateArr = null}, true);
|
||||
|
||||
//librate
|
||||
await saveTable('librate', librateArr, () => {librateArr = null}, true, false, 'number');
|
||||
|
||||
//кэш-таблицы запросов
|
||||
await db.create({table: 'query_cache'});
|
||||
await db.create({table: 'query_time'});
|
||||
|
||||
@@ -25,7 +25,7 @@ class DbSearcher {
|
||||
}
|
||||
|
||||
queryKey(q) {
|
||||
return JSON.stringify([q.author, q.series, q.title, q.genre, q.lang, q.del]);
|
||||
return JSON.stringify([q.author, q.series, q.title, q.genre, q.lang, q.del, q.date, q.librate]);
|
||||
}
|
||||
|
||||
getWhere(a) {
|
||||
@@ -259,6 +259,74 @@ class DbSearcher {
|
||||
|
||||
idsArr.push(delIds);
|
||||
}
|
||||
|
||||
//дата поступления
|
||||
if (query.date) {
|
||||
const dateKey = `author-ids-date-${query.date}`;
|
||||
let dateIds = await this.getCached(dateKey);
|
||||
|
||||
if (dateIds === null) {
|
||||
let [from = '', to = ''] = query.date.split(',');
|
||||
|
||||
const dateRows = await db.select({
|
||||
table: 'date',
|
||||
rawResult: true,
|
||||
where: `
|
||||
const ids = @indexLR('value', ${db.esc(from)} || undefined, ${db.esc(to)} || undefined);
|
||||
|
||||
const result = new Set();
|
||||
for (const id of ids) {
|
||||
const row = @unsafeRow(id);
|
||||
for (const authorId of row.authorId)
|
||||
result.add(authorId);
|
||||
}
|
||||
|
||||
return Array.from(result);
|
||||
`
|
||||
});
|
||||
|
||||
dateIds = dateRows[0].rawResult;
|
||||
await this.putCached(dateKey, dateIds);
|
||||
}
|
||||
|
||||
idsArr.push(dateIds);
|
||||
}
|
||||
|
||||
//оценка
|
||||
if (query.librate) {
|
||||
const librateKey = `author-ids-librate-${query.librate}`;
|
||||
let librateIds = await this.getCached(librateKey);
|
||||
|
||||
if (librateIds === null) {
|
||||
const dateRows = await db.select({
|
||||
table: 'librate',
|
||||
rawResult: true,
|
||||
where: `
|
||||
const rates = ${db.esc(query.librate.split(',').map(n => parseInt(n, 10)).filter(n => !isNaN(n)))};
|
||||
|
||||
const ids = new Set();
|
||||
for (const rate of rates) {
|
||||
for (const id of @indexLR('value', rate, rate))
|
||||
ids.add(id);
|
||||
}
|
||||
|
||||
const result = new Set();
|
||||
for (const id of ids) {
|
||||
const row = @unsafeRow(id);
|
||||
for (const authorId of row.authorId)
|
||||
result.add(authorId);
|
||||
}
|
||||
|
||||
return Array.from(result);
|
||||
`
|
||||
});
|
||||
|
||||
librateIds = dateRows[0].rawResult;
|
||||
await this.putCached(librateKey, librateIds);
|
||||
}
|
||||
|
||||
idsArr.push(librateIds);
|
||||
}
|
||||
/*
|
||||
//ищем пересечение множеств
|
||||
idsArr.push(authorIds);
|
||||
@@ -341,6 +409,26 @@ class DbSearcher {
|
||||
`;
|
||||
}
|
||||
|
||||
//дата поступления
|
||||
if (query.date) {
|
||||
let [from = '0000-00-00', to = '9999-99-99'] = query.date.split(',');
|
||||
filter += `
|
||||
if (!(book.date >= ${db.esc(from)} && book.date <= ${db.esc(to)}))
|
||||
return false;
|
||||
`;
|
||||
}
|
||||
|
||||
//оценка
|
||||
if (query.librate) {
|
||||
closures += `
|
||||
const searchLibrate = new Set(${db.esc(query.librate.split(',').map(n => parseInt(n, 10)).filter(n => !isNaN(n)))});
|
||||
`;
|
||||
filter += `
|
||||
if (!searchLibrate.has(book.librate))
|
||||
return false;
|
||||
`;
|
||||
}
|
||||
|
||||
//серии
|
||||
if (exclude !== 'series' && query.series && query.series !== '*') {
|
||||
closures += `
|
||||
|
||||
Reference in New Issue
Block a user