« 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/composite/data/withPropertyFromObject.js28
-rw-r--r--test/unit/data/composite/data/withPropertyFromObject.js84
2 files changed, 108 insertions, 4 deletions
diff --git a/src/data/composite/data/withPropertyFromObject.js b/src/data/composite/data/withPropertyFromObject.js
index b31bab15..4f240506 100644
--- a/src/data/composite/data/withPropertyFromObject.js
+++ b/src/data/composite/data/withPropertyFromObject.js
@@ -2,11 +2,15 @@
 // If the object itself is null, or the object doesn't have the listed property,
 // the provided dependency will also be null.
 //
+// If the `internal` input is true, this reads the CacheableObject update value
+// of the object rather than its exposed value.
+//
 // See also:
 //  - withPropertiesFromObject
 //  - withPropertyFromList
 //
 
+import CacheableObject from '#cacheable-object';
 import {input, templateCompositeFrom} from '#composite';
 
 export default templateCompositeFrom({
@@ -15,6 +19,7 @@ export default templateCompositeFrom({
   inputs: {
     object: input({type: 'object', acceptsNull: true}),
     property: input({type: 'string'}),
+    internal: input({type: 'boolean', defaultValue: false}),
   },
 
   outputs: ({
@@ -49,20 +54,35 @@ export default templateCompositeFrom({
 
     {
       dependencies: [
-        '#output',
         input('object'),
         input('property'),
+        input('internal'),
       ],
 
       compute: (continuation, {
-        ['#output']: output,
         [input('object')]: object,
         [input('property')]: property,
+        [input('internal')]: internal,
       }) => continuation({
-        [output]:
+        '#value':
           (object === null
             ? null
-            : object[property] ?? null),
+         : internal
+            ? CacheableObject.getUpdateValue(object, property)
+                ?? null
+            : object[property]
+                ?? null),
+      }),
+    },
+
+    {
+      dependencies: ['#output', '#value'],
+
+      compute: (continuation, {
+        ['#output']: output,
+        ['#value']: value,
+      }) => continuation({
+        [output]: value,
       }),
     },
   ],
diff --git a/test/unit/data/composite/data/withPropertyFromObject.js b/test/unit/data/composite/data/withPropertyFromObject.js
index 50ee835c..912c924c 100644
--- a/test/unit/data/composite/data/withPropertyFromObject.js
+++ b/test/unit/data/composite/data/withPropertyFromObject.js
@@ -1,6 +1,7 @@
 import t from 'tap';
 import {quickCheckCompositeOutputs} from '#test-lib';
 
+import CacheableObject from '#cacheable-object';
 import {compositeFrom, input} from '#composite';
 import {exposeDependency} from '#composite/control-flow';
 import {withPropertyFromObject} from '#composite/data';
@@ -43,6 +44,89 @@ t.test(`withPropertyFromObject: basic behavior`, t => {
   }), null);
 });
 
+t.test(`withPropertyFromObject: "internal" input`, t => {
+  t.plan(7);
+
+  const composite = compositeFrom({
+    compose: false,
+
+    steps: [
+      withPropertyFromObject({
+        object: 'object',
+        property: 'property',
+        internal: 'internal',
+      }),
+
+      exposeDependency({dependency: '#value'}),
+    ],
+  });
+
+  const thing = new (class extends CacheableObject {
+    static [CacheableObject.propertyDescriptors] = {
+      foo: {
+        flags: {update: true, expose: false},
+      },
+
+      bar: {
+        flags: {update: true, expose: true},
+      },
+
+      baz: {
+        flags: {update: true, expose: true},
+        expose: {
+          transform: baz => baz * 2,
+        },
+      },
+    };
+  });
+
+  thing.foo = 100;
+  thing.bar = 200;
+  thing.baz = 300;
+
+  t.match(composite, {
+    expose: {
+      dependencies: ['object', 'property', 'internal'],
+    },
+  });
+
+  t.equal(composite.expose.compute({
+    object: thing,
+    property: 'foo',
+    internal: true,
+  }), 100);
+
+  t.equal(composite.expose.compute({
+    object: thing,
+    property: 'bar',
+    internal: true,
+  }), 200);
+
+  t.equal(composite.expose.compute({
+    object: thing,
+    property: 'baz',
+    internal: true,
+  }), 300);
+
+  t.equal(composite.expose.compute({
+    object: thing,
+    property: 'baz',
+    internal: false,
+  }), 600);
+
+  t.equal(composite.expose.compute({
+    object: thing,
+    property: 'bimbam',
+    internal: false,
+  }), null);
+
+  t.equal(composite.expose.compute({
+    object: null,
+    property: 'bambim',
+    internal: false,
+  }), null);
+});
+
 t.test(`withPropertyFromObject: output shapes & values`, t => {
   t.plan(2 * 3 ** 2);