DbSearcher.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. //const _ = require('lodash');
  2. const utils = require('./utils');
  3. class DbSearcher {
  4. constructor(db) {
  5. this.db = db;
  6. }
  7. async selectAuthorIds(query) {
  8. const db = this.db;
  9. let authorRows;
  10. let authorIds = new Set();
  11. //сначала выберем все id авторов по фильтру
  12. //порядок id соответсвует ASC-сортировке по author
  13. if (query.author) {
  14. authorRows = await db.select({
  15. table: 'author',
  16. map: `(r) => ({id: r.id})`,
  17. });
  18. for (const row of authorRows)
  19. authorIds.add(row.id);
  20. } else {//все авторы
  21. if (!db.searchCache.authorIdsAll) {
  22. authorRows = await db.select({
  23. table: 'author',
  24. map: `(r) => ({id: r.id})`,
  25. });
  26. db.searchCache.authorIdsAll = [];
  27. for (const row of authorRows) {
  28. authorIds.add(row.id);
  29. db.searchCache.authorIdsAll.push(row.id);
  30. }
  31. } else {//оптимизация
  32. for (const id of db.searchCache.authorIdsAll) {
  33. authorIds.add(id);
  34. }
  35. }
  36. }
  37. const idsArr = [];
  38. idsArr.push(authorIds);
  39. //серии
  40. //названия
  41. //жанры
  42. //языки
  43. if (idsArr.length > 1)
  44. authorIds = utils.intersectSet(idsArr);
  45. //сортировка
  46. authorIds = Array.from(authorIds);
  47. authorIds.sort((a, b) => a > b);
  48. return authorIds;
  49. }
  50. async getAuthorIds(query) {
  51. const db = this.db;
  52. if (!db.searchCache)
  53. db.searchCache = {};
  54. let result;
  55. //сначала попробуем найти в кеше
  56. const q = query;
  57. const keyArr = [q.author, q.series, q.title, q.genre, q.lang];
  58. const keyStr = keyArr.join('');
  59. if (!keyStr) {//пустой запрос
  60. if (db.searchCache.authorIdsAll)
  61. result = db.searchCache.authorIdsAll;
  62. else
  63. result = await this.selectAuthorIds(query);
  64. } else {//непустой запрос
  65. const key = JSON.stringify(keyArr);
  66. const rows = await db.select({table: 'query_cache', where: `@@id(${db.esc(key)})`});
  67. if (rows.length) {//нашли в кеше
  68. await db.insert({
  69. table: 'query_time',
  70. replace: true,
  71. rows: [{id: key, time: Date.now()}],
  72. });
  73. result = rows[0].value;
  74. } else {//не нашли в кеше, ищем в поисковых таблицах
  75. result = await this.selectAuthorIds(query);
  76. await db.insert({
  77. table: 'query_cache',
  78. replace: true,
  79. rows: [{id: key, value: result}],
  80. });
  81. await db.insert({
  82. table: 'query_time',
  83. replace: true,
  84. rows: [{id: key, time: Date.now()}],
  85. });
  86. }
  87. }
  88. return result;
  89. }
  90. async search(query) {
  91. const db = this.db;
  92. const authorIds = await this.getAuthorIds(query);
  93. const totalFound = authorIds.length;
  94. const limit = (query.limit ? query.limit : 1000);
  95. //выборка найденных авторов
  96. let result = await db.select({
  97. table: 'author',
  98. map: `(r) => ({id: r.id, author: r.author})`,
  99. where: `
  100. const all = @all();
  101. const ids = new Set();
  102. let n = 0;
  103. for (const id of all) {
  104. if (++n > ${db.esc(limit)})
  105. break;
  106. ids.add(id);
  107. }
  108. return ids;
  109. `
  110. });
  111. return {result, totalFound};
  112. }
  113. }
  114. module.exports = DbSearcher;