UNPKG

5.53 kBJavaScriptView Raw
1'use strict';
2var path = require('path')
3 , basename = path.basename(__filename, '.js')
4 , assert = require('assert')
5 , once = require('once')
6 , Promise = typeof global.Promise == 'function' ? global.Promise : require('es6-promise').Promise
7 ;
8
9
10function parallel(tasks, fn) {
11 var errors = [], counter = 0, limit = Object.keys(tasks).length, results = {};
12 if (limit === 0) {
13 fn({}, []);
14 }
15 else {
16 Object.keys(tasks).forEach(function(key) {
17 tasks[key](function(out) {
18 if (counter < limit) {
19 if (out instanceof Error) {
20 errors.push(key);
21 }
22 results[key] = out;
23 counter++;
24 if(counter === limit) {
25 fn(results, errors);
26 }
27 }
28 }
29 );
30 }
31 );
32 }
33}
34
35function Datamodel() {
36
37 var self = this;
38 self._declared = {};
39 self._appended = {};
40 self._prepended = {};
41 self._appended = {};
42 self._completed = {};
43 self._transformer = null;
44}
45
46Datamodel.prototype.declare = function (key, fn)
47{
48 assert.equal(typeof key, 'string');
49 assert.equal(typeof fn, 'function');
50 var self = this;
51 self._declared[key] = fn;
52 return self;
53}
54
55Datamodel.prototype.prepend = function (key, fn)
56{
57 assert.equal(typeof key, 'string');
58 assert.equal(typeof fn, 'function');
59 var self = this;
60 self._prepended[key] = fn;
61 return self;
62}
63
64Datamodel.prototype.append = function (key, fn)
65{
66 assert.equal(typeof key, 'string');
67 assert.equal(typeof fn, 'function');
68 var self = this;
69 self._appended[key] = fn;
70 return self;
71}
72
73Datamodel.prototype.complete = function (key, fn)
74{
75 assert.equal(typeof key, 'string');
76 assert.equal(typeof fn, 'function');
77 var self = this;
78 self._completed[key] = fn;
79 return self;
80}
81
82Datamodel.prototype.transform = function (fn)
83{
84 assert.equal(typeof fn, 'function');
85 var self = this;
86 self._transformer = fn;
87 return self;
88}
89
90Datamodel.prototype.send = function (fn)
91{
92 assert.equal(typeof fn, 'function');
93 var self = this;
94 self._sender = fn;
95 return self;
96}
97
98var apply = function (self, input, output, fn)
99{
100 var results = {}, errors = [];
101
102 function mapper(ino, v) {
103 var ouo = {};
104 Object.keys(ino).forEach(function(k) {
105 ouo[k] = function (callback) {
106 var cb = once(callback);
107 try {
108 ino[k].call(results, input, cb);
109 }
110 catch (e) {
111 cb(e)
112 }
113 }
114 });
115 return ouo;
116 }
117 parallel(mapper(self._declared, 'declare'), function(res1, err1) {
118 Object.keys(res1).forEach(function(key) {
119 results[key] = res1[key];
120 });
121 errors = errors.concat(err1);
122 parallel(mapper(self._prepended, 'prepended'), function(res2a, err2a) {
123 Object.keys(res2a).forEach(function(key) {
124 results[key] = res2a[key];
125 });
126 errors = errors.concat(err2a)
127 parallel(mapper(self._appended, 'appended'), function(res2b, err2b) {
128 Object.keys(res2b).forEach(function(key) {
129 results[key] = res2b[key];
130 });
131 errors = errors.concat(err2b)
132 parallel(mapper(self._completed, 'complete'), function(res3, err3) {
133 Object.keys(res3).forEach(function(key) {
134 results[key] = res3[key];
135 });
136 errors = errors.concat(err3).filter(function(e) {
137 return (results[e] instanceof Error);
138 });
139 var err = null;
140 if (errors.length > 0) {
141 err = results[errors[0]];
142 err.message = "[Datamodel." + errors[0] + "] " + err.message;
143 }
144 if (typeof self._transformer === 'function') {
145 self._transformer.call(results, input, function(newresults) {
146 results = newresults;
147 if (output && typeof self._sender === 'function') {
148 self._sender.call(results, output, fn);
149 }
150 else {
151 fn(err, results);
152 }
153 });
154 }
155 else {
156 if (output && typeof self._sender === 'function') {
157 self._sender.call(results, output, fn);
158 }
159 else {
160 fn(err, results);
161 }
162 }
163 });
164 });
165 });
166 });
167}
168Datamodel.prototype.apply = function (input, output, fn)
169{
170 var self = this;
171 if (typeof input === 'function' && output === undefined && fn === undefined) {
172 fn = input;
173 input = {};
174 output = false;
175 }
176 else if (typeof input !== 'function' && typeof output === 'function' && fn === undefined) {
177 fn = output;
178 output = false;
179 }
180
181 if(typeof fn == 'function') {
182 return apply(self, input, output, fn);
183 }
184 return new Promise(function(resolve, reject) {
185 apply(self, input, output, function(e, r) {
186 if (e) {
187 reject(e);
188 }
189 else {
190 resolve(r);
191 }
192 });
193 });
194}
195Datamodel.prototype.attach = function (module) {
196 var self = this;
197 module.exports = self.takeout();
198 return self;
199};
200
201Datamodel.prototype.takeout = function () {
202 var self = this;
203 return function(input, output, fn) {
204 return self.apply(input, output, fn);
205 }
206};
207
208
209
210module.exports = function (models) {
211 var model = new Datamodel();
212
213 if (Array.isArray(models)) {
214 models.forEach(function(func, i) {
215 if (typeof func === 'function') {
216 func(model);
217 }
218 });
219 }
220
221 return model;
222}