Repository: ViacomInc/data-point
Pull request #236 (2018-03-06 17:35:30)

docs(data-point/README.md): Miscellaneous readme updates
<!-- What changes are being made? (What feature/bug is being fixed here?) -->
**What**: Updates the readme by adding a new section for `Accumulator Object` and combining the `Collection Mapping` section with the `EntityReducer` section

<!-- Why are these changes necessary? -->
**Why**: Now the index for the `Reducers` section only has links to descriptions for reducer types

<!-- 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" -->
- [ ] Has Breaking changes
- [x] Documentation
- [ ] 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/15837360/badge)](https://coveralls.io/builds/15837360)

Coverage remained the same at 100.0% when pulling **884e5feef881cac6224a1b8f8f16e04aed9f8374 on raingerber:readme-updates** into **cd7701998000a7cff0bca64e494f814293a6d5c3 on ViacomInc:master**.

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

Coverage remained the same at 100.0% when pulling **884e5feef881cac6224a1b8f8f16e04aed9f8374 on raingerber:readme-updates** into **cd7701998000a7cff0bca64e494f814293a6d5c3 on ViacomInc:master**.


Patch:
diff --git a/.travis.yml b/.travis.yml
index 5b7d83b..9be444b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,6 +3,8 @@ node_js:
   - 6
   - 8
 sudo: false
+install:
+  - npm install -g codecov
 cache:
   yarn: true
   directories:
@@ -13,4 +15,4 @@ script:
   - "yarn test -- --maxWorkers=4"
   - "scripts/is-it-pretty.sh"
 after_script:
-  - "test -e ./coverage/lcov.info && npm install coveralls@2 && cat ./coverage/lcov.info | coveralls"
+  - codecov
diff --git a/README.md b/README.md
index 9a99283..e699348 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # DataPoint
 
-[![Build Status](https://travis-ci.org/ViacomInc/data-point.svg?branch=master)](https://travis-ci.org/ViacomInc/data-point) [![Coverage Status](https://coveralls.io/repos/github/ViacomInc/data-point/badge.svg?branch=master)](https://coveralls.io/github/ViacomInc/data-point?branch=master) [![All Contributors](https://img.shields.io/badge/all_contributors-7-orange.svg?style=flat-square)](#contributors)
+[![Build Status](https://travis-ci.org/ViacomInc/data-point.svg?branch=master)](https://travis-ci.org/ViacomInc/data-point) [![codecov](https://codecov.io/gh/ViacomInc/data-point/branch/master/graph/badge.svg)](https://codecov.io/gh/ViacomInc/data-point) [![Coverage Status](https://coveralls.io/repos/github/ViacomInc/data-point/badge.svg?branch=master)](https://coveralls.io/github/ViacomInc/data-point?branch=master) [![All Contributors](https://img.shields.io/badge/all_contributors-7-orange.svg?style=flat-square)](#contributors)
 
 > JavaScript Utility for collecting, processing and transforming data.
 
diff --git a/packages/bench-trial/README.md b/packages/bench-trial/README.md
index d4ac74d..ef40592 100644
--- a/packages/bench-trial/README.md
+++ b/packages/bench-trial/README.md
@@ -1,5 +1,7 @@
 # Bench trial
 
+[![Build Status](https://travis-ci.org/ViacomInc/data-point.svg?branch=master)](https://travis-ci.org/ViacomInc/data-point) [![codecov](https://codecov.io/gh/ViacomInc/data-point/branch/master/graph/badge.svg)](https://codecov.io/gh/ViacomInc/data-point) [![Coverage Status](https://coveralls.io/repos/github/ViacomInc/data-point/badge.svg?branch=master)](https://coveralls.io/github/ViacomInc/data-point?branch=master) [![All Contributors](https://img.shields.io/badge/all_contributors-7-orange.svg?style=flat-square)](https://github.com/ViacomInc/data-point#contributors)
+
 > Runs one or multiple benchmark tests
 
 ## Install
diff --git a/packages/data-point-cache/README.md b/packages/data-point-cache/README.md
index 8a8a827..155c769 100644
--- a/packages/data-point-cache/README.md
+++ b/packages/data-point-cache/README.md
@@ -1,7 +1,6 @@
 # data-point-cache
 
-[![Build Status](https://travis-ci.org/ViacomInc/data-point.svg?branch=master)](https://travis-ci.org/ViacomInc/data-point) [![Coverage Status](https://coveralls.io/repos/github/ViacomInc/data-point/badge.svg?branch=master)](https://coveralls.io/github/ViacomInc/data-point?branch=master)
-
+[![Build Status](https://travis-ci.org/ViacomInc/data-point.svg?branch=master)](https://travis-ci.org/ViacomInc/data-point) [![codecov](https://codecov.io/gh/ViacomInc/data-point/branch/master/graph/badge.svg)](https://codecov.io/gh/ViacomInc/data-point) [![Coverage Status](https://coveralls.io/repos/github/ViacomInc/data-point/badge.svg?branch=master)](https://coveralls.io/github/ViacomInc/data-point?branch=master) [![All Contributors](https://img.shields.io/badge/all_contributors-7-orange.svg?style=flat-square)](#contributors)
 
 > DataPoint cache layer
 
diff --git a/packages/data-point-codemods/README.md b/packages/data-point-codemods/README.md
index 2df8236..e55f364 100644
--- a/packages/data-point-codemods/README.md
+++ b/packages/data-point-codemods/README.md
@@ -1,5 +1,7 @@
 # DataPoint codemods
 
+[![Build Status](https://travis-ci.org/ViacomInc/data-point.svg?branch=master)](https://travis-ci.org/ViacomInc/data-point) [![codecov](https://codecov.io/gh/ViacomInc/data-point/branch/master/graph/badge.svg)](https://codecov.io/gh/ViacomInc/data-point) [![Coverage Status](https://coveralls.io/repos/github/ViacomInc/data-point/badge.svg?branch=master)](https://coveralls.io/github/ViacomInc/data-point?branch=master) [![All Contributors](https://img.shields.io/badge/all_contributors-7-orange.svg?style=flat-square)](https://github.com/ViacomInc/data-point#contributors)
+
 > Codemods to help upgrade to newer versions of [data-point](https://github.com/ViacomInc/data-point/)
 
 Codemods, or [jscodeshift](https://github.com/facebook/jscodeshift) transforms, are small programs that help automate changes in a codebase. Think of them as search and replace on steroids. 
diff --git a/packages/data-point-express/README.md b/packages/data-point-express/README.md
index 4224230..3e4d99c 100644
--- a/packages/data-point-express/README.md
+++ b/packages/data-point-express/README.md
@@ -1,7 +1,6 @@
 # DataPoint Express
 
-[![Build Status](https://travis-ci.org/ViacomInc/data-point.svg?branch=master)](https://travis-ci.org/ViacomInc/data-point) [![Coverage Status](https://coveralls.io/repos/github/ViacomInc/data-point/badge.svg?branch=master)](https://coveralls.io/github/ViacomInc/data-point?branch=master)
-
+[![Build Status](https://travis-ci.org/ViacomInc/data-point.svg?branch=master)](https://travis-ci.org/ViacomInc/data-point) [![codecov](https://codecov.io/gh/ViacomInc/data-point/branch/master/graph/badge.svg)](https://codecov.io/gh/ViacomInc/data-point) [![Coverage Status](https://coveralls.io/repos/github/ViacomInc/data-point/badge.svg?branch=master)](https://coveralls.io/github/ViacomInc/data-point?branch=master) [![All Contributors](https://img.shields.io/badge/all_contributors-7-orange.svg?style=flat-square)](https://github.com/ViacomInc/data-point#contributors)
 
 > Create DataPoint service with Express middleware support
 
diff --git a/packages/data-point-service/README.md b/packages/data-point-service/README.md
index a098bf6..4172384 100644
--- a/packages/data-point-service/README.md
+++ b/packages/data-point-service/README.md
@@ -1,6 +1,6 @@
 # DataPoint Factory
 
-[![Build Status](https://travis-ci.org/ViacomInc/data-point.svg?branch=master)](https://travis-ci.org/ViacomInc/data-point) [![Coverage Status](https://coveralls.io/repos/github/ViacomInc/data-point/badge.svg?branch=master)](https://coveralls.io/github/ViacomInc/data-point?branch=master)
+[![Build Status](https://travis-ci.org/ViacomInc/data-point.svg?branch=master)](https://travis-ci.org/ViacomInc/data-point) [![codecov](https://codecov.io/gh/ViacomInc/data-point/branch/master/graph/badge.svg)](https://codecov.io/gh/ViacomInc/data-point) [![Coverage Status](https://coveralls.io/repos/github/ViacomInc/data-point/badge.svg?branch=master)](https://coveralls.io/github/ViacomInc/data-point?branch=master) [![All Contributors](https://img.shields.io/badge/all_contributors-7-orange.svg?style=flat-square)](https://github.com/ViacomInc/data-point#contributors)
 
 > Creates a DataPoint instance with redis support
 
diff --git a/packages/data-point/README.md b/packages/data-point/README.md
index 1f1d672..2ac04ab 100644
--- a/packages/data-point/README.md
+++ b/packages/data-point/README.md
@@ -1,6 +1,6 @@
 # DataPoint
 
-[![Build Status](https://travis-ci.org/ViacomInc/data-point.svg?branch=master)](https://travis-ci.org/ViacomInc/data-point) [![Coverage Status](https://coveralls.io/repos/github/ViacomInc/data-point/badge.svg?branch=master)](https://coveralls.io/github/ViacomInc/data-point?branch=master)
+[![Build Status](https://travis-ci.org/ViacomInc/data-point.svg?branch=master)](https://travis-ci.org/ViacomInc/data-point) [![codecov](https://codecov.io/gh/ViacomInc/data-point/branch/master/graph/badge.svg)](https://codecov.io/gh/ViacomInc/data-point) [![Coverage Status](https://coveralls.io/repos/github/ViacomInc/data-point/badge.svg?branch=master)](https://coveralls.io/github/ViacomInc/data-point?branch=master) [![All Contributors](https://img.shields.io/badge/all_contributors-7-orange.svg?style=flat-square)](https://github.com/ViacomInc/data-point#contributors)
 
 > JavaScript Utility for collecting, processing and transforming data.
 
@@ -23,14 +23,13 @@ npm install --save data-point
 - [Transforms](#transforms)
   - [dataPoint.resolve](#api-data-point-resolve)
   - [dataPoint.transform](#api-data-point-transform)
+- [Accumulator Object](#accumulator-object)
 - [Reducers](#reducers)
-  - [Accumulator](#accumulator)
   - [PathReducer](#path-reducer)
   - [FunctionReducer](#function-reducer)
   - [ObjectReducer](#object-reducer)
   - [EntityReducer](#entity-reducer)
   - [ListReducer](#list-reducer)
-  - [Collection Mapping](#reducer-collection-mapping)
 - [Reducer Helpers](#reducer-helpers)
   - [assign](#reducer-assign)
   - [map](#reducer-map)
@@ -41,6 +40,7 @@ npm install --save data-point
   - [withDefault](#reducer-default)
 - [Entities](#entities)
   - [dataPoint.addEntities](#api-data-point-add-entities)
+  - [Entity factories](#entity-factories)
   - [Built-in entities](#built-in-entities)
     - [Reducer / Transform](#reducer-entity)
     - [Model](#model-entity)
@@ -52,7 +52,6 @@ npm install --save data-point
     - [Schema](#schema-entity)
   - [Entity type checking](#entity-type-check)
   - [Entity ComposeReducer](#entity-compose-reducer)
-  - [Inspecting Entities](#inspecting-entities)
   - [Extending Entities](#extending-entities)
 - [dataPoint.use](#api-data-point-use)
 - [dataPoint.addValue](#api-data-point-add-value)
@@ -328,33 +327,35 @@ 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="reducers">Reducer</a>
 
-Reducers are used to transform values **asynchronously**. DataPoint supports the following reducer types:
+## <a name="accumulator-object">Accumulator Object</a>
 
-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>
+This object is passed to reducers and middleware callbacks; it has contextual information about the current transformation or middleware that's being resolved.
 
-This object is passed to reducers and to middleware callbacks; it contains contextual information about the current transformation (or middleware) being executed. 
-
-The `Accumulator.value` property is the data source from which you want to apply transformations. This property **SHOULD** be treated as **read-only immutable object**. Use it as your initial source and create a new object from it. This ensures that your reducers are [pure functions](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-pure-function-d1c076bec976#.r4iqvt9f0); pure functions produce no side effects. 
+The `accumulator.value` property is the current input data. This property should be treated as a **read-only immutable object**. This helps ensure that your reducers are [pure functions](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-pure-function-d1c076bec976#.r4iqvt9f0) that produce no side effects. If the value is an object, use it as your initial source for creating a new object.
 
 **Properties exposed:**
 
 | Key | Type | Description |
 |:---|:---|:---|
 | *value*  | `Object` | Value to be transformed. |
-| *initialValue*  | `Object` | Initial value passed to the an entity. You can use this value as a reference to the initial value passed to your Entity before any reducer was applied. |
+| *initialValue*  | `Object` | Initial value passed to the entity. You can use this value as a reference to the initial value passed to your Entity before any reducer was applied. |
 | *values*  | `Object` | Access to the values stored via [dataPoint.addValue](#api-data-point-add-value). |
 | *params*  | `Object` | Value of the current Entity's params property. (for all entities except [Reducer](#reducer-entity)) |
 | *locals*  | `Object` | Value passed from the `options` _argument_ when executing [dataPoint.transform](#api-data-point-transform). |
 | *reducer*  | `Object` | Information relative to the current [Reducer](#reducers) being executed. |
 
+
+## <a name="reducers">Reducers</a>
+
+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="path-reducer">PathReducer</a>
 
 PathReducer is a `string` value that extracts a path from the current [Accumulator](#accumulator)`.value` . It uses lodash's [_.get](https://lodash.com/docs/4.17.4#get) behind the scenes.
@@ -372,7 +373,7 @@ PathReducer is a `string` value that extracts a path from the current [Accumulat
 | *$* | Reference to current `accumulator.value`. |
 | *$..* | Gives you full access to current `accumulator`. |
 | *$path* | Simple Object path notation to extract a path from current `accumulator.value`. |
-| *$path[]* | Object path notation with trailing `[]` to extract a value from an array of objects at the `accumulator.value` for each. |
+| *$path[]* | Appending `[]` will map the reducer to each element of an input array. If the current accumulator value is not an array, the reducer will return `undefined`.
 
 #### <a name="root-path">Root path $</a>
 
@@ -494,14 +495,14 @@ Example at: [examples/reducer-path.js](examples/reducer-path.js)
 
 ### <a name="function-reducer">FunctionReducer</a>
 
-A FunctionReducer allows you to use a function to apply a transformation. There are a couple of ways you may write your FunctionReducer:
+A FunctionReducer allows you to use a function to apply a transformation. There are several ways to define a FunctionReducer:
 
 - Synchronous `function` that returns new value
 - Asynchronous `function` that returns a `Promise`
 - Asynchronous `function` with callback parameter
 - Asynchronous through [async/await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) `function` **only if your environment supports it**
 
-**IMPORTANT:** Be careful with the parameters passed to your reducer function, DataPoint relies on the number of arguments to detect the type of ReducerFunction it should expect. 
+**IMPORTANT:** Be careful with the parameters passed to your reducer function; DataPoint relies on the number of arguments to detect the type of ReducerFunction it should expect.
 
 #### <a name="function-reducer">Returning a value</a>
 
@@ -803,7 +804,9 @@ dataPoint.resolve(reducer, input) // => {}
 
 ### <a name="entity-reducer">EntityReducer</a>
 
-An EntityReducer is the actual implementation of an entity. When implementing an EntityReducer, you are actually passing the current [Accumulator](#accumulator) Object to an entity spec, to become its current Accumulator object.
+An EntityReducer is used to execute an entity with the current [Accumulator](#accumulator) as the input.
+
+Appending `[]` to an entity reducer will map the given entity to each element of an input array. If the current accumulator value is not an array, the reducer will return `undefined`.
 
 For information about supported (built-in) entities, see the [Entities](#entities) Section.
 
@@ -823,23 +826,23 @@ For information about supported (built-in) entities, see the [Entities](#entitie
 
 <details>
   <summary>Entity Reducer Example</summary>
-  
+
   ```js
   const input = {
     a: {
       b: 'Hello World'
     }
   }
-  
+
   const toUpperCase = (input) => {
     return input.toUpperCase()
   }
-  
+
   dataPoint.addEntities({
     'transform:getGreeting': '$a.b',
     'transform:toUpperCase': toUpperCase,
   })
-  
+
   // resolve `transform:getGreeting`,
   // pipe value to `transform:toUpperCase`
   dataPoint
@@ -850,6 +853,38 @@ For information about supported (built-in) entities, see the [Entities](#entitie
   ```
 </details>
 
+<details>
+  <summary>Array Mapping Example</summary>
+
+  ```js
+  const input = {
+    a: [
+      'Hello World',
+      'Hello Laia',
+      'Hello Darek',
+      'Hello Italy',
+    ]
+  }
+
+  const toUpperCase = (input) => {
+    return input.toUpperCase()
+  }
+
+  dataPoint.addEntities({
+    'transform:toUpperCase': toUpperCase
+  })
+
+  dataPoint
+    .resolve(['$a | transform:toUpperCase[]'], input)
+    .then((output) => {
+      assert.equal(output[0], 'HELLO WORLD')
+      assert.equal(output[1], 'HELLO LAIA')
+      assert.equal(output[2], 'HELLO DAREK')
+      assert.equal(output[3], 'HELLO ITALY')
+    })
+  ```
+</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.
@@ -921,42 +956,6 @@ dataPoint
 
 Example at: [examples/reducer-conditional-operator.js](examples/reducer-conditional-operator.js)
 
-### <a name="reducer-collection-mapping">Collection Mapping</a>
-
-Adding `[]` at the end of an entity reducer will map the given entity to each result of the current `value` if `value` is a collection. If the value is not a collection, the entity will ignore the `[]` directive.
-
-<details>
-  <summary>Reducer Collection Mapping Example</summary>
-  
-  ```js
-  const input = {
-    a: [
-      'Hello World',
-      'Hello Laia',
-      'Hello Darek',
-      'Hello Italy',
-    ]
-  }
-  
-  const toUpperCase = (input) => {
-    return input.toUpperCase()
-  }
-  
-  dataPoint.addEntities({
-    'transform:toUpperCase': toUpperCase
-  })
-  
-  dataPoint
-    .resolve(['$a | transform:toUpperCase[]'], input)
-    .then((output) => {
-      assert.equal(output[0], 'HELLO WORLD')
-      assert.equal(output[1], 'HELLO LAIA')
-      assert.equal(output[2], 'HELLO DAREK')
-      assert.equal(output[3], 'HELLO ITALY')
-    })
-  ```
-</details>
-
 ## <a name="reducer-helpers">Reducer Helpers</a>
 
 Reducer helpers are factory functions for creating reducers. They're exposed through `DataPoint.helpers`:
@@ -1354,6 +1353,87 @@ dataPoint.addEntities({
 | *EntityType* | `string` | valid entity type to associate with the EntityObject |
 | *EntityId* | `string` | unique entity ID associated with the EntityObject |
 
+### <a name="entity-factories">Entity factories</a>
+
+Entities can be defined with object literals, or with these factory functions:
+
+```js
+const {
+  Entry,
+  Model,
+  Reducer,
+  Collection,
+  Hash,
+  Request,
+  Control,
+  Schema
+} = require('data-point').entityFactories
+```
+
+Each factory has the following signature:
+
+```js
+Factory(name:String, spec:Object):Object
+```
+
+**ARGUMENTS**
+
+| Argument | Type | Description |
+|:---|:---|:---|
+| *name* | `string` | The name of the entity; this will be used to generate an entity ID with the format `<entityType>:<name>` |
+| *spec* | `Object` | The source for generating the entity |
+
+Using these factories is optional, and the following examples are equivalent:
+
+**Example #1 (with object literal)**
+
+```js
+dataPoint.addEntities({
+  'model:hello-world': {
+    value: input => ({
+      hello: 'world'
+    })
+  }
+})
+```
+
+**Example #2 (with factory and assignment)**
+
+```js
+const { Model } = DataPoint.entityFactories
+
+const model = Model('hello-world', {
+  value: input => ({
+    hello: 'world'
+  })
+})
+
+const entities = {}
+
+assert.equal(model.id, 'model:hello-world')
+
+entities[model.id] = model.spec
+
+dataPoint.addEntities(entities)
+```
+
+**Example #3 (with factory and spread syntax)**
+
+```js
+const { Model } = DataPoint.entityFactories
+
+const model = Model('hello-world', {
+  value: input => ({
+    hello: 'world'
+  })
+})
+
+const entities = { ...model }
+
+dataPoint.addEntities(entities)
+```
+
+
 ### <a name="built-in-entities">Built-in Entities</a> 
 
 DataPoint comes with the following built-in entities: 
diff --git a/packages/data-point/lib/core/core.js b/packages/data-point/lib/core/core.js
index 4f0c133..2a860b3 100644
--- a/packages/data-point/lib/core/core.js
+++ b/packages/data-point/lib/core/core.js
@@ -1,22 +1,14 @@
 const _ = require('lodash')
 
-const normalizeEntities = require('./normalize-entities')
 const Transform = require('./transform')
+const normalizeEntities = require('./normalize-entities')
+const entities = require('../entity-types').definitions
 
 const storeValues = require('../stores/values')
 const storeEntities = require('../stores/entities')
 const storeEntityTypes = require('../stores/entity-types')
 const storeMiddleware = require('../stores/middleware')
 
-const EntityTransform = require('../entity-types/entity-transform')
-const EntityEntry = require('../entity-types/entity-entry')
-const EntityHash = require('../entity-types/entity-hash')
-const EntityModel = require('../entity-types/entity-model')
-const EntityCollection = require('../entity-types/entity-collection')
-const EntityRequest = require('../entity-types/entity-request')
-const EntityControl = require('../entity-types/entity-control')
-const EntitySchema = require('../entity-types/entity-schema')
-
 /**
  * @param {Object} store
  * @param {Object} items
@@ -72,18 +64,13 @@ function create (spec) {
   manager.addEntities = _.partial(addEntitiesToStore, manager.entities)
 
   // built-in entity types
-  manager.addEntityType('reducer', EntityTransform)
-  manager.addEntityType('entry', EntityEntry)
-  // alias to entry, may be used to process any object type
-  manager.addEntityType('model', EntityModel)
-  manager.addEntityType('hash', EntityHash)
-  manager.addEntityType('collection', EntityCollection)
-  manager.addEntityType('request', EntityRequest)
+  _.forOwn(entities, (definition, key) => {
+    manager.addEntityType(key.toLowerCase(), definition)
+  })
+
   // for backwards compatibility
-  manager.addEntityType('transform', EntityTransform)
-  manager.addEntityType('source', EntityRequest)
-  manager.addEntityType('control', EntityControl)
-  manager.addEntityType('schema', EntitySchema)
+  manager.addEntityType('transform', entities.Reducer)
+  manager.addEntityType('source', entities.Request)
 
   addToStore(manager.values, options.values, true)
 
diff --git a/packages/data-point/lib/entity-types/factory.js b/packages/data-point/lib/entity-types/factory.js
new file mode 100644
index 0000000..0d1aafd
--- /dev/null
+++ b/packages/data-point/lib/entity-types/factory.js
@@ -0,0 +1,38 @@
+const capitalize = require('lodash/capitalize')
+
+/**
+ * @param {String} _type
+ * @return {Function}
+ */
+function createEntityFactory (_type) {
+  const type = _type.toLowerCase()
+  /**
+   * @param {String} name
+   * @param {Object} spec
+   * @return {Object}
+   */
+  function Factory (name, spec) {
+    const id = `${type}:${name}`
+    const result = { [id]: spec }
+    // these properties are non-enumerable
+    // so that we can do nifty things like:
+    // dataPoint.create({ entities: { ...Hash('name', spec) } })
+    Object.defineProperty(result, 'id', { value: id })
+    Object.defineProperty(result, 'type', { value: type })
+    Object.defineProperty(result, 'name', { value: name })
+    Object.defineProperty(result, 'spec', { value: spec })
+    return result
+  }
+
+  Object.defineProperty(Factory, 'name', {
+    value: `${capitalize(type)}Factory`
+  })
+
+  Object.defineProperty(Factory, 'type', {
+    value: type
+  })
+
+  return Factory
+}
+
+module.exports.createEntityFactory = createEntityFactory
diff --git a/packages/data-point/lib/entity-types/index.js b/packages/data-point/lib/entity-types/index.js
new file mode 100644
index 0000000..1f0ac08
--- /dev/null
+++ b/packages/data-point/lib/entity-types/index.js
@@ -0,0 +1,23 @@
+const mapValues = require('lodash/mapValues')
+
+const { createEntityFactory } = require('./factory')
+
+const definitions = {
+  Entry: require('./entity-entry'),
+  Model: require('./entity-model'),
+  Reducer: require('./entity-transform'),
+  Collection: require('./entity-collection'),
+  Hash: require('./entity-hash'),
+  Request: require('./entity-request'),
+  Control: require('./entity-control'),
+  Schema: require('./entity-schema')
+}
+
+module.exports = {
+  definitions,
+  // this creates a factory for each entity type, which
+  // will be exposed through DataPoint.entityHelpers
+  factories: mapValues(definitions, (value, key) => {
+    return createEntityFactory(key.toLowerCase())
+  })
+}
diff --git a/packages/data-point/lib/helpers/helpers.js b/packages/data-point/lib/helpers/helpers.js
index 59b27a0..4d4a5e4 100644
--- a/packages/data-point/lib/helpers/helpers.js
+++ b/packages/data-point/lib/helpers/helpers.js
@@ -17,6 +17,8 @@ module.exports.helpers = {
   withDefault: stubFactories.withDefault
 }
 
+module.exports.entityFactories = require('../entity-types').factories
+
 module.exports.isReducer = require('../reducer-types').isReducer
 
 module.exports.createReducer = require('../reducer-types').create
diff --git a/packages/data-point/lib/index.js b/packages/data-point/lib/index.js
index 1e69385..87eb77e 100644
--- a/packages/data-point/lib/index.js
+++ b/packages/data-point/lib/index.js
@@ -8,6 +8,7 @@ module.exports = {
   helpers: helpers.helpers,
   createEntity: helpers.createEntity,
   resolveEntity: helpers.resolveEntity,
+  entityFactories: helpers.entityFactories,
   reducify: helpers.reducify,
   reducifyAll: helpers.reducifyAll,
   createReducer: helpers.createReducer,


Test patch:
diff --git a/packages/data-point/lib/__snapshots__/index.test.js.snap b/packages/data-point/lib/__snapshots__/index.test.js.snap
index ca27b25..4a404d7 100644
--- a/packages/data-point/lib/__snapshots__/index.test.js.snap
+++ b/packages/data-point/lib/__snapshots__/index.test.js.snap
@@ -6,6 +6,16 @@ Object {
   "createEntity": [Function],
   "createReducer": [Function],
   "createReducerResolver": [Function],
+  "entityFactories": Object {
+    "Collection": [Function],
+    "Control": [Function],
+    "Entry": [Function],
+    "Hash": [Function],
+    "Model": [Function],
+    "Reducer": [Function],
+    "Request": [Function],
+    "Schema": [Function],
+  },
   "helpers": Object {
     "assign": [Function],
     "constant": [Function],
diff --git a/packages/data-point/lib/entity-types/__snapshots__/factory.test.js.snap b/packages/data-point/lib/entity-types/__snapshots__/factory.test.js.snap
new file mode 100644
index 0000000..4341e79
--- /dev/null
+++ b/packages/data-point/lib/entity-types/__snapshots__/factory.test.js.snap
@@ -0,0 +1,9 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`creating a model with createEntityFactory entity factory should return an object with the expected shape 1`] = `
+Object {
+  "model:nuts": Object {
+    "value": [Function],
+  },
+}
+`;
diff --git a/packages/data-point/lib/entity-types/factory.test.js b/packages/data-point/lib/entity-types/factory.test.js
new file mode 100644
index 0000000..8abac42
--- /dev/null
+++ b/packages/data-point/lib/entity-types/factory.test.js
@@ -0,0 +1,49 @@
+/* eslint-env jest */
+
+const { createEntityFactory } = require('./factory')
+
+let factory
+let spec
+let instance
+
+beforeAll(() => {
+  factory = createEntityFactory('model')
+  spec = { value: input => input }
+  instance = factory('nuts', spec)
+})
+
+describe('creating a model with createEntityFactory', () => {
+  test('createEntityFactory return value should be a function', () => {
+    expect(createEntityFactory).toBeInstanceOf(Function)
+  })
+
+  test('createEntityFactory return value should have the correct "name" property', () => {
+    expect(factory.name).toBe('ModelFactory')
+  })
+
+  test('createEntityFactory return value should have the correct "type" property', () => {
+    expect(factory.type).toBe('model')
+  })
+
+  test('entity factory should return an object with the expected shape', () => {
+    // the 'model:nuts' key should appear in this snapshot,
+    // but other keys shouldn't because they're non-enumerable
+    expect(instance).toMatchSnapshot()
+  })
+
+  test('model should have the correct "id" property', () => {
+    expect(instance.id).toBe('model:nuts')
+  })
+
+  test('model should have the correct "type" property', () => {
+    expect(instance.type).toBe('model')
+  })
+
+  test('model should have the correct "name" property', () => {
+    expect(instance.name).toBe('nuts')
+  })
+
+  test('model should have the correct "spec" property', () => {
+    expect(instance.spec).toEqual(spec)
+  })
+})
diff --git a/packages/data-point/lib/helpers/__snapshots__/helpers.test.js.snap b/packages/data-point/lib/helpers/__snapshots__/helpers.test.js.snap
index 0c788f4..08e1c0a 100644
--- a/packages/data-point/lib/helpers/__snapshots__/helpers.test.js.snap
+++ b/packages/data-point/lib/helpers/__snapshots__/helpers.test.js.snap
@@ -6,6 +6,16 @@ Object {
   "createEntity": [Function],
   "createReducer": [Function],
   "createReducerResolver": [Function],
+  "entityFactories": Object {
+    "Collection": [Function],
+    "Control": [Function],
+    "Entry": [Function],
+    "Hash": [Function],
+    "Model": [Function],
+    "Reducer": [Function],
+    "Request": [Function],
+    "Schema": [Function],
+  },
   "helpers": Object {
     "assign": [Function],
     "constant": [Function],