Repository: ViacomInc/data-point
Pull request #129 (2018-01-08 23:20:27)

feature(data-point/reducer-types): Add more reducer types via DataPoint.helpers
<!-- What changes are being made? (What feature/bug is being fixed here?) -->
**What**: #123

<!-- Why are these changes necessary? -->
**Why**: This adds more functionality to the library, but also lays the groundwork for adding more reducer types in the future (via the `ReducerStub` function).
<!-- How were these changes implemented? -->
**How**: This adds support for "reducer helpers," which are just reducers that are created with a helper function. 

```js
// the helpers are exposed through the helpers property
const { map } = DataPoint.helpers

// "map" is a reducer helper in this example
const reducer = map('$a')

dataPoint.transform(reducer, value)
```

Each helper actually returns a `ReducerStub`, which is a placeholder object that's turned into a reducer when it's passed to the `transform` function.

The reducer helpers in this PR were extracted from the hash and collection entities. This means that each of their modifier keys (like `pickKeys`, `omitKeys`, `map`, `filter`, etc) now use reducer helpers, which also simplifies their `resolve` functions because they're just using the main function for resolving reducers.

One last change is that every reducer now has the code `this[REDUCER_SYMBOL] = true`, so we have a quick way to check if an object is a reducer:

```js
function isReducer (item) {
  return !!(item && item[REDUCER_SYMBOL])
}
```

This is a big PR, but a good amount of the changes are just moving existing code from the hash and collection entities into the `reducer-helpers` directory.

<!-- Have you done all of these things?  -->
**Checklist**:
<!-- add "N/A" to the end of each line that's irrelevant to your changes -->
<!-- to check an item, place an "x" in the box like so: "- [x] Documentation" -->
- [x] Documentation
- [x] Tests
- [x] Ready to be merged <!-- In your opinion, is this ready to be merged as soon as it's reviewed? -->
  
  

coveralls: 
[![Coverage Status](https://coveralls.io/builds/14957432/badge)](https://coveralls.io/builds/14957432)

Coverage remained the same at 100.0% when pulling **ce91ee2889fed3979cc76fa14a05a7c5da67e513 on raingerber:reducer-helpers** into **15ac2f029123f231357d8bef851a8d0d680e2ac9 on ViacomInc:master**.

acatl: ![mog](https://media.giphy.com/media/3cB7aOM6347PW/giphy.gif)
coveralls: 
[![Coverage Status](https://coveralls.io/builds/14957548/badge)](https://coveralls.io/builds/14957548)

Coverage remained the same at 100.0% when pulling **250255afdb95a23a931f3e1d48ad11505c212adf on raingerber:reducer-helpers** into **15ac2f029123f231357d8bef851a8d0d680e2ac9 on ViacomInc:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/14957813/badge)](https://coveralls.io/builds/14957813)

Coverage remained the same at 100.0% when pulling **69d098b5b410ada7c9778ee4d1208f4371798987 on raingerber:reducer-helpers** into **15ac2f029123f231357d8bef851a8d0d680e2ac9 on ViacomInc:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/14965756/badge)](https://coveralls.io/builds/14965756)

Coverage remained the same at 100.0% when pulling **f702c87a51ec4af10bbc465f383f4024f9e392d8 on raingerber:reducer-helpers** into **15ac2f029123f231357d8bef851a8d0d680e2ac9 on ViacomInc:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/14967027/badge)](https://coveralls.io/builds/14967027)

Coverage remained the same at 100.0% when pulling **80d4bc81353a98c7380b10d2fcc5241f217f3a30 on raingerber:reducer-helpers** into **15ac2f029123f231357d8bef851a8d0d680e2ac9 on ViacomInc:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/14967139/badge)](https://coveralls.io/builds/14967139)

Coverage remained the same at 100.0% when pulling **666974e2c027e419af8d1409e3143ea3fbc6de20 on raingerber:reducer-helpers** into **15ac2f029123f231357d8bef851a8d0d680e2ac9 on ViacomInc:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/14973545/badge)](https://coveralls.io/builds/14973545)

Coverage remained the same at 100.0% when pulling **4932b21442413b774dbcc8274b4b34cedeecb91b on raingerber:reducer-helpers** into **15ac2f029123f231357d8bef851a8d0d680e2ac9 on ViacomInc:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/14973545/badge)](https://coveralls.io/builds/14973545)

Coverage remained the same at 100.0% when pulling **4932b21442413b774dbcc8274b4b34cedeecb91b on raingerber:reducer-helpers** into **15ac2f029123f231357d8bef851a8d0d680e2ac9 on ViacomInc:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/14973876/badge)](https://coveralls.io/builds/14973876)

Coverage remained the same at 100.0% when pulling **d47729994120f97b4784d189827ce9a5b6225326 on raingerber:reducer-helpers** into **15ac2f029123f231357d8bef851a8d0d680e2ac9 on ViacomInc:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/14985800/badge)](https://coveralls.io/builds/14985800)

Coverage remained the same at 100.0% when pulling **2306e5943562a1765523bef019998f900f1b5431 on raingerber:reducer-helpers** into **15ac2f029123f231357d8bef851a8d0d680e2ac9 on ViacomInc:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/14986160/badge)](https://coveralls.io/builds/14986160)

Coverage remained the same at 100.0% when pulling **f8b4c5de5048da1225a205f7c10a695b4b936258 on raingerber:reducer-helpers** into **15ac2f029123f231357d8bef851a8d0d680e2ac9 on ViacomInc:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/14986174/badge)](https://coveralls.io/builds/14986174)

Coverage remained the same at 100.0% when pulling **f8b4c5de5048da1225a205f7c10a695b4b936258 on raingerber:reducer-helpers** into **15ac2f029123f231357d8bef851a8d0d680e2ac9 on ViacomInc:master**.


Patch:
diff --git a/packages/data-point/README.md b/packages/data-point/README.md
index c070455..43d37b8 100644
--- a/packages/data-point/README.md
+++ b/packages/data-point/README.md
@@ -31,6 +31,11 @@ npm install --save data-point
   - [EntityReducer](#entity-reducer)
   - [ListReducer](#list-reducer)
   - [Collection Mapping](#reducer-collection-mapping)
+- [Reducer Helpers](#reducer-helpers)
+  - [assign](#reducer-assign)
+  - [map](#reducer-map)
+  - [filter](#reducer-filter)
+  - [find](#reducer-find)
 - [Entities](#entities)
   - [dataPoint.addEntities](#api-data-point-add-entities)
   - [Built-in entities](#built-in-entities)
@@ -901,8 +906,209 @@ Adding `[]` at the end of an entity reducer will map the given entity to each re
   ```
 </details>
 
+## <a name="reducer-helpers">Reducer Helpers</a>
 
-Reducer entity [Examples](test/definitions/integrations.js)
+Reducer helpers are factory functions for creating reducers. They're exposed through `DataPoint.helpers`:
+
+```js
+const {
+  assign,
+  map,
+  filter,
+  find
+} = require('data-point').helpers
+```
+
+### <a name="reducer-assign">assign</a>
+
+The **assign** reducer creates a new Object by copying the values of all enumerable own properties resulting from the provided [Reducer](#reducers) with the current accumulator value. It uses [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) internally.
+
+**SYNOPSIS**
+
+```js
+assign(reducer:Reducer):Object
+```
+
+**Reducer's arguments**
+
+| Argument | Type | Description |
+|:---|:---|:---|
+| *reducer* | [Reducer](#reducers) | Result from the provided reducer will be merged into the current accumulator.value |
+
+**EXAMPLE:**
+
+<details>
+  <summary>Add a key that references a nested value from the accumulator.</summary>
+
+  ```js
+  const {
+    assign
+  } = DataPoint.helpers
+
+  const value = {
+    a: 1
+  }
+
+  // merges the ReducerObject with
+  // accumulator.value
+  const reducer = assign({
+    c: '$b.c'
+  })
+
+  dataPoint
+    .transform(reducer, value)
+    .then(acc => {
+      /*
+       acc.value --> {
+        a: 1,
+        b: {
+          c: 2
+        },
+        c: 2
+      }
+      */
+    })
+
+  ```
+</details>
+
+Example at: [examples/reducer-assign.js](examples/reducer-assign.js)
+
+### <a name="reducer-map">map</a>
+
+The **map** reducer creates a new array with the results of applying the provided [Reducer](#reducers) to every element in the input array.
+
+**SYNOPSIS**
+
+```js
+map(reducer:Reducer):Array
+```
+
+**Reducer's arguments**
+
+| Argument | Type | Description |
+|:---|:---|:---|
+| *reducer* | [Reducer](#reducers) | The reducer will get applied to each element in the array. |
+
+**EXAMPLE:**
+
+<details>
+  <summary>Apply a set of reducers to each item in an array</summary>
+
+  ```js
+  const {
+    map
+  } = DataPoint.helpers
+
+  const value = [{
+    a: 1
+  }, {
+    a: 2
+  }]
+
+  // get path `a` then multiply by 2
+  const reducer = map(
+    ['$a', (acc) => acc.value * 2]
+  )
+
+  dataPoint
+    .transform(reducer, value)
+    .then(acc => {
+      // acc.value -> [2, 4]
+    })
+  ```
+
+</details>
+
+Example at: [examples/reducer-helper-map.js](examples/reducer-helper-map.js)
+
+### <a name="reducer-filter">filter</a>
+
+The **filter** reducer creates a new array with elements that resolve as *truthy* when passed to the given [Reducer](#reducers).
+
+**SYNOPSIS**
+
+```js
+filter(reducer:Reducer):Array
+```
+
+**Reducer's arguments**
+
+| Argument | Type | Description |
+|:---|:---|:---|
+| *reducer* | [Reducer](#reducers) | Reducer result is used to test for _truthy_ on each element of the array. |
+
+**EXAMPLE:**
+
+<details>
+  <summary>Find objects where path `a` is greater than 1</summary>
+
+  ```js
+  const {
+    map
+  } = DataPoint.helpers
+
+  const value = [{ a: 1 }, { a: 2 }]
+
+  // filters array elements that are not
+  // truthy for the given reducer list
+  const reducer = filter(
+    ['$a', (acc) => acc.value > 1]
+  )
+
+  dataPoint
+    .transform(reducer, value) 
+    .then(acc => {
+      // acc.value ->  [{ a: 2 }]
+    })  
+  ```
+</details>
+
+Example at: [examples/reducer-helper-filter.js](examples/reducer-helper-filter.js)
+
+### <a name="reducer-find">find</a>
+
+The **find** reducer returns the first element of an array that resolves to _truthy_ when passed through the provided [Reducer](#reducers). It returns `undefined` if no match is found.
+
+**SYNOPSIS**
+
+```js
+find(reducer:Reducer):*
+```
+
+**Reducer's arguments**
+
+| Argument | Type | Description |
+|:---|:---|:---|
+| *reducer* | [Reducer](#reducers) | Reducer result is used to test for _truthy_ on each element of the array. |
+
+**EXAMPLE:**
+
+<details>
+  <summary>Find elements where path `b` resolves to _truthy_ value</summary>
+
+  ```js
+  const {
+    map
+  } = DataPoint.helpers
+
+  const value = [{ a: 1 }, { b: 2 }]
+
+  // the $b reducer is truthy for the
+  // second element in the array
+  const reducer = find('$b')
+
+  dataPoint
+    .transform(reducer, value) 
+    .then(acc => {
+      // acc.value -> { b: 2 }
+    })
+  ```
+</details>
+
+Example at: [examples/reducer-helper-find.js](examples/reducer-helper-find.js)
+
+### <a name="patterns-and-best-practices">Patterns and Best Practices</a>
 
 **Best Practices (Recommendations) with reducers**
 
@@ -1665,7 +1871,7 @@ A Hash entity transforms a _Hash_ like data structure. It enables you to manipul
 
 To prevent unexpected results, **Hash** can only process **Plain Objects**, which are objects created by the Object constructor. If [Hash.value](#hash-value) does not resolve to a Plain Object it will **throw** an error. 
 
-Hash entities expose a set of reducers: [mapKeys](#hash-mapKeys), [omitKeys](#hash-omitKeys), [pickKeys](#hash-pickKeys), [addKeys](#hash-addKeys), [addValues](#hash-addValues). You may apply one or more of these available reducers to a Hash entity. Keep in mind that those reducers will always be executed in a specific order:
+Hash entities expose a set of reducers: [mapKeys](#hash-mapKeys), [omitKeys](#hash-omitKeys), [pickKeys](#hash-pickKeys), [addKeys](#hash-addKeys), [addValues](#hash-addValues). You may apply one or more of these reducers to a Hash entity. Keep in mind that those reducers will always be executed in a specific order:
 
 ```js
 omitKeys -> pickKeys -> mapKeys -> addValues -> addKeys
@@ -1689,7 +1895,7 @@ dataPoint.addEntities({
     addKeys: TransformMap,
     addValues: Object,
     compose: ComposeReducer[],
-    
+
     after: Reducer,
     error: Reducer,
     params: Object,
@@ -1702,11 +1908,11 @@ dataPoint.addEntities({
 | Key | Type | Description |
 |:---|:---|:---|
 | *value* | [Reducer](#reducers) | The value to which the Entity resolves |
-| *mapKeys* | [TransformMap](#transform-map) | Map to a new set of key/values. Each value accepts a transform |
-| *omitKeys* | `String[]` | Omits keys from acc.value (Array of strings) |
-| *pickKeys* | `String[]` | Picks keys from acc.value (Array of strings) |
-| *addKeys* | [TransformMap](#transform-map) | Add/Override key/values. Each value accepts a transform |
-| *addValues* | `Object` | Add/Override hard-coded key/values |
+| *mapKeys* | [ObjectReducer](#object-reducer) | Map to a new set of key/values. Each value accepts a reducer |
+| *omitKeys* | `String[]` | Omits keys from acc.value. Internally, this uses the [omit](#reducer-omit) reducer helper |
+| *pickKeys* | `String[]` | Picks keys from acc.value. Internally, this uses the [pick](#reducer-pick) reducer helper |
+| *addKeys* | [ObjectReducer](#object-reducer) | Add/Override key/values. Each value accepts a reducer. Internally, this uses the [assign](#reducer-assign) reducer helper |
+| *addValues* | `Object` | Add/Override hard-coded key/values. Internally, this uses the [assign](#reducer-assign) reducer helper |
 | *compose* | [ComposeReducer](#compose-reducer)`[]` | Modify the value of accumulator through an Array of `ComposeReducer` objects. Think of it as a [Compose/Flow Operation](https://en.wikipedia.org/wiki/Function_composition_(computer_science)), where the result of one operation gets passed to the next one|
 | *before*  | [Reducer](#reducers) | reducer to be resolved **before** the entity resolution |
 | *after*   | [Reducer](#reducers) | reducer to be resolved **after** the entity resolution |
@@ -1750,7 +1956,7 @@ Example at: [examples/entity-hash-context.js](examples/entity-hash-context.js)
 
 ##### <a name="hash-mapKeys">Hash.mapKeys</a>
 
-Maps to a new set of key/value pairs through a [TransformMap](#transform-map), where each value is a [Reducer](#reducers).
+Maps to a new set of key/value pairs through a [ObjectReducer](#object-reducer), where each value is a [Reducer](#reducers).
 
 Going back to our GitHub API examples, let's map some keys from the result of a request:
 
@@ -1792,20 +1998,6 @@ Going back to our GitHub API examples, let's map some keys from the result of a
 
 Example at: [examples/entity-hash-mapKeys.js](examples/entity-hash-mapKeys.js)
 
-###### <a name="transform-map">TransformMap</a>
-
-This structure allows you to map key/value pairs, where each value is a [Reducer](#reducers).
-
-**SYNOPSIS**
-
-```js
-{
-  key1: Reducer,
-  key2: Reducer,
-  ...
-}
-```
-
 ##### <a name="hash-addKeys">Hash.addKeys</a>
 
 Adds keys to the current Hash value. If an added key already exists, it will be overridden. 
@@ -2113,7 +2305,7 @@ dataPoint.addEntities({
     map: Reducer,
     find: Reducer,
     compose: ComposeReducer[],
-    
+
     after: Reducer,
     error: Reducer,
     params: Object,
@@ -2127,9 +2319,9 @@ dataPoint.addEntities({
 |:---|:---|:---|
 | *before*  | [Reducer](#reducers) | reducer to be resolved **before** the entity resolution |
 | *value* | [Reducer](#reducers) | The value to which the Entity resolves |
-| *map* | [Reducer](#reducers) | Maps the items of an array. **NOTE**: this operation happens asynchronously, so be careful to use it only when async operation is needed; otherwise, use a synchronous equivalent (native array filter or third party solution) |
-| *find* | [Reducer](#reducers) | Find an item in the array. **NOTE**: this operation happens asynchronously, so be careful to use it only when async operation is needed; otherwise, use a synchronous equivalent (native array filter or third party solution) |
-| *filter* | [Reducer](#reducers) | Filters the items of an array. **NOTE**: this operation happens asynchronously, so be careful to use it only when async operation is needed; otherwise, use a synchronous equivalent (native array filter or third party solution) |
+| *map* | [Reducer](#reducers) | Maps the items of an array. Internally, this uses the [map](#reducer-map) reducer helper |
+| *find* | [Reducer](#reducers) | Find an item in the array. Internally, this uses the [find](#reducer-find) reducer helper |
+| *filter* | [Reducer](#reducers) | Filters the items of an array. Internally, this uses the [filter](#reducer-filter) reducer helper |
 | *compose* | [ComposeReducer](#compose-reducer)`[]` | Modify the value of accumulator through an Array of `ComposeReducer` objects. Think of it as a [Compose/Flow Operation](https://en.wikipedia.org/wiki/Function_composition_(computer_science)), where the result of one object gets passed to the next one |
 | *after* | [Reducer](#reducers) | reducer to be resolved **after** the entity resolution |
 | *error* | [Reducer](#reducers) | reducer to be resolved in case of an error |
diff --git a/packages/data-point/examples/reducer-helper-assign.js b/packages/data-point/examples/reducer-helper-assign.js
new file mode 100644
index 0000000..b1bb7ad
--- /dev/null
+++ b/packages/data-point/examples/reducer-helper-assign.js
@@ -0,0 +1,30 @@
+/* eslint-env jest */
+const assert = require('assert')
+
+const DataPoint = require('../')
+const dataPoint = DataPoint.create()
+
+const { assign } = DataPoint.helpers
+
+const value = {
+  a: 1,
+  b: {
+    c: 2
+  }
+}
+
+// merges the ReducerObject with
+// the result with accumulator.value
+const reducer = assign({
+  c: '$b.c'
+})
+
+dataPoint.transform(reducer, value).then(acc => {
+  assert.deepEqual(acc.value, {
+    a: 1,
+    b: {
+      c: 2
+    },
+    c: 2
+  })
+})
diff --git a/packages/data-point/examples/reducer-helper-filter.js b/packages/data-point/examples/reducer-helper-filter.js
new file mode 100644
index 0000000..20c20a8
--- /dev/null
+++ b/packages/data-point/examples/reducer-helper-filter.js
@@ -0,0 +1,24 @@
+/* eslint-env jest */
+const assert = require('assert')
+
+const DataPoint = require('../')
+const dataPoint = DataPoint.create()
+
+const { filter } = DataPoint.helpers
+
+const value = [
+  {
+    a: 1
+  },
+  {
+    a: 2
+  }
+]
+
+// filters array elements that are not
+// truthy for the given reducer list
+const reducer = filter(['$a', acc => acc.value > 1])
+
+dataPoint.transform(reducer, value).then(acc => {
+  assert.deepEqual(acc.value, [{ a: 2 }])
+})
diff --git a/packages/data-point/examples/reducer-helper-find.js b/packages/data-point/examples/reducer-helper-find.js
new file mode 100644
index 0000000..939d4f8
--- /dev/null
+++ b/packages/data-point/examples/reducer-helper-find.js
@@ -0,0 +1,26 @@
+/* eslint-env jest */
+const assert = require('assert')
+
+const DataPoint = require('../')
+const dataPoint = DataPoint.create()
+
+const { find } = DataPoint.helpers
+
+const value = [
+  {
+    a: 1
+  },
+  {
+    b: 2
+  }
+]
+
+// the $b reducer is truthy for the
+// second element in the array
+const reducer = find('$b')
+
+dataPoint.transform(reducer, value).then(acc => {
+  assert.deepEqual(acc.value, {
+    b: 2
+  })
+})
diff --git a/packages/data-point/examples/reducer-helper-map.js b/packages/data-point/examples/reducer-helper-map.js
new file mode 100644
index 0000000..255ec5f
--- /dev/null
+++ b/packages/data-point/examples/reducer-helper-map.js
@@ -0,0 +1,24 @@
+/* eslint-env jest */
+const assert = require('assert')
+
+const DataPoint = require('../')
+const dataPoint = DataPoint.create()
+
+const { map } = DataPoint.helpers
+
+const value = [
+  {
+    a: 1
+  },
+  {
+    a: 2
+  }
+]
+
+// applies the $a reducer to each
+// item in the array
+const reducer = map(['$a', acc => acc.value * 2])
+
+dataPoint.transform(reducer, value).then(acc => {
+  assert.deepEqual(acc.value, [2, 4])
+})
diff --git a/packages/data-point/lib/entity-types/entity-collection/factory.js b/packages/data-point/lib/entity-types/entity-collection/factory.js
index 6ec6ade..c40a6f6 100644
--- a/packages/data-point/lib/entity-types/entity-collection/factory.js
+++ b/packages/data-point/lib/entity-types/entity-collection/factory.js
@@ -1,9 +1,9 @@
 'use strict'
 
-const _ = require('lodash')
 const parseCompose = require('../parse-compose')
 const createReducer = require('../../reducer-types').create
 const createBaseEntity = require('../base-entity').create
+const reducerHelpers = require('../../reducer-types/reducer-helpers')
 
 /**
  * @class
@@ -14,17 +14,28 @@ module.exports.EntityCollection = EntityCollection
 
 const modifierKeys = ['filter', 'map', 'find']
 
-function createCompose (composeParse) {
-  return composeParse.map(modifier => {
-    return _.assign({}, modifier, {
-      reducer: createReducer(modifier.spec)
-    })
+const modifiers = {
+  filter: reducerHelpers.stubFactories.filter,
+  find: reducerHelpers.stubFactories.find,
+  map: reducerHelpers.stubFactories.map
+}
+
+/**
+ * @param {Array<Object>} composeSpec
+ * @return {Array<Object>}
+ */
+function createCompose (composeSpec) {
+  const stubs = composeSpec.map(modifier => {
+    const factory = modifiers[modifier.type]
+    return factory(modifier.spec)
   })
+
+  return createReducer(stubs)
 }
 
 /**
  * Creates new Entity Object
- * @param  {Object} spec - spec
+ * @param {Object} spec - spec
  * @param {string} id - Entity id
  * @return {EntityCollection} Entity Object
  */
@@ -33,9 +44,10 @@ function create (spec, id) {
 
   const entity = createBaseEntity(EntityCollection, spec, id)
 
-  const compose = parseCompose.parse(spec, modifierKeys)
-  parseCompose.validateCompose(entity.id, compose, modifierKeys)
-  entity.compose = createCompose(compose)
+  const composeSpec = parseCompose.parse(spec, modifierKeys)
+  parseCompose.validateCompose(entity.id, composeSpec, modifierKeys)
+
+  entity.compose = createCompose(composeSpec)
 
   return Object.freeze(entity)
 }
diff --git a/packages/data-point/lib/entity-types/entity-collection/resolve.js b/packages/data-point/lib/entity-types/entity-collection/resolve.js
index 05874e1..6de816d 100644
--- a/packages/data-point/lib/entity-types/entity-collection/resolve.js
+++ b/packages/data-point/lib/entity-types/entity-collection/resolve.js
@@ -1,93 +1,22 @@
 'use strict'
 
-const _ = require('lodash')
-const Promise = require('bluebird')
-const utils = require('../../utils')
 const Util = require('util')
+const Promise = require('bluebird')
+const _ = require('lodash')
 
-function resolveMapReducer (accumulator, reducer, resolveReducer) {
-  if (utils.reducerIsEmpty(reducer)) {
-    return Promise.resolve(accumulator)
-  }
-  return Promise.map(accumulator.value, itemValue => {
-    const itemContext = utils.set(accumulator, 'value', itemValue)
-    return resolveReducer(itemContext, reducer).then(res => {
-      return res.value
-    })
-  })
-    .then(result => utils.set(accumulator, 'value', result))
-    .catch(err => {
-      err.message = `Entity: ${accumulator.reducer.spec.id}.map ${err.message}`
-      throw err
-    })
-}
-
-function resolveFilterReducer (accumulator, reducer, resolveReducer) {
-  if (utils.reducerIsEmpty(reducer)) {
-    return Promise.resolve(accumulator)
-  }
-  return Promise.filter(accumulator.value, itemValue => {
-    const itemContext = utils.set(accumulator, 'value', itemValue)
-    return resolveReducer(itemContext, reducer).then(res => {
-      return !!res.value
-    })
-  })
-    .then(result => utils.set(accumulator, 'value', result))
-    .catch(err => {
-      err.message = `Entity: ${accumulator.reducer.spec.id}.filter ${
-        err.message
-      }`
-      throw err
-    })
-}
-
-function resolveFindReducer (accumulator, reducer, resolveReducer) {
-  if (utils.reducerIsEmpty(reducer)) {
-    return Promise.resolve(accumulator)
-  }
-  return Promise.reduce(
-    accumulator.value,
-    (result, itemValue) => {
-      const itemContext = utils.set(accumulator, 'value', itemValue)
-      return (
-        result ||
-        resolveReducer(itemContext, reducer).then(res => {
-          return res.value ? itemValue : undefined
-        })
-      )
-    },
-    null
-  )
-    .then(result => utils.set(accumulator, 'value', result))
-    .catch(err => {
-      err.message = `Entity: ${accumulator.reducer.spec.id}.find ${err.message}`
-      throw err
-    })
-}
-
-const modifierFunctionMap = {
-  filter: resolveFilterReducer,
-  map: resolveMapReducer,
-  find: resolveFindReducer
-}
+const utils = require('../../utils')
 
-function resolveCompose (accumulator, composeReducers, resolveReducer) {
-  if (composeReducers.length === 0) {
+/**
+ * @param {Accumulator} accumulator
+ * @param {reducer} composeReducer
+ * @param {Function} resolveReducer
+ */
+function resolveCompose (accumulator, composeReducer, resolveReducer) {
+  if (utils.reducerIsEmpty(composeReducer)) {
     return Promise.resolve(accumulator)
   }
 
-  return Promise.reduce(
-    composeReducers,
-    (resultContext, modifierSpec) => {
-      const modifierFunction = modifierFunctionMap[modifierSpec.type]
-      return modifierFunction(
-        resultContext,
-        modifierSpec.reducer,
-        resolveReducer
-      )
-    },
-    accumulator
-  )
+  return resolveReducer(accumulator, composeReducer)
 }
 
 // NOTE: as expensive as this might be, this is to avoid 'surprises'
@@ -110,6 +39,10 @@ function validateAsArray (acc) {
     )
 }
 
+/**
+ * @param {Accumulator} accumulator
+ * @param {Function} resolveReducer
+ */
 function resolve (accumulator, resolveReducer) {
   const entity = accumulator.reducer.spec
 
diff --git a/packages/data-point/lib/entity-types/entity-hash/factory.js b/packages/data-point/lib/entity-types/entity-hash/factory.js
index 1a56330..7713f18 100644
--- a/packages/data-point/lib/entity-types/entity-hash/factory.js
+++ b/packages/data-point/lib/entity-types/entity-hash/factory.js
@@ -1,9 +1,10 @@
 'use strict'
 
-const _ = require('lodash')
 const createReducer = require('../../reducer-types').create
-const createReducerObject = require('../../reducer-types/reducer-object').create
 const deepFreeze = require('deep-freeze')
+const constant = require('lodash/constant')
+const defaultTo = require('lodash/defaultTo')
+const reducerHelpers = require('../../reducer-types/reducer-helpers')
 const parseCompose = require('../parse-compose')
 const createBaseEntity = require('../base-entity').create
 
@@ -16,29 +17,39 @@ module.exports.EntityHash = EntityHash
 
 const modifierKeys = ['omitKeys', 'pickKeys', 'mapKeys', 'addValues', 'addKeys']
 
+const modifiers = {
+  omit: reducerHelpers.stubFactories.omit,
+  pick: reducerHelpers.stubFactories.pick,
+  map: reducerHelpers.stubFactories.map,
+  assign: reducerHelpers.stubFactories.assign
+}
+
 function createCompose (composeParse) {
-  return composeParse.map(modifier => {
+  const specList = composeParse.map(modifier => {
     let spec
-    let reducer
     switch (modifier.type) {
-      case 'addValues':
-        spec = _.defaultTo(modifier.spec, {})
-        reducer = deepFreeze(spec)
-        break
       case 'omitKeys':
+        spec = modifiers.omit(modifier.spec)
+        break
       case 'pickKeys':
-        spec = _.defaultTo(modifier.spec, [])
-        reducer = Object.freeze(spec.slice(0))
+        spec = modifiers.pick(modifier.spec)
         break
       case 'mapKeys':
+        spec = modifier.spec
+        break
+      case 'addValues':
+        const values = deepFreeze(defaultTo(modifier.spec, {}))
+        spec = modifiers.assign(constant(values))
+        break
       case 'addKeys':
-        reducer = createReducerObject(createReducer, modifier.spec)
+        spec = modifiers.assign(modifier.spec)
+        break
     }
 
-    return Object.assign({}, modifier, {
-      reducer
-    })
+    return spec
   })
+
+  return createReducer(specList)
 }
 
 /**
diff --git a/packages/data-point/lib/entity-types/entity-hash/resolve.js b/packages/data-point/lib/entity-types/entity-hash/resolve.js
index 45fa4bd..bcfbc21 100644
--- a/packages/data-point/lib/entity-types/entity-hash/resolve.js
+++ b/packages/data-point/lib/entity-types/entity-hash/resolve.js
@@ -5,55 +5,19 @@ const Promise = require('bluebird')
 const utils = require('../../utils')
 const Util = require('util')
 
-function resolveMapKeys (accumulator, reducer, resolveReducer) {
-  return resolveReducer(accumulator, reducer).then(acc => {
-    return utils.set(accumulator, 'value', acc.value)
-  })
-}
-
-module.exports.resolveMapKeys = resolveMapKeys
-
-function resolveAddKeys (accumulator, reducer, resolveReducer) {
-  return resolveReducer(accumulator, reducer).then(acc => {
-    return resolveAddValues(accumulator, acc.value)
-  })
-}
-
-module.exports.resolveAddKeys = resolveAddKeys
-
-function resolveAddValues (accumulator, modelValues) {
-  if (Object.keys(modelValues).length === 0) {
+/**
+ * @param {Accumulator} accumulator
+ * @param {reducer} composeReducer
+ * @param {Function} resolveReducer
+ */
+function resolveCompose (accumulator, composeReducer, resolveReducer) {
+  if (utils.reducerIsEmpty(composeReducer)) {
     return Promise.resolve(accumulator)
   }
-  const value = _.assign({}, accumulator.value, modelValues)
-  const resolvedReducer = utils.set(accumulator, 'value', value)
-  return Promise.resolve(resolvedReducer)
-}
-
-module.exports.resolveAddValues = resolveAddValues
-
-function resolveOmitKeys (accumulator, modelOmit) {
-  if (modelOmit.length === 0) {
-    return Promise.resolve(accumulator)
-  }
-  const value = _.omit(accumulator.value, modelOmit)
-  const resolvedReducer = utils.set(accumulator, 'value', value)
-  return Promise.resolve(resolvedReducer)
-}
-
-module.exports.resolveOmitKeys = resolveOmitKeys
 
-function resolvePickKeys (accumulator, modelPick) {
-  if (modelPick.length === 0) {
-    return Promise.resolve(accumulator)
-  }
-  const value = _.pick(accumulator.value, modelPick)
-  const resolvedReducer = utils.set(accumulator, 'value', value)
-  return Promise.resolve(resolvedReducer)
+  return resolveReducer(accumulator, composeReducer)
 }
 
-module.exports.resolvePickKeys = resolvePickKeys
-
 // NOTE: as expensive as this might be, this is to avoid 'surprises'
 function validateAsObject (acc) {
   const entity = acc.reducer.spec
@@ -75,38 +39,15 @@ function validateAsObject (acc) {
   )
 }
 
-const modifierFunctionMap = {
-  omitKeys: resolveOmitKeys,
-  pickKeys: resolvePickKeys,
-  mapKeys: resolveMapKeys,
-  addValues: resolveAddValues,
-  addKeys: resolveAddKeys
-}
-
-function resolveCompose (accumulator, composeReducers, resolveReducer) {
-  if (composeReducers.length === 0) {
-    return Promise.resolve(accumulator)
-  }
-
-  return Promise.reduce(
-    composeReducers,
-    (resultContext, modifierSpec) => {
-      const modifierFunction = modifierFunctionMap[modifierSpec.type]
-      return modifierFunction(
-        resultContext,
-        modifierSpec.reducer,
-        resolveReducer
-      )
-    },
-    accumulator
-  )
-}
-
-function resolve (acc, resolveReducer) {
-  const entity = acc.reducer.spec
+/**
+ * @param {Accumulator} accumulator
+ * @param {Function} resolveReducer
+ */
+function resolve (accumulator, resolveReducer) {
+  const entity = accumulator.reducer.spec
 
-  return resolveReducer(acc, entity.value)
-    .then(itemContext => validateAsObject(itemContext))
+  return resolveReducer(accumulator, entity.value)
+    .then(validateAsObject)
     .then(acc => resolveCompose(acc, entity.compose, resolveReducer))
 }
 
diff --git a/packages/data-point/lib/entity-types/parse-compose/parse-compose.js b/packages/data-point/lib/entity-types/parse-compose/parse-compose.js
index f291918..f634dfe 100644
--- a/packages/data-point/lib/entity-types/parse-compose/parse-compose.js
+++ b/packages/data-point/lib/entity-types/parse-compose/parse-compose.js
@@ -77,6 +77,7 @@ module.exports.createComposeReducer = createComposeReducer
 
 /**
  * @param {Object} modifierSpec
+ * @throws if the spec does not contain exactly one key
  * @returns {Object}
  */
 function parseModifierSpec (modifierSpec) {
diff --git a/packages/data-point/lib/helpers/helpers.js b/packages/data-point/lib/helpers/helpers.js
index b6c74e2..ae73620 100644
--- a/packages/data-point/lib/helpers/helpers.js
+++ b/packages/data-point/lib/helpers/helpers.js
@@ -5,14 +5,9 @@ const Promise = require('bluebird')
 const resolveReducer = require('../reducer-types').resolve
 const AccumulatorFactory = require('../accumulator/factory')
 
-const ReducerEntity = require('../reducer-types/reducer-entity/factory')
-  .ReducerEntity
-const ReducerFunction = require('../reducer-types/reducer-function/factory')
-  .ReducerFunction
-const ReducerList = require('../reducer-types/reducer-list/factory').ReducerList
-const ReducerObject = require('../reducer-types/reducer-object/factory')
-  .ReducerObject
-const ReducerPath = require('../reducer-types/reducer-path/factory').ReducerPath
+module.exports.helpers = require('../reducer-types/reducer-helpers').stubFactories
+
+module.exports.isReducer = require('../reducer-types').isReducer
 
 module.exports.createReducer = require('../reducer-types').create
 
@@ -71,19 +66,3 @@ function createReducerResolver (dataPoint) {
 }
 
 module.exports.createReducerResolver = createReducerResolver
-
-/**
- * @param {*} data
- * @returns {boolean}
- */
-function isReducer (data) {
-  return (
-    data instanceof ReducerEntity ||
-    data instanceof ReducerFunction ||
-    data instanceof ReducerList ||
-    data instanceof ReducerObject ||
-    data instanceof ReducerPath
-  )
-}
-
-module.exports.isReducer = isReducer
diff --git a/packages/data-point/lib/reducer-types/factory.js b/packages/data-point/lib/reducer-types/factory.js
index 3ff00bc..323fc85 100644
--- a/packages/data-point/lib/reducer-types/factory.js
+++ b/packages/data-point/lib/reducer-types/factory.js
@@ -3,8 +3,11 @@
 const _ = require('lodash')
 const util = require('util')
 
+const REDUCER_SYMBOL = require('./reducer-symbol')
+
 const ReducerEntity = require('./reducer-entity')
 const ReducerFunction = require('./reducer-function')
+const ReducerHelpers = require('./reducer-helpers')
 const ReducerList = require('./reducer-list')
 const ReducerObject = require('./reducer-object')
 const ReducerPath = require('./reducer-path')
@@ -12,11 +15,22 @@ const ReducerPath = require('./reducer-path')
 const reducerTypes = [
   ReducerEntity,
   ReducerFunction,
+  ReducerHelpers,
   ReducerList,
   ReducerObject,
   ReducerPath
 ]
 
+/**
+ * @param {*} item
+ * @returns {boolean}
+ */
+function isReducer (item) {
+  return !!(item && item[REDUCER_SYMBOL])
+}
+
+module.exports.isReducer = isReducer
+
 /**
  * this is here because ReducerLists can be arrays or | separated strings
  * @param {*} source
@@ -40,7 +54,7 @@ function dealWithPipeOperators (source) {
  */
 function createReducer (source) {
   source = dealWithPipeOperators(source)
-  const reducer = _.find(reducerTypes, r => r.isType(source))
+  const reducer = reducerTypes.find(r => r.isType(source))
 
   if (_.isUndefined(reducer)) {
     const message = [
diff --git a/packages/data-point/lib/reducer-types/index.js b/packages/data-point/lib/reducer-types/index.js
index 8de7fdf..35db237 100644
--- a/packages/data-point/lib/reducer-types/index.js
+++ b/packages/data-point/lib/reducer-types/index.js
@@ -2,5 +2,6 @@
 
 module.exports = {
   create: require('./factory').create,
+  isReducer: require('./factory').isReducer,
   resolve: require('./resolve').resolve
 }
diff --git a/packages/data-point/lib/reducer-types/reducer-entity/factory.js b/packages/data-point/lib/reducer-types/reducer-entity/factory.js
index 5de6d86..933a486 100644
--- a/packages/data-point/lib/reducer-types/reducer-entity/factory.js
+++ b/packages/data-point/lib/reducer-types/reducer-entity/factory.js
@@ -2,6 +2,8 @@
 
 const _ = require('lodash')
 
+const REDUCER_SYMBOL = require('../reducer-symbol')
+
 const REDUCER_ENTITY = 'ReducerEntity'
 
 module.exports.type = REDUCER_ENTITY
@@ -14,6 +16,7 @@ module.exports.type = REDUCER_ENTITY
  * @property {string} entityType - type of entity
  */
 function ReducerEntity () {
+  this[REDUCER_SYMBOL] = true
   this.type = REDUCER_ENTITY
   this.name = ''
   this.entityType = null
diff --git a/packages/data-point/lib/reducer-types/reducer-function/factory.js b/packages/data-point/lib/reducer-types/reducer-function/factory.js
index 34aa18b..2b34ffb 100644
--- a/packages/data-point/lib/reducer-types/reducer-function/factory.js
+++ b/packages/data-point/lib/reducer-types/reducer-function/factory.js
@@ -2,6 +2,8 @@
 
 const _ = require('lodash')
 
+const REDUCER_SYMBOL = require('../reducer-symbol')
+
 const REDUCER_FUNCTION = 'ReducerFunction'
 
 module.exports.type = REDUCER_FUNCTION
@@ -15,6 +17,7 @@ module.exports.type = REDUCER_FUNCTION
  * @property {Function} body - actual function body
  */
 function ReducerFunction () {
+  this[REDUCER_SYMBOL] = true
   this.type = REDUCER_FUNCTION
   this.body = undefined
 }
diff --git a/packages/data-point/lib/reducer-types/reducer-function/resolve.js b/packages/data-point/lib/reducer-types/reducer-function/resolve.js
index 0608df6..d744825 100644
--- a/packages/data-point/lib/reducer-types/reducer-function/resolve.js
+++ b/packages/data-point/lib/reducer-types/reducer-function/resolve.js
@@ -7,7 +7,7 @@ const utils = require('../../utils')
  * @param {Object} manager
  * @param {Function} resolveReducer
  * @param {Accumulator} accumulator
- * @param {ReducerFunction} reducer
+ * @param {ReducerObject} reducer
  * @returns {Promise<Accumulator>}
  */
 function resolve (manager, resolveReducer, accumulator, reducer) {
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/index.js b/packages/data-point/lib/reducer-types/reducer-helpers/index.js
new file mode 100644
index 0000000..2b0076f
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/index.js
@@ -0,0 +1,67 @@
+const createStub = require('./reducer-stub').create
+
+const reducerAssign = require('./reducer-assign')
+const reducerFilter = require('./reducer-filter')
+const reducerFind = require('./reducer-find')
+const reducerMap = require('./reducer-map')
+const reducerOmit = require('./reducer-omit')
+const reducerPick = require('./reducer-pick')
+
+/*
+"Reducer helpers" are functions that create reducers.
+
+They generate a ReducerStub, which is a temporary
+object that is later used to generate a reducer:
+
+// first, the user creates a ReducerStub
+
+const reducer = ReducerStub('filter', '$a.b')
+
+// then, when the stub is passed to transform,
+// it will be used to generate a reducer object
+
+dp.transform(reducer, data)
+
+The helpers exposed on DataPoint are the ReducerStub
+function bound to a string identifier using bindStubFunction
+*/
+
+module.exports.isType = require('./reducer-stub').isType
+
+const reducers = {
+  [reducerAssign.type]: reducerAssign,
+  [reducerFilter.type]: reducerFilter,
+  [reducerFind.type]: reducerFind,
+  [reducerMap.type]: reducerMap,
+  [reducerOmit.type]: reducerOmit,
+  [reducerPick.type]: reducerPick
+}
+
+module.exports.reducers = reducers
+
+function bindStubFunction (reducerType) {
+  return createStub.bind(null, reducerType)
+}
+
+const stubFactories = {
+  [reducerAssign.name]: bindStubFunction(reducerAssign.type),
+  [reducerFilter.name]: bindStubFunction(reducerFilter.type),
+  [reducerFind.name]: bindStubFunction(reducerFind.type),
+  [reducerMap.name]: bindStubFunction(reducerMap.type),
+  [reducerOmit.name]: bindStubFunction(reducerOmit.type),
+  [reducerPick.name]: bindStubFunction(reducerPick.type)
+}
+
+module.exports.stubFactories = stubFactories
+
+/**
+ * @param {Function} createReducer
+ * @param {ReducerStub} stub
+ * @returns {reducer}
+ */
+function createFromStub (createReducer, stub) {
+  const args = [createReducer].concat(stub.args)
+  return reducers[stub.type].create.apply(null, args)
+}
+
+module.exports.create = createFromStub
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-assign/factory.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-assign/factory.js
new file mode 100644
index 0000000..251e3a0
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-assign/factory.js
@@ -0,0 +1,35 @@
+const REDUCER_SYMBOL = require('../../reducer-symbol')
+
+const REDUCER_ASSIGN = 'ReducerAssign'
+
+module.exports.type = REDUCER_ASSIGN
+
+const HELPER_NAME = 'assign'
+
+module.exports.name = HELPER_NAME
+
+/**
+ * @class
+ * @property {string} type
+ * @property {reducer} reducer
+ */
+function ReducerAssign () {
+  this[REDUCER_SYMBOL] = true
+  this.type = REDUCER_ASSIGN
+  this.reducer = undefined
+}
+
+module.exports.ReducerAssign = ReducerAssign
+
+/**
+ * @param {Function} createReducer
+ * @param {*} source - raw source for a reducer
+ * @return {ReducerAssign}
+ */
+function create (createReducer, source) {
+  const reducer = new ReducerAssign()
+  reducer.reducer = createReducer(source)
+  return reducer
+}
+
+module.exports.create = create
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-assign/index.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-assign/index.js
new file mode 100644
index 0000000..fafee9c
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-assign/index.js
@@ -0,0 +1,9 @@
+const factory = require('./factory')
+const resolve = require('./resolve').resolve
+
+module.exports = {
+  create: factory.create,
+  type: factory.type,
+  name: factory.name,
+  resolve: resolve
+}
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-assign/resolve.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-assign/resolve.js
new file mode 100644
index 0000000..94762e2
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-assign/resolve.js
@@ -0,0 +1,18 @@
+const utils = require('../../../utils')
+
+/**
+ * @param {Object} manager
+ * @param {Function} resolveReducer
+ * @param {Accumulator} accumulator
+ * @param {ReducerAssign} reducerAssign
+ * @returns {Promise<Accumulator>}
+ */
+function resolve (manager, resolveReducer, accumulator, reducerAssign) {
+  const reducer = reducerAssign.reducer
+  return resolveReducer(manager, accumulator, reducer).then(acc => {
+    const value = Object.assign({}, accumulator.value, acc.value)
+    return utils.set(accumulator, 'value', value)
+  })
+}
+
+module.exports.resolve = resolve
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-filter/factory.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-filter/factory.js
new file mode 100644
index 0000000..300690a
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-filter/factory.js
@@ -0,0 +1,35 @@
+const REDUCER_SYMBOL = require('../../reducer-symbol')
+
+const REDUCER_FILTER = 'ReducerFilter'
+
+module.exports.type = REDUCER_FILTER
+
+const HELPER_NAME = 'filter'
+
+module.exports.name = HELPER_NAME
+
+/**
+ * @class
+ * @property {string} type
+ * @property {reducer} transform
+ */
+function ReducerFilter () {
+  this[REDUCER_SYMBOL] = true
+  this.type = REDUCER_FILTER
+  this.transform = undefined
+}
+
+module.exports.ReducerFilter = ReducerFilter
+
+/**
+ * @param {Function} createReducer
+ * @param {*} source - raw source for a reducer
+ * @return {ReducerFilter}
+ */
+function create (createReducer, source) {
+  const reducer = new ReducerFilter()
+  reducer.reducer = createReducer(source)
+  return reducer
+}
+
+module.exports.create = create
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-filter/index.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-filter/index.js
new file mode 100644
index 0000000..fafee9c
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-filter/index.js
@@ -0,0 +1,9 @@
+const factory = require('./factory')
+const resolve = require('./resolve').resolve
+
+module.exports = {
+  create: factory.create,
+  type: factory.type,
+  name: factory.name,
+  resolve: resolve
+}
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-filter/resolve.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-filter/resolve.js
new file mode 100644
index 0000000..cc0f5d6
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-filter/resolve.js
@@ -0,0 +1,25 @@
+const Promise = require('bluebird')
+const utils = require('../../../utils')
+
+/**
+ * @param {Object} manager
+ * @param {Function} resolveReducer
+ * @param {Accumulator} accumulator
+ * @param {ReducerFilter} reducerFilter
+ * @returns {Promise<Accumulator>}
+ */
+function resolve (manager, resolveReducer, accumulator, reducerFilter) {
+  const reducer = reducerFilter.reducer
+  if (utils.reducerIsEmpty(reducer)) {
+    return Promise.resolve(accumulator)
+  }
+
+  return Promise.filter(accumulator.value, itemValue => {
+    const itemContext = utils.set(accumulator, 'value', itemValue)
+    return resolveReducer(manager, itemContext, reducer).then(res => {
+      return !!res.value
+    })
+  }).then(result => utils.set(accumulator, 'value', result))
+}
+
+module.exports.resolve = resolve
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-find/factory.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-find/factory.js
new file mode 100644
index 0000000..d98e7c8
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-find/factory.js
@@ -0,0 +1,35 @@
+const REDUCER_SYMBOL = require('../../reducer-symbol')
+
+const REDUCER_FIND = 'ReducerFind'
+
+module.exports.type = REDUCER_FIND
+
+const HELPER_NAME = 'find'
+
+module.exports.name = HELPER_NAME
+
+/**
+ * @class
+ * @property {string} type
+ * @property {reducer} reducer
+ */
+function ReducerFind () {
+  this[REDUCER_SYMBOL] = true
+  this.type = REDUCER_FIND
+  this.reducer = undefined
+}
+
+module.exports.ReducerFind = ReducerFind
+
+/**
+ * @param {Function} createReducer
+ * @param {*} source - raw source for a reducer
+ * @return {ReducerFind}
+ */
+function create (createReducer, source) {
+  const reducer = new ReducerFind()
+  reducer.reducer = createReducer(source)
+  return reducer
+}
+
+module.exports.create = create
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-find/index.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-find/index.js
new file mode 100644
index 0000000..fafee9c
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-find/index.js
@@ -0,0 +1,9 @@
+const factory = require('./factory')
+const resolve = require('./resolve').resolve
+
+module.exports = {
+  create: factory.create,
+  type: factory.type,
+  name: factory.name,
+  resolve: resolve
+}
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-find/resolve.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-find/resolve.js
new file mode 100644
index 0000000..8c72c48
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-find/resolve.js
@@ -0,0 +1,32 @@
+const Promise = require('bluebird')
+const utils = require('../../../utils')
+
+/**
+ * @param {Object} manager
+ * @param {Function} resolveReducer
+ * @param {Accumulator} accumulator
+ * @param {ReducerFind} reducerFind
+ * @returns {Promise<Accumulator>}
+ */
+function resolve (manager, resolveReducer, accumulator, reducerFind) {
+  const reducer = reducerFind.reducer
+  if (utils.reducerIsEmpty(reducer)) {
+    return Promise.resolve(accumulator)
+  }
+
+  return Promise.reduce(
+    accumulator.value,
+    (result, itemValue) => {
+      const itemContext = utils.set(accumulator, 'value', itemValue)
+      return (
+        result ||
+        resolveReducer(manager, itemContext, reducer).then(res => {
+          return res.value ? itemValue : undefined
+        })
+      )
+    },
+    null
+  ).then(result => utils.set(accumulator, 'value', result))
+}
+
+module.exports.resolve = resolve
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-map/factory.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-map/factory.js
new file mode 100644
index 0000000..478c5e5
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-map/factory.js
@@ -0,0 +1,35 @@
+const REDUCER_SYMBOL = require('../../reducer-symbol')
+
+const REDUCER_MAP = 'ReducerMap'
+
+module.exports.type = REDUCER_MAP
+
+const HELPER_NAME = 'map'
+
+module.exports.name = HELPER_NAME
+
+/**
+ * @class
+ * @property {string} type
+ * @property {reducer} reducer
+ */
+function ReducerMap () {
+  this[REDUCER_SYMBOL] = true
+  this.type = REDUCER_MAP
+  this.reducer = undefined
+}
+
+module.exports.ReducerMap = ReducerMap
+
+/**
+ * @param {Function} createReducer
+ * @param {*} source - raw source for a reducer
+ * @return {ReducerMap}
+ */
+function create (createReducer, source) {
+  const reducer = new ReducerMap()
+  reducer.reducer = createReducer(source)
+  return reducer
+}
+
+module.exports.create = create
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-map/index.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-map/index.js
new file mode 100644
index 0000000..fafee9c
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-map/index.js
@@ -0,0 +1,9 @@
+const factory = require('./factory')
+const resolve = require('./resolve').resolve
+
+module.exports = {
+  create: factory.create,
+  type: factory.type,
+  name: factory.name,
+  resolve: resolve
+}
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-map/resolve.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-map/resolve.js
new file mode 100644
index 0000000..63c6504
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-map/resolve.js
@@ -0,0 +1,25 @@
+const Promise = require('bluebird')
+const utils = require('../../../utils')
+
+/**
+ * @param {Object} manager
+ * @param {Function} resolveReducer
+ * @param {Accumulator} accumulator
+ * @param {ReducerMap} reducerMap
+ * @returns {Promise<Accumulator>}
+ */
+function resolve (manager, resolveReducer, accumulator, reducerMap) {
+  const reducer = reducerMap.reducer
+  if (utils.reducerIsEmpty(reducer)) {
+    return Promise.resolve(accumulator)
+  }
+
+  return Promise.map(accumulator.value, itemValue => {
+    const itemContext = utils.set(accumulator, 'value', itemValue)
+    return resolveReducer(manager, itemContext, reducer).then(res => {
+      return res.value
+    })
+  }).then(result => utils.set(accumulator, 'value', result))
+}
+
+module.exports.resolve = resolve
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-omit/factory.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-omit/factory.js
new file mode 100644
index 0000000..35c6ef4
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-omit/factory.js
@@ -0,0 +1,35 @@
+const REDUCER_SYMBOL = require('../../reducer-symbol')
+
+const REDUCER_OMIT = 'ReducerOmit'
+
+module.exports.type = REDUCER_OMIT
+
+const HELPER_NAME = 'omit'
+
+module.exports.name = HELPER_NAME
+
+/**
+ * @class
+ * @property {string} type
+ * @property {Array<string>} keys
+ */
+function ReducerOmit () {
+  this[REDUCER_SYMBOL] = true
+  this.type = REDUCER_OMIT
+  this.keys = undefined
+}
+
+module.exports.ReducerOmit = ReducerOmit
+
+/**
+ * @param {Function} createReducer
+ * @param {Array<string>} keys
+ * @return {ReducerOmit}
+ */
+function create (createReducer, keys) {
+  const reducer = new ReducerOmit()
+  reducer.keys = Object.freeze(keys.slice(0))
+  return reducer
+}
+
+module.exports.create = create
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-omit/index.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-omit/index.js
new file mode 100644
index 0000000..fafee9c
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-omit/index.js
@@ -0,0 +1,9 @@
+const factory = require('./factory')
+const resolve = require('./resolve').resolve
+
+module.exports = {
+  create: factory.create,
+  type: factory.type,
+  name: factory.name,
+  resolve: resolve
+}
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-omit/resolve.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-omit/resolve.js
new file mode 100644
index 0000000..5fce62b
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-omit/resolve.js
@@ -0,0 +1,23 @@
+const Promise = require('bluebird')
+const omit = require('lodash/omit')
+
+const utils = require('../../../utils')
+
+/**
+ * @param {Object} manager
+ * @param {Function} resolveReducer
+ * @param {Accumulator} accumulator
+ * @param {ReducerOmit} reducerOmit
+ * @returns {Promise<Accumulator>}
+ */
+function resolve (manager, resolveReducer, accumulator, reducerOmit) {
+  const keys = reducerOmit.keys
+  if (keys.length === 0) {
+    return Promise.resolve(accumulator)
+  }
+
+  const value = omit(accumulator.value, keys)
+  return Promise.resolve(utils.set(accumulator, 'value', value))
+}
+
+module.exports.resolve = resolve
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-pick/factory.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-pick/factory.js
new file mode 100644
index 0000000..cff61e8
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-pick/factory.js
@@ -0,0 +1,35 @@
+const REDUCER_SYMBOL = require('../../reducer-symbol')
+
+const REDUCER_PICK = 'ReducerPick'
+
+module.exports.type = REDUCER_PICK
+
+const HELPER_NAME = 'pick'
+
+module.exports.name = HELPER_NAME
+
+/**
+ * @class
+ * @property {string} type
+ * @property {Array<string>} keys
+ */
+function ReducerPick () {
+  this[REDUCER_SYMBOL] = true
+  this.type = REDUCER_PICK
+  this.keys = undefined
+}
+
+module.exports.ReducerPick = ReducerPick
+
+/**
+ * @param {Function} createReducer
+ * @param {Array<string>} keys
+ * @return {ReducerPick}
+ */
+function create (createReducer, keys) {
+  const reducer = new ReducerPick()
+  reducer.keys = Object.freeze(keys.slice(0))
+  return reducer
+}
+
+module.exports.create = create
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-pick/index.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-pick/index.js
new file mode 100644
index 0000000..fafee9c
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-pick/index.js
@@ -0,0 +1,9 @@
+const factory = require('./factory')
+const resolve = require('./resolve').resolve
+
+module.exports = {
+  create: factory.create,
+  type: factory.type,
+  name: factory.name,
+  resolve: resolve
+}
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-pick/resolve.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-pick/resolve.js
new file mode 100644
index 0000000..aed13f7
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-pick/resolve.js
@@ -0,0 +1,22 @@
+const Promise = require('bluebird')
+const pick = require('lodash/pick')
+const utils = require('../../../utils')
+
+/**
+ * @param {Object} manager
+ * @param {Function} resolveReducer
+ * @param {Accumulator} accumulator
+ * @param {ReducerPick} reducerPick
+ * @returns {Promise<Accumulator>}
+ */
+function resolve (manager, resolveReducer, accumulator, reducerPick) {
+  const keys = reducerPick.keys
+  if (keys.length === 0) {
+    return Promise.resolve(accumulator)
+  }
+
+  const value = pick(accumulator.value, keys)
+  return Promise.resolve(utils.set(accumulator, 'value', value))
+}
+
+module.exports.resolve = resolve
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-stub.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-stub.js
new file mode 100644
index 0000000..1fa4372
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-stub.js
@@ -0,0 +1,36 @@
+const REDUCER_STUB_SYMBOL = Symbol('reducer stub')
+
+module.exports.REDUCER_STUB_SYMBOL = REDUCER_STUB_SYMBOL
+
+/**
+ * @class
+ * @param {string} type
+ * @param {Array} args
+ */
+function ReducerStub (type, args) {
+  this[REDUCER_STUB_SYMBOL] = true
+  this.type = type
+  this.args = args
+}
+
+module.exports.ReducerStub = ReducerStub
+
+/**
+ * @param {*} source
+ * @returns {boolean}
+ */
+function isType (source) {
+  return source[REDUCER_STUB_SYMBOL] === true
+}
+
+module.exports.isType = isType
+
+/**
+ * @param {string} type
+ * @returns {ReducerStub}
+ */
+function create (type, ...args) {
+  return new ReducerStub(type, args)
+}
+
+module.exports.create = create
diff --git a/packages/data-point/lib/reducer-types/reducer-list/factory.js b/packages/data-point/lib/reducer-types/reducer-list/factory.js
index ce6ce25..28ac653 100644
--- a/packages/data-point/lib/reducer-types/reducer-list/factory.js
+++ b/packages/data-point/lib/reducer-types/reducer-list/factory.js
@@ -2,6 +2,8 @@
 
 const _ = require('lodash')
 
+const REDUCER_SYMBOL = require('../reducer-symbol')
+
 const REDUCER_LIST = 'ReducerList'
 
 module.exports.type = REDUCER_LIST
@@ -12,6 +14,7 @@ module.exports.type = REDUCER_LIST
  * @property {Array<reducer>} reducers
  */
 function ReducerList () {
+  this[REDUCER_SYMBOL] = true
   this.type = 'ReducerList'
   this.reducers = []
 }
diff --git a/packages/data-point/lib/reducer-types/reducer-object/factory.js b/packages/data-point/lib/reducer-types/reducer-object/factory.js
index 9d6f4cc..20dffc9 100644
--- a/packages/data-point/lib/reducer-types/reducer-object/factory.js
+++ b/packages/data-point/lib/reducer-types/reducer-object/factory.js
@@ -1,5 +1,7 @@
 const isPlainObject = require('lodash/isPlainObject')
 
+const REDUCER_SYMBOL = require('../reducer-symbol')
+
 const REDUCER_OBJECT = 'ReducerObject'
 
 module.exports.type = REDUCER_OBJECT
@@ -10,6 +12,7 @@ module.exports.type = REDUCER_OBJECT
  * @property {Array} props
  */
 function ReducerObject () {
+  this[REDUCER_SYMBOL] = true
   this.type = REDUCER_OBJECT
   this.props = undefined
 }
diff --git a/packages/data-point/lib/reducer-types/reducer-path/factory.js b/packages/data-point/lib/reducer-types/reducer-path/factory.js
index f7e689c..b407a89 100644
--- a/packages/data-point/lib/reducer-types/reducer-path/factory.js
+++ b/packages/data-point/lib/reducer-types/reducer-path/factory.js
@@ -2,6 +2,8 @@
 
 const _ = require('lodash')
 
+const REDUCER_SYMBOL = require('../reducer-symbol')
+
 const REDUCER_PATH = 'ReducerPath'
 
 module.exports.type = REDUCER_PATH
@@ -13,6 +15,7 @@ module.exports.type = REDUCER_PATH
  * @property {Array} parameters - collection of  @see {@link Parameter} items
  */
 function ReducerPath () {
+  this[REDUCER_SYMBOL] = true
   this.type = REDUCER_PATH
   this.name = ''
   this.body = undefined
diff --git a/packages/data-point/lib/reducer-types/reducer-symbol.js b/packages/data-point/lib/reducer-types/reducer-symbol.js
new file mode 100644
index 0000000..1d459f8
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-symbol.js
@@ -0,0 +1,1 @@
+module.exports = Symbol('reducer')
diff --git a/packages/data-point/lib/reducer-types/resolve.js b/packages/data-point/lib/reducer-types/resolve.js
index 042e1c8..5cee57a 100644
--- a/packages/data-point/lib/reducer-types/resolve.js
+++ b/packages/data-point/lib/reducer-types/resolve.js
@@ -4,13 +4,15 @@ const ReducerList = require('./reducer-list')
 const ReducerObject = require('./reducer-object')
 const ReducerPath = require('./reducer-path')
 
-const resolveFunctions = {
-  [ReducerEntity.type]: ReducerEntity.resolve,
-  [ReducerFunction.type]: ReducerFunction.resolve,
-  [ReducerList.type]: ReducerList.resolve,
-  [ReducerObject.type]: ReducerObject.resolve,
-  [ReducerPath.type]: ReducerPath.resolve
-}
+const ReducerHelpers = require('./reducer-helpers').reducers
+
+const reducers = Object.assign({}, ReducerHelpers, {
+  [ReducerEntity.type]: ReducerEntity,
+  [ReducerFunction.type]: ReducerFunction,
+  [ReducerList.type]: ReducerList,
+  [ReducerObject.type]: ReducerObject,
+  [ReducerPath.type]: ReducerPath
+})
 
 /**
  * apply a Reducer to an accumulator
@@ -27,13 +29,13 @@ function resolve (manager, accumulator, reducer) {
     return Promise.resolve(accumulator)
   }
 
-  const resolveReducer = resolveFunctions[reducer.type]
-  if (!resolveReducer) {
+  const reducerType = reducers[reducer.type]
+  if (!reducerType) {
     throw new Error(`Reducer type '${reducer.type}' was not recognized`)
   }
 
   // NOTE: recursive call
-  return resolveReducer(manager, resolve, accumulator, reducer)
+  return reducerType.resolve(manager, resolve, accumulator, reducer)
 }
 
 module.exports.resolve = resolve


Test patch:
diff --git a/packages/data-point/lib/entity-types/entity-collection/__snapshots__/factory.test.js.snap b/packages/data-point/lib/entity-types/entity-collection/__snapshots__/factory.test.js.snap
new file mode 100644
index 0000000..c5ecd8b
--- /dev/null
+++ b/packages/data-point/lib/entity-types/entity-collection/__snapshots__/factory.test.js.snap
@@ -0,0 +1,3 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`parse compose modifier throw error if compose is not an array 1`] = `"Entity undefined compose property is expected to be an instance of Array, but found [object Object]"`;
diff --git a/packages/data-point/lib/entity-types/entity-collection/factory.test.js b/packages/data-point/lib/entity-types/entity-collection/factory.test.js
index e50f7a0..14f966e 100644
--- a/packages/data-point/lib/entity-types/entity-collection/factory.test.js
+++ b/packages/data-point/lib/entity-types/entity-collection/factory.test.js
@@ -2,6 +2,7 @@
 'use strict'
 
 const modelFactory = require('./factory')
+const helpers = require('../../helpers')
 
 test('modelFactory#create default', () => {
   const result = modelFactory.create({})
@@ -12,7 +13,7 @@ test('modelFactory#create default', () => {
   expect(result.params).toEqual({})
 
   expect(result).not.toHaveProperty('value')
-  expect(result.compose).toBeInstanceOf(Array)
+  expect(helpers.isReducer(result.compose)).toBe(true)
 })
 
 describe('parse loose modifiers', () => {
@@ -21,9 +22,9 @@ describe('parse loose modifiers', () => {
       map: '$a'
     })
 
-    expect(result.compose).toBeInstanceOf(Array)
-    expect(result.compose[0]).toHaveProperty('type', 'map')
-    expect(result.compose[0].reducer).toHaveProperty('type', 'ReducerPath')
+    expect(helpers.isReducer(result.compose)).toBe(true)
+    expect(result.compose).toHaveProperty('type', 'ReducerMap')
+    expect(result.compose.reducer).toHaveProperty('type', 'ReducerPath')
   })
 
   test('modelFactory#create default', () => {
@@ -33,10 +34,11 @@ describe('parse loose modifiers', () => {
       filter: '$a'
     })
 
-    expect(result.compose).toBeInstanceOf(Array)
-    expect(result.compose[0]).toHaveProperty('type', 'filter')
-    expect(result.compose[1]).toHaveProperty('type', 'map')
-    expect(result.compose[2]).toHaveProperty('type', 'find')
+    expect(helpers.isReducer(result.compose)).toBe(true)
+    expect(result.compose).toHaveProperty('type', 'ReducerList')
+    expect(result.compose.reducers[0]).toHaveProperty('type', 'ReducerFilter')
+    expect(result.compose.reducers[1]).toHaveProperty('type', 'ReducerMap')
+    expect(result.compose.reducers[2]).toHaveProperty('type', 'ReducerFind')
   })
 })
 
@@ -46,9 +48,9 @@ describe('parse compose modifier', () => {
       compose: [{ map: '$a' }]
     })
 
-    expect(result.compose).toBeInstanceOf(Array)
-    expect(result.compose[0]).toHaveProperty('type', 'map')
-    expect(result.compose[0].reducer).toHaveProperty('type', 'ReducerPath')
+    expect(helpers.isReducer(result.compose)).toBe(true)
+    expect(result.compose).toHaveProperty('type', 'ReducerMap')
+    expect(result.compose.reducer).toHaveProperty('type', 'ReducerPath')
   })
 
   test('throw error if compose is not an array', () => {
@@ -56,10 +58,10 @@ describe('parse compose modifier', () => {
       modelFactory.create({
         compose: { map: '$a' }
       })
-    }).toThrow()
+    }).toThrowErrorMatchingSnapshot()
   })
 
-  test('throw error if compose is mixed with inline modoifiers (map, filter, ..) ', () => {
+  test('throw error if compose is mixed with inline modifiers (map, filter, ..) ', () => {
     expect(() => {
       modelFactory.create(
         {
@@ -77,9 +79,10 @@ describe('parse compose modifier', () => {
       compose: [{ map: '$a' }, { find: '$a' }, { filter: '$a' }]
     })
 
-    expect(result.compose).toBeInstanceOf(Array)
-    expect(result.compose[0]).toHaveProperty('type', 'map')
-    expect(result.compose[1]).toHaveProperty('type', 'find')
-    expect(result.compose[2]).toHaveProperty('type', 'filter')
+    expect(helpers.isReducer(result.compose)).toBe(true)
+    expect(result.compose).toHaveProperty('type', 'ReducerList')
+    expect(result.compose.reducers[0]).toHaveProperty('type', 'ReducerMap')
+    expect(result.compose.reducers[1]).toHaveProperty('type', 'ReducerFind')
+    expect(result.compose.reducers[2]).toHaveProperty('type', 'ReducerFilter')
   })
 })
diff --git a/packages/data-point/lib/entity-types/entity-collection/resolve.test.js b/packages/data-point/lib/entity-types/entity-collection/resolve.test.js
index 21f8d33..215d355 100644
--- a/packages/data-point/lib/entity-types/entity-collection/resolve.test.js
+++ b/packages/data-point/lib/entity-types/entity-collection/resolve.test.js
@@ -148,23 +148,22 @@ describe('entity.collection.compose', () => {
       .catch(acc => acc)
       .then(acc => {
         expect(acc).toBeInstanceOf(Error)
-        expect(acc.message).toMatch(/collection:j.3.map/)
       })
   })
+
   test('find should handle error and rethrow with appended information', () => {
     return transform('collection:j.4', testData)
       .catch(acc => acc)
       .then(acc => {
         expect(acc).toBeInstanceOf(Error)
-        expect(acc.message).toMatch(/collection:j.4.find/)
       })
   })
+
   test('filter should handle error and rethrow with appended information', () => {
     return transform('collection:j.5', testData)
       .catch(acc => acc)
       .then(acc => {
         expect(acc).toBeInstanceOf(Error)
-        expect(acc.message).toMatch(/collection:j.5.filter/)
       })
   })
 })
diff --git a/packages/data-point/lib/entity-types/entity-hash/__snapshots__/factory.test.js.snap b/packages/data-point/lib/entity-types/entity-hash/__snapshots__/factory.test.js.snap
new file mode 100644
index 0000000..03e3f45
--- /dev/null
+++ b/packages/data-point/lib/entity-types/entity-hash/__snapshots__/factory.test.js.snap
@@ -0,0 +1,7 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`factory#parse composed modifiers throw error if compose and loose modifiers are mixed 1`] = `"Entity hash:invalid is invalid; when 'compose' is defined the keys: 'mapKeys' should be inside compose."`;
+
+exports[`factory#parse composed modifiers throw error if compose non array 1`] = `"Entity hash:invalid compose property is expected to be an instance of Array, but found [object Object]"`;
+
+exports[`factory#parse composed modifiers throw error if modifier is invalid 1`] = `"Modifier 'invalidKey' in undefined doesn't match any of the registered Modifiers: omitKeys,pickKeys,mapKeys,addValues,addKeys"`;
diff --git a/packages/data-point/lib/entity-types/entity-hash/factory.test.js b/packages/data-point/lib/entity-types/entity-hash/factory.test.js
index 97da93f..a21f624 100644
--- a/packages/data-point/lib/entity-types/entity-hash/factory.test.js
+++ b/packages/data-point/lib/entity-types/entity-hash/factory.test.js
@@ -2,6 +2,7 @@
 'use strict'
 
 const factory = require('./factory')
+const helpers = require('../../helpers')
 
 test('factory#create default', () => {
   const result = factory.create({})
@@ -12,7 +13,7 @@ test('factory#create default', () => {
   expect(result).not.toHaveProperty('value')
   expect(result.params).toEqual({})
 
-  expect(result.compose).toBeInstanceOf(Array)
+  expect(helpers.isReducer(result.compose)).toBe(true)
 })
 
 describe('factory#parse loose modifiers', () => {
@@ -23,9 +24,10 @@ describe('factory#parse loose modifiers', () => {
       }
     })
 
-    expect(result.compose[0]).toHaveProperty('type', 'mapKeys')
-    expect(result.compose[0].reducer).toHaveProperty('type', 'ReducerObject')
+    expect(helpers.isReducer(result.compose)).toBe(true)
+    expect(result.compose).toHaveProperty('type', 'ReducerObject')
   })
+
   test('factory#addKeys', () => {
     const result = factory.create({
       addKeys: {
@@ -33,24 +35,28 @@ describe('factory#parse loose modifiers', () => {
       }
     })
 
-    expect(result.compose[0]).toHaveProperty('type', 'addKeys')
-    expect(result.compose[0].reducer).toHaveProperty('type', 'ReducerObject')
+    expect(helpers.isReducer(result.compose)).toBe(true)
+    expect(result.compose).toHaveProperty('type', 'ReducerAssign')
   })
+
   test('factory#omitKeys', () => {
     const result = factory.create({
       omitKeys: ['a']
     })
 
-    expect(result.compose[0]).toHaveProperty('type', 'omitKeys')
-    expect(result.compose[0].reducer).toEqual(['a'])
+    expect(helpers.isReducer(result.compose)).toBe(true)
+    expect(result.compose).toHaveProperty('type', 'ReducerOmit')
+    expect(result.compose.keys).toEqual(['a'])
   })
+
   test('factory#pickKeys', () => {
     const result = factory.create({
       pickKeys: ['a']
     })
 
-    expect(result.compose[0]).toHaveProperty('type', 'pickKeys')
-    expect(result.compose[0].reducer).toEqual(['a'])
+    expect(helpers.isReducer(result.compose)).toBe(true)
+    expect(result.compose).toHaveProperty('type', 'ReducerPick')
+    expect(result.compose.keys).toEqual(['a'])
   })
 })
 
@@ -62,8 +68,9 @@ describe('factory#parse composed modifiers', () => {
     }
     expect(() => {
       factory.create(spec)
-    }).toThrow()
+    }).toThrowErrorMatchingSnapshot()
   })
+
   test('throw error if compose and loose modifiers are mixed', () => {
     const spec = {
       id: 'hash:invalid',
@@ -76,8 +83,9 @@ describe('factory#parse composed modifiers', () => {
     }
     expect(() => {
       factory.create(spec)
-    }).toThrow()
+    }).toThrowErrorMatchingSnapshot()
   })
+
   test('throw error if modifier is invalid', () => {
     const spec = {
       id: 'hash:invalid',
@@ -89,8 +97,9 @@ describe('factory#parse composed modifiers', () => {
     }
     expect(() => {
       factory.create(spec)
-    }).toThrow()
+    }).toThrowErrorMatchingSnapshot()
   })
+
   test('factory#one modifier', () => {
     const result = factory.create({
       compose: [
@@ -102,9 +111,10 @@ describe('factory#parse composed modifiers', () => {
       ]
     })
 
-    expect(result.compose[0]).toHaveProperty('type', 'mapKeys')
-    expect(result.compose[0].reducer).toHaveProperty('type', 'ReducerObject')
+    expect(helpers.isReducer(result.compose)).toBe(true)
+    expect(result.compose).toHaveProperty('type', 'ReducerObject')
   })
+
   test('factory#multiple modifiers', () => {
     const result = factory.create({
       compose: [
@@ -124,21 +134,23 @@ describe('factory#parse composed modifiers', () => {
       ]
     })
 
-    expect(result.compose[0]).toHaveProperty('type', 'addKeys')
-    expect(result.compose[0].reducer).toHaveProperty('type', 'ReducerObject')
-    expect(result.compose[0].reducer.props[0].path).toEqual(['a'])
-    expect(result.compose[0].reducer.props[0].reducer).toHaveProperty(
+    expect(helpers.isReducer(result.compose)).toBe(true)
+    expect(result.compose).toHaveProperty('type', 'ReducerList')
+
+    expect(result.compose.reducers[0]).toHaveProperty('type', 'ReducerAssign')
+    expect(result.compose.reducers[0].reducer).toHaveProperty(
       'type',
-      'ReducerPath'
+      'ReducerObject'
     )
-    expect(result.compose[1]).toHaveProperty('type', 'mapKeys')
-    expect(result.compose[1].reducer).toHaveProperty('type', 'ReducerObject')
-    expect(result.compose[1].reducer.props[0].path).toEqual(['a'])
-    expect(result.compose[1].reducer.props[0].reducer).toHaveProperty(
+
+    expect(result.compose.reducers[1]).toHaveProperty('type', 'ReducerObject')
+    expect(result.compose.reducers[1].props).toHaveLength(1)
+    expect(result.compose.reducers[1].props[0].reducer).toHaveProperty(
       'type',
       'ReducerPath'
     )
-    expect(result.compose[2]).toHaveProperty('type', 'omitKeys')
-    expect(result.compose[2].reducer).toEqual(['a'])
+
+    expect(result.compose.reducers[2]).toHaveProperty('type', 'ReducerOmit')
+    expect(result.compose.reducers[2].keys).toEqual(['a'])
   })
 })
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-assign/factory.test.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-assign/factory.test.js
new file mode 100644
index 0000000..ddc2400
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-assign/factory.test.js
@@ -0,0 +1,14 @@
+/* eslint-env jest */
+'use strict'
+
+const Factory = require('./factory')
+const createReducer = require('../../index').create
+
+describe('ReducerAssign#factory', () => {
+  test('It should create a ReducerAssign object', () => {
+    const reducer = Factory.create(createReducer, {})
+    expect(reducer).toBeInstanceOf(Factory.ReducerAssign)
+    expect(reducer.type).toBe(Factory.type)
+    expect(reducer.reducer).toHaveProperty('type', 'ReducerObject')
+  })
+})
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-assign/resolve.test.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-assign/resolve.test.js
new file mode 100644
index 0000000..282472c
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-assign/resolve.test.js
@@ -0,0 +1,88 @@
+/* eslint-env jest */
+'use strict'
+
+const Factory = require('./factory')
+const Resolve = require('./resolve')
+
+const Reducer = require('../../index')
+
+const DataPoint = require('../../../index')
+
+const AccumulatorFactory = require('../../../accumulator/factory')
+
+let manager
+
+beforeAll(() => {
+  manager = DataPoint.create({
+    entities: {
+      'transform:a': () => ({
+        b: 22,
+        c: 33
+      })
+    }
+  })
+})
+
+describe('ReducerAssign#resolve', () => {
+  test('It should work for empty objects', () => {
+    const accumulator = AccumulatorFactory.create({
+      value: {}
+    })
+
+    const reducer = Factory.create(Reducer.create, () => ({}))
+    return Resolve.resolve(manager, Reducer.resolve, accumulator, reducer).then(
+      result => {
+        expect(result.value).toEqual({})
+      }
+    )
+  })
+
+  test('It should work for valid input', () => {
+    const accumulator = AccumulatorFactory.create({
+      value: {
+        a: 1,
+        b: 2
+      }
+    })
+
+    const reducer = Factory.create(Reducer.create, 'transform:a')
+    return Resolve.resolve(manager, Reducer.resolve, accumulator, reducer).then(
+      result => {
+        expect(result.value).toEqual({
+          a: 1,
+          b: 22,
+          c: 33
+        })
+      }
+    )
+  })
+
+  test('It should not merge nested objects', () => {
+    const accumulator = AccumulatorFactory.create({
+      value: {
+        a: 1,
+        b: {
+          a: 1
+        }
+      }
+    })
+
+    const reducer = Factory.create(Reducer.create, () => ({
+      a: 1,
+      b: {
+        b: 2
+      }
+    }))
+
+    return Resolve.resolve(manager, Reducer.resolve, accumulator, reducer).then(
+      result => {
+        expect(result.value).toEqual({
+          a: 1,
+          b: {
+            b: 2
+          }
+        })
+      }
+    )
+  })
+})
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-filter/factory.test.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-filter/factory.test.js
new file mode 100644
index 0000000..5783925
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-filter/factory.test.js
@@ -0,0 +1,14 @@
+/* eslint-env jest */
+'use strict'
+
+const Factory = require('./factory')
+const createReducer = require('../../index').create
+
+describe('ReducerFilter#factory', () => {
+  test('It should create a ReducerFilter object', () => {
+    const reducer = Factory.create(createReducer, {})
+    expect(reducer).toBeInstanceOf(Factory.ReducerFilter)
+    expect(reducer.type).toBe(Factory.type)
+    expect(reducer.reducer).toHaveProperty('type', 'ReducerObject')
+  })
+})
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-filter/resolve.test.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-filter/resolve.test.js
new file mode 100644
index 0000000..61207b6
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-filter/resolve.test.js
@@ -0,0 +1,56 @@
+/* eslint-env jest */
+'use strict'
+
+const Factory = require('./factory')
+const Resolve = require('./resolve')
+
+const Reducer = require('../../index')
+
+const DataPoint = require('../../../index')
+
+const AccumulatorFactory = require('../../../accumulator/factory')
+
+let manager
+
+beforeAll(() => {
+  manager = DataPoint.create()
+})
+
+describe('ReducerFilter#resolve', () => {
+  test('It should return the accumulator when resolver is empty', () => {
+    const value = [
+      {
+        a: 1
+      }
+    ]
+    const accumulator = AccumulatorFactory.create({ value })
+    const reducer = Factory.create(Reducer.create, [])
+    return Resolve.resolve(manager, Reducer.resolve, accumulator, reducer).then(
+      result => {
+        expect(result.value).toEqual(value)
+      }
+    )
+  })
+
+  test('It should filter an array of objects', () => {
+    const value = [
+      {
+        a: 1
+      },
+      {
+        a: 2
+      }
+    ]
+    const accumulator = AccumulatorFactory.create({ value })
+    const reducer = Factory.create(Reducer.create, ['$a', acc => acc.value > 1])
+    return Resolve.resolve(manager, Reducer.resolve, accumulator, reducer).then(
+      result => {
+        expect(result.value).toEqual([
+          {
+            a: 2
+          }
+        ])
+      }
+    )
+  })
+})
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-find/factory.test.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-find/factory.test.js
new file mode 100644
index 0000000..bf6cca7
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-find/factory.test.js
@@ -0,0 +1,14 @@
+/* eslint-env jest */
+'use strict'
+
+const Factory = require('./factory')
+const createReducer = require('../../index').create
+
+describe('ReducerFind#factory', () => {
+  test('It should create a ReducerFind object', () => {
+    const reducer = Factory.create(createReducer, {})
+    expect(reducer).toBeInstanceOf(Factory.ReducerFind)
+    expect(reducer.type).toBe(Factory.type)
+    expect(reducer.reducer).toHaveProperty('type', 'ReducerObject')
+  })
+})
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-find/resolve.test.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-find/resolve.test.js
new file mode 100644
index 0000000..d1f143f
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-find/resolve.test.js
@@ -0,0 +1,72 @@
+/* eslint-env jest */
+'use strict'
+
+const Factory = require('./factory')
+const Resolve = require('./resolve')
+
+const Reducer = require('../../index')
+
+const DataPoint = require('../../../index')
+
+const AccumulatorFactory = require('../../../accumulator/factory')
+
+let manager
+
+beforeAll(() => {
+  manager = DataPoint.create()
+})
+
+describe('ReducerFind#resolve', () => {
+  test('It should return the accumulator when resolver is empty', () => {
+    const value = [
+      {
+        a: 1
+      }
+    ]
+    const accumulator = AccumulatorFactory.create({ value })
+    const reducer = Factory.create(Reducer.create, [])
+    return Resolve.resolve(manager, Reducer.resolve, accumulator, reducer).then(
+      result => {
+        expect(result.value).toEqual(value)
+      }
+    )
+  })
+
+  test('It should find a matching object', () => {
+    const value = [
+      {
+        a: 1
+      },
+      {
+        a: 2
+      }
+    ]
+    const accumulator = AccumulatorFactory.create({ value })
+    const reducer = Factory.create(Reducer.create, ['$a', acc => acc.value > 1])
+    return Resolve.resolve(manager, Reducer.resolve, accumulator, reducer).then(
+      result => {
+        expect(result.value).toEqual({
+          a: 2
+        })
+      }
+    )
+  })
+
+  test('It should return undefined when no match is found', () => {
+    const value = [
+      {
+        a: 1
+      },
+      {
+        a: 2
+      }
+    ]
+    const accumulator = AccumulatorFactory.create({ value })
+    const reducer = Factory.create(Reducer.create, '$c')
+    return Resolve.resolve(manager, Reducer.resolve, accumulator, reducer).then(
+      result => {
+        expect(result.value).toBeUndefined()
+      }
+    )
+  })
+})
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-map/factory.test.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-map/factory.test.js
new file mode 100644
index 0000000..9f31c4a
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-map/factory.test.js
@@ -0,0 +1,14 @@
+/* eslint-env jest */
+'use strict'
+
+const Factory = require('./factory')
+const createReducer = require('../../index').create
+
+describe('ReducerMap#factory', () => {
+  test('It should create a ReducerMap object', () => {
+    const reducer = Factory.create(createReducer, {})
+    expect(reducer).toBeInstanceOf(Factory.ReducerMap)
+    expect(reducer.type).toBe(Factory.type)
+    expect(reducer.reducer).toHaveProperty('type', 'ReducerObject')
+  })
+})
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-map/resolve.test.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-map/resolve.test.js
new file mode 100644
index 0000000..1eb88e9
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-map/resolve.test.js
@@ -0,0 +1,52 @@
+/* eslint-env jest */
+'use strict'
+
+const Factory = require('./factory')
+const Resolve = require('./resolve')
+
+const Reducer = require('../../index')
+
+const DataPoint = require('../../../index')
+
+const AccumulatorFactory = require('../../../accumulator/factory')
+
+let manager
+
+beforeAll(() => {
+  manager = DataPoint.create()
+})
+
+describe('ReducerMap#resolve', () => {
+  test('It should return the accumulator when resolver is empty', () => {
+    const value = [
+      {
+        a: 1
+      }
+    ]
+    const accumulator = AccumulatorFactory.create({ value })
+    const reducer = Factory.create(Reducer.create, [])
+    return Resolve.resolve(manager, Reducer.resolve, accumulator, reducer).then(
+      result => {
+        expect(result.value).toEqual(value)
+      }
+    )
+  })
+
+  test('It should map an array of objects', () => {
+    const value = [
+      {
+        a: 1
+      },
+      {
+        a: 2
+      }
+    ]
+    const accumulator = AccumulatorFactory.create({ value })
+    const reducer = Factory.create(Reducer.create, ['$a', acc => acc.value + 1])
+    return Resolve.resolve(manager, Reducer.resolve, accumulator, reducer).then(
+      result => {
+        expect(result.value).toEqual([2, 3])
+      }
+    )
+  })
+})
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-omit/factory.test.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-omit/factory.test.js
new file mode 100644
index 0000000..f1a104e
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-omit/factory.test.js
@@ -0,0 +1,15 @@
+/* eslint-env jest */
+'use strict'
+
+const Factory = require('./factory')
+const createReducer = require('../../index').create
+
+describe('ReducerOmit#factory', () => {
+  test('It should create a ReducerOmit object', () => {
+    const args = ['$a', '$b']
+    const reducer = Factory.create(createReducer, args)
+    expect(reducer).toBeInstanceOf(Factory.ReducerOmit)
+    expect(reducer.type).toBe(Factory.type)
+    expect(reducer.keys).toEqual(args)
+  })
+})
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-omit/resolve.test.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-omit/resolve.test.js
new file mode 100644
index 0000000..d467513
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-omit/resolve.test.js
@@ -0,0 +1,51 @@
+/* eslint-env jest */
+'use strict'
+
+const Factory = require('./factory')
+const Resolve = require('./resolve')
+
+const Reducer = require('../../index')
+
+const DataPoint = require('../../../index')
+
+const AccumulatorFactory = require('../../../accumulator/factory')
+
+let manager
+
+beforeAll(() => {
+  manager = DataPoint.create()
+})
+
+describe('ReducerOmit#resolve', () => {
+  test('It should return the accumulator when no keys are provided', () => {
+    const value = [
+      {
+        a: 1
+      }
+    ]
+    const accumulator = AccumulatorFactory.create({ value })
+    const reducer = Factory.create(Reducer.create, [])
+    return Resolve.resolve(manager, Reducer.resolve, accumulator, reducer).then(
+      result => {
+        expect(result.value).toEqual(value)
+      }
+    )
+  })
+
+  test('It should omit the given keys', () => {
+    const value = {
+      a: 1,
+      b: 2,
+      c: 3
+    }
+    const accumulator = AccumulatorFactory.create({ value })
+    const reducer = Factory.create(Reducer.create, ['a', 'b', 'q'])
+    return Resolve.resolve(manager, Reducer.resolve, accumulator, reducer).then(
+      result => {
+        expect(result.value).toEqual({
+          c: 3
+        })
+      }
+    )
+  })
+})
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-pick/factory.test.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-pick/factory.test.js
new file mode 100644
index 0000000..c54f5f0
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-pick/factory.test.js
@@ -0,0 +1,15 @@
+/* eslint-env jest */
+'use strict'
+
+const Factory = require('./factory')
+const createReducer = require('../../index').create
+
+describe('ReducerPick#factory', () => {
+  test('It should create a ReducerPick object', () => {
+    const args = ['$a', '$b']
+    const reducer = Factory.create(createReducer, args)
+    expect(reducer).toBeInstanceOf(Factory.ReducerPick)
+    expect(reducer.type).toBe(Factory.type)
+    expect(reducer.keys).toEqual(args)
+  })
+})
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-pick/resolve.test.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-pick/resolve.test.js
new file mode 100644
index 0000000..f7d7832
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-pick/resolve.test.js
@@ -0,0 +1,51 @@
+/* eslint-env jest */
+'use strict'
+
+const Factory = require('./factory')
+const Resolve = require('./resolve')
+
+const Reducer = require('../../index')
+
+const DataPoint = require('../../../index')
+
+const AccumulatorFactory = require('../../../accumulator/factory')
+
+let manager
+
+beforeAll(() => {
+  manager = DataPoint.create()
+})
+
+describe('ReducerPick#resolve', () => {
+  test('It should return the accumulator when no keys are provided', () => {
+    const value = [
+      {
+        a: 1
+      }
+    ]
+    const accumulator = AccumulatorFactory.create({ value })
+    const reducer = Factory.create(Reducer.create, [])
+    return Resolve.resolve(manager, Reducer.resolve, accumulator, reducer).then(
+      result => {
+        expect(result.value).toEqual(value)
+      }
+    )
+  })
+
+  test('It should pick the given keys', () => {
+    const value = {
+      a: 1,
+      b: 2,
+      c: 3
+    }
+    const accumulator = AccumulatorFactory.create({ value })
+    const reducer = Factory.create(Reducer.create, ['c', 'q'])
+    return Resolve.resolve(manager, Reducer.resolve, accumulator, reducer).then(
+      result => {
+        expect(result.value).toEqual({
+          c: 3
+        })
+      }
+    )
+  })
+})
diff --git a/packages/data-point/lib/reducer-types/reducer-helpers/reducer-stub.test.js b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-stub.test.js
new file mode 100644
index 0000000..f3e78df
--- /dev/null
+++ b/packages/data-point/lib/reducer-types/reducer-helpers/reducer-stub.test.js
@@ -0,0 +1,16 @@
+/* eslint-env jest */
+'use strict'
+
+const Factory = require('./reducer-stub')
+
+describe('ReducerStub#factory', () => {
+  test('It should create a ReducerStub object', () => {
+    const reducer = Factory.create('ReducerPick', '$a', '$b')
+    expect(reducer).toBeInstanceOf(Factory.ReducerStub)
+    expect(Factory.isType(reducer)).toBe(true)
+    expect(Factory.isType({ type: 'ReducerStub' })).toBe(false)
+    expect(reducer[Factory.REDUCER_STUB_SYMBOL]).toBe(true)
+    expect(reducer.type).toBe('ReducerPick')
+    expect(reducer.args).toEqual(['$a', '$b'])
+  })
+})
diff --git a/packages/data-point/lib/reducer-types/reducer-object/__snapshots__/factory.test.js.snap b/packages/data-point/lib/reducer-types/reducer-object/__snapshots__/factory.test.js.snap
index edeb3e7..530a4f5 100644
--- a/packages/data-point/lib/reducer-types/reducer-object/__snapshots__/factory.test.js.snap
+++ b/packages/data-point/lib/reducer-types/reducer-object/__snapshots__/factory.test.js.snap
@@ -11,6 +11,7 @@ Array [
       "body": [Function],
       "name": "a",
       "type": "ReducerPath",
+      Symbol(reducer): true,
     },
   },
   Object {
@@ -25,13 +26,16 @@ Array [
           "body": [Function],
           "name": "a2",
           "type": "ReducerPath",
+          Symbol(reducer): true,
         },
         ReducerFunction {
           "body": [Function],
           "type": "ReducerFunction",
+          Symbol(reducer): true,
         },
       ],
       "type": "ReducerList",
+      Symbol(reducer): true,
     },
   },
   Object {
@@ -53,6 +57,7 @@ Array [
             "name": "entity-name",
             "type": "ReducerEntity",
             "withEmptyConditional": false,
+            Symbol(reducer): true,
           },
         },
         Object {
@@ -64,10 +69,12 @@ Array [
             "body": [Function],
             "name": "b1.b2.b3",
             "type": "ReducerPath",
+            Symbol(reducer): true,
           },
         },
       ],
       "type": "ReducerObject",
+      Symbol(reducer): true,
     },
   },
 ]