pure-orm 2.2.0 → 4.0.0-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +2 -2
- package/README.md +169 -242
- package/examples/basic/bo/person.js +4 -3
- package/examples/basic/dao/person.js +1 -2
- package/examples/basic/db.js +6 -15
- package/examples/basic/orm.js +8 -0
- package/examples/blog/bo/article.js +5 -2
- package/examples/blog/bo/article_tag.js +5 -2
- package/examples/blog/bo/article_tags.js +4 -3
- package/examples/blog/bo/articles.js +4 -3
- package/examples/blog/bo/person.js +4 -2
- package/examples/blog/bo/tag.js +4 -2
- package/examples/blog/business-objects.js +1 -10
- package/examples/blog/orm.js +14 -0
- package/examples/order/bo/line-item.js +5 -2
- package/examples/order/bo/line-items.js +4 -3
- package/examples/order/bo/order.js +5 -2
- package/examples/order/bo/orders.js +4 -3
- package/examples/order/bo/product-variant.js +5 -2
- package/examples/order/bo/product-variants.js +4 -3
- package/examples/order/bo/product.js +5 -2
- package/examples/order/bo/products.js +4 -3
- package/examples/order/bo/utm-source.js +4 -2
- package/examples/order/orm.js +20 -0
- package/examples/order-more/bo/actual-product-variant.js +5 -2
- package/examples/order-more/bo/actual-product-variants.js +4 -3
- package/examples/order-more/bo/color.js +5 -2
- package/examples/order-more/bo/colors.js +4 -3
- package/examples/order-more/bo/customer.js +5 -2
- package/examples/order-more/bo/customers.js +4 -3
- package/examples/order-more/bo/gender.js +5 -2
- package/examples/order-more/bo/genders.js +4 -3
- package/examples/order-more/bo/inventory-level.js +5 -2
- package/examples/order-more/bo/inventory-levels.js +4 -3
- package/examples/order-more/bo/line-item.js +5 -2
- package/examples/order-more/bo/line-items.js +4 -3
- package/examples/order-more/bo/order.js +5 -2
- package/examples/order-more/bo/orders.js +4 -3
- package/examples/order-more/bo/parcel-event.js +5 -2
- package/examples/order-more/bo/parcel-events.js +4 -3
- package/examples/order-more/bo/parcel-line-item.js +5 -2
- package/examples/order-more/bo/parcel-line-items.js +4 -3
- package/examples/order-more/bo/parcel.js +5 -2
- package/examples/order-more/bo/parcels.js +4 -3
- package/examples/order-more/bo/physical-address.js +5 -2
- package/examples/order-more/bo/physical-addresses.js +4 -3
- package/examples/order-more/bo/product-variant-image.js +5 -2
- package/examples/order-more/bo/product-variant-images.js +4 -3
- package/examples/order-more/bo/product-variant.js +5 -2
- package/examples/order-more/bo/product-variants.js +4 -3
- package/examples/order-more/bo/product.js +5 -2
- package/examples/order-more/bo/products.js +4 -3
- package/examples/order-more/bo/refund.js +5 -2
- package/examples/order-more/bo/refunds.js +4 -3
- package/examples/order-more/bo/shipment-actual-product-variant.js +5 -2
- package/examples/order-more/bo/shipment-actual-product-variants.js +4 -3
- package/examples/order-more/bo/shipment.js +5 -2
- package/examples/order-more/bo/shipments.js +4 -3
- package/examples/order-more/bo/size.js +5 -2
- package/examples/order-more/bo/sizes.js +4 -3
- package/examples/order-more/bo/utm-medium.js +4 -2
- package/examples/order-more/bo/utm-source.js +4 -2
- package/examples/order-more/orm.js +49 -0
- package/package.json +4 -2
- package/src/bo.js +393 -0
- package/src/{bo/base-bo.spec.js → bo.spec.js} +73 -37
- package/src/factory.js +167 -0
- package/src/factory.spec.js +11 -0
- package/src/index.js +49 -6
- package/test-utils/five/bo/line-item.js +5 -2
- package/test-utils/five/bo/line-items.js +4 -3
- package/test-utils/five/bo/order.js +5 -2
- package/test-utils/five/bo/orders.js +4 -3
- package/test-utils/five/bo/parcel-event.js +5 -2
- package/test-utils/five/bo/parcel-events.js +4 -3
- package/test-utils/five/bo/parcel-line-item.js +5 -2
- package/test-utils/five/bo/parcel-line-items.js +4 -3
- package/test-utils/five/bo/parcel.js +5 -2
- package/test-utils/five/bo/parcels.js +4 -3
- package/test-utils/five/orm.js +19 -0
- package/test-utils/nine/bo/feature-switch.js +5 -2
- package/test-utils/nine/bo/feature-switches.js +4 -3
- package/test-utils/nine/orm.js +9 -0
- package/test-utils/six/bo/customer.js +5 -2
- package/test-utils/six/bo/customers.js +4 -3
- package/test-utils/six/bo/line-item.js +5 -2
- package/test-utils/six/bo/line-items.js +4 -3
- package/test-utils/six/bo/order.js +5 -2
- package/test-utils/six/bo/orders.js +4 -3
- package/test-utils/six/bo/parcel-line-item.js +5 -2
- package/test-utils/six/bo/parcel-line-items.js +4 -3
- package/test-utils/six/bo/parcel.js +5 -2
- package/test-utils/six/bo/parcels.js +4 -3
- package/test-utils/six/orm.js +19 -0
- package/test-utils/thirteen/bo/audience.js +21 -0
- package/test-utils/thirteen/bo/audiences.js +10 -0
- package/{examples/basic → test-utils/thirteen}/bo/base.js +0 -0
- package/test-utils/thirteen/bo/brand.js +21 -0
- package/test-utils/thirteen/bo/brands.js +10 -0
- package/test-utils/thirteen/bo/categories.js +13 -0
- package/test-utils/thirteen/bo/category.js +21 -0
- package/test-utils/thirteen/bo/member.js +21 -0
- package/test-utils/thirteen/bo/members.js +10 -0
- package/test-utils/thirteen/bo/passion.js +21 -0
- package/test-utils/thirteen/bo/passions.js +10 -0
- package/test-utils/thirteen/bo/product.js +22 -0
- package/test-utils/thirteen/bo/products.js +10 -0
- package/test-utils/thirteen/bo/recommendation-audience.js +27 -0
- package/test-utils/thirteen/bo/recommendation-audiences.js +10 -0
- package/test-utils/thirteen/bo/recommendation.js +33 -0
- package/test-utils/thirteen/bo/recommendations.js +10 -0
- package/test-utils/thirteen/orm.js +25 -0
- package/test-utils/thirteen/results.json +74 -0
- package/test-utils/twelve/bo/member.js +5 -2
- package/test-utils/twelve/bo/members.js +4 -3
- package/test-utils/twelve/bo/prompt.js +5 -2
- package/test-utils/twelve/bo/prompts.js +4 -3
- package/test-utils/twelve/orm.js +10 -0
- package/examples/basic/business-objects.js +0 -9
- package/examples/basic/dao/base.js +0 -9
- package/examples/blog/bo/base.js +0 -5
- package/examples/order/bo/base.js +0 -5
- package/examples/order/business-objects.js +0 -11
- package/examples/order-more/bo/base.js +0 -5
- package/examples/order-more/business-objects.js +0 -26
- package/src/bo/base-bo-collection.js +0 -15
- package/src/bo/base-bo.js +0 -379
- package/src/dao/base-dao.js +0 -146
- package/src/dao/base-dao.spec.js +0 -6
- package/src/util/helpers.js +0 -28
- package/src/util/helpers.spec.js +0 -6
- package/test-utils/five/business-objects.js +0 -11
- package/test-utils/nine/business-objects.js +0 -7
- package/test-utils/six/business-objects.js +0 -11
- package/test-utils/twelve/business-objects.js +0 -8
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/* eslint-disable global-require */
|
|
2
|
-
const getBusinessObjects = () => [
|
|
3
|
-
// These need to be imported here to get around circular dependencies
|
|
4
|
-
require('./bo/utm-source'),
|
|
5
|
-
require('./bo/order'),
|
|
6
|
-
require('./bo/line-item'),
|
|
7
|
-
require('./bo/product-variant'),
|
|
8
|
-
require('./bo/product')
|
|
9
|
-
];
|
|
10
|
-
|
|
11
|
-
module.exports = getBusinessObjects;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/* eslint-disable global-require */
|
|
2
|
-
const getBusinessObjects = () => [
|
|
3
|
-
// These need to be imported here to get around circular dependencies
|
|
4
|
-
require('./bo/inventory-level'),
|
|
5
|
-
require('./bo/actual-product-variant'),
|
|
6
|
-
require('./bo/product-variant'),
|
|
7
|
-
require('./bo/product-variant-image'),
|
|
8
|
-
require('./bo/product'),
|
|
9
|
-
require('./bo/size'),
|
|
10
|
-
require('./bo/color'),
|
|
11
|
-
require('./bo/gender'),
|
|
12
|
-
require('./bo/shipment'),
|
|
13
|
-
require('./bo/shipment-actual-product-variant'),
|
|
14
|
-
require('./bo/refund'),
|
|
15
|
-
require('./bo/order'),
|
|
16
|
-
require('./bo/line-item'),
|
|
17
|
-
require('./bo/customer'),
|
|
18
|
-
require('./bo/physical-address'),
|
|
19
|
-
require('./bo/utm-source'),
|
|
20
|
-
require('./bo/utm-medium'),
|
|
21
|
-
require('./bo/parcel-line-item'),
|
|
22
|
-
require('./bo/parcel'),
|
|
23
|
-
require('./bo/parcel-event')
|
|
24
|
-
];
|
|
25
|
-
|
|
26
|
-
module.exports = getBusinessObjects;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
class BaseBoCollection {
|
|
2
|
-
constructor(props = {}) {
|
|
3
|
-
this.models = props.models || [];
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
static get displayName() {
|
|
7
|
-
return `${this.Bo.displayName}s`;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
filter(predicate) {
|
|
11
|
-
return new this.constructor({ models: this.models.filter(predicate) });
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
module.exports = BaseBoCollection;
|
package/src/bo/base-bo.js
DELETED
|
@@ -1,379 +0,0 @@
|
|
|
1
|
-
const camelCase = require('camelcase');
|
|
2
|
-
|
|
3
|
-
module.exports = ({ getBusinessObjects }) =>
|
|
4
|
-
class Base {
|
|
5
|
-
constructor(props) {
|
|
6
|
-
Object.assign(this, props);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
static primaryKey() {
|
|
10
|
-
const primaryKey = this.sqlColumnsData.filter(x => x.primaryKey);
|
|
11
|
-
return primaryKey.length > 0 ? primaryKey : ['id'];
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
static get columns() {
|
|
15
|
-
return this.sqlColumnsData.map(
|
|
16
|
-
x => x.property || camelCase(x.column || x)
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
static get sqlColumns() {
|
|
21
|
-
return this.sqlColumnsData.map(x => x.column || x);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
static get references() {
|
|
25
|
-
return this.sqlColumnsData
|
|
26
|
-
.filter(x => x.references)
|
|
27
|
-
.reduce(
|
|
28
|
-
(accum, item) =>
|
|
29
|
-
Object.assign({}, accum, {
|
|
30
|
-
[item.property || camelCase(item.column || item)]: item.references
|
|
31
|
-
}),
|
|
32
|
-
{}
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
static get displayName() {
|
|
37
|
-
return camelCase(this.tableName);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
static getPrefixedColumnNames() {
|
|
41
|
-
return this.sqlColumns.map(col => `${this.tableName}#${col}`);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
static getSQLSelectClause() {
|
|
45
|
-
return this.getPrefixedColumnNames()
|
|
46
|
-
.map(
|
|
47
|
-
(prefixed, index) =>
|
|
48
|
-
`"${this.tableName}".${this.sqlColumns[index]} as "${prefixed}"`
|
|
49
|
-
)
|
|
50
|
-
.join(', ');
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/*
|
|
54
|
-
* Make objects (based on special table#column names) from flat database
|
|
55
|
-
* return value.
|
|
56
|
-
*/
|
|
57
|
-
static objectifyDatabaseResult(result) {
|
|
58
|
-
return Object.keys(result).reduce((obj, text) => {
|
|
59
|
-
const tableName =
|
|
60
|
-
text.indexOf('#') > -1 ? text.split('#')[0] : this.tableName;
|
|
61
|
-
const column = text.indexOf('#') > -1 ? text.split('#')[1] : text;
|
|
62
|
-
obj[tableName] = obj[tableName] || {};
|
|
63
|
-
obj[tableName][column] = result[text];
|
|
64
|
-
return obj;
|
|
65
|
-
}, {});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
static mapToBos(objectified) {
|
|
69
|
-
return Object.keys(objectified).map(tableName => {
|
|
70
|
-
const Bo = getBusinessObjects().find(bo => bo.tableName === tableName);
|
|
71
|
-
if (!Bo) {
|
|
72
|
-
throw Error(`No business object with table name "${tableName}"`);
|
|
73
|
-
}
|
|
74
|
-
const propified = Object.keys(objectified[tableName]).reduce(
|
|
75
|
-
(obj, column) => {
|
|
76
|
-
let propertyName = Bo.columns[Bo.sqlColumns.indexOf(column)];
|
|
77
|
-
if (!propertyName) {
|
|
78
|
-
if (column.startsWith('meta_')) {
|
|
79
|
-
propertyName = camelCase(column);
|
|
80
|
-
} else {
|
|
81
|
-
throw Error(
|
|
82
|
-
`No property name for "${column}" in business object "${
|
|
83
|
-
Bo.displayName
|
|
84
|
-
}". Non-spec'd columns must begin with "meta_".`
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
obj[propertyName] = objectified[tableName][column];
|
|
89
|
-
return obj;
|
|
90
|
-
},
|
|
91
|
-
{}
|
|
92
|
-
);
|
|
93
|
-
return new Bo(propified);
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/*
|
|
98
|
-
* Clump array of flat objects into groups based on id of root
|
|
99
|
-
* In:
|
|
100
|
-
* [
|
|
101
|
-
* [Article {id: 32}, ArticleTag {id: 54}]
|
|
102
|
-
* [Article {id: 32}, ArticleTag {id: 55}]
|
|
103
|
-
* [Article {id: 33}, ArticleTag {id: 56}]
|
|
104
|
-
* ]
|
|
105
|
-
* Out:
|
|
106
|
-
* [
|
|
107
|
-
* [
|
|
108
|
-
* [Article {id: 32}, ArticleTag {id: 54}]
|
|
109
|
-
* [Article {id: 32}, ArticleTag {id: 55}]
|
|
110
|
-
* ]
|
|
111
|
-
* [
|
|
112
|
-
* [Article {id: 33}, ArticleTag {id: 56}]
|
|
113
|
-
* ]
|
|
114
|
-
* ]
|
|
115
|
-
*/
|
|
116
|
-
static clumpIntoGroups(processed) {
|
|
117
|
-
const clumps = processed.reduce((accum, item) => {
|
|
118
|
-
const id = this.primaryKey()
|
|
119
|
-
.map(key => item.find(x => x.constructor === this)[key])
|
|
120
|
-
.join('@');
|
|
121
|
-
if (accum.has(id)) {
|
|
122
|
-
accum.set(id, [...accum.get(id), item]);
|
|
123
|
-
} else {
|
|
124
|
-
accum.set(id, [item]);
|
|
125
|
-
}
|
|
126
|
-
return accum;
|
|
127
|
-
}, new Map());
|
|
128
|
-
return [...clumps.values()];
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/*
|
|
132
|
-
* In:
|
|
133
|
-
* [
|
|
134
|
-
* [Article {id: 32}, ArticleTag {id: 54}]
|
|
135
|
-
* [Article {id: 32}, ArticleTag {id: 55}]
|
|
136
|
-
* ]
|
|
137
|
-
* Out:
|
|
138
|
-
* Article {id: 32, ArticleTags articleTags: [ArticleTag {id: 54}, ArticleTag {id: 55}]
|
|
139
|
-
*/
|
|
140
|
-
static nestClump(clump) {
|
|
141
|
-
clump = clump.map(x => Object.values(x)); // clump wasn't actually what I have documented
|
|
142
|
-
const root = clump[0][0];
|
|
143
|
-
clump = clump.map(row => row.filter((item, index) => index !== 0));
|
|
144
|
-
const built = { [root.constructor.displayName]: root };
|
|
145
|
-
|
|
146
|
-
let nodes = [root];
|
|
147
|
-
|
|
148
|
-
// Wowzer is this both CPU and Memory inefficient
|
|
149
|
-
clump.forEach(array => {
|
|
150
|
-
array.forEach(_bo => {
|
|
151
|
-
const nodeAlreadySeen = nodes.find(
|
|
152
|
-
x =>
|
|
153
|
-
x.constructor.name === _bo.constructor.name &&
|
|
154
|
-
x.getId() === _bo.getId()
|
|
155
|
-
);
|
|
156
|
-
const bo = nodeAlreadySeen || _bo;
|
|
157
|
-
const isNodeAlreadySeen = !!nodeAlreadySeen;
|
|
158
|
-
const nodePointingToIt = nodes.find(node => {
|
|
159
|
-
const indexes = Object.values(node.constructor.references)
|
|
160
|
-
.map((x, i) => (x === bo.constructor ? i : null))
|
|
161
|
-
.filter(x => x != null);
|
|
162
|
-
if (!indexes.length) {
|
|
163
|
-
return false;
|
|
164
|
-
}
|
|
165
|
-
for (const index of indexes) {
|
|
166
|
-
const property = Object.keys(node.constructor.references)[index];
|
|
167
|
-
if (node[property] === bo.id) {
|
|
168
|
-
return true;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
return false;
|
|
172
|
-
});
|
|
173
|
-
// For first obj type which is has an instance in nodes array,
|
|
174
|
-
// get its index in nodes array
|
|
175
|
-
const indexOfOldestParent = array.reduce((answer, obj) => {
|
|
176
|
-
if (answer != null) {
|
|
177
|
-
return answer;
|
|
178
|
-
}
|
|
179
|
-
const index = nodes.findIndex(
|
|
180
|
-
n => n.constructor === obj.constructor
|
|
181
|
-
);
|
|
182
|
-
if (index !== -1) {
|
|
183
|
-
return index;
|
|
184
|
-
}
|
|
185
|
-
return null;
|
|
186
|
-
}, null);
|
|
187
|
-
const parentHeirarchy = [
|
|
188
|
-
...nodes.slice(0, indexOfOldestParent + 1).reverse(),
|
|
189
|
-
root
|
|
190
|
-
];
|
|
191
|
-
const nodeItPointsTo = parentHeirarchy.find(parent => {
|
|
192
|
-
const index = Object.values(bo.constructor.references).indexOf(
|
|
193
|
-
parent.constructor
|
|
194
|
-
);
|
|
195
|
-
if (index === -1) {
|
|
196
|
-
return false;
|
|
197
|
-
}
|
|
198
|
-
const property = Object.keys(bo.constructor.references)[index];
|
|
199
|
-
return bo[property] === parent.id;
|
|
200
|
-
});
|
|
201
|
-
if (isNodeAlreadySeen) {
|
|
202
|
-
if (nodeItPointsTo && !nodePointingToIt) {
|
|
203
|
-
nodes = [bo, ...nodes];
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
// If the nodePointingToIt (eg, parcel_event) is part of an
|
|
207
|
-
// existing collection on this node (eg, parcel) which is a
|
|
208
|
-
// nodeAlreadySeen, early return so we don't create it (parcel) on
|
|
209
|
-
// the nodePointingToIt (parcel_event), since it (parcel) has been
|
|
210
|
-
// shown to be the parent (of parcel_events).
|
|
211
|
-
const ec = bo[nodePointingToIt.BoCollection.displayName];
|
|
212
|
-
if (ec && ec.models.find(m => m === nodePointingToIt)) {
|
|
213
|
-
nodes = [bo, ...nodes];
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
if (nodePointingToIt) {
|
|
218
|
-
nodePointingToIt[bo.constructor.displayName] = bo;
|
|
219
|
-
} else if (nodeItPointsTo) {
|
|
220
|
-
let collection = nodeItPointsTo[bo.BoCollection.displayName];
|
|
221
|
-
if (collection) {
|
|
222
|
-
collection.models.push(bo);
|
|
223
|
-
} else {
|
|
224
|
-
nodeItPointsTo[bo.BoCollection.displayName] = new bo.BoCollection(
|
|
225
|
-
{ models: [bo] }
|
|
226
|
-
);
|
|
227
|
-
}
|
|
228
|
-
} else {
|
|
229
|
-
if (!bo.getId()) {
|
|
230
|
-
// If the join is fruitless; todo: add a test for this path
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
throw Error(
|
|
234
|
-
`Could not find how this BO fits: ${JSON.stringify(bo)}`
|
|
235
|
-
);
|
|
236
|
-
}
|
|
237
|
-
nodes = [bo, ...nodes];
|
|
238
|
-
});
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
return built;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
static createFromDatabase(_result) {
|
|
245
|
-
const result = Array.isArray(_result) ? _result : [_result];
|
|
246
|
-
const objectified = result.map(this.objectifyDatabaseResult.bind(this));
|
|
247
|
-
const boified = objectified.map(this.mapToBos.bind(this));
|
|
248
|
-
const clumps = this.clumpIntoGroups(boified);
|
|
249
|
-
const nested = clumps.map(this.nestClump.bind(this));
|
|
250
|
-
const models = nested.map(n => Object.values(n)[0]);
|
|
251
|
-
return new new this().BoCollection({ models });
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
static createOneFromDatabase(_result) {
|
|
255
|
-
const collection = this.createFromDatabase(_result);
|
|
256
|
-
if (collection.models.length > 1) {
|
|
257
|
-
throw Error('Got more than one.');
|
|
258
|
-
} else if (collection.models.length === 0) {
|
|
259
|
-
throw Error('Did not get one.');
|
|
260
|
-
}
|
|
261
|
-
return collection.models[0];
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
static createOneOrNoneFromDatabase(_result) {
|
|
265
|
-
if (!_result) {
|
|
266
|
-
return _result;
|
|
267
|
-
}
|
|
268
|
-
const collection = this.createFromDatabase(_result);
|
|
269
|
-
if (collection.models.length > 1) {
|
|
270
|
-
throw Error('Got more than one.');
|
|
271
|
-
}
|
|
272
|
-
return collection.models[0];
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
static createManyFromDatabase(_result) {
|
|
276
|
-
const collection = this.createFromDatabase(_result);
|
|
277
|
-
if (collection.models.length === 0) {
|
|
278
|
-
throw Error('Did not get at least one.');
|
|
279
|
-
}
|
|
280
|
-
return collection;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
getSqlInsertParts() {
|
|
284
|
-
const columns = this.constructor.sqlColumns
|
|
285
|
-
.filter(
|
|
286
|
-
(column, index) => this[this.constructor.columns[index]] != null
|
|
287
|
-
)
|
|
288
|
-
.map(col => `"${col}"`)
|
|
289
|
-
.join(', ');
|
|
290
|
-
const values = this.constructor.columns
|
|
291
|
-
.map(column => this[column])
|
|
292
|
-
.filter(value => value != null);
|
|
293
|
-
const valuesVar = values.map((value, index) => `$${index + 1}`);
|
|
294
|
-
return { columns, values, valuesVar };
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
getSqlUpdateParts(on = 'id') {
|
|
298
|
-
const clauseArray = this.constructor.sqlColumns
|
|
299
|
-
.filter(
|
|
300
|
-
(sqlColumn, index) => this[this.constructor.columns[index]] != null
|
|
301
|
-
)
|
|
302
|
-
.map((sqlColumn, index) => `"${sqlColumn}" = $${index + 1}`);
|
|
303
|
-
const clause = clauseArray.join(', ');
|
|
304
|
-
const idVar = `$${clauseArray.length + 1}`;
|
|
305
|
-
const _values = this.constructor.columns
|
|
306
|
-
.map(column => this[column])
|
|
307
|
-
.filter(value => value != null);
|
|
308
|
-
const values = [..._values, this[on]];
|
|
309
|
-
return { clause, idVar, values };
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
getMatchingParts() {
|
|
313
|
-
const whereClause = this.constructor.columns
|
|
314
|
-
.map((col, index) =>
|
|
315
|
-
this[col] != null
|
|
316
|
-
? `"${this.constructor.tableName}"."${
|
|
317
|
-
this.constructor.sqlColumns[index]
|
|
318
|
-
}"`
|
|
319
|
-
: null
|
|
320
|
-
)
|
|
321
|
-
.filter(x => x != null)
|
|
322
|
-
.map((x, i) => `${x} = $${i + 1}`)
|
|
323
|
-
.join(' AND ');
|
|
324
|
-
const values = this.constructor.columns
|
|
325
|
-
.map(col => (this[col] != null ? this[col] : null))
|
|
326
|
-
.filter(x => x != null);
|
|
327
|
-
return { whereClause, values };
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// This one returns an object, which allows it to be more versatile.
|
|
331
|
-
// Todo: make this one even better and use it instead of the one above.
|
|
332
|
-
getMatchingPartsObject() {
|
|
333
|
-
const whereClause = this.constructor.columns
|
|
334
|
-
.map((col, index) =>
|
|
335
|
-
this[col] != null
|
|
336
|
-
? `"${this.constructor.tableName}"."${
|
|
337
|
-
this.constructor.sqlColumns[index]
|
|
338
|
-
}"`
|
|
339
|
-
: null
|
|
340
|
-
)
|
|
341
|
-
.filter(x => x != null)
|
|
342
|
-
.map((x, i) => `${x} = $(${i + 1})`)
|
|
343
|
-
.join(' AND ');
|
|
344
|
-
const values = this.constructor.columns
|
|
345
|
-
.map(col => (this[col] != null ? this[col] : null))
|
|
346
|
-
.filter(x => x != null)
|
|
347
|
-
.reduce(
|
|
348
|
-
(accum, val, index) => Object.assign({}, accum, { [index + 1]: val }),
|
|
349
|
-
{}
|
|
350
|
-
);
|
|
351
|
-
return { whereClause, values };
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
getNewWith(sqlColumns, values) {
|
|
355
|
-
const Constructor = this.constructor;
|
|
356
|
-
const boKeys = sqlColumns.map(
|
|
357
|
-
key => Constructor.columns[Constructor.sqlColumns.indexOf(key)]
|
|
358
|
-
);
|
|
359
|
-
const boData = boKeys.reduce((data, key, index) => {
|
|
360
|
-
data[key] = values[index];
|
|
361
|
-
return data;
|
|
362
|
-
}, {});
|
|
363
|
-
return new Constructor(boData);
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
getValueBySqlColumn(sqlColumn) {
|
|
367
|
-
return this[
|
|
368
|
-
this.constructor.columns[this.constructor.sqlColumns.indexOf(sqlColumn)]
|
|
369
|
-
];
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// Returns unique identifier of bo (the values of the primary keys)
|
|
373
|
-
getId() {
|
|
374
|
-
return this.constructor
|
|
375
|
-
.primaryKey()
|
|
376
|
-
.map(key => this[key])
|
|
377
|
-
.join('');
|
|
378
|
-
}
|
|
379
|
-
};
|
package/src/dao/base-dao.js
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* A wrapper function returning the base data access abstraction.
|
|
3
|
-
*/
|
|
4
|
-
module.exports = ({ db: closureDB, logError: closureLogError }) =>
|
|
5
|
-
class BaseDAO {
|
|
6
|
-
constructor({ db, logError } = {}) {
|
|
7
|
-
this.db = db || closureDB;
|
|
8
|
-
this.logError = logError || closureLogError;
|
|
9
|
-
this.ensureExists = this.getOrCreate; // alias
|
|
10
|
-
this.manyOrNone = this.any; // alias
|
|
11
|
-
this.errorHandler = this.errorHandler.bind(this);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/* Nice abstractions over this.db ---------------------------------------*/
|
|
15
|
-
/* ----------------------------------------------------------------------*/
|
|
16
|
-
|
|
17
|
-
one(query, values, errorHandler = this.errorHandler) {
|
|
18
|
-
return this.db
|
|
19
|
-
.many(query, values)
|
|
20
|
-
.then(rows => this.Bo.createOneFromDatabase(rows))
|
|
21
|
-
.catch(errorHandler);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
oneOrNone(query, values, errorHandler = this.errorHandler) {
|
|
25
|
-
return this.db
|
|
26
|
-
.any(query, values)
|
|
27
|
-
.then(rows => this.Bo.createOneOrNoneFromDatabase(rows))
|
|
28
|
-
.catch(errorHandler);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
many(query, values, errorHandler = this.errorHandler) {
|
|
32
|
-
return this.db
|
|
33
|
-
.any(query, values)
|
|
34
|
-
.then(rows => this.Bo.createManyFromDatabase(rows))
|
|
35
|
-
.catch(errorHandler);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
any(query, values, errorHandler = this.errorHandler) {
|
|
39
|
-
return this.db
|
|
40
|
-
.any(query, values)
|
|
41
|
-
.then(rows => this.Bo.createFromDatabase(rows))
|
|
42
|
-
.catch(errorHandler);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
none(query, values, errorHandler = this.errorHandler) {
|
|
46
|
-
return this.db
|
|
47
|
-
.none(query, values)
|
|
48
|
-
.then(() => null)
|
|
49
|
-
.catch(errorHandler);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/* Piecemeal endings if using this.db directly --------------------------*/
|
|
53
|
-
/* ----------------------------------------------------------------------*/
|
|
54
|
-
|
|
55
|
-
errorHandler(err) {
|
|
56
|
-
if (!err.name === 'QueryResultError') {
|
|
57
|
-
this.logError(err);
|
|
58
|
-
}
|
|
59
|
-
throw err;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/* Built-in basic DAO methods -------------------------------------------*/
|
|
63
|
-
/* ----------------------------------------------------------------------*/
|
|
64
|
-
|
|
65
|
-
// Standard create
|
|
66
|
-
create(bo) {
|
|
67
|
-
const { columns, values, valuesVar } = bo.getSqlInsertParts();
|
|
68
|
-
const query = `
|
|
69
|
-
INSERT INTO "${bo.constructor.tableName}" ( ${columns} )
|
|
70
|
-
VALUES ( ${valuesVar} )
|
|
71
|
-
RETURNING ${bo.constructor.getSQLSelectClause()};
|
|
72
|
-
`;
|
|
73
|
-
return this.one(query, values);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Standard update
|
|
77
|
-
update(bo, { on = 'id' } = {}) {
|
|
78
|
-
const { clause, idVar, values } = bo.getSqlUpdateParts(on);
|
|
79
|
-
const query = `
|
|
80
|
-
UPDATE "${bo.constructor.tableName}"
|
|
81
|
-
SET ${clause}
|
|
82
|
-
WHERE "${bo.constructor.tableName}".${on} = ${idVar}
|
|
83
|
-
RETURNING ${bo.constructor.getSQLSelectClause()};
|
|
84
|
-
`;
|
|
85
|
-
return this.one(query, values);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Standard delete
|
|
89
|
-
delete(bo) {
|
|
90
|
-
const id = bo.id;
|
|
91
|
-
const query = `
|
|
92
|
-
DELETE FROM "${bo.constructor.tableName}"
|
|
93
|
-
WHERE "${bo.constructor.tableName}".id = ${id}
|
|
94
|
-
`;
|
|
95
|
-
return this.none(query);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
deleteMatching(bo) {
|
|
99
|
-
const { whereClause, values } = bo.getMatchingParts();
|
|
100
|
-
const query = `
|
|
101
|
-
DELETE FROM "${bo.constructor.tableName}"
|
|
102
|
-
WHERE ${whereClause};
|
|
103
|
-
`;
|
|
104
|
-
return this.none(query, values);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
getMatching(bo) {
|
|
108
|
-
const { whereClause, values } = bo.getMatchingParts();
|
|
109
|
-
const query = `
|
|
110
|
-
SELECT ${bo.constructor.getSQLSelectClause()}
|
|
111
|
-
FROM "${bo.constructor.tableName}"
|
|
112
|
-
WHERE ${whereClause};
|
|
113
|
-
`;
|
|
114
|
-
return this.one(query, values);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
getOneOrNoneMatching(bo) {
|
|
118
|
-
const { whereClause, values } = bo.getMatchingParts();
|
|
119
|
-
const query = `
|
|
120
|
-
SELECT ${bo.constructor.getSQLSelectClause()}
|
|
121
|
-
FROM "${bo.constructor.tableName}"
|
|
122
|
-
WHERE ${whereClause};
|
|
123
|
-
`;
|
|
124
|
-
return this.oneOrNone(query, values);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
getAnyMatching(bo) {
|
|
128
|
-
const { whereClause, values } = bo.getMatchingParts();
|
|
129
|
-
const query = `
|
|
130
|
-
SELECT ${bo.constructor.getSQLSelectClause()}
|
|
131
|
-
FROM "${bo.constructor.tableName}"
|
|
132
|
-
WHERE ${whereClause};
|
|
133
|
-
`;
|
|
134
|
-
return this.any(query, values);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
getAllMatching(bo) {
|
|
138
|
-
const { whereClause, values } = bo.getMatchingParts();
|
|
139
|
-
const query = `
|
|
140
|
-
SELECT ${bo.constructor.getSQLSelectClause()}
|
|
141
|
-
FROM "${bo.constructor.tableName}"
|
|
142
|
-
WHERE ${whereClause};
|
|
143
|
-
`;
|
|
144
|
-
return this.many(query, values);
|
|
145
|
-
}
|
|
146
|
-
};
|
package/src/dao/base-dao.spec.js
DELETED
package/src/util/helpers.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
// Previously keys and values were parsed from the error string, but the
|
|
2
|
-
// presence of commas in the values section messed it up. So now, it
|
|
3
|
-
// returns just gets the keys from the error message and gets the values
|
|
4
|
-
// from the business object (previously did not accept a business object).
|
|
5
|
-
const getColumnsValuesFromInsertErrorOLD = (error = '') => {
|
|
6
|
-
let keys, values;
|
|
7
|
-
try {
|
|
8
|
-
const results = /.*Key.*\((.*)\)=.*\((.*)\).*/g.exec(error);
|
|
9
|
-
const [, keyString, valueString] = results;
|
|
10
|
-
keys = keyString.split(', ');
|
|
11
|
-
values = valueString.split(', ');
|
|
12
|
-
} catch (_err) {}
|
|
13
|
-
return [keys, values];
|
|
14
|
-
};
|
|
15
|
-
void getColumnsValuesFromInsertErrorOLD;
|
|
16
|
-
|
|
17
|
-
const getColumnsValuesFromInsertError = (error = '', bo) => {
|
|
18
|
-
let keys, values;
|
|
19
|
-
try {
|
|
20
|
-
const results = /.*Key.*\((.*)\)=.*\((.*)\).*/g.exec(error);
|
|
21
|
-
const [, keyString] = results;
|
|
22
|
-
keys = keyString.split(', ');
|
|
23
|
-
values = keys.map(key => bo.getValueBySqlColumn(key));
|
|
24
|
-
} catch (_err) {}
|
|
25
|
-
return [keys, values];
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
module.exports.getColumnsValuesFromInsertError = getColumnsValuesFromInsertError;
|
package/src/util/helpers.spec.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/* eslint-disable global-require */
|
|
2
|
-
const getBusinessObjects = () => [
|
|
3
|
-
// These need to be imported here to get around circular dependencies
|
|
4
|
-
require('./bo/order'),
|
|
5
|
-
require('./bo/line-item'),
|
|
6
|
-
require('./bo/parcel-line-item'),
|
|
7
|
-
require('./bo/parcel'),
|
|
8
|
-
require('./bo/parcel-event')
|
|
9
|
-
];
|
|
10
|
-
|
|
11
|
-
module.exports = getBusinessObjects;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/* eslint-disable global-require */
|
|
2
|
-
const getBusinessObjects = () => [
|
|
3
|
-
// These need to be imported here to get around circular dependencies
|
|
4
|
-
require('./bo/parcel'),
|
|
5
|
-
require('./bo/parcel-line-item'),
|
|
6
|
-
require('./bo/line-item'),
|
|
7
|
-
require('./bo/order'),
|
|
8
|
-
require('./bo/customer')
|
|
9
|
-
];
|
|
10
|
-
|
|
11
|
-
module.exports = getBusinessObjects;
|