Repository: ViacomInc/data-point
Pull request #114 (2018-01-04 18:47:59)

Remove transform expressions
<!-- What changes are being made? (What feature/bug is being fixed here?) -->
**What**: Replaces TransformExpressions with a new reducer type called ReducerList #95. I opened and closed another PR to fix the same issue https://github.com/ViacomInc/data-point/pull/104, but that PR had a lot of extraneous changes that I removed for this one.

<!-- Why are these changes necessary? -->
**Why**: This simplifies the API because we only have reducers instead of having both reducers and TransformExpressions. One benefit is that we no longer have a `TransformExpression#resolve` function and a `Reducer#resolve` function - we just have a single `Reducer#resolve` that can deal with either single reducers or lists of reducers of any type.

The code still has a lot of references to a `resolveTransform` function. I can open a follow up PR to rename that function to `resolveReducer` -  the only reason I haven't done that yet was to keep the size of this PR smaller.

<!-- 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/14903989/badge)](https://coveralls.io/builds/14903989)

Coverage remained the same at 100.0% when pulling **9ca08c18feac9d2fe1b8fcd0be1d56f63822127b on raingerber:remove-transform-expressions** into **825f9a3b9c1cc7dd2f627801e9411718cbc91e31 on ViacomInc:master**.

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

Coverage remained the same at 100.0% when pulling **4563ae20579b6c9d7710205ad2b079a87f6cf21c on raingerber:remove-transform-expressions** into **825f9a3b9c1cc7dd2f627801e9411718cbc91e31 on ViacomInc:master**.

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

Coverage remained the same at 100.0% when pulling **61233f4ecb3a5e97fb08cd0088666a5dde270579 on raingerber:remove-transform-expressions** into **825f9a3b9c1cc7dd2f627801e9411718cbc91e31 on ViacomInc:master**.

acatl: lets go with what you have, this is a super clean PR! thanks for improving it! 
coveralls: 
[![Coverage Status](https://coveralls.io/builds/14905639/badge)](https://coveralls.io/builds/14905639)

Coverage remained the same at 100.0% when pulling **c851954475bc577be18b0767919d6f875dac18e1 on raingerber:remove-transform-expressions** into **c8de847cb1465e20159e33b68a0d449c0d1abb73 on ViacomInc:master**.


Patch:
diff --git a/packages/data-point/README.md b/packages/data-point/README.md
index e5850a9..6629039 100644
--- a/packages/data-point/README.md
+++ b/packages/data-point/README.md
@@ -22,7 +22,6 @@ npm install --save data-point
 - [DataPoint.create](#api-data-point-create)
 - [Transforms](#transforms)
   - [dataPoint.transform](#api-data-point-transform)
-  - [TransformExpression](#transform-expression)
 - [Reducers](#reducers)
   - [Accumulator](#accumulator)
   - [PathReducer](#path-reducer)
@@ -224,15 +223,15 @@ DataPoint instance.
 
 ### <a name="api-data-point-transform">dataPoint.transform()</a>
 
-Execute a [TransformExpression](#transform-expression) against a given _input_ value.
+Execute a [Reducer](#reducers) against an input value.
 
 **SYNOPSIS**
 
 ```js
 // promise
-dataPoint.transform(transformExpression, value, options)
+dataPoint.transform(reducer, value, options)
 // nodejs callback function
-dataPoint.transform(transformExpression, value, options, done) 
+dataPoint.transform(reducer, value, options, done)
 ```
 
 This method will return a **Promise** if `done` is omitted.
@@ -241,7 +240,7 @@ This method will return a **Promise** if `done` is omitted.
 
 | Argument | Type | Description |
 |:---|:---|:---|
-| *transformExpression* | [TransformExpression](#transform-expression) | Valid Transform Expression |
+| *reducer* | [Reducer](#reducers) | Reducer |
 | *value* | `Object` | Value that you want to transform. If **none**, pass `null` or empty object `{}`. |
 | *options* | [TransformOptions](#transform-options) | Options within the scope of the current transformation |
 | *done* | `function` _(optional)_ | Error-first callback [Node.js style callback](https://nodejs.org/api/errors.html#errors_node_js_style_callbacks) that has the arguments `(error, result)`, where `result` contains the final resolved [Accumulator](#accumulator). The actual transformation result will be inside the `result.value` property. |
@@ -257,36 +256,15 @@ The following table describes the properties of the `options` argument.
 | *locals* | `Object` | Hash with values you want exposed to every reducer. See [example](#acc-locals-example). |
 | *trace* | `boolean` | Set this to `true` to trace the entities and the time each one is taking to execute. **Use this option for debugging.** |
 
-### <a name="transform-expression">Transform Expression</a>
-
-**Description**
-
-A **TransformExpression** object consists of a chain containing one or more [Reducers](#reducers), where the result (transformed value) of one reducer gets passed as input value to the next reducer in the chain. All reducers are executed serially and **asynchronously**.
-
-Transform Expressions can be represented in different ways: 
-
-| TransformExpression | Description |
-|:---|:---|
-| `'$.'` | Get **root** value of *acc.value* |
-| `'$name'` | Get property `name` from *acc.value* |
-| `'$results[0].users'` | Get path `results[0].users` from *acc.value* |
-| `'$results[0].users \| hash:User[]'` | Get path `results[0].users` from *acc.value* and **map** each user to a `hash:User` entity |
-| `(acc) => { ... }` | Call function reducer, returned value gets passed to next reducer |
-| `['$a.b', (acc) => { ... }]` | Get path `a.b`, pipe value to function reducer |
-| `['$a.b', (acc) => { ... }, 'hash:Foo']` | Get path `a.b`, pipe value to function reducer, pipe result to `hash:Foo` |
-
 ## <a name="reducers">Reducer</a>
 
-Reducers are used to build a [TransformExpression](#transform-expression) object.
-
-Reducers transform values, and are executed both **serially** &amp; **asynchronously**.
-
-DataPoint supports the following reducer types:
+Reducers are used to transform values **asynchronously**. DataPoint supports the following reducer types:
 
 1. [PathReducer](#path-reducer)
 2. [FunctionReducer](#function-reducer)
 3. [ObjectReducer](#object-reducer)
 4. [EntityReducer](#entity-reducer)
+5. [ListReducer](#list-reducer)
 
 ### <a name="accumulator">Accumulator</a>
 
@@ -589,7 +567,7 @@ Example at: [examples/reducer-function-error.js](examples/reducer-function-error
 
 ### <a name="object-reducer">ObjectReducer</a>
 
-ObjectReducers are plain objects where the values are TransformExpressions. They're used to aggregate data or transform objects.
+ObjectReducers are plain objects where the values are reducers. They're used to aggregate data or transform objects.
 
 <details>
   <summary>Transforming an object</summary>
@@ -651,7 +629,7 @@ ObjectReducers are plain objects where the values are TransformExpressions. They
 </details>
 
 
-Each of the TransformExpressions, including the nested ones, are resolved against the same accumulator value. This means that input objects can be rearranged at any level:
+Each of the reducers, including the nested ones, are resolved against the same accumulator value. This means that input objects can be rearranged at any level:
 
 <details>
   <summary>Rearranging input data</summary>
@@ -691,7 +669,7 @@ Each of the TransformExpressions, including the nested ones, are resolved agains
 </details>
 
 
-Each of the TransformExpressions might also contain more ObjectReducers (which might contain TransformExpressions, and so on). Notice how the output changes based on the position of the ObjectReducers in the two expressions:
+Each of the reducers might contain more ObjectReducers (which might contain reducers, and so on). Notice how the output changes based on the position of the ObjectReducers in the two expressions:
 
 <details>
   <summary>Nested Transform Expressions</summary>
@@ -825,6 +803,14 @@ For information about supported (built-in) entities, see the [Entities](#entitie
   ```
 </details>
 
+### <a name="list-reducer">ListReducer</a>
+
+A ListReducer is an array of reducers where the result of each reducer becomes the input to the next reducer. The reducers are executed serially and **asynchronously**. It's possible for a ListReducer to contain other ListReducers.
+
+| ListReducer | Description |
+|:---|:---|
+| `['$a.b', (acc) => { ... }]` | Get path `a.b`, pipe value to function reducer |
+| `['$a.b', (acc) => { ... }, 'hash:Foo']` | Get path `a.b`, pipe value to function reducer, pipe result to `hash:Foo` |
 
 ### <a name="reducer-conditional-operator">Conditionally execute an entity</a>
 
@@ -997,14 +983,14 @@ All entities share a common API (except for [Transform](#transform-entity)).
 ```js
 {
   // executes --before-- everything else
-  before: TransformExpression,
+  before: Reducer,
   
   // executes --after-- everything else
-  after: TransformExpression,
+  after: Reducer,
   
   // executes in case there is an error at any
   // point of the entire transformation
-  error: TransformExpression,
+  error: Reducer,
   
   // this object allows you to store and eventually
   // access it at any given time on any reducer
@@ -1016,16 +1002,16 @@ All entities share a common API (except for [Transform](#transform-entity)).
 
 | Key | Type | Description |
 |:---|:---|:---|
-| *before*  | [TransformExpression](#transform-expression) | Transform to be resolved **before** the entity resolution |
-| *after*   | [TransformExpression](#transform-expression) | Transform to be resolved **after** the entity resolution |
-| *error*   | [TransformExpression](#transform-expression) | Transform to be resolved in case of an error |
+| *before*  | [Reducer](#reducers) | reducer to be resolved **before** the entity resolution |
+| *after*   | [Reducer](#reducers) | reducer to be resolved **after** the entity resolution |
+| *error*   | [Reducer](#reducers) | reducer to be resolved in case of an error |
 | *params*  | `Object` | User defined Hash that will be passed to every transform within the context of the transform's execution |
 
 ##### <a name="transform-entity">Transform Entity</a>
 
-A Transform entity is meant to be used as a 'snippet' entity that you can re-use in other entities. It does not expose the common before/after/error/params API that other entities have.
+A Transform entity is meant to be used as a 'snippet' entity that you can re-use in other entities. It does not expose the before/after/error/params API that other entities have.
 
-The value of a Transform entity is a [TransformExpression](#transform-expression).
+The value of a Transform entity is a [Reducer](#reducers).
 
 IMPORTANT: Transform Entities **do not support** (extension)[#extending-entities].
 
@@ -1033,7 +1019,7 @@ IMPORTANT: Transform Entities **do not support** (extension)[#extending-entities
 
 ```js
 dataPoint.addEntities({
-  'transform:<entityId>': TransformExpression
+  'transform:<entityId>': Reducer
 })
 ```
 
@@ -1079,10 +1065,10 @@ An Entry entity is where your data manipulation starts. As a best practice, use
 ```js
 dataPoint.addEntities({
   'entry:<entityId>': {
-    before: TransformExpression,
-    value: TransformExpression,
-    after: TransformExpression,
-    error: TransformExpression,
+    before: Reducer,
+    value: Reducer,
+    after: Reducer,
+    error: Reducer,
     params: Object
   }
 })
@@ -1092,11 +1078,11 @@ dataPoint.addEntities({
 
 | Key | Type | Description |
 |:---|:---|:---|
-| *before*  | [TransformExpression](#transform-expression) | Transform to be resolved **before** the entity resolution |
-| *value* | [TransformExpression](#transform-expression) | The value to which the Entity resolves |
-| *after*   | [TransformExpression](#transform-expression) | Transform to be resolved **after** the entity resolution |
-| *error*   | [TransformExpression](#transform-expression) | Transform to be resolved in case of an error |
-| *params*    | `Object` | User defined Hash that will be passed to every transform within the context of this transform's execution |
+| *before*  | [Reducer](#reducers) | reducer to be resolved **before** the entity resolution |
+| *value* | [Reducer](#reducers) | reducer to be resolved
+| *after*   | [Reducer](#reducers) | reducer to be resolved **after** the entity resolution |
+| *error*   | [Reducer](#reducers) | reducer to be resolved in case of an error |
+| *params*    | `Object` | user defined Hash that will be passed to every transform within the context of this transform's execution |
 
 ##### <a name="entry-value">Entry.value</a>
 
@@ -1424,12 +1410,12 @@ Requests a remote source, using [request](https://github.com/request/request) be
 ```js
 dataPoint.addEntities({
   'request:<entityId>': {
-    before: TransformExpression,
+    before: Reducer,
     url: StringTemplate,
     options: TransformObject,
-    beforeRequest: TransformExpression,
-    after: TransformExpression,
-    error: TransformExpression,
+    beforeRequest: Reducer,
+    after: Reducer,
+    error: Reducer,
     params: Object
   }
 })
@@ -1439,13 +1425,13 @@ dataPoint.addEntities({
 
 | Key | Type | Description |
 |:---|:---|:---|
-| *before*  | [TransformExpression](#transform-expression) | Transform to be resolved **before** the entity resolution |
+| *before*  | [Reducer](#reducers) | reducer to be resolved **before** the entity resolution |
 | *url*   | [StringTemplate](#string-template) | String value to resolve the request's url |
 | *options* | [TransformObject](#transform-object) | Request's options. These map directly to [request.js](https://github.com/request/request) options
-| *beforeRequest* | [TransformExpression](#transform-expression) | `acc.value` at this point will be the request options object being passed to the final request. You may do any modifications here, and then pass to the next reducer |
-| *after*   | [TransformExpression](#transform-expression) | Transform to be resolved **after** the entity resolution |
-| *error*   | [TransformExpression](#transform-expression) | Transform to be resolved in case of an error |
-| *params*    | `Object` | User defined Hash that will be passed to every transform within the context of the transform's execution |
+| *beforeRequest* | [Reducer](#reducers) | `acc.value` at this point will be the request options object being passed to the final request. You may do any modifications here, and then pass to the next reducer |
+| *after*   | [Reducer](#reducers) | reducer to be resolved **after** the entity resolution |
+| *error*   | [Reducer](#reducers) | reducer to be resolved in case of an error |
+| *params*    | `Object` | User defined Hash that will be passed to every reducer within the context of the transform function's execution |
 
 ##### <a name="request-url">Request.url</a>
 
@@ -1571,9 +1557,9 @@ Example at: [examples/entity-request-string-template.js](examples/entity-request
 
 ##### <a name="transform-object">TransformObject</a>
 
-A TransformObject is a Object where any property (at any level), that its key starts with the character `$` is treated as a [TransformExpression](#transform-expression). Properties that do not start with a `$` character will be left untouched.
+A TransformObject is a Object where any property (at any level), that its key starts with the character `$` is treated as a [Reducer](#reducers). Properties that do not start with a `$` character will be left untouched.
 
-When a TransformObject is to be resolved, all TransformExpressions are resolved in parallel, and their values will be injected in place of the TransformExpression. Also the `$` character will be removed from the resolved property.
+When a TransformObject is to be resolved, all reducers are resolved in parallel. The `$` character will also be removed from the resolved property.
 
 <details>
   <summary>TransformObject Example</summary>
@@ -1588,7 +1574,7 @@ When a TransformObject is to be resolved, all TransformExpressions are resolved
         qs: {
           // because the key starts
           // with $ it will be treated
-          // as a TransformExpression
+          // as a reducer
           $search: '$query'
         }
       }
@@ -1693,9 +1679,9 @@ If you want to have more control over the order of execution, you may use the [c
 ```js
 dataPoint.addEntities({
   'hash:<entityId>': {
-    before: TransformExpression,
+    before: Reducer,
 
-    value: TransformExpression,
+    value: Reducer,
     mapKeys: TransformMap,
     omitKeys: String[],
     pickKeys: String[],
@@ -1703,8 +1689,8 @@ dataPoint.addEntities({
     addValues: Object,
     compose: ComposeReducer[],
     
-    after: TransformExpression,
-    error: TransformExpression,
+    after: Reducer,
+    error: Reducer,
     params: Object,
   }
 })
@@ -1714,17 +1700,17 @@ dataPoint.addEntities({
 
 | Key | Type | Description |
 |:---|:---|:---|
-| *value* | [TransformExpression](#transform-expression) | The value to which the Entity resolves |
+| *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 |
 | *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*  | [TransformExpression](#transform-expression) | Transform to be resolved **before** the entity resolution |
-| *after*   | [TransformExpression](#transform-expression) | Transform to be resolved **after** the entity resolution |
-| *error*   | [TransformExpression](#transform-expression) | Transform to be resolved in case of an error |
-| *params*    | `Object` | User-defined Hash that will be passed to every transform within the context of the transform's execution |
+| *before*  | [Reducer](#reducers) | reducer to be resolved **before** the entity resolution |
+| *after*   | [Reducer](#reducers) | reducer to be resolved **after** the entity resolution |
+| *error*   | [Reducer](#reducers) | reducer to be resolved in case of an error |
+| *params*    | `Object` | User-defined Hash that will be passed to every reducer within the context of the transform function's execution |
 
 ##### <a name="hash-value">Hash.value</a>
 
@@ -1763,7 +1749,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 accepts a [TransformExpression](#transform-expression).
+Maps to a new set of key/value pairs through a [TransformMap](#transform-map), 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:
 
@@ -1807,14 +1793,14 @@ 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 of type [TransformExpression](#transform-expression).
+This structure allows you to map key/value pairs, where each value is a [Reducer](#reducers).
 
 **SYNOPSIS**
 
 ```js
 {
-  key1: TransformExpression,
-  key2: TransformExpression,
+  key1: Reducer,
+  key2: Reducer,
   ...
 }
 ```
@@ -2117,16 +2103,16 @@ Collection entities expose a set of reducers that you may apply to them: [map](#
 ```js
 dataPoint.addEntities({
   'collection:<entityId>': {
-    before: TransformExpression,
+    before: Reducer,
 
-    value: TransformExpression,
-    filter: TransformExpression,
-    map: TransformExpression,
-    find: TransformExpression,
+    value: Reducer,
+    filter: Reducer,
+    map: Reducer,
+    find: Reducer,
     compose: ComposeReducer[],
     
-    after: TransformExpression,
-    error: TransformExpression,
+    after: Reducer,
+    error: Reducer,
     params: Object,
   }
 })
@@ -2136,15 +2122,15 @@ dataPoint.addEntities({
 
 | Key | Type | Description |
 |:---|:---|:---|
-| *before*  | [TransformExpression](#transform-expression) | Transform to be resolved **before** the entity resolution |
-| *value* | [TransformExpression](#transform-expression) | The value to which the Entity resolves |
-| *map* | [TransformExpression](#transform-expression) | 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* | [TransformExpression](#transform-expression) | 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* | [TransformExpression](#transform-expression) | 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) |
+| *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) |
 | *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* | [TransformExpression](#transform-expression) | Transform to be resolved **after** the entity resolution |
-| *error* | [TransformExpression](#transform-expression) | Transform to be resolved in case of an error |
-| *params* | `Object` | User-defined Hash that will be passed to every transform within the context of the transform's execution |
+| *after* | [Reducer](#reducers) | reducer to be resolved **after** the entity resolution |
+| *error* | [Reducer](#reducers) | reducer to be resolved in case of an error |
+| *params* | `Object` | User-defined Hash that will be passed to every reducer within the context of the transform function's execution |
 
 <a name="collection-reducers-order">The order of execution of is:</a>
 
@@ -2205,7 +2191,7 @@ The above example is fairly simple. The following example hits each of these url
 _For the purpose of this example, let's imagine that GitHub does not provide the url api to get the list of tags._
 
 <details>
-  <summary>Using a TransformExpression in a Collection.map</summary>
+  <summary>Using a reducer in a Collection.map</summary>
 
   ```js
   dataPoint.addEntities({
@@ -2345,7 +2331,7 @@ The following example filters the data to identify all the repos that have more
 </details>
 
 
-Because `filter` accepts a transformExpression, you could use it to check whether a property evaluates to a [Truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) value.
+Because `filter` accepts a reducer, you could use it to check whether a property evaluates to a [Truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) value.
 
 The following example gets all the repos that are actually forks. In this case, because the `fork` property is a boolean, then you can do the following:
 
@@ -2560,13 +2546,13 @@ The Flow Control entity allows you to control the flow of your transformations.
 dataPoint.addEntities({
   'control:<entityId>': {
     select: [
-      { case: TransformExpression, do: Transform },
+      { case: Reducer, do: Transform },
       ...
       { default: Transform }
     ],
-    before: TransformExpression,
-    after: TransformExpression,
-    error: TransformExpression,
+    before: Reducer,
+    after: Reducer,
+    error: Reducer,
     params: Object,
   }
 })
@@ -2578,13 +2564,13 @@ dataPoint.addEntities({
 |:---|:---|:---|
 | *select* | [Case Statements](#case-statements)`[]` | Array of case statements, and a default fallback |
 | *params* | `Object` | User-defined Hash that will be passed to every transform within the context of the transform's execution |
-| *before* | [TransformExpression](#transform-expression) | Transform to be resolved **before** the entity resolution |
-| *after* | [TransformExpression](#transform-expression) | Transform to be resolved **after** the entity resolution |
-| *error* | [TransformExpression](#transform-expression) | Transform to be resolved in case of an error |
+| *before* | [Reducer](#reducers) | reducer to be resolved **before** the entity resolution |
+| *after* | [Reducer](#reducers) | reducer to be resolved **after** the entity resolution |
+| *error* | [Reducer](#reducers) | reducer to be resolved in case of an error |
 
 ##### <a name="case-statements">Case Statements</a>
 
-The `select` array may contain one or more case statements, similar to a `switch` in plain JavaScript. It executes from top to bottom, until it finds a case statement that results in a `truthy` value. Once it finds a match, it will execute its `do` transform to resolve the entity.
+The `select` array may contain one or more case statements, similar to a `switch` in plain JavaScript. It executes from top to bottom, until it finds a case statement that results in a `truthy` value. Once it finds a match, it will execute its `do` reducer to resolve the entity.
 
 If no case statement resolves to `truthy`, then the default statement will be used as the entity's resolution. 
 
@@ -2645,13 +2631,13 @@ For examples of control entities, see the ones used on the unit tests: [Control
 ```js
 dataPoint.addEntities({
   'schema:<entityId>': {
-    value: TransformExpression,
+    value: Reducer,
     schema: JSONSchema,
     options: Object,
 
-    before: TransformExpression,
-    after: TransformExpression,
-    error: TransformExpression,
+    before: Reducer,
+    after: Reducer,
+    error: Reducer,
     params: Object
   }
 })
@@ -2661,13 +2647,13 @@ dataPoint.addEntities({
 
 | Key | Type | Description |
 |:---|:---|:---|
-| *value* | [TransformExpression](#transform-expression) | The value that this entity will pass to the schema validation |
+| *value* | [Reducer](#reducers) | The value that this entity will pass to the schema validation |
 | *schema* | `Object` | Valid [JSON Schema](http://json-schema.org/documentation.html) object |
 | *options* | `Object` | Avj's [options](https://github.com/epoberezkin/ajv#options) object
 | *params* | `Object` | User-defined Hash that will be passed to every transform within the context of the transform's execution |
-| *before* | [TransformExpression](#transform-expression) | Transform to be resolved **before** the entity resolution |
-| *after* | [TransformExpression](#transform-expression) | Transform to be resolved **after** the entity resolution |
-| *error* | [TransformExpression](#transform-expression) | Transform to be resolved in case of an error |
+| *before* | [Reducer](#reducers) | reducer to be resolved **before** the entity resolution |
+| *after* | [Reducer](#reducers) | reducer to be resolved **after** the entity resolution |
+| *error* | [Reducer](#reducers) | reducer to be resolved in case of an error |
 
 **EXAMPLES**
 
@@ -2930,15 +2916,12 @@ function resolve(acc:Accumulator, resolveTransform:function):Promise<Accumulator
   function resolve (accumulator, resolveTransform) {
     // get Entity Spec
     const spec = accumulator.reducer.spec
-    // resolve 'spec.value' TransformExpression
-    // against accumulator
+    // resolve 'spec.value' reducer against accumulator
     return resolveTransform(accumulator, spec.value)
       .then((acc) => {
-        // execute lodash template against
-        // accumulator value
+        // execute lodash template against accumulator value
         const output = spec.template(acc.value)
-        // set new accumulator.value
-        // this method creates a new acc object
+        // set new accumulator.value this method creates a new acc object
         return DataPoint.set(acc, 'value', output)
       })
   }
diff --git a/packages/data-point/examples/custom-entity-type.js b/packages/data-point/examples/custom-entity-type.js
index 2811bac..217142d 100644
--- a/packages/data-point/examples/custom-entity-type.js
+++ b/packages/data-point/examples/custom-entity-type.js
@@ -28,7 +28,7 @@ function create (spec, id) {
 function resolve (accumulator, resolveTransform) {
   // get Entity Spec
   const spec = accumulator.reducer.spec
-  // resolve 'spec.value' TransformExpression
+  // resolve 'spec.value' reducer
   // against accumulator
   return resolveTransform(accumulator, spec.value).then(acc => {
     // execute lodash template against
diff --git a/packages/data-point/examples/entity-request-transform-object.js b/packages/data-point/examples/entity-request-transform-object.js
index e49a2ec..8da3e1c 100644
--- a/packages/data-point/examples/entity-request-transform-object.js
+++ b/packages/data-point/examples/entity-request-transform-object.js
@@ -6,7 +6,7 @@ dataPoint.addEntities({
     options: {
       qs: {
         // because the key starts with $
-        // it will be treated as a TransformExpression
+        // it will be treated as a reducer
         $search: acc => {
           return acc.value.search
         }
diff --git a/packages/data-point/lib/core/transform.js b/packages/data-point/lib/core/transform.js
index e51781f..4efd871 100644
--- a/packages/data-point/lib/core/transform.js
+++ b/packages/data-point/lib/core/transform.js
@@ -3,9 +3,8 @@
 const _ = require('lodash')
 const Promise = require('bluebird')
 
+const Reducer = require('../reducer')
 const AccumulatorFactory = require('../accumulator/factory')
-const TransformExpression = require('../transform-expression')
-const resolveTransform = require('../transform-expression').resolve
 
 function getOptions (spec) {
   return _.defaults({}, spec, {
@@ -13,7 +12,7 @@ function getOptions (spec) {
   })
 }
 
-function resolve (manager, transformSource, value, options) {
+function resolve (manager, reducerSource, value, options) {
   const contextOptions = getOptions(options)
   const context = AccumulatorFactory.create({
     value: value,
@@ -22,14 +21,14 @@ function resolve (manager, transformSource, value, options) {
     values: manager.values.getStore()
   })
 
-  const transform = TransformExpression.create(transformSource)
+  const transform = Reducer.create(reducerSource)
 
-  return resolveTransform(manager, context, transform)
+  return Reducer.resolve(manager, context, transform)
 }
 
-function transform (manager, transformSource, value, options, done) {
+function transform (manager, reducerSource, value, options, done) {
   return Promise.resolve()
-    .then(() => resolve(manager, transformSource, value, options))
+    .then(() => resolve(manager, reducerSource, value, options))
     .asCallback(done)
 }
 
diff --git a/packages/data-point/lib/entity-types/base-entity/factory.js b/packages/data-point/lib/entity-types/base-entity/factory.js
index 687637a..48316c3 100644
--- a/packages/data-point/lib/entity-types/base-entity/factory.js
+++ b/packages/data-point/lib/entity-types/base-entity/factory.js
@@ -1,7 +1,7 @@
 const deepFreeze = require('deep-freeze')
 const defaultTo = require('lodash/defaultTo')
 
-const createTransform = require('../../transform-expression').create
+const createReducer = require('../../reducer').create
 
 /**
  * @param {function} Factory - factory function to create the entity
@@ -14,19 +14,19 @@ function create (Factory, spec, id) {
   entity.id = id
 
   if (spec.before) {
-    entity.before = createTransform(spec.before)
+    entity.before = createReducer(spec.before)
   }
 
   if (spec.value) {
-    entity.value = createTransform(spec.value)
+    entity.value = createReducer(spec.value)
   }
 
   if (spec.after) {
-    entity.after = createTransform(spec.after)
+    entity.after = createReducer(spec.after)
   }
 
   if (spec.error) {
-    entity.error = createTransform(spec.error)
+    entity.error = createReducer(spec.error)
   }
 
   entity.params = deepFreeze(defaultTo(spec.params, {}))
diff --git a/packages/data-point/lib/entity-types/base-entity/resolve.js b/packages/data-point/lib/entity-types/base-entity/resolve.js
index e6f4180..00516f1 100644
--- a/packages/data-point/lib/entity-types/base-entity/resolve.js
+++ b/packages/data-point/lib/entity-types/base-entity/resolve.js
@@ -8,15 +8,14 @@ const middleware = require('../../middleware')
 const utils = require('../../utils')
 
 function resolveErrorReducers (error, accumulator, resolveReducer) {
-  const errorTransform = accumulator.reducer.spec.error
-
-  if (!errorTransform || errorTransform.reducers.length === 0) {
+  const errorReducer = accumulator.reducer.spec.error
+  if (utils.reducerIsEmpty(errorReducer)) {
     return Promise.reject(error)
   }
 
   const errorAccumulator = utils.set(accumulator, 'value', error)
 
-  const reducerResolved = resolveReducer(errorAccumulator, errorTransform)
+  const reducerResolved = resolveReducer(errorAccumulator, errorReducer)
 
   return reducerResolved.then(result =>
     utils.set(accumulator, 'value', result.value)
@@ -84,7 +83,7 @@ module.exports.resolveMiddleware = resolveMiddleware
 
 function resolveEntity (
   manager,
-  resolveTransform,
+  resolveReducer,
   accumulator,
   reducer,
   mainResolver
@@ -106,14 +105,15 @@ function resolveEntity (
     timeId = `⧖ ${accUid.context.id}(${accUid.euid})`
     console.time(timeId)
   }
+
   return Promise.resolve(accUid)
     .then(acc => resolveMiddleware(manager, `before`, acc))
     .then(acc =>
       resolveMiddleware(manager, `${reducer.entityType}:before`, acc)
     )
-    .then(acc => resolveTransform(acc, acc.reducer.spec.before))
-    .then(acc => mainResolver(acc, resolveTransform))
-    .then(acc => resolveTransform(acc, acc.reducer.spec.after))
+    .then(acc => resolveReducer(acc, acc.reducer.spec.before))
+    .then(acc => mainResolver(acc, resolveReducer))
+    .then(acc => resolveReducer(acc, acc.reducer.spec.after))
     .then(acc =>
       middleware.resolve(manager, `${reducer.entityType}:after`, acc)
     )
@@ -126,7 +126,7 @@ function resolveEntity (
       // attach entity information to help debug
       error.entityId = currentAccumulator.reducer.spec.id
 
-      return resolveErrorReducers(error, currentAccumulator, resolveTransform)
+      return resolveErrorReducers(error, currentAccumulator, resolveReducer)
     })
     .then(resultContext => {
       if (trace === true) {
@@ -148,12 +148,12 @@ function resolve (manager, resolveReducer, accumulator, reducer, mainResolver) {
     return Promise.resolve(accumulator)
   }
 
-  const resolveTransform = _.partial(resolveReducer, manager)
+  const resolveReducerBound = _.partial(resolveReducer, manager)
 
   if (!reducer.asCollection) {
     return resolveEntity(
       manager,
-      resolveTransform,
+      resolveReducerBound,
       accumulator,
       reducer,
       mainResolver
@@ -173,7 +173,7 @@ function resolve (manager, resolveReducer, accumulator, reducer, mainResolver) {
 
     return resolveEntity(
       manager,
-      resolveTransform,
+      resolveReducerBound,
       itemCtx,
       reducer,
       mainResolver
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 7469562..4da2aa8 100644
--- a/packages/data-point/lib/entity-types/entity-collection/factory.js
+++ b/packages/data-point/lib/entity-types/entity-collection/factory.js
@@ -1,8 +1,8 @@
 'use strict'
 
 const _ = require('lodash')
-const createTransform = require('../../transform-expression').create
 const parseCompose = require('../parse-compose')
+const createReducer = require('../../reducer').create
 const createBaseEntity = require('../base-entity').create
 
 /**
@@ -17,7 +17,7 @@ const modifierKeys = ['filter', 'map', 'find']
 function createCompose (composeParse) {
   return composeParse.map(modifier => {
     return _.assign({}, modifier, {
-      transform: createTransform(modifier.spec)
+      transform: createReducer(modifier.spec)
     })
   })
 }
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 05dba4e..0143c4f 100644
--- a/packages/data-point/lib/entity-types/entity-collection/resolve.js
+++ b/packages/data-point/lib/entity-types/entity-collection/resolve.js
@@ -5,7 +5,7 @@ const Promise = require('bluebird')
 const utils = require('../../utils')
 
 function resolveMapTransform (accumulator, transform, resolveTransform) {
-  if (transform.reducers.length === 0) {
+  if (utils.reducerIsEmpty(transform)) {
     return Promise.resolve(accumulator)
   }
   return Promise.map(accumulator.value, itemValue => {
@@ -22,7 +22,7 @@ function resolveMapTransform (accumulator, transform, resolveTransform) {
 }
 
 function resolveFilterTransform (accumulator, transform, resolveTransform) {
-  if (transform.reducers.length === 0) {
+  if (utils.reducerIsEmpty(transform)) {
     return Promise.resolve(accumulator)
   }
   return Promise.filter(accumulator.value, itemValue => {
@@ -41,7 +41,7 @@ function resolveFilterTransform (accumulator, transform, resolveTransform) {
 }
 
 function resolveFindTransform (accumulator, transform, resolveTransform) {
-  if (transform.reducers.length === 0) {
+  if (utils.reducerIsEmpty(transform)) {
     return Promise.resolve(accumulator)
   }
   return Promise.reduce(
diff --git a/packages/data-point/lib/entity-types/entity-control/factory.js b/packages/data-point/lib/entity-types/entity-control/factory.js
index 18bb6f3..4a5bec3 100644
--- a/packages/data-point/lib/entity-types/entity-control/factory.js
+++ b/packages/data-point/lib/entity-types/entity-control/factory.js
@@ -2,7 +2,7 @@
 
 const _ = require('lodash')
 
-const createTransform = require('../../transform-expression').create
+const createReducer = require('../../reducer').create
 const createBaseEntity = require('../base-entity').create
 
 /**
@@ -15,20 +15,20 @@ function EntityControl () {
 module.exports.EntityControl = EntityControl
 
 /**
- * map each key from spec into a Transform object
+ * map each key from spec into a reducer
  *
- * @param {hash} spec - key/value where each value will be mapped into a Transform
+ * @param {hash} spec - key/value where each value will be mapped into a reducer
  * @returns
  */
 function parseCaseStatement (spec) {
-  return _.mapValues(spec, createTransform)
+  return _.mapValues(spec, createReducer)
 }
 module.exports.parseCaseStatement = parseCaseStatement
 
 /**
  * Parse only case statements
  *
- * @param {hash} spec - key/value where each value will be mapped into a Transform
+ * @param {hash} spec - key/value where each value will be mapped into a reducer
  * @returns
  */
 function parseCaseStatements (spec) {
@@ -53,7 +53,7 @@ function parseDefaultStatement (id, select) {
   return defaultCase.default
 }
 /**
- * parse spec into transform strucure
+ * parse spec
  *
  * @param {any} spec
  * @returns
@@ -63,7 +63,7 @@ function parseSwitch (spec) {
   const defaultStatement = parseDefaultStatement(spec.id, select)
   return {
     cases: parseCaseStatements(select),
-    default: createTransform(defaultStatement)
+    default: createReducer(defaultStatement)
   }
 }
 module.exports.parseSwitch = parseSwitch
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 adae8fa..3b2f27d 100644
--- a/packages/data-point/lib/entity-types/entity-hash/factory.js
+++ b/packages/data-point/lib/entity-types/entity-hash/factory.js
@@ -1,7 +1,7 @@
 'use strict'
 
 const _ = require('lodash')
-const createTransform = require('../../transform-expression').create
+const createReducer = require('../../reducer').create
 const createReducerObject = require('../../reducer-object').create
 const deepFreeze = require('deep-freeze')
 const parseCompose = require('../parse-compose')
@@ -32,7 +32,7 @@ function createCompose (composeParse) {
         break
       case 'mapKeys':
       case 'addKeys':
-        transform = createReducerObject(createTransform, modifier.spec)
+        transform = createReducerObject(createReducer, modifier.spec)
     }
 
     return Object.assign({}, modifier, {
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 41ecda9..3175b71 100644
--- a/packages/data-point/lib/entity-types/entity-hash/resolve.js
+++ b/packages/data-point/lib/entity-types/entity-hash/resolve.js
@@ -5,8 +5,7 @@ const Promise = require('bluebird')
 const utils = require('../../utils')
 
 function resolveMapKeys (accumulator, reducer, resolveTransform) {
-  const transform = { reducers: [reducer] }
-  return resolveTransform(accumulator, transform).then(acc => {
+  return resolveTransform(accumulator, reducer).then(acc => {
     return utils.set(accumulator, 'value', acc.value)
   })
 }
@@ -14,8 +13,7 @@ function resolveMapKeys (accumulator, reducer, resolveTransform) {
 module.exports.resolveMapKeys = resolveMapKeys
 
 function resolveAddKeys (accumulator, reducer, resolveTransform) {
-  const transform = { reducers: [reducer] }
-  return resolveTransform(accumulator, transform).then(acc => {
+  return resolveTransform(accumulator, reducer).then(acc => {
     return resolveAddValues(accumulator, acc.value)
   })
 }
diff --git a/packages/data-point/lib/entity-types/entity-request/factory.js b/packages/data-point/lib/entity-types/entity-request/factory.js
index 3214198..e281622 100644
--- a/packages/data-point/lib/entity-types/entity-request/factory.js
+++ b/packages/data-point/lib/entity-types/entity-request/factory.js
@@ -2,8 +2,8 @@
 
 const _ = require('lodash')
 const fp = require('lodash/fp')
-const createTransform = require('../../transform-expression').create
 const createBaseEntity = require('../base-entity').create
+const createReducer = require('../../reducer').create
 const TransformKeys = require('./transform-keys')
 
 /**
@@ -21,7 +21,7 @@ function getTransformKeys (options) {
   const transformKeys = TransformKeys.getTransformKeys(options)
   return transformKeys.map(key => {
     return Object.assign({}, key, {
-      transform: createTransform(key.value)
+      transform: createReducer(key.value)
     })
   })
 }
@@ -44,7 +44,7 @@ function create (spec, id) {
   const entity = createBaseEntity(EntityRequest, spec, id)
   const options = _.defaultTo(spec.options, {})
   entity.url = _.defaultTo(spec.url, '')
-  entity.beforeRequest = createTransform(spec.beforeRequest)
+  entity.beforeRequest = createReducer(spec.beforeRequest)
   entity.transformOptionKeys = getTransformKeys(options)
   entity.options = unsetTransformKeys(options, entity.transformOptionKeys)
 
diff --git a/packages/data-point/lib/helpers/helpers.js b/packages/data-point/lib/helpers/helpers.js
index 98f4c54..dc9c829 100644
--- a/packages/data-point/lib/helpers/helpers.js
+++ b/packages/data-point/lib/helpers/helpers.js
@@ -2,9 +2,15 @@
 
 const _ = require('lodash')
 const Promise = require('bluebird')
-const resolveTransform = require('../transform-expression').resolve
+const resolveTransform = require('../reducer').resolve
 const AccumulatorFactory = require('../accumulator/factory')
 
+const ReducerEntity = require('../reducer-entity/factory').ReducerEntity
+const ReducerFunction = require('../reducer-function/factory').ReducerFunction
+const ReducerList = require('../reducer-list/factory').ReducerList
+const ReducerObject = require('../reducer-object/factory').ReducerObject
+const ReducerPath = require('../reducer-path/factory').ReducerPath
+
 function reducify (method) {
   return function () {
     const partialArguments = Array.prototype.slice.call(arguments)
@@ -38,9 +44,10 @@ function mockReducer (reducer, acc) {
 
 module.exports.mockReducer = mockReducer
 
-const createTransform = require('../transform-expression').create
+const createReducer = require('../reducer').create
 
-module.exports.createTransform = createTransform
+// this is named createTransform for backwards compatibility
+module.exports.createTransform = createReducer
 
 const createEntity = require('../entity-types/base-entity').create
 
@@ -69,9 +76,17 @@ function createResolveTransform (dataPoint) {
 
 module.exports.createResolveTransform = createResolveTransform
 
-function isTransform (transform) {
+/**
+ * @param {*} data
+ * @returns {boolean}
+ */
+function isTransform (data) {
   return (
-    _.isArray(transform.reducers) && transform.typeOf === 'TransformExpression'
+    data instanceof ReducerEntity ||
+    data instanceof ReducerFunction ||
+    data instanceof ReducerList ||
+    data instanceof ReducerObject ||
+    data instanceof ReducerPath
   )
 }
 
diff --git a/packages/data-point/lib/locals/factory.js b/packages/data-point/lib/locals/factory.js
index 3d06e07..f8ff14c 100644
--- a/packages/data-point/lib/locals/factory.js
+++ b/packages/data-point/lib/locals/factory.js
@@ -7,8 +7,7 @@ function Locals () {}
 module.exports.Locals = Locals
 
 /**
- * parses a raw transform
- * @param  {string} transformRaw raw value path to be parsed
+ * @param {Object} spec
  * @return {Locals}
  */
 function create (spec) {
diff --git a/packages/data-point/lib/transform-expression/factory.js b/packages/data-point/lib/reducer-list/factory.js
similarity index 54%
rename from packages/data-point/lib/transform-expression/factory.js
rename to packages/data-point/lib/reducer-list/factory.js
index 31efd3c..ce6ce25 100644
--- a/packages/data-point/lib/transform-expression/factory.js
+++ b/packages/data-point/lib/reducer-list/factory.js
@@ -1,29 +1,43 @@
 'use strict'
 
 const _ = require('lodash')
-const reducerFactory = require('../reducer/factory')
+
+const REDUCER_LIST = 'ReducerList'
+
+module.exports.type = REDUCER_LIST
 
 /**
- * Describes the transform parts used to reduce a context
  * @class
- * @property {Array} reducers - collection of reducers that will be applied
+ * @property {string} type
+ * @property {Array<reducer>} reducers
  */
-function TransformExpression () {
+function ReducerList () {
+  this.type = 'ReducerList'
   this.reducers = []
-  this.typeOf = 'TransformExpression'
 }
 
-module.exports.TransformExpression = TransformExpression
+module.exports.ReducerList = ReducerList
+
+/**
+ * @param {*} source
+ * @returns {boolean}
+ */
+function isType (source) {
+  return Array.isArray(source)
+}
+
+module.exports.isType = isType
 
 /**
  * @param {string} source
  * @returns {Array}
  */
 function parseFromString (source) {
-  const transformSource = _.defaultTo(source, '')
-  const tokens = _.compact(transformSource.split(' | '))
+  const reducerSource = _.defaultTo(source, '')
+  const tokens = _.compact(reducerSource.split(' | '))
   return tokens
 }
+
 module.exports.parseFromString = parseFromString
 
 /**
@@ -33,6 +47,7 @@ module.exports.parseFromString = parseFromString
 function parseTokenExpression (source) {
   return _.isString(source) ? parseFromString(source) : source
 }
+
 module.exports.parseTokenExpression = parseTokenExpression
 
 /**
@@ -60,21 +75,19 @@ function parse (source) {
 module.exports.parse = parse
 
 /**
- * parses a raw transform
- * @param {string} source
- * @return {Transform}
+ * @param {Function} createReducer
+ * @param {Array} source
+ * @return {reducer}
  */
-function create (source = []) {
+function create (createReducer, source = []) {
   const tokens = parse(source)
 
-  const transform = new TransformExpression()
+  const reducers = tokens.map(token => createReducer(token))
 
-  transform.reducers = tokens.map(token => {
-    // NOTE: recursive call
-    return reducerFactory.create(create, token)
-  })
+  const reducer = new ReducerList()
+  reducer.reducers = reducers
 
-  return Object.freeze(transform)
+  return Object.freeze(reducer)
 }
 
 module.exports.create = create
diff --git a/packages/data-point/lib/reducer-list/index.js b/packages/data-point/lib/reducer-list/index.js
new file mode 100644
index 0000000..84c8826
--- /dev/null
+++ b/packages/data-point/lib/reducer-list/index.js
@@ -0,0 +1,12 @@
+/* eslint global-require: 0 */
+
+const factory = require('./factory')
+const resolve = require('./resolve').resolve
+
+module.exports = {
+  parse: factory.parse,
+  create: factory.create,
+  type: factory.type,
+  isType: factory.isType,
+  resolve: resolve
+}
diff --git a/packages/data-point/lib/reducer-list/resolve.js b/packages/data-point/lib/reducer-list/resolve.js
new file mode 100644
index 0000000..052961f
--- /dev/null
+++ b/packages/data-point/lib/reducer-list/resolve.js
@@ -0,0 +1,27 @@
+'use strict'
+
+const Promise = require('bluebird')
+const partial = require('lodash/partial')
+
+/**
+ * @param {Object} manager
+ * @param {Function} resolveTransform
+ * @param {Accumulator} accumulator
+ * @param {ReducerList} reducerList
+ * @returns {Promise<Accumulator>}
+ */
+function resolve (manager, resolveTransform, accumulator, reducerList) {
+  if (reducerList.reducers.length === 0) {
+    return Promise.resolve(accumulator)
+  }
+
+  const result = Promise.reduce(
+    reducerList.reducers,
+    partial(resolveTransform, manager),
+    accumulator
+  )
+
+  return result
+}
+
+module.exports.resolve = resolve
diff --git a/packages/data-point/lib/reducer-object/factory.js b/packages/data-point/lib/reducer-object/factory.js
index 223beb3..488b453 100644
--- a/packages/data-point/lib/reducer-object/factory.js
+++ b/packages/data-point/lib/reducer-object/factory.js
@@ -27,30 +27,25 @@ function isObject (source) {
 module.exports.isObject = isObject
 
 /**
- * @param {Function} createTransform
+ * @param {Function} createReducer
  * @param {Object} source
  * @param {Array} path
  * @param {Array} reducerProps
  * @returns {Array}
  */
-function getReducerProps (
-  createTransform,
-  source,
-  path = [],
-  reducerProps = []
-) {
+function getReducerProps (createReducer, source, path = [], reducerProps = []) {
   for (let key of Object.keys(source)) {
     const value = source[key]
     const fullPath = path.concat(key)
     if (isPlainObject(value)) {
       // NOTE: recursive call
-      getReducerProps(createTransform, value, fullPath, reducerProps)
+      getReducerProps(createReducer, value, fullPath, reducerProps)
       continue
     }
 
     reducerProps.push({
       path: fullPath,
-      transform: createTransform(value)
+      transform: createReducer(value)
     })
   }
 
@@ -60,13 +55,13 @@ function getReducerProps (
 module.exports.getReducerProps = getReducerProps
 
 /**
- * @param {Function} createTransform
+ * @param {Function} createReducer
  * @param {Object} source
  * @returns {reducer}
  */
-function create (createTransform, source = {}) {
+function create (createReducer, source = {}) {
   const reducer = new ReducerObject()
-  reducer.props = getReducerProps(createTransform, source)
+  reducer.props = getReducerProps(createReducer, source)
 
   return Object.freeze(reducer)
 }
diff --git a/packages/data-point/lib/reducer/factory.js b/packages/data-point/lib/reducer/factory.js
index 47b589b..06939c9 100644
--- a/packages/data-point/lib/reducer/factory.js
+++ b/packages/data-point/lib/reducer/factory.js
@@ -6,21 +6,41 @@ const ReducerPath = require('../reducer-path')
 const ReducerFunction = require('../reducer-function')
 const ReducerObject = require('../reducer-object')
 const ReducerEntity = require('../reducer-entity')
+const ReducerList = require('../reducer-list')
 const util = require('util')
 
 const reducerTypes = [ReducerPath, ReducerFunction, ReducerEntity]
 
+/**
+ * this is here because ReducerLists can be arrays or | separated strings
+ * @param {*} source
+ * @returns {Array<reducer>|reducer}
+ */
+function dealWithPipeOperators (source) {
+  let result = ReducerList.parse(source)
+  if (result.length === 1) {
+    // do not create a ReducerList that only contains a single reducer
+    result = result[0]
+  }
+
+  return result
+}
+
 /**
  * parse reducer
- * @param {Function} createTransform
  * @param {*} source
  * @throws if source is not a valid type for creating a reducer
  * @return {reducer}
  */
-function create (createTransform, source) {
-  // ReducerObject requires an extra parameter, so it's not included in the reducerTypes array
+function createReducer (source) {
+  source = dealWithPipeOperators(source)
+
   if (ReducerObject.isType(source)) {
-    return ReducerObject.create(createTransform, source)
+    return ReducerObject.create(createReducer, source)
+  }
+
+  if (ReducerList.isType(source)) {
+    return ReducerList.create(createReducer, source)
   }
 
   const reducer = _.find(reducerTypes, r => r.isType(source))
@@ -40,4 +60,4 @@ function create (createTransform, source) {
   return reducer.create(source)
 }
 
-module.exports.create = create
+module.exports.create = createReducer
diff --git a/packages/data-point/lib/reducer/resolve.js b/packages/data-point/lib/reducer/resolve.js
index 16a9fbb..18f76f6 100644
--- a/packages/data-point/lib/reducer/resolve.js
+++ b/packages/data-point/lib/reducer/resolve.js
@@ -3,6 +3,7 @@ const resolveReducerPath = require('../reducer-path').resolve
 const resolveReducerFunction = require('../reducer-function').resolve
 const resolveReducerObject = require('../reducer-object').resolve
 const resolveReducerEntity = require('../reducer-entity').resolve
+const resolveReducerList = require('../reducer-list').resolve
 
 /**
  * @param {Object} manager
@@ -29,6 +30,10 @@ function getReducerFunction (manager, resolveTransform, reducerType) {
       // NOTE: recursive call
       resolver = partial(resolveReducerEntity, manager, resolveTransform)
       break
+    case 'ReducerList':
+      // NOTE: recursive call
+      resolver = partial(resolveReducerList, manager, resolveTransform)
+      break
     default:
       throw new Error(`Reducer type '${reducerType}' was not recognized`)
   }
@@ -41,17 +46,16 @@ module.exports.getReducerFunction = getReducerFunction
 /**
  * apply a Reducer to an accumulator
  * @param {Object} manager
- * @param {Function} resolveTransform
  * @param {Accumulator} accumulator
  * @param {Reducer} reducer
  * @returns {Promise<Accumulator>}
  */
-function resolve (manager, resolveTransform, accumulator, reducer) {
-  const reducerFunction = getReducerFunction(
-    manager,
-    resolveTransform,
-    reducer.type
-  )
+function resolve (manager, accumulator, reducer) {
+  if (!reducer) {
+    return Promise.resolve(accumulator)
+  }
+
+  const reducerFunction = getReducerFunction(manager, resolve, reducer.type)
   const result = reducerFunction(accumulator, reducer)
   return result
 }
diff --git a/packages/data-point/lib/transform-expression/index.js b/packages/data-point/lib/transform-expression/index.js
deleted file mode 100644
index 8de7fdf..0000000
--- a/packages/data-point/lib/transform-expression/index.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/* eslint global-require: 0 */
-
-module.exports = {
-  create: require('./factory').create,
-  resolve: require('./resolve').resolve
-}
diff --git a/packages/data-point/lib/transform-expression/resolve.js b/packages/data-point/lib/transform-expression/resolve.js
deleted file mode 100644
index 2841e9e..0000000
--- a/packages/data-point/lib/transform-expression/resolve.js
+++ /dev/null
@@ -1,31 +0,0 @@
-'use strict'
-
-const Promise = require('bluebird')
-const partial = require('lodash/partial')
-
-const resolveReducer = require('../reducer').resolve
-
-/**
- * resolves a given transform
- * @param {Object} manager
- * @param {Accumulator} accumulator
- * @param {TransformExpression} transform
- * @returns {Promise<Accumulator>}
- */
-function resolve (manager, accumulator, transform) {
-  if (!transform || transform.reducers.length === 0) {
-    return Promise.resolve(accumulator)
-  }
-
-  // NOTE: recursive call
-  const reduceTransformReducer = partial(resolveReducer, manager, resolve)
-  const result = Promise.reduce(
-    transform.reducers,
-    reduceTransformReducer,
-    accumulator
-  )
-
-  return result
-}
-
-module.exports.resolve = resolve
diff --git a/packages/data-point/lib/utils/index.js b/packages/data-point/lib/utils/index.js
index 155cdbb..ff4c770 100644
--- a/packages/data-point/lib/utils/index.js
+++ b/packages/data-point/lib/utils/index.js
@@ -89,6 +89,28 @@ function inspectProperties (obj, props, indent = '') {
 
 module.exports.inspectProperties = inspectProperties
 
+/**
+ * @param {reducer} reducer
+ * @returns {boolean}
+ */
+function reducerIsEmpty (reducer) {
+  if (!reducer) {
+    return true
+  }
+
+  if (reducer.type === 'ReducerList') {
+    return _.isEmpty(reducer.reducers)
+  }
+
+  if (reducer.type === 'ReducerObject') {
+    return _.isEmpty(reducer.props)
+  }
+
+  return false
+}
+
+module.exports.reducerIsEmpty = reducerIsEmpty
+
 function isFalsy (val) {
   return val === null || val === false || typeof val === 'undefined'
 }


Test patch:
diff --git a/packages/data-point-express/lib/middleware.test.js b/packages/data-point-express/lib/middleware.test.js
index 1808c02..e3c17e5 100644
--- a/packages/data-point-express/lib/middleware.test.js
+++ b/packages/data-point-express/lib/middleware.test.js
@@ -28,7 +28,7 @@ function createReq () {
   return req
 }
 
-describe('buildTransfromOptions', () => {
+describe('buildTransformOptions', () => {
   const req = createReq()
 
   test('It should have locals object', () => {
diff --git a/packages/data-point/lib/entity-types/base-entity/factory.test.js b/packages/data-point/lib/entity-types/base-entity/factory.test.js
index a2aae39..92a0ac2 100644
--- a/packages/data-point/lib/entity-types/base-entity/factory.test.js
+++ b/packages/data-point/lib/entity-types/base-entity/factory.test.js
@@ -18,9 +18,9 @@ describe('factory.createBaseEntity', () => {
     )
 
     expect(entity).toHaveProperty('id', 'foo')
-    expect(entity).toHaveProperty('value.typeOf', 'TransformExpression')
-    expect(entity).toHaveProperty('error.typeOf', 'TransformExpression')
-    expect(entity).toHaveProperty('after.typeOf', 'TransformExpression')
+    expect(entity).toHaveProperty('value.type', 'ReducerPath')
+    expect(entity).toHaveProperty('error.type', 'ReducerPath')
+    expect(entity).toHaveProperty('after.type', 'ReducerPath')
     expect(entity).toHaveProperty('params', {})
   })
 })
diff --git a/packages/data-point/lib/entity-types/base-entity/resolve.test.js b/packages/data-point/lib/entity-types/base-entity/resolve.test.js
index 285c0c0..4fe77b4 100644
--- a/packages/data-point/lib/entity-types/base-entity/resolve.test.js
+++ b/packages/data-point/lib/entity-types/base-entity/resolve.test.js
@@ -2,18 +2,20 @@
 'use strict'
 
 const ResolveEntity = require('./resolve')
-const ReducerEntity = require('../../reducer-entity')
+const createReducerEntity = require('../../reducer-entity').create
+const createReducer = require('../../reducer').create
+const resolveTransform = require('../../reducer').resolve
 
 const FixtureStore = require('../../../test/utils/fixture-store')
 const helpers = require('../../helpers')
 const utils = require('../../utils')
 
 let dataPoint
-let resolveTransform
+let resolveTransformBound
 
 beforeAll(() => {
   dataPoint = FixtureStore.create()
-  resolveTransform = helpers.createResolveTransform(dataPoint)
+  resolveTransformBound = helpers.createResolveTransform(dataPoint)
 })
 
 afterEach(() => {
@@ -27,14 +29,14 @@ describe('ResolveEntity.resolveErrorReducers', () => {
       {},
       {
         context: {
-          error: helpers.createTransform([])
+          error: createReducer([])
         }
       }
     )
     return ResolveEntity.resolveErrorReducers(
       err,
       accumulator,
-      resolveTransform
+      resolveTransformBound
     )
       .catch(reason => reason)
       .then(acc => {
@@ -49,14 +51,14 @@ describe('ResolveEntity.resolveErrorReducers', () => {
       {},
       {
         context: {
-          error: helpers.createTransform((acc, next) => next(null, 'pass'))
+          error: createReducer((acc, next) => next(null, 'pass'))
         }
       }
     )
     return ResolveEntity.resolveErrorReducers(
       err,
       accumulator,
-      resolveTransform
+      resolveTransformBound
     ).then(acc => {
       expect(acc.value).toEqual('pass')
     })
@@ -66,7 +68,7 @@ describe('ResolveEntity.resolveErrorReducers', () => {
 describe('ResolveEntity.createCurrentAccumulator', () => {
   let acc
   beforeAll(() => {
-    const reducerEntity = ReducerEntity.create('hash:base')
+    const reducerEntity = createReducerEntity('hash:base')
     const accumulator = helpers.createAccumulator({
       foo: 'bar'
     })
@@ -129,17 +131,15 @@ describe('ResolveEntity.resolveMiddleware', () => {
   })
 })
 
-const ResolveTransform = require('../../transform-expression/resolve')
-
 describe('ResolveEntity.resolveEntity', () => {
   const defaultResolver = (acc, resolveTransform) => Promise.resolve(acc)
 
   const resolveEntity = (entityId, input, options, resolver) => {
     const racc = helpers.createAccumulator.call(null, input, options)
-    const reducer = ReducerEntity.create(entityId)
+    const reducer = createReducerEntity(entityId)
     return ResolveEntity.resolveEntity(
       dataPoint,
-      resolveTransform,
+      resolveTransformBound,
       racc,
       reducer,
       resolver || defaultResolver
@@ -203,10 +203,10 @@ describe('ResolveEntity.resolveEntity', () => {
 describe('ResolveEntity.resolve', () => {
   const resolve = resolver => (entityId, input, options) => {
     const racc = helpers.createAccumulator.call(null, input, options)
-    const reducer = ReducerEntity.create(entityId)
+    const reducer = createReducerEntity(entityId)
     return ResolveEntity.resolve(
       dataPoint,
-      ResolveTransform.resolve,
+      resolveTransform,
       racc,
       reducer,
       resolver
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 bbb32fc..7b28820 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
@@ -23,10 +23,7 @@ describe('parse loose modifiers', () => {
 
     expect(result.compose).toBeInstanceOf(Array)
     expect(result.compose[0]).toHaveProperty('type', 'map')
-    expect(result.compose[0].transform).toHaveProperty(
-      'typeOf',
-      'TransformExpression'
-    )
+    expect(result.compose[0].transform).toHaveProperty('type', 'ReducerPath')
   })
 
   test('modelFactory#create default', () => {
@@ -51,10 +48,7 @@ describe('parse compose modifier', () => {
 
     expect(result.compose).toBeInstanceOf(Array)
     expect(result.compose[0]).toHaveProperty('type', 'map')
-    expect(result.compose[0].transform).toHaveProperty(
-      'typeOf',
-      'TransformExpression'
-    )
+    expect(result.compose[0].transform).toHaveProperty('type', 'ReducerPath')
   })
 
   test('throw error if compose is not an array', () => {
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 fe570ad..515b75f 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
@@ -128,15 +128,15 @@ describe('factory#parse composed modifiers', () => {
     expect(result.compose[0].transform).toHaveProperty('type', 'ReducerObject')
     expect(result.compose[0].transform.props[0].path).toEqual(['a'])
     expect(result.compose[0].transform.props[0].transform).toHaveProperty(
-      'typeOf',
-      'TransformExpression'
+      'type',
+      'ReducerPath'
     )
     expect(result.compose[1]).toHaveProperty('type', 'mapKeys')
     expect(result.compose[1].transform).toHaveProperty('type', 'ReducerObject')
     expect(result.compose[1].transform.props[0].path).toEqual(['a'])
     expect(result.compose[1].transform.props[0].transform).toHaveProperty(
-      'typeOf',
-      'TransformExpression'
+      'type',
+      'ReducerPath'
     )
     expect(result.compose[2]).toHaveProperty('type', 'omitKeys')
     expect(result.compose[2].transform).toEqual(['a'])
diff --git a/packages/data-point/lib/entity-types/entity-request/factory.test.js b/packages/data-point/lib/entity-types/entity-request/factory.test.js
index a1421c1..e743d29 100644
--- a/packages/data-point/lib/entity-types/entity-request/factory.test.js
+++ b/packages/data-point/lib/entity-types/entity-request/factory.test.js
@@ -4,7 +4,6 @@
 const requests = require('../../../test/definitions/requests')
 
 const requestFactory = require('./factory')
-const helpers = require('../../helpers')
 
 describe('create', () => {
   let request
@@ -41,7 +40,7 @@ describe('create', () => {
     request.transformOptionKeys.forEach(element => {
       expect(element).toHaveProperty('path')
       expect(element).toHaveProperty('transform')
-      expect(helpers.isTransform(element.transform)).toBe(true)
+      expect(element.transform).toHaveProperty('type', 'ReducerFunction')
     }, this)
   })
 })
diff --git a/packages/data-point/lib/entity-types/entity-request/resolve.test.js b/packages/data-point/lib/entity-types/entity-request/resolve.test.js
index ee44c09..6b31a4c 100644
--- a/packages/data-point/lib/entity-types/entity-request/resolve.test.js
+++ b/packages/data-point/lib/entity-types/entity-request/resolve.test.js
@@ -7,7 +7,6 @@ const Resolve = require('./resolve')
 
 const AccumulatorFactory = require('../../accumulator/factory')
 const ReducerFactory = require('../../reducer/factory')
-const createTransform = require('../../transform-expression/factory').create
 const LocalsFactory = require('../../locals/factory')
 
 const ResolveEntity = require('../base-entity/resolve')
@@ -39,7 +38,7 @@ function helperMockContext (accumulatorData, reducerSource, requestName) {
     locals,
     values
   })
-  const reducer = ReducerFactory.create(createTransform, reducerSource)
+  const reducer = ReducerFactory.create(reducerSource)
   return ResolveEntity.createCurrentAccumulator(dataPoint, accumulator, reducer)
 }
 
@@ -132,7 +131,7 @@ describe('resolveOptions', () => {
           transformOptionKeys: [
             {
               path: 'qs.key',
-              transform: helpers.createTransform('$foo.bar')
+              transform: ReducerFactory.create('$foo.bar')
             }
           ]
         }
diff --git a/packages/data-point/lib/entity-types/entity-transform/factory.test.js b/packages/data-point/lib/entity-types/entity-transform/factory.test.js
index f989b1f..6cb10dd 100644
--- a/packages/data-point/lib/entity-types/entity-transform/factory.test.js
+++ b/packages/data-point/lib/entity-types/entity-transform/factory.test.js
@@ -7,5 +7,5 @@ test('modelFactory#create default', () => {
   const result = modelFactory.create('$a', 'test')
 
   expect(result).toHaveProperty('id', 'test')
-  expect(result.value).toHaveProperty('typeOf', 'TransformExpression')
+  expect(result.value).toHaveProperty('type', 'ReducerPath')
 })
diff --git a/packages/data-point/lib/helpers/helpers.test.js b/packages/data-point/lib/helpers/helpers.test.js
index 58d3f9c..fde7760 100644
--- a/packages/data-point/lib/helpers/helpers.test.js
+++ b/packages/data-point/lib/helpers/helpers.test.js
@@ -4,6 +4,12 @@
 const _ = require('lodash')
 const helpers = require('./helpers')
 
+const ReducerEntity = require('../reducer-entity/factory').ReducerEntity
+const ReducerFunction = require('../reducer-function/factory').ReducerFunction
+const ReducerList = require('../reducer-list/factory').ReducerList
+const ReducerObject = require('../reducer-object/factory').ReducerObject
+const ReducerPath = require('../reducer-path/factory').ReducerPath
+
 describe('helpers.reducify', () => {
   test('pass simple', done => {
     const rpick = helpers.reducify(_.pick)
@@ -95,8 +101,16 @@ describe('helpers.createResolveTransform', () => {
   })
 })
 
-describe('isTransform', () => {
-  test('It should recognize as transform', () => {
-    expect(helpers.isTransform(helpers.createTransform([]))).toBe(true)
+describe('helpers.isTransform', () => {
+  test('It should return true for reducers', () => {
+    expect(helpers.isTransform()).toBe(false)
+    expect(helpers.isTransform({})).toBe(false)
+    expect(helpers.isTransform([])).toBe(false)
+    expect(helpers.isTransform({ type: 'ReducerPath' })).toBe(false)
+    expect(helpers.isTransform(new ReducerEntity())).toBe(true)
+    expect(helpers.isTransform(new ReducerFunction())).toBe(true)
+    expect(helpers.isTransform(new ReducerList())).toBe(true)
+    expect(helpers.isTransform(new ReducerObject())).toBe(true)
+    expect(helpers.isTransform(new ReducerPath())).toBe(true)
   })
 })
diff --git a/packages/data-point/lib/reducer-function/resolve.test.js b/packages/data-point/lib/reducer-function/resolve.test.js
index dc36ccb..324193f 100644
--- a/packages/data-point/lib/reducer-function/resolve.test.js
+++ b/packages/data-point/lib/reducer-function/resolve.test.js
@@ -4,7 +4,6 @@
 const AccumulatorFactory = require('../accumulator/factory')
 const reducerFactory = require('../reducer/factory')
 const resolveFunction = require('./resolve')
-const createTransform = require('../transform-expression').create
 
 describe('resolve#filter.resolve', () => {
   test('resolves node style callback', () => {
@@ -12,7 +11,7 @@ describe('resolve#filter.resolve', () => {
       value: 'test'
     })
 
-    const reducer = reducerFactory.create(createTransform, (acc, done) =>
+    const reducer = reducerFactory.create((acc, done) =>
       done(null, `${acc.value}node`)
     )
 
@@ -26,10 +25,7 @@ describe('resolve#filter.resolve', () => {
       value: 'test'
     })
 
-    const reducer = reducerFactory.create(
-      createTransform,
-      acc => `${acc.value}sync`
-    )
+    const reducer = reducerFactory.create(acc => `${acc.value}sync`)
 
     return resolveFunction.resolve(accumulator, reducer).then(result => {
       expect(result.value).toBe('testsync')
@@ -41,7 +37,7 @@ describe('resolve#filter.resolve', () => {
       value: 'test'
     })
 
-    const reducer = reducerFactory.create(createTransform, acc =>
+    const reducer = reducerFactory.create(acc =>
       Promise.resolve(`${acc.value}promise`)
     )
 
@@ -55,7 +51,7 @@ describe('resolve#filter.resolve', () => {
       value: 'test'
     })
 
-    const reducer = reducerFactory.create(createTransform, (acc, done) => {
+    const reducer = reducerFactory.create((acc, done) => {
       return done(new Error('Test'))
     })
 
diff --git a/packages/data-point/lib/transform-expression/factory.test.js b/packages/data-point/lib/reducer-list/factory.test.js
similarity index 58%
rename from packages/data-point/lib/transform-expression/factory.test.js
rename to packages/data-point/lib/reducer-list/factory.test.js
index b65eaa5..34ea863 100644
--- a/packages/data-point/lib/transform-expression/factory.test.js
+++ b/packages/data-point/lib/reducer-list/factory.test.js
@@ -2,19 +2,20 @@
 'use strict'
 
 const _ = require('lodash')
-const TransformFactory = require('./factory')
+const factory = require('./factory')
+const createReducer = require('../reducer').create
 
-describe('TransformFactory#create', () => {
-  test('TransformFactory#create default', () => {
-    const result = TransformFactory.create()
+describe('factory#create', () => {
+  test('factory#create default', () => {
+    const result = factory.create(createReducer)
 
-    expect(result).toBeInstanceOf(TransformFactory.TransformExpression)
+    expect(result).toBeInstanceOf(factory.ReducerList)
     expect(result.context).toBeUndefined()
     expect(result.reducers).toHaveLength(0)
   })
 
-  test('TransformFactory#create only path', () => {
-    const result = TransformFactory.create('$foo.bar')
+  test('factory#create only path', () => {
+    const result = factory.create(createReducer, '$foo.bar')
     expect(result.reducers).toHaveLength(1)
 
     const reducer = _.first(result.reducers)
@@ -23,8 +24,8 @@ describe('TransformFactory#create', () => {
     expect(reducer.asCollection).toBe(false)
   })
 
-  test('TransformFactory#create path as collection', () => {
-    const result = TransformFactory.create('$foo.bar[]')
+  test('factory#create path as collection', () => {
+    const result = factory.create(createReducer, '$foo.bar[]')
     expect(result.reducers).toHaveLength(1)
 
     const reducer = _.first(result.reducers)
@@ -33,8 +34,8 @@ describe('TransformFactory#create', () => {
     expect(reducer.asCollection).toBe(true)
   })
 
-  test('TransformFactory#create context with reducers', () => {
-    const result = TransformFactory.create([
+  test('factory#create context with reducers', () => {
+    const result = factory.create(createReducer, [
       '$foo.bar | reducer:add',
       () => true
     ])
@@ -45,8 +46,8 @@ describe('TransformFactory#create', () => {
     expect(result.reducers[2].type).toBe('ReducerFunction')
   })
 
-  test('TransformFactory#create context with reducers', () => {
-    const result = TransformFactory.create([
+  test('factory#create context with reducers', () => {
+    const result = factory.create(createReducer, [
       '$foo.bar',
       'reducer:add',
       () => true
@@ -59,41 +60,43 @@ describe('TransformFactory#create', () => {
   })
 })
 
-describe('TransformFactory#create', () => {
-  test('TransformFactory#create transfrom empty array', () => {
-    const result = TransformFactory.create([])
+describe('factory#create', () => {
+  test('factory#create reducer from empty array', () => {
+    const result = factory.create(createReducer, [])
     expect(result.reducers).toHaveLength(0)
   })
 
-  test('TransformFactory#create transfrom with single function', () => {
-    const result = TransformFactory.create((acc, done) => done(null, acc.value))
+  test('factory#create reducer from single function', () => {
+    const result = factory.create(createReducer, (acc, done) =>
+      done(null, acc.value)
+    )
     expect(result.reducers).toHaveLength(1)
     expect(result.reducers[0].type).toBe('ReducerFunction')
   })
 
-  test('TransformFactory#create transfrom with string', () => {
-    const result = TransformFactory.create(['$foo', '$bar'])
+  test('factory#create reducer from string', () => {
+    const result = factory.create(createReducer, ['$foo', '$bar'])
     expect(result.reducers).toHaveLength(2)
     expect(result.reducers[0].type).toBe('ReducerPath')
     expect(result.reducers[1].type).toBe('ReducerPath')
   })
 
-  test('TransformFactory#create transfrom with grouped reducers and single reducers', () => {
-    const result = TransformFactory.create(['$foo | $bar', '$baz'])
+  test('factory#create reducer from grouped reducers and single reducers', () => {
+    const result = factory.create(createReducer, ['$foo | $bar', '$baz'])
     expect(result.reducers).toHaveLength(3)
     expect(result.reducers[0].type).toBe('ReducerPath')
     expect(result.reducers[1].type).toBe('ReducerPath')
     expect(result.reducers[2].type).toBe('ReducerPath')
   })
 
-  test('TransformFactory#create errors if invalid reducer type', () => {
-    const result = _.attempt(TransformFactory.create, 1)
+  test('factory#create errors if invalid reducer type', () => {
+    const result = _.attempt(factory.create, createReducer, 1)
 
     expect(result).toBeInstanceOf(Error)
   })
 
-  test('TransformFactory#create transfrom from array', () => {
-    const result = TransformFactory.create([
+  test('factory#create reducer from array', () => {
+    const result = factory.create(createReducer, [
       '$foo.bar',
       'reducer:add | $foo.bar.zeta',
       (acc, done) => done(null, acc.value)
diff --git a/packages/data-point/lib/reducer-list/resolve.test.js b/packages/data-point/lib/reducer-list/resolve.test.js
new file mode 100644
index 0000000..acc38b5
--- /dev/null
+++ b/packages/data-point/lib/reducer-list/resolve.test.js
@@ -0,0 +1,156 @@
+/* eslint-env jest */
+'use strict'
+
+const nock = require('nock')
+
+const createReducerList = require('./index').create
+const resolveReducerList = require('./index').resolve
+const createReducer = require('../reducer').create
+const resolveReducer = require('../reducer').resolve
+const AccumulatorFactory = require('../accumulator/factory')
+
+const fixtureStore = require('../../test/utils/fixture-store')
+const testData = require('../../test/data.json')
+
+let manager
+
+beforeAll(() => {
+  manager = fixtureStore.create()
+})
+
+test('resolve#reducer.resolve - reducer empty', () => {
+  const accumulator = AccumulatorFactory.create({
+    value: testData.a.g
+  })
+
+  const reducerList = createReducerList(createReducer, '')
+
+  return resolveReducerList(
+    manager,
+    resolveReducer,
+    accumulator,
+    reducerList
+  ).then(result => expect(result.value).toEqual(testData.a.g))
+})
+
+describe('resolve#reducer.resolve - with valid reducers', () => {
+  test('one reducer', () => {
+    const accumulator = AccumulatorFactory.create({
+      value: testData
+    })
+
+    const reducerList = createReducerList(createReducer, '$a.g')
+
+    return resolveReducerList(
+      manager,
+      resolveReducer,
+      accumulator,
+      reducerList
+    ).then(result => expect(result.value).toEqual(testData.a.g))
+  })
+
+  test('multiple reducers', () => {
+    const accumulator = AccumulatorFactory.create({
+      value: testData
+    })
+
+    const reducerList = createReducerList(createReducer, '$a.g | $g1')
+
+    return resolveReducerList(
+      manager,
+      resolveReducer,
+      accumulator,
+      reducerList
+    ).then(result => expect(result.value).toBe(1))
+  })
+})
+
+describe('resolve#reducer.resolve - reducer model', () => {
+  test('simplest model', () => {
+    const accumulator = AccumulatorFactory.create({
+      value: testData
+    })
+
+    const reducerList = createReducerList(createReducer, 'hash:asIs')
+
+    return resolveReducerList(
+      manager,
+      resolveReducer,
+      accumulator,
+      reducerList
+    ).then(result => expect(result.value).toEqual(testData))
+  })
+
+  test('multiple models', () => {
+    const accumulator = AccumulatorFactory.create({
+      value: testData
+    })
+
+    const reducerList = createReducerList(createReducer, 'hash:asIs | hash:a.1')
+
+    return resolveReducerList(
+      manager,
+      resolveReducer,
+      accumulator,
+      reducerList
+    ).then(result => expect(result.value).toEqual(testData.a.h))
+  })
+})
+
+describe('resolve#reducer.resolve - reducer request', () => {
+  test('simplest request', () => {
+    nock('http://remote.test')
+      .get('/source1')
+      .reply(200, {
+        ok: true
+      })
+
+    const accumulator = AccumulatorFactory.create({
+      value: testData.foo
+    })
+
+    const reducerList = createReducerList(createReducer, 'request:a1')
+
+    return resolveReducerList(
+      manager,
+      resolveReducer,
+      accumulator,
+      reducerList
+    ).then(result =>
+      expect(result.value).toEqual({
+        ok: true
+      })
+    )
+  })
+
+  test('multiple models', () => {
+    nock('http://remote.test')
+      .get('/source1')
+      .reply(200, {
+        itemPath: '/source2'
+      })
+
+    nock('http://remote.test')
+      .get('/source2')
+      .reply(200, {
+        ok: true
+      })
+
+    const accumulator = AccumulatorFactory.create({
+      value: testData
+    })
+
+    const reducer = createReducerList(createReducer, 'request:a1 | request:a3')
+
+    return resolveReducerList(
+      manager,
+      resolveReducer,
+      accumulator,
+      reducer
+    ).then(result =>
+      expect(result.value).toEqual({
+        ok: true
+      })
+    )
+  })
+})
diff --git a/packages/data-point/lib/reducer-object/__snapshots__/factory.test.js.snap b/packages/data-point/lib/reducer-object/__snapshots__/factory.test.js.snap
index fc31da8..ee4d71e 100644
--- a/packages/data-point/lib/reducer-object/__snapshots__/factory.test.js.snap
+++ b/packages/data-point/lib/reducer-object/__snapshots__/factory.test.js.snap
@@ -6,16 +6,11 @@ Array [
     "path": Array [
       "a1",
     ],
-    "transform": TransformExpression {
-      "reducers": Array [
-        ReducerPath {
-          "asCollection": true,
-          "body": [Function],
-          "name": "a",
-          "type": "ReducerPath",
-        },
-      ],
-      "typeOf": "TransformExpression",
+    "transform": ReducerPath {
+      "asCollection": true,
+      "body": [Function],
+      "name": "a",
+      "type": "ReducerPath",
     },
   },
   Object {
@@ -23,7 +18,7 @@ Array [
       "b1",
       "a2",
     ],
-    "transform": TransformExpression {
+    "transform": ReducerList {
       "reducers": Array [
         ReducerPath {
           "asCollection": false,
@@ -36,7 +31,7 @@ Array [
           "type": "ReducerFunction",
         },
       ],
-      "typeOf": "TransformExpression",
+      "type": "ReducerList",
     },
   },
   Object {
@@ -44,50 +39,35 @@ Array [
       "b1",
       "b2",
     ],
-    "transform": TransformExpression {
-      "reducers": Array [
-        ReducerObject {
-          "props": Array [
-            Object {
-              "path": Array [
-                "a3",
-              ],
-              "transform": TransformExpression {
-                "reducers": Array [
-                  ReducerEntity {
-                    "asCollection": false,
-                    "entityType": "transform",
-                    "hasEmptyConditional": false,
-                    "id": "transform:entity-name",
-                    "name": "entity-name",
-                    "type": "ReducerEntity",
-                    "withEmptyConditional": false,
-                  },
-                ],
-                "typeOf": "TransformExpression",
-              },
-            },
-            Object {
-              "path": Array [
-                "b3",
-              ],
-              "transform": TransformExpression {
-                "reducers": Array [
-                  ReducerPath {
-                    "asCollection": false,
-                    "body": [Function],
-                    "name": "b1.b2.b3",
-                    "type": "ReducerPath",
-                  },
-                ],
-                "typeOf": "TransformExpression",
-              },
-            },
+    "transform": ReducerObject {
+      "props": Array [
+        Object {
+          "path": Array [
+            "a3",
+          ],
+          "transform": ReducerEntity {
+            "asCollection": false,
+            "entityType": "transform",
+            "hasEmptyConditional": false,
+            "id": "transform:entity-name",
+            "name": "entity-name",
+            "type": "ReducerEntity",
+            "withEmptyConditional": false,
+          },
+        },
+        Object {
+          "path": Array [
+            "b3",
           ],
-          "type": "ReducerObject",
+          "transform": ReducerPath {
+            "asCollection": false,
+            "body": [Function],
+            "name": "b1.b2.b3",
+            "type": "ReducerPath",
+          },
         },
       ],
-      "typeOf": "TransformExpression",
+      "type": "ReducerObject",
     },
   },
 ]
diff --git a/packages/data-point/lib/reducer-object/factory.test.js b/packages/data-point/lib/reducer-object/factory.test.js
index 3ceea19..c699823 100644
--- a/packages/data-point/lib/reducer-object/factory.test.js
+++ b/packages/data-point/lib/reducer-object/factory.test.js
@@ -2,7 +2,7 @@
 'use strict'
 
 const factory = require('./factory')
-const createTransform = require('../transform-expression').create
+const createReducer = require('../reducer').create
 
 test('reducer/reducer-function#isObject', () => {
   expect(factory.isObject('$foo')).toBe(false)
@@ -13,11 +13,11 @@ test('reducer/reducer-function#isObject', () => {
 
 describe('reducer/reducer-function#getReducerProps', () => {
   it('should accept an empty object', () => {
-    const reducer = factory.getReducerProps(createTransform, {})
+    const reducer = factory.getReducerProps(createReducer, {})
     expect(reducer).toEqual([])
   })
   it('should accept a non-empty object', () => {
-    const reducer = factory.getReducerProps(createTransform, {
+    const reducer = factory.getReducerProps(createReducer, {
       a1: '$a[]',
       b1: {
         a2: ['$a2', () => false],
@@ -35,17 +35,17 @@ describe('reducer/reducer-function#getReducerProps', () => {
 
 describe('reducer/reducer-path#create', () => {
   it('reducer object with no props argument', () => {
-    const reducer = factory.create(createTransform)
+    const reducer = factory.create(createReducer)
     expect(reducer.type).toBe('ReducerObject')
     expect(reducer.props).toBeInstanceOf(Array)
   })
   it('reducer object with empty props argument', () => {
-    const reducer = factory.create(createTransform, {})
+    const reducer = factory.create(createReducer, {})
     expect(reducer.type).toBe('ReducerObject')
     expect(reducer.props).toBeInstanceOf(Array)
   })
   it('reducer object with props argument', () => {
-    const reducer = factory.create(createTransform, {
+    const reducer = factory.create(createReducer, {
       a: '$a',
       b: '$b',
       c: '$c'
diff --git a/packages/data-point/lib/reducer-object/resolve.test.js b/packages/data-point/lib/reducer-object/resolve.test.js
index cb2fb47..e628f06 100644
--- a/packages/data-point/lib/reducer-object/resolve.test.js
+++ b/packages/data-point/lib/reducer-object/resolve.test.js
@@ -1,11 +1,11 @@
 /* eslint-env jest */
 'use strict'
 
+const createReducerObject = require('./index').create
+const resolveReducerObject = require('./index').resolve
+const createReducer = require('../reducer').create
+const resolveReducer = require('../reducer').resolve
 const AccumulatorFactory = require('../accumulator/factory')
-const reducerFactory = require('../reducer/factory')
-const resolveObject = require('./resolve').resolve
-const createTransform = require('../transform-expression').create
-const resolveTransform = require('../transform-expression').resolve
 const FixtureStore = require('../../test/utils/fixture-store')
 
 let dataPoint
@@ -16,7 +16,7 @@ beforeAll(() => {
 
 describe('resolve#reducerObject.resolve', () => {
   it('should return the accumulator for an empty reducer object', () => {
-    const reducer = reducerFactory.create(createTransform, {})
+    const reducer = createReducerObject(createReducer, {})
 
     const accumulator = AccumulatorFactory.create({
       value: {
@@ -28,9 +28,9 @@ describe('resolve#reducerObject.resolve', () => {
       }
     })
 
-    return resolveObject(
+    return resolveReducerObject(
       dataPoint,
-      resolveTransform,
+      resolveReducer,
       accumulator,
       reducer
     ).then(result => {
@@ -39,7 +39,7 @@ describe('resolve#reducerObject.resolve', () => {
   })
 
   it('should resolve a reducer object', () => {
-    const reducer = reducerFactory.create(createTransform, {
+    const reducer = createReducerObject(createReducer, {
       y: '$x.y',
       zPlusOne: ['$x.y.z', acc => acc.value + 1]
     })
@@ -54,9 +54,9 @@ describe('resolve#reducerObject.resolve', () => {
       }
     })
 
-    return resolveObject(
+    return resolveReducerObject(
       dataPoint,
-      resolveTransform,
+      resolveReducer,
       accumulator,
       reducer
     ).then(result => {
@@ -70,7 +70,7 @@ describe('resolve#reducerObject.resolve', () => {
   })
 
   it('should resolve a reducer object', () => {
-    const reducer = reducerFactory.create(createTransform, {
+    const reducer = createReducerObject(createReducer, {
       x: '$c.x',
       y: '$c.y',
       z: {
@@ -90,9 +90,9 @@ describe('resolve#reducerObject.resolve', () => {
       }
     })
 
-    return resolveObject(
+    return resolveReducerObject(
       dataPoint,
-      resolveTransform,
+      resolveReducer,
       accumulator,
       reducer
     ).then(result => {
@@ -108,7 +108,7 @@ describe('resolve#reducerObject.resolve', () => {
   })
 
   it('should resolve a reducer object', () => {
-    const reducer = reducerFactory.create(createTransform, {
+    const reducer = createReducerObject(createReducer, {
       x: [
         '$a',
         {
@@ -132,9 +132,9 @@ describe('resolve#reducerObject.resolve', () => {
       }
     })
 
-    return resolveObject(
+    return resolveReducerObject(
       dataPoint,
-      resolveTransform,
+      resolveReducer,
       accumulator,
       reducer
     ).then(result => {
diff --git a/packages/data-point/lib/reducer-path/resolve.test.js b/packages/data-point/lib/reducer-path/resolve.test.js
index 3e5ba71..bace4bb 100644
--- a/packages/data-point/lib/reducer-path/resolve.test.js
+++ b/packages/data-point/lib/reducer-path/resolve.test.js
@@ -1,10 +1,8 @@
 /* eslint-env jest */
 'use strict'
 
+const reducerPath = require('./index')
 const AccumulatorFactory = require('../accumulator/factory')
-const reducerFactory = require('../reducer/factory')
-const reducerPath = require('../reducer-path')
-const createTransform = require('../transform-expression').create
 
 describe('resolve#transform.resolve', () => {
   function resolve (value, rawReducer) {
@@ -16,10 +14,7 @@ describe('resolve#transform.resolve', () => {
       locals
     })
 
-    return reducerPath.resolve(
-      accumulator,
-      reducerFactory.create(createTransform, rawReducer)
-    )
+    return reducerPath.resolve(accumulator, reducerPath.create(rawReducer))
   }
 
   test('resolve current value', () => {
diff --git a/packages/data-point/lib/reducer/factory.test.js b/packages/data-point/lib/reducer/factory.test.js
index 3ceb661..bb428af 100644
--- a/packages/data-point/lib/reducer/factory.test.js
+++ b/packages/data-point/lib/reducer/factory.test.js
@@ -7,29 +7,28 @@ const ReducerPath = require('../reducer-path')
 const ReducerFunction = require('../reducer-function')
 const ReducerObject = require('../reducer-object')
 const ReducerEntity = require('../reducer-entity')
-const createTransform = require('../transform-expression/factory').create
 
 describe('reducer#create', () => {
   test('create path', () => {
-    const reducer = Factory.create(createTransform, '$foo.bar[2]')
+    const reducer = Factory.create('$foo.bar[2]')
     expect(reducer.type).toBe(ReducerPath.type)
     expect(reducer.name).toBe('foo.bar[2]')
   })
 
   test('create function', () => {
-    const reducer = Factory.create(createTransform, () => true)
+    const reducer = Factory.create(() => true)
     expect(reducer.type).toBe(ReducerFunction.type)
     expect(reducer.body).toHaveLength(0)
   })
 
   test('create object', () => {
-    const reducer = Factory.create(ReducerObject, {})
+    const reducer = Factory.create({})
     expect(reducer.type).toBe(ReducerObject.type)
     expect(reducer.props).toHaveLength(0)
   })
 
   test('create entity', () => {
-    const reducer = Factory.create(createTransform, 'fooEntity:foo.bar')
+    const reducer = Factory.create('fooEntity:foo.bar')
     expect(reducer.type).toBe(ReducerEntity.type)
     expect(reducer.name).toBe('foo.bar')
     expect(reducer.entityType).toBe('fooEntity')
@@ -37,15 +36,15 @@ describe('reducer#create', () => {
 
   test('detect invalid', () => {
     expect(() => {
-      Factory.create(createTransform, 'a')
+      Factory.create('a')
     }).toThrowErrorMatchingSnapshot()
 
     expect(() => {
-      Factory.create(createTransform, true)
+      Factory.create(true)
     }).toThrowErrorMatchingSnapshot()
 
     expect(() => {
-      Factory.create(createTransform, 1)
+      Factory.create(1)
     }).toThrowErrorMatchingSnapshot()
   })
 })
diff --git a/packages/data-point/lib/reducer/resolve.test.js b/packages/data-point/lib/reducer/resolve.test.js
index c1e96d9..ad58a76 100644
--- a/packages/data-point/lib/reducer/resolve.test.js
+++ b/packages/data-point/lib/reducer/resolve.test.js
@@ -5,11 +5,12 @@ const Factory = require('./factory')
 const Resolve = require('./resolve')
 
 const reducers = require('../../test/utils/reducers')
+const resolveReducerList = require('../reducer-list').resolve
+
 const fixtureStore = require('../../test/utils/fixture-store')
 const testData = require('../../test/data.json')
 
 const AccumulatorFactory = require('../accumulator/factory')
-const TransformExpression = require('../transform-expression')
 
 let manager
 
@@ -21,7 +22,7 @@ describe('reducer.getReducerFunction', () => {
   test('resolve to ReducerPath', () => {
     const resolver = Resolve.getReducerFunction(
       manager,
-      TransformExpression.resolve,
+      resolveReducerList,
       'ReducerPath'
     )
     expect(resolver).toBeInstanceOf(Function)
@@ -29,7 +30,7 @@ describe('reducer.getReducerFunction', () => {
   test('resolve to ReducerFunction', () => {
     const resolver = Resolve.getReducerFunction(
       manager,
-      TransformExpression.resolve,
+      resolveReducerList,
       'ReducerFunction'
     )
     expect(resolver).toBeInstanceOf(Function)
@@ -37,18 +38,14 @@ describe('reducer.getReducerFunction', () => {
   test('resolve to ReducerEntity', () => {
     const resolver = Resolve.getReducerFunction(
       manager,
-      TransformExpression.resolve,
+      resolveReducerList,
       'ReducerEntity'
     )
     expect(resolver).toBeInstanceOf(Function)
   })
   test('resolve to ReducerEntity', () => {
     expect(() => {
-      Resolve.getReducerFunction(
-        manager,
-        TransformExpression.resolve,
-        'INVALID TYPE'
-      )
+      Resolve.getReducerFunction(manager, resolveReducerList, 'INVALID TYPE')
     }).toThrow()
   })
 })
@@ -58,16 +55,8 @@ test('resolve#reducer.resolve', () => {
     value: testData.a.b.c
   })
 
-  const reducer = Factory.create(
-    TransformExpression.create,
-    reducers.addCollectionValues()
-  )
-  return Resolve.resolve(
-    manager,
-    TransformExpression.resolve,
-    accumulator,
-    reducer
-  ).then(result => {
+  const reducer = Factory.create(reducers.addCollectionValues())
+  return Resolve.resolve(manager, accumulator, reducer).then(result => {
     expect(result.value).toEqual(6)
   })
 })
diff --git a/packages/data-point/lib/transform-expression/resolve.test.js b/packages/data-point/lib/transform-expression/resolve.test.js
deleted file mode 100644
index 32910d0..0000000
--- a/packages/data-point/lib/transform-expression/resolve.test.js
+++ /dev/null
@@ -1,129 +0,0 @@
-/* eslint-env jest */
-'use strict'
-
-const nock = require('nock')
-
-const fixtureStore = require('../../test/utils/fixture-store')
-const testData = require('../../test/data.json')
-
-const AccumulatorFactory = require('../accumulator/factory')
-const TransformExpression = require('./factory')
-
-const ResolveTransform = require('./resolve')
-
-let manager
-
-beforeAll(() => {
-  manager = fixtureStore.create()
-})
-
-test('resolve#reducer.resolve - reducer empty', () => {
-  const accumulator = AccumulatorFactory.create({
-    value: testData.a.g
-  })
-
-  const transform = TransformExpression.create('')
-
-  return ResolveTransform.resolve(manager, accumulator, transform).then(
-    result => expect(result.value).toEqual(testData.a.g)
-  )
-})
-
-describe('resolve#reducer.resolve - reducer transform', () => {
-  test('only transform', () => {
-    const accumulator = AccumulatorFactory.create({
-      value: testData
-    })
-
-    const transform = TransformExpression.create('$a.g')
-    return ResolveTransform.resolve(manager, accumulator, transform).then(
-      result => expect(result.value).toEqual(testData.a.g)
-    )
-  })
-
-  test('multiple transforms', () => {
-    const accumulator = AccumulatorFactory.create({
-      value: testData
-    })
-
-    const transform = TransformExpression.create('$a.g | $g1')
-
-    return ResolveTransform.resolve(manager, accumulator, transform).then(
-      result => expect(result.value).toBe(1)
-    )
-  })
-})
-
-describe('resolve#reducer.resolve - reducer model', () => {
-  test('simplest model', () => {
-    const accumulator = AccumulatorFactory.create({
-      value: testData
-    })
-
-    const transform = TransformExpression.create('hash:asIs')
-    return ResolveTransform.resolve(manager, accumulator, transform).then(
-      result => expect(result.value).toEqual(testData)
-    )
-  })
-
-  test('multiple models', () => {
-    const accumulator = AccumulatorFactory.create({
-      value: testData
-    })
-
-    const transform = TransformExpression.create('hash:asIs | hash:a.1')
-
-    return ResolveTransform.resolve(manager, accumulator, transform).then(
-      result => expect(result.value).toEqual(testData.a.h)
-    )
-  })
-})
-
-describe('resolve#reducer.resolve - reducer request', () => {
-  test('simplest request', () => {
-    nock('http://remote.test')
-      .get('/source1')
-      .reply(200, {
-        ok: true
-      })
-
-    const accumulator = AccumulatorFactory.create({
-      value: testData.foo
-    })
-
-    const transform = TransformExpression.create('request:a1')
-    return ResolveTransform.resolve(manager, accumulator, transform).then(
-      result =>
-        expect(result.value).toEqual({
-          ok: true
-        })
-    )
-  })
-
-  test('multiple models', () => {
-    nock('http://remote.test')
-      .get('/source1')
-      .reply(200, {
-        itemPath: '/source2'
-      })
-
-    nock('http://remote.test')
-      .get('/source2')
-      .reply(200, {
-        ok: true
-      })
-
-    const accumulator = AccumulatorFactory.create({
-      value: testData
-    })
-
-    const transform = TransformExpression.create('request:a1 | request:a3')
-
-    return ResolveTransform.resolve(manager, accumulator, transform).then(
-      result =>
-        expect(result.value).toEqual({
-          ok: true
-        })
-    )
-  })
-})
diff --git a/packages/data-point/lib/utils/utils.test.js b/packages/data-point/lib/utils/utils.test.js
index be12f26..a10e049 100644
--- a/packages/data-point/lib/utils/utils.test.js
+++ b/packages/data-point/lib/utils/utils.test.js
@@ -3,6 +3,7 @@
 
 const _ = require('lodash')
 const utils = require('./index')
+const createReducer = require('../reducer/factory').create
 
 describe('utils.set', () => {
   const target = { b: 1 }
@@ -121,8 +122,21 @@ describe('inspectProperties', () => {
   })
 })
 
-describe('isEmpty', () => {
-  test('It should test for empty', () => {
+describe('reducerIsEmpty', () => {
+  test('It should test for empty reducers', () => {
+    expect(utils.reducerIsEmpty()).toEqual(true)
+    expect(utils.reducerIsEmpty(null)).toEqual(true)
+    expect(utils.reducerIsEmpty(createReducer([]))).toEqual(true)
+    expect(utils.reducerIsEmpty(createReducer({}))).toEqual(true)
+    expect(utils.reducerIsEmpty(createReducer('$a'))).toEqual(false)
+    expect(utils.reducerIsEmpty(createReducer(['$a']))).toEqual(false)
+    expect(utils.reducerIsEmpty(createReducer(['$a', '$a']))).toEqual(false)
+    expect(utils.reducerIsEmpty(createReducer({ a: '$a' }))).toEqual(false)
+  })
+})
+
+describe('isFalsy', () => {
+  test('It should test for falsy values', () => {
     expect(utils.isFalsy(null)).toEqual(true)
     expect(utils.isFalsy(undefined)).toEqual(true)
     expect(utils.isFalsy(false)).toEqual(true)