« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/data/things/album.js19
-rw-r--r--src/data/things/composite.js72
-rw-r--r--src/data/things/thing.js17
3 files changed, 94 insertions, 14 deletions
diff --git a/src/data/things/album.js b/src/data/things/album.js
index 288caa04..e11d0909 100644
--- a/src/data/things/album.js
+++ b/src/data/things/album.js
@@ -10,7 +10,7 @@ import {
   exposeUpdateValueOrContinue,
   fillMissingListItems,
   withFlattenedArray,
-  withPropertyFromList,
+  withPropertiesFromList,
   withUnflattenedArray,
   withUpdateValueAsDependency,
 } from '#composite';
@@ -86,17 +86,22 @@ export class Album extends Thing {
 
       withUpdateValueAsDependency({into: '#sections'}),
 
-      withPropertyFromList({list: '#sections', property: 'tracks', into: '#sections.trackRefs'}),
-      withPropertyFromList({list: '#sections', property: 'dateOriginallyReleased'}),
-      withPropertyFromList({list: '#sections', property: 'isDefaultTrackSection'}),
-      withPropertyFromList({list: '#sections', property: 'color'}),
+      withPropertiesFromList({
+        list: '#sections',
+        properties: [
+          'tracks',
+          'dateOriginallyReleased',
+          'isDefaultTrackSection',
+          'color',
+        ],
+      }),
 
-      fillMissingListItems({list: '#sections.trackRefs', value: []}),
+      fillMissingListItems({list: '#sections.tracks', value: []}),
       fillMissingListItems({list: '#sections.isDefaultTrackSection', value: false}),
       fillMissingListItems({list: '#sections.color', dependency: 'color'}),
 
       withFlattenedArray({
-        from: '#sections.trackRefs',
+        from: '#sections.tracks',
         into: '#trackRefs',
         intoIndices: '#sections.startIndex',
       }),
diff --git a/src/data/things/composite.js b/src/data/things/composite.js
index b37b8e31..e3225563 100644
--- a/src/data/things/composite.js
+++ b/src/data/things/composite.js
@@ -1119,6 +1119,39 @@ export function withPropertyFromObject({
   };
 }
 
+// Gets the listed properties from some object, providing each property's value
+// as a dependency prefixed with the same name as the object (by default).
+// If the object itself is null, all provided dependencies will be null;
+// if it's missing only select properties, those will be provided as null.
+export function withPropertiesFromObject({
+  object,
+  properties,
+  prefix =
+    (object.startsWith('#')
+      ? object
+      : `#${object}`),
+}) {
+  return {
+    annotation: `withPropertiesFromObject`,
+    flags: {expose: true, compose: true},
+
+    expose: {
+      mapDependencies: {object},
+      options: {prefix, properties},
+
+      compute: ({object, '#options': {prefix, properties}}, continuation) =>
+        continuation(
+          Object.fromEntries(
+            properties.map(property => [
+              `${prefix}.${property}`,
+              (object === null || object === undefined
+                ? null
+                : object[property] ?? null),
+            ]))),
+    },
+  };
+}
+
 // Gets a property from each of a list of objects (in a dependency) and
 // provides the results. This doesn't alter any list indices, so positions
 // which were null in the original list are kept null here. Objects which don't
@@ -1159,6 +1192,45 @@ export function withPropertyFromList({
   };
 }
 
+// Gets the listed properties from each of a list of objects, providing lists
+// of property values each into a dependency prefixed with the same name as the
+// list (by default). Like withPropertyFromList, this doesn't alter indices.
+export function withPropertiesFromList({
+  list,
+  properties,
+  prefix =
+    (list.startsWith('#')
+      ? list
+      : `#${list}`),
+}) {
+  return {
+    annotation: `withPropertiesFromList`,
+    flags: {expose: true, compose: true},
+
+    expose: {
+      mapDependencies: {list},
+      options: {prefix, properties},
+
+      compute({list, '#options': {prefix, properties}}, continuation) {
+        const lists =
+          Object.fromEntries(
+            properties.map(property => [`${prefix}.${property}`, []]));
+
+        for (const item of list) {
+          for (const property of properties) {
+            lists[`${prefix}.${property}`].push(
+              (item === null || item === undefined
+                ? null
+                : item[property] ?? null));
+          }
+        }
+
+        return continuation(lists);
+      }
+    }
+  }
+}
+
 // Replaces items of a list, which are null or undefined, with some fallback
 // value, either a constant (set {value}) or from a dependency ({dependency}).
 // By default, this replaces the passed dependency.
diff --git a/src/data/things/thing.js b/src/data/things/thing.js
index a87e6ed6..52f0b773 100644
--- a/src/data/things/thing.js
+++ b/src/data/things/thing.js
@@ -15,7 +15,7 @@ import {
   exposeDependency,
   exposeDependencyOrContinue,
   raiseWithoutDependency,
-  withPropertyFromList,
+  withPropertiesFromList,
   withUpdateValueAsDependency,
 } from '#composite';
 
@@ -409,21 +409,24 @@ export function withResolvedContribs({
       raise: {into: []},
     }),
 
-    withPropertyFromList({list: from, property: 'who', into: '#artistRefs'}),
-    withPropertyFromList({list: from, property: 'what', into: '#what'}),
+    withPropertiesFromList({
+      list: from,
+      properties: ['who', 'what'],
+      prefix: '#contribs',
+    }),
 
     withResolvedReferenceList({
-      list: '#artistRefs',
+      list: '#contribs.who',
       data: 'artistData',
-      into: '#who',
+      into: '#contribs.who',
       find: find.artist,
       notFoundMode: 'null',
     }),
 
     {
-      dependencies: ['#who', '#what'],
+      dependencies: ['#contribs.who', '#contribs.what'],
       mapContinuation: {into},
-      compute({'#who': who, '#what': what}, continuation) {
+      compute({'#contribs.who': who, '#contribs.what': what}, continuation) {
         filterMultipleArrays(who, what, (who, _what) => who);
         return continuation({
           into: stitchArrays({who, what}),