diff options
author | (quasar) nebula <qznebula@protonmail.com> | 2025-10-08 20:52:28 -0300 |
---|---|---|
committer | (quasar) nebula <qznebula@protonmail.com> | 2025-10-08 20:52:28 -0300 |
commit | 9be32e448e65efeef59fa1ed6c2f4190c86d83d4 (patch) | |
tree | 017b01a752ad658073cd8b6770ead0de01612184 | |
parent | c60c6b04114efa65da26ded995fb5793c893d066 (diff) |
search: query -> select, factor out backend parts of searchSpec
-rw-r--r-- | package.json | 3 | ||||
-rw-r--r-- | src/common-util/search-shape.js | 104 | ||||
-rw-r--r-- | src/search-select.js (renamed from src/common-util/search-spec.js) | 109 | ||||
-rw-r--r-- | src/search.js | 3 | ||||
-rw-r--r-- | src/static/js/search-worker.js | 3 |
5 files changed, 125 insertions, 97 deletions
diff --git a/package.json b/package.json index 7ad8fd07..7ec7fafb 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,8 @@ "#replacer": "./src/replacer.js", "#reverse": "./src/reverse.js", "#search": "./src/search.js", - "#search-spec": "./src/common-util/search-spec.js", + "#search-shape": "./src/common-util/search-shape.js", + "#search-select": "./src/search-select.js", "#serialize": "./src/data/serialize.js", "#sort": "./src/common-util/sort.js", "#sugar": "./src/common-util/sugar.js", diff --git a/src/common-util/search-shape.js b/src/common-util/search-shape.js new file mode 100644 index 00000000..7f81a089 --- /dev/null +++ b/src/common-util/search-shape.js @@ -0,0 +1,104 @@ +// Index structures shared by client and server, and relevant interfaces. +// First and foremost, this is complemented by src/search-select.js, which +// actually fills the search indexes up with stuff. During build this all +// gets consumed by src/search.js to make an index, fill it with stuff +// (as described by search-select.js), and export it to disk; then on +// the client that export is consumed by src/static/js/search-worker.js, +// which builds an index in the same shape and imports the data for query. + +const baselineStore = [ + 'primaryName', + 'disambiguator', + 'artwork', + 'color', +]; + +const genericStore = baselineStore; + +const searchShape = { + generic: { + index: [ + 'primaryName', + 'parentName', + 'artTags', + 'additionalNames', + 'contributors', + 'groups', + ].map(field => ({field, tokenize: 'forward'})), + + store: genericStore, + }, + + verbatim: { + index: [ + 'primaryName', + 'parentName', + 'artTags', + 'additionalNames', + 'contributors', + 'groups', + ], + + store: genericStore, + }, +}; + +export default searchShape; + +export function makeSearchIndex(descriptor, {FlexSearch}) { + return new FlexSearch.Document({ + id: 'reference', + index: descriptor.index, + store: descriptor.store, + + // Disable scoring, always return results according to provided order + // (specified above in `genericQuery`, etc). + resolution: 1, + }); +} + +// TODO: This function basically mirrors bind-utilities.js, which isn't +// exactly robust, but... binding might need some more thought across the +// codebase in *general.* +function bindSearchUtilities({ + checkIfImagePathHasCachedThumbnails, + getThumbnailEqualOrSmaller, + thumbsCache, + urls, +}) { + // TODO: :boom: + + const bound = { + urls, + }; + + bound.checkIfImagePathHasCachedThumbnails = + (imagePath) => + checkIfImagePathHasCachedThumbnails(imagePath, thumbsCache); + + bound.getThumbnailEqualOrSmaller = + (preferred, imagePath) => + getThumbnailEqualOrSmaller(preferred, imagePath, thumbsCache); + + return bound; +} + +export function populateSearchIndex(index, descriptor, opts) { + const {wikiData} = opts; + const bound = bindSearchUtilities(opts); + + for (const thing of descriptor.select(wikiData)) { + const reference = thing.constructor.getReference(thing); + + let processed; + try { + processed = descriptor.process(thing, bound); + } catch (caughtError) { + throw new Error( + `Failed to process searchable thing ${reference}`, + {cause: caughtError}); + } + + index.add({reference, ...processed}); + } +} diff --git a/src/common-util/search-spec.js b/src/search-select.js index 731e5495..e7372ad4 100644 --- a/src/common-util/search-spec.js +++ b/src/search-select.js @@ -1,4 +1,8 @@ -// Index structures shared by client and server, and relevant interfaces. +// Complements the specs in search-shape.js with the functions that actually +// process live wiki data into records that are appropriate for storage. +// These files totally go together, so read them side by side, okay? + +import baseSearchSpec from '#search-shape'; function prepareArtwork(artwork, thing, { checkIfImagePathHasCachedThumbnails, @@ -65,14 +69,7 @@ function baselineProcess(thing, opts) { return fields; } -const baselineStore = [ - 'primaryName', - 'disambiguator', - 'artwork', - 'color', -]; - -function genericQuery(wikiData) { +function genericSelect(wikiData) { const groupOrder = wikiData.wikiInfo.divideTrackListsByGroups; @@ -108,7 +105,7 @@ function genericQuery(wikiData) { sortByGroupRank( wikiData.trackData - .filter(track => !track.mainReleaseTrack)), + .filter(track => track.isMainRelease)), ].flat(); } @@ -197,96 +194,20 @@ function genericProcess(thing, opts) { return fields; } -const genericStore = baselineStore; - -export const searchSpec = { +const spiffySearchSpec = { generic: { - query: genericQuery, - process: genericProcess, + ...baseSearchSpec.generic, - index: [ - 'primaryName', - 'parentName', - 'artTags', - 'additionalNames', - 'contributors', - 'groups', - ].map(field => ({field, tokenize: 'forward'})), - - store: genericStore, + select: genericSelect, + process: genericProcess, }, verbatim: { - query: genericQuery, - process: genericProcess, + ...baseSearchSpec.verbatim, - index: [ - 'primaryName', - 'parentName', - 'artTags', - 'additionalNames', - 'contributors', - 'groups', - ], - - store: genericStore, + select: genericSelect, + process: genericProcess, }, }; -export function makeSearchIndex(descriptor, {FlexSearch}) { - return new FlexSearch.Document({ - id: 'reference', - index: descriptor.index, - store: descriptor.store, - - // Disable scoring, always return results according to provided order - // (specified above in `genericQuery`, etc). - resolution: 1, - }); -} - -// TODO: This function basically mirrors bind-utilities.js, which isn't -// exactly robust, but... binding might need some more thought across the -// codebase in *general.* -function bindSearchUtilities({ - checkIfImagePathHasCachedThumbnails, - getThumbnailEqualOrSmaller, - thumbsCache, - urls, -}) { - const bound = { - urls, - }; - - bound.checkIfImagePathHasCachedThumbnails = - (imagePath) => - checkIfImagePathHasCachedThumbnails(imagePath, thumbsCache); - - bound.getThumbnailEqualOrSmaller = - (preferred, imagePath) => - getThumbnailEqualOrSmaller(preferred, imagePath, thumbsCache); - - return bound; -} - -export function populateSearchIndex(index, descriptor, opts) { - const {wikiData} = opts; - const bound = bindSearchUtilities(opts); - - const collection = descriptor.query(wikiData); - - for (const thing of collection) { - const reference = thing.constructor.getReference(thing); - - let processed; - try { - processed = descriptor.process(thing, bound); - } catch (caughtError) { - throw new Error( - `Failed to process searchable thing ${reference}`, - {cause: caughtError}); - } - - index.add({reference, ...processed}); - } -} +export default spiffySearchSpec; diff --git a/src/search.js b/src/search.js index a2dae9e1..5d4c7331 100644 --- a/src/search.js +++ b/src/search.js @@ -9,7 +9,8 @@ import FlexSearch from 'flexsearch'; import {pack} from 'msgpackr'; import {logWarn} from '#cli'; -import {makeSearchIndex, populateSearchIndex, searchSpec} from '#search-spec'; +import {makeSearchIndex, populateSearchIndex} from '#search-shape'; +import searchSpec from '#search-select'; import {stitchArrays} from '#sugar'; import {checkIfImagePathHasCachedThumbnails, getThumbnailEqualOrSmaller} from '#thumbs'; diff --git a/src/static/js/search-worker.js b/src/static/js/search-worker.js index 3e9fbfca..387cbca0 100644 --- a/src/static/js/search-worker.js +++ b/src/static/js/search-worker.js @@ -2,7 +2,8 @@ import FlexSearch from '../lib/flexsearch/flexsearch.bundle.module.min.js'; -import {makeSearchIndex, searchSpec} from '../shared-util/search-spec.js'; +import {default as searchSpec, makeSearchIndex} + from '../shared-util/search-shape.js'; import { empty, |