« get me outta code hell

search: query -> select, factor out backend parts of searchSpec - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
diff options
context:
space:
mode:
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
commit9be32e448e65efeef59fa1ed6c2f4190c86d83d4 (patch)
tree017b01a752ad658073cd8b6770ead0de01612184
parentc60c6b04114efa65da26ded995fb5793c893d066 (diff)
search: query -> select, factor out backend parts of searchSpec
-rw-r--r--package.json3
-rw-r--r--src/common-util/search-shape.js104
-rw-r--r--src/search-select.js (renamed from src/common-util/search-spec.js)109
-rw-r--r--src/search.js3
-rw-r--r--src/static/js/search-worker.js3
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,