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,9 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
class ProductVariantImages extends BaseBoCollection {
|
|
1
|
+
class ProductVariantImages {
|
|
4
2
|
static get Bo() {
|
|
5
3
|
return require('./product-variant-image'); // eslint-disable-line
|
|
6
4
|
}
|
|
5
|
+
constructor(props = {}) {
|
|
6
|
+
this.models = props.models || [];
|
|
7
|
+
}
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
module.exports = ProductVariantImages;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
const Base = require('./base');
|
|
2
1
|
const ProductVariants = require('./product-variants');
|
|
3
2
|
const Product = require('./product');
|
|
4
3
|
const ActualProductVariant = require('./actual-product-variant');
|
|
@@ -6,7 +5,11 @@ const Color = require('./color');
|
|
|
6
5
|
const Gender = require('./gender');
|
|
7
6
|
const Size = require('./size');
|
|
8
7
|
|
|
9
|
-
class ProductVariant
|
|
8
|
+
class ProductVariant {
|
|
9
|
+
constructor(props) {
|
|
10
|
+
Object.assign(this, props);
|
|
11
|
+
}
|
|
12
|
+
|
|
10
13
|
get BoCollection() {
|
|
11
14
|
return ProductVariants;
|
|
12
15
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
class ProductVariants extends BaseBoCollection {
|
|
1
|
+
class ProductVariants {
|
|
4
2
|
static get Bo() {
|
|
5
3
|
return require('./product-variant'); // eslint-disable-line
|
|
6
4
|
}
|
|
5
|
+
constructor(props = {}) {
|
|
6
|
+
this.models = props.models || [];
|
|
7
|
+
}
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
module.exports = ProductVariants;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
class Products extends BaseBoCollection {
|
|
1
|
+
class Products {
|
|
4
2
|
static get Bo() {
|
|
5
3
|
return require('./product'); // eslint-disable-line
|
|
6
4
|
}
|
|
5
|
+
constructor(props = {}) {
|
|
6
|
+
this.models = props.models || [];
|
|
7
|
+
}
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
module.exports = Products;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
const Base = require('./base');
|
|
2
1
|
const Order = require('./order');
|
|
3
2
|
const Refunds = require('./refunds');
|
|
4
3
|
|
|
5
|
-
class Refund
|
|
4
|
+
class Refund {
|
|
5
|
+
constructor(props) {
|
|
6
|
+
Object.assign(this, props);
|
|
7
|
+
}
|
|
8
|
+
|
|
6
9
|
get BoCollection() {
|
|
7
10
|
return Refunds;
|
|
8
11
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
class Refunds extends BaseBoCollection {
|
|
1
|
+
class Refunds {
|
|
4
2
|
static get Bo() {
|
|
5
3
|
return require('./refund'); // eslint-disable-line
|
|
6
4
|
}
|
|
5
|
+
constructor(props = {}) {
|
|
6
|
+
this.models = props.models || [];
|
|
7
|
+
}
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
module.exports = Refunds;
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
const Base = require('./base');
|
|
2
1
|
const ShipmentActualProductVariants = require('./shipment-actual-product-variants');
|
|
3
2
|
const ActualProductVariant = require('./actual-product-variant');
|
|
4
3
|
const Shipment = require('./shipment');
|
|
5
4
|
|
|
6
|
-
class ShipmentActualProductVariant
|
|
5
|
+
class ShipmentActualProductVariant {
|
|
6
|
+
constructor(props) {
|
|
7
|
+
Object.assign(this, props);
|
|
8
|
+
}
|
|
9
|
+
|
|
7
10
|
get BoCollection() {
|
|
8
11
|
return ShipmentActualProductVariants;
|
|
9
12
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
class ShipmentActualProductVariants extends BaseBoCollection {
|
|
1
|
+
class ShipmentActualProductVariants {
|
|
4
2
|
static get Bo() {
|
|
5
3
|
return require('./shipment-actual-product-variant'); // eslint-disable-line
|
|
6
4
|
}
|
|
5
|
+
constructor(props = {}) {
|
|
6
|
+
this.models = props.models || [];
|
|
7
|
+
}
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
module.exports = ShipmentActualProductVariants;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
class Shipments extends BaseBoCollection {
|
|
1
|
+
class Shipments {
|
|
4
2
|
static get Bo() {
|
|
5
3
|
return require('./shipment'); // eslint-disable-line
|
|
6
4
|
}
|
|
5
|
+
constructor(props = {}) {
|
|
6
|
+
this.models = props.models || [];
|
|
7
|
+
}
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
module.exports = Shipments;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
class Sizes extends BaseBoCollection {
|
|
1
|
+
class Sizes {
|
|
4
2
|
static get Bo() {
|
|
5
3
|
return require('./size'); // eslint-disable-line
|
|
6
4
|
}
|
|
5
|
+
constructor(props = {}) {
|
|
6
|
+
this.models = props.models || [];
|
|
7
|
+
}
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
module.exports = Sizes;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const { create } = require('pure-orm');
|
|
2
|
+
const InventoryLevel = require('./bo/inventory-level');
|
|
3
|
+
const ActualProductVariant = require('./bo/actual-product-variant');
|
|
4
|
+
const ProductVariant = require('./bo/product-variant');
|
|
5
|
+
const ProductVariantImage = require('./bo/product-variant-image');
|
|
6
|
+
const Product = require('./bo/product');
|
|
7
|
+
const Size = require('./bo/size');
|
|
8
|
+
const Color = require('./bo/color');
|
|
9
|
+
const Gender = require('./bo/gender');
|
|
10
|
+
const Shipment = require('./bo/shipment');
|
|
11
|
+
const ShipmentActualProductVariant = require('./bo/shipment-actual-product-variant');
|
|
12
|
+
const Refund = require('./bo/refund');
|
|
13
|
+
const Order = require('./bo/order');
|
|
14
|
+
const LineItem = require('./bo/line-item');
|
|
15
|
+
const Customer = require('./bo/customer');
|
|
16
|
+
const PhysicalAddress = require('./bo/physical-address');
|
|
17
|
+
const UtmSource = require('./bo/utm-source');
|
|
18
|
+
const UtmMedium = require('./bo/utm-medium');
|
|
19
|
+
const ParcelLineItem = require('./bo/parcel-line-item');
|
|
20
|
+
const Parcel = require('./bo/parcel');
|
|
21
|
+
const ParcelEvent = require('./bo/parcel-event');
|
|
22
|
+
const getBusinessObjects = () => [
|
|
23
|
+
InventoryLevel,
|
|
24
|
+
ActualProductVariant,
|
|
25
|
+
ProductVariant,
|
|
26
|
+
ProductVariantImage,
|
|
27
|
+
Product,
|
|
28
|
+
Size,
|
|
29
|
+
Color,
|
|
30
|
+
Gender,
|
|
31
|
+
Shipment,
|
|
32
|
+
ShipmentActualProductVariant,
|
|
33
|
+
Refund,
|
|
34
|
+
Order,
|
|
35
|
+
LineItem,
|
|
36
|
+
Customer,
|
|
37
|
+
PhysicalAddress,
|
|
38
|
+
UtmSource,
|
|
39
|
+
UtmMedium,
|
|
40
|
+
ParcelLineItem,
|
|
41
|
+
Parcel,
|
|
42
|
+
ParcelEvent
|
|
43
|
+
];
|
|
44
|
+
const orm = create({
|
|
45
|
+
getBusinessObjects,
|
|
46
|
+
db: void 0
|
|
47
|
+
});
|
|
48
|
+
module.exports = orm;
|
|
49
|
+
module.exports.getBusinessObjects = getBusinessObjects;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pure-orm",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0-0",
|
|
4
4
|
"main": "src/index.js",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=6"
|
|
@@ -12,12 +12,14 @@
|
|
|
12
12
|
"test:unit:debug": "node --inspect-brk node_modules/.bin/jest --runInBand --verbose",
|
|
13
13
|
"test:format": "prettier -l \"**/*.{js,json,md}\" \"!src/**/*.spec.js\" \"!coverage/**/*\"",
|
|
14
14
|
"format": "prettier --write \"**/*.{js,json,md}\" \"!src/**/*.spec.js\" \"!coverage/**/*\"",
|
|
15
|
+
"lint": "eslint .",
|
|
15
16
|
"pub": "npm run test && np"
|
|
16
17
|
},
|
|
17
18
|
"dependencies": {
|
|
18
19
|
"camelcase": "^5.0.0"
|
|
19
20
|
},
|
|
20
21
|
"devDependencies": {
|
|
22
|
+
"eslint": "^2.8.0",
|
|
21
23
|
"jest": "^24.8.0",
|
|
22
24
|
"np": "^5.0.1",
|
|
23
25
|
"prettier": "^1.9.2"
|
|
@@ -46,6 +48,6 @@
|
|
|
46
48
|
"pure",
|
|
47
49
|
"toolkit",
|
|
48
50
|
"business objects",
|
|
49
|
-
"data access
|
|
51
|
+
"data access layer"
|
|
50
52
|
]
|
|
51
53
|
}
|
package/src/bo.js
ADDED
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
const camelCase = require('camelcase');
|
|
2
|
+
|
|
3
|
+
const getPrimaryKey = Bo => {
|
|
4
|
+
const primaryKey = Bo.sqlColumnsData.filter(x => x.primaryKey);
|
|
5
|
+
return primaryKey.length > 0 ? primaryKey : ['id'];
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const getProperties = Bo => {
|
|
9
|
+
return Bo.sqlColumnsData.map(x => x.property || camelCase(x.column || x));
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const getSqlColumns = Bo => {
|
|
13
|
+
return Bo.sqlColumnsData.map(x => x.column || x);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const getReferences = Bo => {
|
|
17
|
+
return Bo.sqlColumnsData
|
|
18
|
+
.filter(x => x.references)
|
|
19
|
+
.reduce(
|
|
20
|
+
(accum, item) =>
|
|
21
|
+
Object.assign({}, accum, {
|
|
22
|
+
[item.property || camelCase(item.column || item)]: item.references
|
|
23
|
+
}),
|
|
24
|
+
{}
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const getDisplayName = Bo => {
|
|
29
|
+
return camelCase(Bo.tableName);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const getCollectionDisplayName = bo => {
|
|
33
|
+
return bo.BoCollection.displayName || `${getDisplayName(bo.constructor)}s`;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const getPrefixedColumnNames = Bo => {
|
|
37
|
+
return getSqlColumns(Bo).map(col => `${Bo.tableName}#${col}`);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const getColumns = Bo => {
|
|
41
|
+
return getPrefixedColumnNames(Bo)
|
|
42
|
+
.map(
|
|
43
|
+
(prefixed, index) =>
|
|
44
|
+
`"${Bo.tableName}".${getSqlColumns(Bo)[index]} as "${prefixed}"`
|
|
45
|
+
)
|
|
46
|
+
.join(', ');
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Returns unique identifier of bo (the values of the primary keys)
|
|
50
|
+
const getId = bo => {
|
|
51
|
+
return getPrimaryKey(bo.constructor)
|
|
52
|
+
.map(key => bo[key])
|
|
53
|
+
.join('');
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/*
|
|
57
|
+
* In:
|
|
58
|
+
* [
|
|
59
|
+
* [Article {id: 32}, ArticleTag {id: 54}]
|
|
60
|
+
* [Article {id: 32}, ArticleTag {id: 55}]
|
|
61
|
+
* ]
|
|
62
|
+
* Out:
|
|
63
|
+
* Article {id: 32, ArticleTags articleTags: [ArticleTag {id: 54}, ArticleTag {id: 55}]
|
|
64
|
+
*/
|
|
65
|
+
const nestClump = clump => {
|
|
66
|
+
clump = clump.map(x => Object.values(x)); // clump wasn't actually what I have documented
|
|
67
|
+
const root = clump[0][0];
|
|
68
|
+
clump = clump.map(row => row.filter((item, index) => index !== 0));
|
|
69
|
+
const built = { [root.constructor.displayName]: root };
|
|
70
|
+
|
|
71
|
+
let nodes = [root];
|
|
72
|
+
|
|
73
|
+
// Wowzer is this both CPU and Memory inefficient
|
|
74
|
+
clump.forEach(array => {
|
|
75
|
+
array.forEach(_bo => {
|
|
76
|
+
const nodeAlreadySeen = nodes.find(
|
|
77
|
+
x =>
|
|
78
|
+
x.constructor.name === _bo.constructor.name && getId(x) === getId(_bo)
|
|
79
|
+
);
|
|
80
|
+
const bo = nodeAlreadySeen || _bo;
|
|
81
|
+
const isNodeAlreadySeen = !!nodeAlreadySeen;
|
|
82
|
+
const nodePointingToIt = nodes.find(node => {
|
|
83
|
+
const indexes = Object.values(getReferences(node.constructor))
|
|
84
|
+
.map((x, i) => (x === bo.constructor ? i : null))
|
|
85
|
+
.filter(x => x != null);
|
|
86
|
+
if (!indexes.length) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
for (const index of indexes) {
|
|
90
|
+
const property = Object.keys(getReferences(node.constructor))[index];
|
|
91
|
+
if (node[property] === bo.id) {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return false;
|
|
96
|
+
});
|
|
97
|
+
// For first obj type which is has an instance in nodes array,
|
|
98
|
+
// get its index in nodes array
|
|
99
|
+
const indexOfOldestParent = array.reduce((answer, obj) => {
|
|
100
|
+
if (answer != null) {
|
|
101
|
+
return answer;
|
|
102
|
+
}
|
|
103
|
+
const index = nodes.findIndex(n => n.constructor === obj.constructor);
|
|
104
|
+
if (index !== -1) {
|
|
105
|
+
return index;
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
}, null);
|
|
109
|
+
const parentHeirarchy = [
|
|
110
|
+
root,
|
|
111
|
+
...nodes.slice(0, indexOfOldestParent + 1).reverse()
|
|
112
|
+
];
|
|
113
|
+
const nodeItPointsTo = parentHeirarchy.find(parent => {
|
|
114
|
+
const index = Object.values(getReferences(bo.constructor)).indexOf(
|
|
115
|
+
parent.constructor
|
|
116
|
+
);
|
|
117
|
+
if (index === -1) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
const property = Object.keys(getReferences(bo.constructor))[index];
|
|
121
|
+
return bo[property] === parent.id;
|
|
122
|
+
});
|
|
123
|
+
if (isNodeAlreadySeen) {
|
|
124
|
+
if (nodeItPointsTo && !nodePointingToIt) {
|
|
125
|
+
nodes = [bo, ...nodes];
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
// If the nodePointingToIt (eg, parcel_event) is part of an
|
|
129
|
+
// existing collection on this node (eg, parcel) which is a
|
|
130
|
+
// nodeAlreadySeen, early return so we don't create it (parcel) on
|
|
131
|
+
// the nodePointingToIt (parcel_event), since it (parcel) has been
|
|
132
|
+
// shown to be the parent (of parcel_events).
|
|
133
|
+
const ec = bo[getCollectionDisplayName(nodePointingToIt)];
|
|
134
|
+
if (ec && ec.models.find(m => m === nodePointingToIt)) {
|
|
135
|
+
nodes = [bo, ...nodes];
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (nodePointingToIt) {
|
|
140
|
+
nodePointingToIt[getDisplayName(bo.constructor)] = bo;
|
|
141
|
+
} else if (nodeItPointsTo) {
|
|
142
|
+
let collection = nodeItPointsTo[getCollectionDisplayName(bo)];
|
|
143
|
+
if (collection) {
|
|
144
|
+
collection.models.push(bo);
|
|
145
|
+
} else {
|
|
146
|
+
nodeItPointsTo[getCollectionDisplayName(bo)] = new bo.BoCollection({
|
|
147
|
+
models: [bo]
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
} else {
|
|
151
|
+
if (!getId(bo)) {
|
|
152
|
+
// If the join is fruitless; todo: add a test for this path
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
throw Error(`Could not find how this BO fits: ${JSON.stringify(bo)}`);
|
|
156
|
+
}
|
|
157
|
+
nodes = [bo, ...nodes];
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
return built;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
/*
|
|
165
|
+
* Clump array of flat objects into groups based on id of root
|
|
166
|
+
* In:
|
|
167
|
+
* [
|
|
168
|
+
* [Article {id: 32}, ArticleTag {id: 54}]
|
|
169
|
+
* [Article {id: 32}, ArticleTag {id: 55}]
|
|
170
|
+
* [Article {id: 33}, ArticleTag {id: 56}]
|
|
171
|
+
* ]
|
|
172
|
+
* Out:
|
|
173
|
+
* [
|
|
174
|
+
* [
|
|
175
|
+
* [Article {id: 32}, ArticleTag {id: 54}]
|
|
176
|
+
* [Article {id: 32}, ArticleTag {id: 55}]
|
|
177
|
+
* ]
|
|
178
|
+
* [
|
|
179
|
+
* [Article {id: 33}, ArticleTag {id: 56}]
|
|
180
|
+
* ]
|
|
181
|
+
* ]
|
|
182
|
+
*/
|
|
183
|
+
const clumpIntoGroups = processed => {
|
|
184
|
+
const rootBo = processed[0][0].constructor;
|
|
185
|
+
const clumps = processed.reduce((accum, item) => {
|
|
186
|
+
const id = getPrimaryKey(rootBo)
|
|
187
|
+
.map(key => item.find(x => x.constructor === rootBo)[key])
|
|
188
|
+
.join('@');
|
|
189
|
+
if (accum.has(id)) {
|
|
190
|
+
accum.set(id, [...accum.get(id), item]);
|
|
191
|
+
} else {
|
|
192
|
+
accum.set(id, [item]);
|
|
193
|
+
}
|
|
194
|
+
return accum;
|
|
195
|
+
}, new Map());
|
|
196
|
+
return [...clumps.values()];
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const mapToBos = (objectified, getBusinessObjects) => {
|
|
200
|
+
return Object.keys(objectified).map(tableName => {
|
|
201
|
+
const Bo = getBusinessObjects().find(bo => bo.tableName === tableName);
|
|
202
|
+
if (!Bo) {
|
|
203
|
+
throw Error(`No business object with table name "${tableName}"`);
|
|
204
|
+
}
|
|
205
|
+
const propified = Object.keys(objectified[tableName]).reduce(
|
|
206
|
+
(obj, column) => {
|
|
207
|
+
let propertyName = getProperties(Bo)[getSqlColumns(Bo).indexOf(column)];
|
|
208
|
+
if (!propertyName) {
|
|
209
|
+
if (column.startsWith('meta_')) {
|
|
210
|
+
propertyName = camelCase(column);
|
|
211
|
+
} else {
|
|
212
|
+
throw Error(
|
|
213
|
+
`No property name for "${column}" in business object "${getDisplayName(
|
|
214
|
+
Bo
|
|
215
|
+
)}". Non-spec'd columns must begin with "meta_".`
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
obj[propertyName] = objectified[tableName][column];
|
|
220
|
+
return obj;
|
|
221
|
+
},
|
|
222
|
+
{}
|
|
223
|
+
);
|
|
224
|
+
return new Bo(propified);
|
|
225
|
+
});
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
/*
|
|
229
|
+
* Make objects (based on special table#column names) from flat database
|
|
230
|
+
* return value.
|
|
231
|
+
*/
|
|
232
|
+
const objectifyDatabaseResult = result => {
|
|
233
|
+
return Object.keys(result).reduce((obj, text) => {
|
|
234
|
+
const tableName = text.split('#')[0];
|
|
235
|
+
const column = text.split('#')[1];
|
|
236
|
+
obj[tableName] = obj[tableName] || {};
|
|
237
|
+
obj[tableName][column] = result[text];
|
|
238
|
+
return obj;
|
|
239
|
+
}, {});
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const createFromDatabase = (_result, getBusinessObjects) => {
|
|
243
|
+
const result = Array.isArray(_result) ? _result : [_result];
|
|
244
|
+
const objectified = result.map(objectifyDatabaseResult);
|
|
245
|
+
const boified = objectified.map(x => mapToBos(x, getBusinessObjects));
|
|
246
|
+
const clumps = clumpIntoGroups(boified);
|
|
247
|
+
const nested = clumps.map(nestClump);
|
|
248
|
+
const models = nested.map(n => Object.values(n)[0]);
|
|
249
|
+
return models.length ? new models[0].BoCollection({ models }) : void 0;
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
const createOneFromDatabase = (_result, getBusinessObjects) => {
|
|
253
|
+
const collection = createFromDatabase(_result, getBusinessObjects);
|
|
254
|
+
if (!collection || collection.models.length === 0) {
|
|
255
|
+
throw Error('Did not get one.');
|
|
256
|
+
} else if (collection.models.length > 1) {
|
|
257
|
+
throw Error('Got more than one.');
|
|
258
|
+
}
|
|
259
|
+
return collection.models[0];
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const createOneOrNoneFromDatabase = (_result, getBusinessObjects) => {
|
|
263
|
+
if (!_result) {
|
|
264
|
+
return _result;
|
|
265
|
+
}
|
|
266
|
+
const collection = createFromDatabase(_result, getBusinessObjects);
|
|
267
|
+
if (collection && collection.models.length > 1) {
|
|
268
|
+
throw Error('Got more than one.');
|
|
269
|
+
}
|
|
270
|
+
return collection && collection.models[0];
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
const createManyFromDatabase = (_result, getBusinessObjects) => {
|
|
274
|
+
const collection = createFromDatabase(_result, getBusinessObjects);
|
|
275
|
+
if (!collection || collection.models.length === 0) {
|
|
276
|
+
throw Error('Did not get at least one.');
|
|
277
|
+
}
|
|
278
|
+
return collection;
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
const getSqlInsertParts = bo => {
|
|
282
|
+
const columns = getSqlColumns(bo.constructor)
|
|
283
|
+
.filter(
|
|
284
|
+
(column, index) => bo[getProperties(bo.constructor)[index]] !== void 0
|
|
285
|
+
)
|
|
286
|
+
.map(col => `"${col}"`)
|
|
287
|
+
.join(', ');
|
|
288
|
+
const values = getProperties(bo.constructor)
|
|
289
|
+
.map(property => bo[property])
|
|
290
|
+
.filter(value => value !== void 0);
|
|
291
|
+
const valuesVar = values.map((value, index) => `$${index + 1}`);
|
|
292
|
+
return { columns, values, valuesVar };
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
const getSqlUpdateParts = (bo, on = 'id') => {
|
|
296
|
+
const clauseArray = getSqlColumns(bo.constructor)
|
|
297
|
+
.filter(
|
|
298
|
+
(sqlColumn, index) => bo[getProperties(bo.constructor)[index]] !== void 0
|
|
299
|
+
)
|
|
300
|
+
.map((sqlColumn, index) => `"${sqlColumn}" = $${index + 1}`);
|
|
301
|
+
const clause = clauseArray.join(', ');
|
|
302
|
+
const idVar = `$${clauseArray.length + 1}`;
|
|
303
|
+
const _values = getProperties(bo.constructor)
|
|
304
|
+
.map(property => bo[property])
|
|
305
|
+
.filter(value => value !== void 0);
|
|
306
|
+
const values = [..._values, bo[on]];
|
|
307
|
+
return { clause, idVar, values };
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
const getMatchingParts = bo => {
|
|
311
|
+
const whereClause = getProperties(bo.constructor)
|
|
312
|
+
.map((property, index) =>
|
|
313
|
+
bo[property] != null
|
|
314
|
+
? `"${bo.constructor.tableName}"."${
|
|
315
|
+
getSqlColumns(bo.constructor)[index]
|
|
316
|
+
}"`
|
|
317
|
+
: null
|
|
318
|
+
)
|
|
319
|
+
.filter(x => x != null)
|
|
320
|
+
.map((x, i) => `${x} = $${i + 1}`)
|
|
321
|
+
.join(' AND ');
|
|
322
|
+
const values = getProperties(bo.constructor)
|
|
323
|
+
.map(property => (bo[property] != null ? bo[property] : null))
|
|
324
|
+
.filter(x => x != null);
|
|
325
|
+
return { whereClause, values };
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
// This one returns an object, which allows it to be more versatile.
|
|
329
|
+
// To-do: make this one even better and use it instead of the one above.
|
|
330
|
+
const getMatchingPartsObject = bo => {
|
|
331
|
+
const whereClause = getProperties(bo.constructor)
|
|
332
|
+
.map((property, index) =>
|
|
333
|
+
bo[property] != null
|
|
334
|
+
? `"${bo.constructor.tableName}"."${
|
|
335
|
+
getSqlColumns(bo.constructor)[index]
|
|
336
|
+
}"`
|
|
337
|
+
: null
|
|
338
|
+
)
|
|
339
|
+
.filter(x => x != null)
|
|
340
|
+
.map((x, i) => `${x} = $(${i + 1})`)
|
|
341
|
+
.join(' AND ');
|
|
342
|
+
const values = getProperties(bo.constructor)
|
|
343
|
+
.map(property => (bo[property] != null ? bo[property] : null))
|
|
344
|
+
.filter(x => x != null)
|
|
345
|
+
.reduce(
|
|
346
|
+
(accum, val, index) => Object.assign({}, accum, { [index + 1]: val }),
|
|
347
|
+
{}
|
|
348
|
+
);
|
|
349
|
+
return { whereClause, values };
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
const getNewWith = (bo, sqlColumns, values) => {
|
|
353
|
+
const Constructor = bo.constructor;
|
|
354
|
+
const boKeys = sqlColumns.map(
|
|
355
|
+
key => Constructor.properties[Constructor.sqlColumns.indexOf(key)]
|
|
356
|
+
);
|
|
357
|
+
const boData = boKeys.reduce((data, key, index) => {
|
|
358
|
+
data[key] = values[index];
|
|
359
|
+
return data;
|
|
360
|
+
}, {});
|
|
361
|
+
return new Constructor(boData);
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
const getValueBySqlColumn = (bo, sqlColumn) => {
|
|
365
|
+
return bo[
|
|
366
|
+
getProperties(bo.constructor)[
|
|
367
|
+
getSqlColumns(bo.constructor).indexOf(sqlColumn)
|
|
368
|
+
]
|
|
369
|
+
];
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
module.exports.getPrimaryKey = getPrimaryKey;
|
|
373
|
+
module.exports.getProperties = getProperties;
|
|
374
|
+
module.exports.getSqlColumns = getSqlColumns;
|
|
375
|
+
module.exports.getReferences = getReferences;
|
|
376
|
+
module.exports.getDisplayName = getDisplayName;
|
|
377
|
+
module.exports.getPrefixedColumnNames = getPrefixedColumnNames;
|
|
378
|
+
module.exports.getColumns = getColumns;
|
|
379
|
+
module.exports.nestClump = nestClump;
|
|
380
|
+
module.exports.clumpIntoGroups = clumpIntoGroups;
|
|
381
|
+
module.exports.mapToBos = mapToBos;
|
|
382
|
+
module.exports.objectifyDatabaseResult = objectifyDatabaseResult;
|
|
383
|
+
module.exports.createFromDatabase = createFromDatabase;
|
|
384
|
+
module.exports.createOneFromDatabase = createOneFromDatabase;
|
|
385
|
+
module.exports.createOneOrNoneFromDatabase = createOneOrNoneFromDatabase;
|
|
386
|
+
module.exports.createManyFromDatabase = createManyFromDatabase;
|
|
387
|
+
module.exports.getSqlInsertParts = getSqlInsertParts;
|
|
388
|
+
module.exports.getSqlUpdateParts = getSqlUpdateParts;
|
|
389
|
+
module.exports.getMatchingParts = getMatchingParts;
|
|
390
|
+
module.exports.getMatchingPartsObject = getMatchingPartsObject;
|
|
391
|
+
module.exports.getNewWith = getNewWith;
|
|
392
|
+
module.exports.getValueBySqlColumn = getValueBySqlColumn;
|
|
393
|
+
module.exports.getId = getId;
|