« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/reverse.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/reverse.js')
-rw-r--r--src/reverse.js59
1 files changed, 58 insertions, 1 deletions
diff --git a/src/reverse.js b/src/reverse.js
index 324cbabe..9cab5ef8 100644
--- a/src/reverse.js
+++ b/src/reverse.js
@@ -1,10 +1,67 @@
 import * as fr from './find-reverse.js';
 
+import {sortByDate} from '#sort';
+import {stitchArrays} from '#sugar';
+
 function reverseHelper(spec) {
   const cache = new WeakMap();
 
   return (thing, data) => {
-    return ({spec, from: thing, data: data.length});
+    // Check for an existing cache record which corresponds to this data.
+    // If it exists, query it for the requested thing, and return that;
+    // if it doesn't, create it and put it where it needs to be.
+
+    if (cache.has(data)) {
+      return cache.get(data).get(thing) ?? [];
+    }
+
+    const cacheRecord = new WeakMap();
+    cache.set(data, cacheRecord);
+
+    // Get the referencing and referenced things. This is the meat of how
+    // one reverse spec is different from another.
+
+    const referencingThings =
+      data.flatMap(thing => spec.referencing(thing));
+
+    const referencedThings =
+      referencingThings.map(thing => spec.referenced(thing));
+
+    // Actually fill in the cache record. Since we're building up a *reverse*
+    // reference list, track connections in terms of the referenced thing.
+    // Also gather all referenced things into a set, for sorting purposes.
+
+    const allReferencedThings = new Set();
+
+    stitchArrays({
+      referencingThing: referencingThings,
+      referencedThings: referencedThings,
+    }).forEach(({referencingThing, referencedThings}) => {
+        for (const referencedThing of referencedThings) {
+          if (cacheRecord.has(referencedThing)) {
+            cacheRecord.get(referencedThing).push(referencingThing);
+          } else {
+            cacheRecord.set(referencedThing, [referencingThing]);
+            allReferencedThings.add(referencedThing);
+          }
+        }
+      });
+
+    // Sort the entries in the cache records, too, just by date. The rest of
+    // sorting should be handled externally - either preceding the reverse
+    // call (changing the data input) or following (sorting the output).
+
+    for (const referencedThing of allReferencedThings) {
+      if (cacheRecord.has(referencedThing)) {
+        const referencingThings = cacheRecord.get(referencedThing);
+        sortByDate(referencingThings);
+      }
+    }
+
+    // Then just pluck out the requested thing from the now-filled
+    // cache record!
+
+    return cacheRecord.get(thing) ?? [];
   };
 }