1 | 'use strict';
|
2 | var DomainError, EntityPool, FixtureLoader, Scope, Util, debug,
|
3 | indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
4 |
|
5 | EntityPool = require('./entity-pool');
|
6 |
|
7 | DomainError = require('./lib/domain-error');
|
8 |
|
9 | Util = require('./util');
|
10 |
|
11 | debug = require('debug')('base-domain:fixture-loader');
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 | FixtureLoader = (function() {
|
22 | function FixtureLoader(facade, fixtureDirs) {
|
23 | this.facade = facade;
|
24 | this.fixtureDirs = fixtureDirs != null ? fixtureDirs : [];
|
25 | if (!Array.isArray(this.fixtureDirs)) {
|
26 | this.fixtureDirs = [this.fixtureDirs];
|
27 | }
|
28 | this.entityPool = new EntityPool;
|
29 | this.fixturesByModel = {};
|
30 | }
|
31 |
|
32 |
|
33 | |
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 | FixtureLoader.prototype.load = function(options) {
|
42 | var e, error, ext, file, fixtureDir, fs, fx, j, k, l, len, len1, len2, modelName, modelNames, names, path, ref, ref1, ref2, ref3, ref4, requireFile;
|
43 | if (options == null) {
|
44 | options = {};
|
45 | }
|
46 | ref = this.facade.constructor, fs = ref.fs, requireFile = ref.requireFile;
|
47 | try {
|
48 | modelNames = [];
|
49 | ref1 = this.fixtureDirs;
|
50 | for (j = 0, len = ref1.length; j < len; j++) {
|
51 | fixtureDir = ref1[j];
|
52 | ref2 = fs.readdirSync(fixtureDir + '/data');
|
53 | for (k = 0, len1 = ref2.length; k < len1; k++) {
|
54 | file = ref2[k];
|
55 | ref3 = file.split('.'), modelName = ref3[0], ext = ref3[1];
|
56 | if (ext !== 'coffee' && ext !== 'js' && ext !== 'json') {
|
57 | continue;
|
58 | }
|
59 | path = fixtureDir + '/data/' + file;
|
60 | fx = requireFile(path);
|
61 | fx.path = path;
|
62 | fx.fixtureDir = fixtureDir;
|
63 | this.fixturesByModel[modelName] = fx;
|
64 | modelNames.push(modelName);
|
65 | }
|
66 | }
|
67 | modelNames = this.topoSort(modelNames);
|
68 | names = (ref4 = options.names) != null ? ref4 : modelNames;
|
69 | modelNames = modelNames.filter(function(name) {
|
70 | return indexOf.call(names, name) >= 0;
|
71 | });
|
72 | if (options.async) {
|
73 | return this.saveAsync(modelNames).then((function(_this) {
|
74 | return function() {
|
75 | return _this.entityPool;
|
76 | };
|
77 | })(this));
|
78 | } else {
|
79 | for (l = 0, len2 = modelNames.length; l < len2; l++) {
|
80 | modelName = modelNames[l];
|
81 | this.loadAndSaveModels(modelName);
|
82 | }
|
83 | return this.entityPool;
|
84 | }
|
85 | } catch (error) {
|
86 | e = error;
|
87 | if (options.async) {
|
88 | return Promise.reject(e);
|
89 | } else {
|
90 | throw e;
|
91 | }
|
92 | }
|
93 | };
|
94 |
|
95 |
|
96 | |
97 |
|
98 |
|
99 |
|
100 | FixtureLoader.prototype.saveAsync = function(modelNames) {
|
101 | var modelName;
|
102 | if (!modelNames.length) {
|
103 | return Promise.resolve(true);
|
104 | }
|
105 | modelName = modelNames.shift();
|
106 | return Promise.resolve(this.loadAndSaveModels(modelName)).then((function(_this) {
|
107 | return function() {
|
108 | return _this.saveAsync(modelNames);
|
109 | };
|
110 | })(this));
|
111 | };
|
112 |
|
113 |
|
114 | |
115 |
|
116 |
|
117 |
|
118 | FixtureLoader.prototype.loadAndSaveModels = function(modelName) {
|
119 | var PORTION_SIZE, data, e, error, fx, ids, repo, saveModelsByPortion;
|
120 | fx = this.fixturesByModel[modelName];
|
121 | data = (function() {
|
122 | switch (typeof fx.data) {
|
123 | case 'string':
|
124 | return this.readTSV(fx.fixtureDir, fx.data);
|
125 | case 'function':
|
126 | return fx.data.call(new Scope(this, fx), this.entityPool);
|
127 | case 'object':
|
128 | return fx.data;
|
129 | }
|
130 | }).call(this);
|
131 | try {
|
132 | repo = this.facade.createPreferredRepository(modelName);
|
133 | } catch (error) {
|
134 | e = error;
|
135 | console.error(e.message);
|
136 | return;
|
137 | }
|
138 | if (data == null) {
|
139 | throw new Error("Invalid fixture in model '" + modelName + "'. Check the fixture file: " + fx.path);
|
140 | }
|
141 | ids = Object.keys(data);
|
142 | debug('inserting %s models into %s', ids.length, modelName);
|
143 | PORTION_SIZE = 5;
|
144 | return (saveModelsByPortion = (function(_this) {
|
145 | return function() {
|
146 | var id, idsPortion, obj, results;
|
147 | if (ids.length === 0) {
|
148 | return;
|
149 | }
|
150 | idsPortion = ids.slice(0, PORTION_SIZE);
|
151 | ids = ids.slice(idsPortion.length);
|
152 | results = (function() {
|
153 | var j, len, results1;
|
154 | results1 = [];
|
155 | for (j = 0, len = idsPortion.length; j < len; j++) {
|
156 | id = idsPortion[j];
|
157 | obj = data[id];
|
158 | obj.id = id;
|
159 | results1.push(this.saveModel(repo, obj));
|
160 | }
|
161 | return results1;
|
162 | }).call(_this);
|
163 | if (Util.isPromise(results[0])) {
|
164 | return Promise.all(results).then(function() {
|
165 | return saveModelsByPortion();
|
166 | });
|
167 | } else {
|
168 | return saveModelsByPortion();
|
169 | }
|
170 | };
|
171 | })(this))();
|
172 | };
|
173 |
|
174 | FixtureLoader.prototype.saveModel = function(repo, obj) {
|
175 | var result;
|
176 | result = repo.save(obj, {
|
177 | method: 'create',
|
178 | fixtureInsertion: true,
|
179 | include: {
|
180 | entityPool: this.entityPool
|
181 | }
|
182 | });
|
183 | if (Util.isPromise(result)) {
|
184 | return result.then((function(_this) {
|
185 | return function(entity) {
|
186 | return _this.entityPool.set(entity);
|
187 | };
|
188 | })(this));
|
189 | } else {
|
190 | return this.entityPool.set(result);
|
191 | }
|
192 | };
|
193 |
|
194 |
|
195 | |
196 |
|
197 |
|
198 |
|
199 |
|
200 |
|
201 |
|
202 | FixtureLoader.prototype.topoSort = function(names) {
|
203 | var add, el, j, k, len, len1, namesWithDependencies, sortedNames, visit, visited;
|
204 | namesWithDependencies = [];
|
205 | for (j = 0, len = names.length; j < len; j++) {
|
206 | el = names[j];
|
207 | (add = (function(_this) {
|
208 | return function(name) {
|
209 | var depname, fx, k, len1, ref, ref1, results1;
|
210 | if (indexOf.call(namesWithDependencies, name) >= 0) {
|
211 | return;
|
212 | }
|
213 | namesWithDependencies.push(name);
|
214 | fx = _this.fixturesByModel[name];
|
215 | if (fx == null) {
|
216 | throw new DomainError('base-domain:modelNotFound', "model '" + name + "' is not found. It might be written in some 'dependencies' property.");
|
217 | }
|
218 | ref1 = (ref = fx.dependencies) != null ? ref : [];
|
219 | results1 = [];
|
220 | for (k = 0, len1 = ref1.length; k < len1; k++) {
|
221 | depname = ref1[k];
|
222 | results1.push(add(depname));
|
223 | }
|
224 | return results1;
|
225 | };
|
226 | })(this))(el);
|
227 | }
|
228 | visited = {};
|
229 | sortedNames = [];
|
230 | for (k = 0, len1 = namesWithDependencies.length; k < len1; k++) {
|
231 | el = namesWithDependencies[k];
|
232 | (visit = (function(_this) {
|
233 | return function(name, ancestors) {
|
234 | var depname, fx, l, len2, ref, ref1;
|
235 | fx = _this.fixturesByModel[name];
|
236 | if (visited[name] != null) {
|
237 | return;
|
238 | }
|
239 | ancestors.push(name);
|
240 | visited[name] = true;
|
241 | ref1 = (ref = fx.dependencies) != null ? ref : [];
|
242 | for (l = 0, len2 = ref1.length; l < len2; l++) {
|
243 | depname = ref1[l];
|
244 | if (indexOf.call(ancestors, depname) >= 0) {
|
245 | throw new DomainError('base-domain:dependencyLoop', 'dependency chain is making loop');
|
246 | }
|
247 | visit(depname, ancestors.slice());
|
248 | }
|
249 | return sortedNames.push(name);
|
250 | };
|
251 | })(this))(el, []);
|
252 | }
|
253 | return sortedNames;
|
254 | };
|
255 |
|
256 |
|
257 | |
258 |
|
259 |
|
260 |
|
261 |
|
262 |
|
263 |
|
264 | FixtureLoader.prototype.readTSV = function(fixtureDir, file) {
|
265 | var data, fs, i, id, j, k, len, len1, line, lines, name, names, obj, objs, tsv, value;
|
266 | fs = this.facade.constructor.fs;
|
267 | objs = {};
|
268 | lines = fs.readFileSync(fixtureDir + '/tsvs/' + file, 'utf8').split('\n');
|
269 | tsv = (function() {
|
270 | var j, len, results1;
|
271 | results1 = [];
|
272 | for (j = 0, len = lines.length; j < len; j++) {
|
273 | line = lines[j];
|
274 | results1.push(line.split('\t'));
|
275 | }
|
276 | return results1;
|
277 | })();
|
278 | names = tsv.shift();
|
279 | names.shift();
|
280 | for (j = 0, len = tsv.length; j < len; j++) {
|
281 | data = tsv[j];
|
282 | obj = {};
|
283 | id = data.shift();
|
284 | obj.id = id;
|
285 | if (!id) {
|
286 | break;
|
287 | }
|
288 | for (i = k = 0, len1 = names.length; k < len1; i = ++k) {
|
289 | name = names[i];
|
290 | if (!name) {
|
291 | break;
|
292 | }
|
293 | value = data[i];
|
294 | if (value.match(/^[0-9]+$/)) {
|
295 | value = Number(value);
|
296 | }
|
297 | obj[name] = value;
|
298 | }
|
299 | objs[obj.id] = obj;
|
300 | }
|
301 | return objs;
|
302 | };
|
303 |
|
304 | return FixtureLoader;
|
305 |
|
306 | })();
|
307 |
|
308 |
|
309 |
|
310 |
|
311 |
|
312 |
|
313 |
|
314 |
|
315 |
|
316 |
|
317 |
|
318 |
|
319 |
|
320 |
|
321 |
|
322 |
|
323 |
|
324 | Scope = (function() {
|
325 | function Scope(loader, fx1) {
|
326 | this.loader = loader;
|
327 | this.fx = fx1;
|
328 | }
|
329 |
|
330 |
|
331 | |
332 |
|
333 |
|
334 |
|
335 |
|
336 |
|
337 | Scope.prototype.readTSV = function(filename) {
|
338 | return this.loader.readTSV(this.fx.fixtureDir, filename);
|
339 | };
|
340 |
|
341 | return Scope;
|
342 |
|
343 | })();
|
344 |
|
345 | module.exports = FixtureLoader;
|