Explorar o código

Работа над списком книг в серии

Book Pauk %!s(int64=2) %!d(string=hai) anos
pai
achega
0e2ef4133e

+ 10 - 0
client/components/Api/Api.vue

@@ -220,6 +220,16 @@ class Api {
         return response;
     }
 
+    async getSeriesBookList(seriesId) {
+        const response = await this.request({action: 'get-series-book-list', seriesId});
+
+        if (response.error) {
+            throw new Error(response.error);
+        }
+
+        return response;
+    }
+
     async getGenreTree() {
         const response = await this.request({action: 'get-genre-tree'});
 

+ 23 - 0
client/components/Search/Search.vue

@@ -878,6 +878,29 @@ class Search {
         }
     }
 
+    async loadSeriesBooks(seriesId) {
+        try {
+            let result;
+
+            if (this.abCacheEnabled) {
+                const key = `series-${seriesId}-${this.inpxHash}`;
+                const data = await authorBooksStorage.getData(key);
+                if (data) {
+                    result = JSON.parse(data);
+                } else {
+                    result = await this.api.getBookList(seriesId);
+                    await authorBooksStorage.setData(key, JSON.stringify(result));
+                }
+            } else {
+                result = await this.api.getBookList(seriesId);
+            }
+
+            return JSON.parse(result.books);
+        } catch (e) {
+            this.$root.stdDialog.alert(e.message, 'Ошибка');
+        }
+    }
+
     filterBooks(loadedBooks) {
         const s = this.search;
 

+ 11 - 0
server/controllers/WebSocketController.js

@@ -79,6 +79,8 @@ class WebSocketController {
                     await this.search(req, ws); break;
                 case 'get-book-list':
                     await this.getBookList(req, ws); break;
+                case 'get-series-book-list':
+                    await this.getSeriesBookList(req, ws); break;
                 case 'get-genre-tree':
                     await this.getGenreTree(req, ws); break;
                 case 'get-book-link':
@@ -150,6 +152,15 @@ class WebSocketController {
         this.send(result, req, ws);
     }
 
+    async getSeriesBookList(req, ws) {
+        if (!utils.hasProp(req, 'seriesId'))
+            throw new Error(`seriesId is empty`);
+
+        const result = await this.webWorker.getSeriesBookList(req.seriesId);
+
+        this.send(result, req, ws);
+    }
+
     async getGenreTree(req, ws) {
         const result = await this.webWorker.getGenreTree();
 

+ 19 - 9
server/core/DbCreator.js

@@ -307,12 +307,12 @@ class DbCreator {
         callback({progress: 1});
 
         //чистка памяти, ибо жрет как не в себя
-        await db.drop({table: 'book'});
+        await db.close({table: 'book'});
         await db.freeMemory();
         utils.freeMemory();
 
         //парсинг 2, подготовка
-        const parseField = (fieldValue, fieldMap, fieldArr, authorIds) => {
+        const parseField = (fieldValue, fieldMap, fieldArr, authorIds, bookId) => {
             if (!fieldValue)
                 fieldValue = emptyFieldValue;
 
@@ -324,6 +324,8 @@ class DbCreator {
                 fieldRec = fieldArr[fieldId];
             } else {
                 fieldRec = {id: fieldArr.length, value, authorId: new Set()};
+                if (bookId)
+                    fieldRec.bookId = new Set();
                 fieldArr.push(fieldRec);
                 fieldMap.set(value, fieldRec.id);
             }
@@ -331,6 +333,9 @@ class DbCreator {
             for (const id of authorIds) {
                 fieldRec.authorId.add(id);
             }
+
+            if (bookId)
+                fieldRec.bookId.add(bookId);
         };
 
         const parseBookRec = (rec) => {
@@ -346,7 +351,7 @@ class DbCreator {
             }
 
             //серии
-            parseField(rec.series, seriesMap, seriesArr, authorIds);
+            parseField(rec.series, seriesMap, seriesArr, authorIds, rec.id);
 
             //названия
             parseField(rec.title, titleMap, titleArr, authorIds);
@@ -464,7 +469,7 @@ class DbCreator {
         //сохраним поисковые таблицы
         const chunkSize = 10000;
 
-        const saveTable = async(table, arr, nullArr, authorIdToArray = true) => {
+        const saveTable = async(table, arr, nullArr, authorIdToArray = false, bookIdToArray = false) => {
             
             arr.sort((a, b) => a.value.localeCompare(b.value));
 
@@ -482,6 +487,11 @@ class DbCreator {
                         rec.authorId = Array.from(rec.authorId);
                 }
 
+                if (bookIdToArray) {
+                    for (const rec of chunk)
+                        rec.bookId = Array.from(rec.bookId);
+                }
+
                 await db.insert({table, rows: chunk});
 
                 if (i % 5 == 0) {
@@ -500,23 +510,23 @@ class DbCreator {
 
         //author
         callback({job: 'author save', jobMessage: 'Сохранение индекса авторов', jobStep: 6, progress: 0});
-        await saveTable('author', authorArr, () => {authorArr = null}, false);
+        await saveTable('author', authorArr, () => {authorArr = null});
 
         //series
         callback({job: 'series save', jobMessage: 'Сохранение индекса серий', jobStep: 7, progress: 0});
-        await saveTable('series', seriesArr, () => {seriesArr = null});
+        await saveTable('series', seriesArr, () => {seriesArr = null}, true, true);
 
         //title
         callback({job: 'title save', jobMessage: 'Сохранение индекса названий', jobStep: 8, progress: 0});
-        await saveTable('title', titleArr, () => {titleArr = null});
+        await saveTable('title', titleArr, () => {titleArr = null}, true);
 
         //genre
         callback({job: 'genre save', jobMessage: 'Сохранение индекса жанров', jobStep: 9, progress: 0});
-        await saveTable('genre', genreArr, () => {genreArr = null});
+        await saveTable('genre', genreArr, () => {genreArr = null}, true);
 
         //lang
         callback({job: 'lang save', jobMessage: 'Сохранение индекса языков', jobStep: 10, progress: 0});
-        await saveTable('lang', langArr, () => {langArr = null});
+        await saveTable('lang', langArr, () => {langArr = null}, true);
 
         //кэш-таблицы запросов
         await db.create({table: 'query_cache'});

+ 70 - 1
server/core/DbSearcher.js

@@ -273,7 +273,7 @@ class DbSearcher {
         });
 
         let author = '';
-        let books = [];
+        let books = '';
 
         if (rows.length) {
             author = rows[0].author;
@@ -331,6 +331,75 @@ class DbSearcher {
         }
     }
 
+    async selectSeriesBookList(seriesId) {
+        const db = this.db;
+
+        //выборка серии по seriesId
+        const rows = await db.select({
+            table: 'series',
+            where: `@@id(${db.esc(seriesId)})`
+        });
+
+        let books = [];
+
+        if (rows.length) {
+            books = await db.select({
+                table: 'book',
+                where: `@@id(${db.esc(rows[0].bookId)})`
+            });
+        }
+
+        return {books: JSON.stringify(books)};
+    }
+
+    async getSeriesBookList(seriesId) {
+        if (this.closed)
+            throw new Error('DbSearcher closed');
+
+        this.searchFlag++;
+
+        try {
+            const db = this.db;
+
+            let result;
+
+            if (this.config.queryCacheEnabled) {
+                const key = `series_books-${seriesId}`;
+                const rows = await db.select({table: 'query_cache', where: `@@id(${db.esc(key)})`});
+
+                if (rows.length) {//нашли в кеше
+                    await db.insert({
+                        table: 'query_time',
+                        replace: true,
+                        rows: [{id: key, time: Date.now()}],
+                    });
+
+                    result = rows[0].value;
+                } else {//не нашли в кеше
+                    result = await this.selectSeriesBookList(seriesId);
+
+                    //кладем в кеш
+                    await db.insert({
+                        table: 'query_cache',
+                        replace: true,
+                        rows: [{id: key, value: result}],
+                    });
+                    await db.insert({
+                        table: 'query_time',
+                        replace: true,
+                        rows: [{id: key, time: Date.now()}],
+                    });
+                }
+            } else {
+                result = await this.selectSeriesBookList(seriesId);
+            }
+
+            return result;
+        } finally {
+            this.searchFlag--;
+        }
+    }
+
     async periodicCleanCache() {
         this.timer = null;
         const cleanInterval = this.config.cacheCleanInterval*60*1000;

+ 6 - 0
server/core/WebWorker.js

@@ -227,6 +227,12 @@ class WebWorker {
         return await this.dbSearcher.getBookList(authorId);
     }
 
+    async getSeriesBookList(seriesId) {
+        this.checkMyState();
+
+        return await this.dbSearcher.getSeriesBookList(seriesId);
+    }
+
     async getGenreTree() {
         this.checkMyState();