forked from petejkim/factory-lady
/
Factory.js
128 lines (114 loc) · 4.15 KB
/
Factory.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import asyncPopulate from './utils/asyncPopulate';
export default class Factory {
name = null;
Model = null;
initializer = null;
options = {};
constructor(Model, initializer, options = {}) {
if (!Model) {
throw new Error('Invalid Model constructor passed to the factory');
}
if ((typeof initializer !== 'object' && typeof initializer !== 'function') ||
!initializer) {
throw new Error('Invalid initializer passed to the factory');
}
this.Model = Model;
this.initializer = initializer;
this.options = { ...this.options, ...options };
}
getFactoryAttrs(buildOptions = {}) {
let attrs;
if (typeof this.initializer === 'function') {
attrs = this.initializer(buildOptions);
} else {
attrs = { ...this.initializer };
}
return Promise.resolve(attrs);
}
async attrs(extraAttrs = {}, buildOptions = {}) {
const factoryAttrs = await this.getFactoryAttrs(buildOptions);
const modelAttrs = {};
const filteredAttrs = Object.keys(factoryAttrs).reduce((attrs, name) => {
if (!extraAttrs.hasOwnProperty(name)) attrs[name] = factoryAttrs[name];
return attrs;
}, {});
await asyncPopulate(modelAttrs, filteredAttrs);
await asyncPopulate(modelAttrs, extraAttrs);
return modelAttrs;
}
async build(adapter, extraAttrs = {}, buildOptions = {}) {
const modelAttrs = await this.attrs(extraAttrs, buildOptions);
const model = adapter.build(this.Model, modelAttrs);
return this.options.afterBuild ?
this.options.afterBuild(model, extraAttrs, buildOptions) :
model;
}
async create(adapter, attrs = {}, buildOptions = {}) {
const model = await this.build(adapter, attrs, buildOptions);
return adapter.save(model, this.Model)
.then(savedModel => (this.options.afterCreate ?
this.options.afterCreate(savedModel, attrs, buildOptions) :
savedModel
));
}
attrsMany(num, attrsArray = [], buildOptionsArray = []) {
let attrObject = null;
let buildOptionsObject = null;
if (typeof attrsArray === 'object' && !Array.isArray(attrsArray)) {
attrObject = attrsArray;
attrsArray = [];
}
if (typeof buildOptionsArray === 'object' && !Array.isArray(buildOptionsArray)) {
buildOptionsObject = buildOptionsArray;
buildOptionsArray = [];
}
if (typeof num !== 'number' || num < 1) {
return Promise.reject(new Error('Invalid number of objects requested'));
}
if (!Array.isArray(attrsArray)) {
return Promise.reject(new Error('Invalid attrsArray passed'));
}
if (!Array.isArray(buildOptionsArray)) {
return Promise.reject(new Error('Invalid buildOptionsArray passed'));
}
attrsArray.length = buildOptionsArray.length = num;
const models = [];
for (let i = 0; i < num; i++) {
models[i] = this.attrs(
attrObject || attrsArray[i] || {},
buildOptionsObject || buildOptionsArray[i] || {}
);
}
return Promise.all(models);
}
async buildMany(adapter, num, attrsArray = [], buildOptionsArray = [],
buildCallbacks = true) {
const attrs = await this.attrsMany(num, attrsArray, buildOptionsArray);
const models = attrs.map(attr => adapter.build(this.Model, attr));
return Promise.all(models)
.then(builtModels => (this.options.afterBuild && buildCallbacks ?
Promise.all(builtModels.map(builtModel => this.options.afterBuild(
builtModel, attrsArray, buildOptionsArray
))) :
builtModels
));
}
async createMany(adapter, num, attrsArray = [], buildOptionsArray = []) {
if (Array.isArray(num)) {
buildOptionsArray = attrsArray;
attrsArray = num;
num = attrsArray.length;
}
const models = await this.buildMany(
adapter, num, attrsArray, buildOptionsArray
);
const savedModels = models.map(model => adapter.save(model, this.Model));
return Promise.all(savedModels)
.then(createdModels => (this.options.afterCreate ?
Promise.all(createdModels.map(createdModel => this.options.afterCreate(
createdModel, attrsArray, buildOptionsArray
))) :
createdModels
));
}
}