mappable
v0.1.3
Published
A base class for objects to be recursively mapped to a view-friendly object structure
Downloads
5
Readme
node-mappable
Inherit from this base class to enable recursive mapping to a view-friendly object structure.
Use case
- You need to present objects to views. (JSON or HTML)
- Your objects need to selectively include properties and entities from the underlying data model.
- The properties and entities you present need to be transformed, asynchronously fetched or otherwise consistently mapped.
- You want to keep all this logic DRY. (see Don't repeat yourself)
Example
To output Assets from this object model:
Do this:
Asset.findById(req.params.id, function(err, asset){
asset.toViewObject({
// Selectively include non-default properties in output
asset: { owner: { lastSeenAt: true } }
}, function(err, viewObject){
res.send(viewObject);
});
});
Or for collections of Assets:
Asset.findAll(function(err, assets, summary){
ViewContext.create({
assets: assets,
summary: summary
}).template({
assets: { owner: { lastSeenAt: true } },
summary: true
}).toViewObject(function(err, viewObject){
res.send(viewObject);
});
});
See examples:
Installation
$ npm install mappable
How to use
Inherit from mappable Base
For each of the classes in your object model, inherit from Base.
function MyClass(){
MyClass.super_.apply(this);
}
util.inherits(MyClass, require('mappable').Base);
(If your class already inherits from something else, wrap instances using ViewContext or consider wrapping it within a class that inherits from Base.)
Define the mappings
MyClass.prototype.__defineViewMappings__({
// Simple deep map by specifying the path
'deepValue': 'doc.deeper.value',
// Synchronously return a value
'syncValue': function(){
return new Date(doc.updatedAtMs);
},
// Asynchronously return a value
'asyncValue': function(done) {
this.fetchValue(done);
},
// Or with `self` already declared, for use with deeper callbacks
'asyncValueSelf': function(self, done) {
self.fetchValueAlt(function(err, valueAlt){
if (err) return done(err);
self.fetchWithAlt(valueAlt, done);
});
}
});
Define the default properties
MyClass.prototype.__defineViewTemplate__({
deepValue: true,
syncValue: true
});
Convert a single mappable instance to a view object
Mappable#toViewObject(template, callback)
Arguments:
- template (optional) specifies which properties to include in addition to the default properties:
'*'
will include all properties available, recursively (not recommended for production)- Object to extend default properties, with values of either
true
or a sub-template Object, e.g.{ updatedAt: true, owner: { updatedAt: true }}
- callback function taking arguments for error and the new view object, e.g.
function(err, viewObject){}
Convert a custom object structure to a view object
Use a ViewContext instance to recursively convert a custom object containing instances.
var ViewContext = require('mappable').ViewContext;
ViewContext.create(obj)
Returns a new ViewContext instance.
Arguments:
- obj an Object containing individual instances or arrays of instances
ViewContext#map(mappings)
Returns the same ViewContext instance for chaining.
ViewContext#template(template)
Returns the same ViewContext instance for chaining.
ViewContext#toViewObject(template, callback)
See instance#toViewObject.
ViewContext#on(eventName, fn)
Events:
'error'
e.gfunction(err){}
'complete'
e.g.function(viewObject){}
Concurrency
The default is to run mapping operations in parallel. To limit the number of concurrent mappings:
require('mappable').setConcurrencyLimit(5);
Or, for series:
require('mappable').setConcurrencyLimit(1);