pure-orm 2.0.1 → 3.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/README.md +36 -11
- package/package.json +1 -1
- package/src/bo/base-bo.js +18 -13
- package/src/bo/base-bo.spec.js +73 -1
- package/test-utils/eleven/results.json +818 -0
- package/test-utils/thirteen/bo/audience.js +18 -0
- package/test-utils/thirteen/bo/audiences.js +9 -0
- package/test-utils/thirteen/bo/base.js +5 -0
- package/test-utils/thirteen/bo/brand.js +18 -0
- package/test-utils/thirteen/bo/brands.js +9 -0
- package/test-utils/thirteen/bo/categories.js +12 -0
- package/test-utils/thirteen/bo/category.js +18 -0
- package/test-utils/thirteen/bo/member.js +18 -0
- package/test-utils/thirteen/bo/members.js +9 -0
- package/test-utils/thirteen/bo/passion.js +18 -0
- package/test-utils/thirteen/bo/passions.js +9 -0
- package/test-utils/thirteen/bo/product.js +19 -0
- package/test-utils/thirteen/bo/products.js +9 -0
- package/test-utils/thirteen/bo/recommendation-audience.js +24 -0
- package/test-utils/thirteen/bo/recommendation-audiences.js +9 -0
- package/test-utils/thirteen/bo/recommendation.js +30 -0
- package/test-utils/thirteen/bo/recommendations.js +9 -0
- package/test-utils/thirteen/business-objects.js +14 -0
- package/test-utils/thirteen/results.json +74 -0
- package/test-utils/twelve/bo/base.js +5 -0
- package/test-utils/twelve/bo/member.js +16 -0
- package/test-utils/twelve/bo/members.js +9 -0
- package/test-utils/twelve/bo/prompt.js +20 -0
- package/test-utils/twelve/bo/prompts.js +9 -0
- package/test-utils/twelve/business-objects.js +8 -0
- package/test-utils/twelve/results.json +8 -0
package/README.md
CHANGED
|
@@ -76,7 +76,7 @@ class PersonDAO extends BaseDAO {
|
|
|
76
76
|
And use it like this:
|
|
77
77
|
|
|
78
78
|
```javascript
|
|
79
|
-
const person = personDAO.get(55);
|
|
79
|
+
const person = await personDAO.get({ id: 55 });
|
|
80
80
|
console.log(person);
|
|
81
81
|
```
|
|
82
82
|
|
|
@@ -100,7 +100,7 @@ Person {
|
|
|
100
100
|
Job {
|
|
101
101
|
id: 278,
|
|
102
102
|
personId: 55,
|
|
103
|
-
employerId: 26
|
|
103
|
+
employerId: 26,
|
|
104
104
|
startDate: '2021-01-01',
|
|
105
105
|
endDate: '2021-12-31',
|
|
106
106
|
employer: Employer {
|
|
@@ -115,11 +115,37 @@ Person {
|
|
|
115
115
|
|
|
116
116
|
> This is a quick showcase. To see how to wire up this code, see the full [Practical Example](#practical-example) below.
|
|
117
117
|
|
|
118
|
-
Things to
|
|
118
|
+
### Things to Note:
|
|
119
119
|
|
|
120
|
-
- Our DAO returns a single Person business object which is properly structured from the relational row records!
|
|
120
|
+
- Our DAO returns a single Person business object which is properly structured from the many relational row records!
|
|
121
121
|
- Our query is executed with a `one` method. The DAO methods for `one`, `oneOrNone`, `many`, `any` ensure their count against the number of generated top level business objects - not the number of relational row records the sql expression returns!
|
|
122
|
-
- Rather than manually specifying our columns in the sql select expression, we use the business object's `getSQLSelectClause`. This is purely a convenience method which namespaces each column with the table name prefix to ensure column names don't collide.
|
|
122
|
+
- Rather than manually specifying our columns in the sql select expression, we use the business object's `getSQLSelectClause`. This is purely a convenience method which namespaces each column with the table name prefix to ensure column names don't collide (for example, the person, job, and employer `id`s would collide if not namespaced, as would person and employer `name`s). You are welcome to do this by hand instead of using the convenience methods (as were used above), if you don't mind the tedium:
|
|
123
|
+
```javascript
|
|
124
|
+
class PersonDAO extends BaseDAO {
|
|
125
|
+
get({ id }) {
|
|
126
|
+
// Example showing you can manually specific the select expression fields
|
|
127
|
+
// instead of using a business object's `getSQLSelectClause` convenience
|
|
128
|
+
// method. Note: you must namespace the field with table name and hashtag.
|
|
129
|
+
const query = `
|
|
130
|
+
SELECT
|
|
131
|
+
person.id as "person#id",
|
|
132
|
+
person.name as "person#name",
|
|
133
|
+
job.id as "job#id",
|
|
134
|
+
job.person_id: "job#person_id",
|
|
135
|
+
job.employer_id: "job#employer_id",
|
|
136
|
+
job.start_date: "job#start_date",
|
|
137
|
+
job.end_date: "job#end_date",
|
|
138
|
+
employer.id as "employer#id",
|
|
139
|
+
employer.name as "employer#name"
|
|
140
|
+
FROM person
|
|
141
|
+
JOIN job on person.id = job.person_id
|
|
142
|
+
JOIN employer on job.employer_id = employer.id
|
|
143
|
+
WHERE id = $(id)
|
|
144
|
+
`;
|
|
145
|
+
return this.one(query, { id });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
123
149
|
|
|
124
150
|
## Usage
|
|
125
151
|
|
|
@@ -160,18 +186,18 @@ const renderProfile = (req, res) => {
|
|
|
160
186
|
endDate: '2020-12-31',
|
|
161
187
|
employer: {
|
|
162
188
|
id: 17,
|
|
163
|
-
name: 'Good Corp'
|
|
189
|
+
name: 'Good Corp'
|
|
164
190
|
}
|
|
165
191
|
},
|
|
166
192
|
{
|
|
167
193
|
id: 278,
|
|
168
194
|
personId: 55,
|
|
169
|
-
employerId: 26
|
|
195
|
+
employerId: 26,
|
|
170
196
|
startDate: '2021-01-01',
|
|
171
197
|
endDate: '2021-12-31',
|
|
172
198
|
employer: {
|
|
173
199
|
id: 26,
|
|
174
|
-
name: 'Better Corp'
|
|
200
|
+
name: 'Better Corp'
|
|
175
201
|
}
|
|
176
202
|
}
|
|
177
203
|
]
|
|
@@ -233,7 +259,7 @@ const renderProfile = (req, res) => {
|
|
|
233
259
|
- {
|
|
234
260
|
- id: 278,
|
|
235
261
|
- personId: 55,
|
|
236
|
-
- employerId: 26
|
|
262
|
+
- employerId: 26,
|
|
237
263
|
- startDate: '2021-01-01',
|
|
238
264
|
- endDate: '2021-12-31',
|
|
239
265
|
- employer: {
|
|
@@ -244,8 +270,7 @@ const renderProfile = (req, res) => {
|
|
|
244
270
|
- ]
|
|
245
271
|
- }
|
|
246
272
|
- };
|
|
247
|
-
+ const
|
|
248
|
-
+ const person = personDAO.get({personId});
|
|
273
|
+
+ const person = personDAO.get({ id: req.params.id });
|
|
249
274
|
res.render('profile.html', person);
|
|
250
275
|
```
|
|
251
276
|
|
package/package.json
CHANGED
package/src/bo/base-bo.js
CHANGED
|
@@ -156,14 +156,19 @@ module.exports = ({ getBusinessObjects }) =>
|
|
|
156
156
|
const bo = nodeAlreadySeen || _bo;
|
|
157
157
|
const isNodeAlreadySeen = !!nodeAlreadySeen;
|
|
158
158
|
const nodePointingToIt = nodes.find(node => {
|
|
159
|
-
const
|
|
160
|
-
bo.constructor
|
|
161
|
-
|
|
162
|
-
if (
|
|
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
163
|
return false;
|
|
164
164
|
}
|
|
165
|
-
const
|
|
166
|
-
|
|
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;
|
|
167
172
|
});
|
|
168
173
|
// For first obj type which is has an instance in nodes array,
|
|
169
174
|
// get its index in nodes array
|
|
@@ -180,8 +185,8 @@ module.exports = ({ getBusinessObjects }) =>
|
|
|
180
185
|
return null;
|
|
181
186
|
}, null);
|
|
182
187
|
const parentHeirarchy = [
|
|
183
|
-
|
|
184
|
-
|
|
188
|
+
root,
|
|
189
|
+
...nodes.slice(0, indexOfOldestParent + 1).reverse()
|
|
185
190
|
];
|
|
186
191
|
const nodeItPointsTo = parentHeirarchy.find(parent => {
|
|
187
192
|
const index = Object.values(bo.constructor.references).indexOf(
|
|
@@ -205,7 +210,7 @@ module.exports = ({ getBusinessObjects }) =>
|
|
|
205
210
|
// shown to be the parent (of parcel_events).
|
|
206
211
|
const ec = bo[nodePointingToIt.BoCollection.displayName];
|
|
207
212
|
if (ec && ec.models.find(m => m === nodePointingToIt)) {
|
|
208
|
-
|
|
213
|
+
nodes = [bo, ...nodes];
|
|
209
214
|
return;
|
|
210
215
|
}
|
|
211
216
|
}
|
|
@@ -278,13 +283,13 @@ module.exports = ({ getBusinessObjects }) =>
|
|
|
278
283
|
getSqlInsertParts() {
|
|
279
284
|
const columns = this.constructor.sqlColumns
|
|
280
285
|
.filter(
|
|
281
|
-
(column, index) => this[this.constructor.columns[index]]
|
|
286
|
+
(column, index) => this[this.constructor.columns[index]] !== void 0
|
|
282
287
|
)
|
|
283
288
|
.map(col => `"${col}"`)
|
|
284
289
|
.join(', ');
|
|
285
290
|
const values = this.constructor.columns
|
|
286
291
|
.map(column => this[column])
|
|
287
|
-
.filter(value => value
|
|
292
|
+
.filter(value => value !== void 0);
|
|
288
293
|
const valuesVar = values.map((value, index) => `$${index + 1}`);
|
|
289
294
|
return { columns, values, valuesVar };
|
|
290
295
|
}
|
|
@@ -292,14 +297,14 @@ module.exports = ({ getBusinessObjects }) =>
|
|
|
292
297
|
getSqlUpdateParts(on = 'id') {
|
|
293
298
|
const clauseArray = this.constructor.sqlColumns
|
|
294
299
|
.filter(
|
|
295
|
-
(sqlColumn, index) => this[this.constructor.columns[index]]
|
|
300
|
+
(sqlColumn, index) => this[this.constructor.columns[index]] !== void 0
|
|
296
301
|
)
|
|
297
302
|
.map((sqlColumn, index) => `"${sqlColumn}" = $${index + 1}`);
|
|
298
303
|
const clause = clauseArray.join(', ');
|
|
299
304
|
const idVar = `$${clauseArray.length + 1}`;
|
|
300
305
|
const _values = this.constructor.columns
|
|
301
306
|
.map(column => this[column])
|
|
302
|
-
.filter(value => value
|
|
307
|
+
.filter(value => value !== void 0);
|
|
303
308
|
const values = [..._values, this[on]];
|
|
304
309
|
return { clause, idVar, values };
|
|
305
310
|
}
|
package/src/bo/base-bo.spec.js
CHANGED
|
@@ -17,6 +17,11 @@ const seven = require('../../test-utils/seven/results.json');
|
|
|
17
17
|
const eight = require('../../test-utils/eight/results.json');
|
|
18
18
|
const nine = require('../../test-utils/nine/results.json');
|
|
19
19
|
const ten = require('../../test-utils/ten/results.json');
|
|
20
|
+
const eleven = require('../../test-utils/eleven/results.json');
|
|
21
|
+
const twelve = require('../../test-utils/twelve/results.json');
|
|
22
|
+
const Prompt = require('../../test-utils/twelve/bo/prompt');
|
|
23
|
+
const thirteen = require('../../test-utils/thirteen/results.json');
|
|
24
|
+
const Member = require('../../test-utils/thirteen/bo/member');
|
|
20
25
|
|
|
21
26
|
test('Bo#parseFromDatabase where multiple rows reduce to one nested object (with all one-to-one or one-to-many tables)', () => {
|
|
22
27
|
const order = Order.createOneFromDatabase(one);
|
|
@@ -392,7 +397,7 @@ test('Bo#parseFromDatabase with just top level nodes', () => {
|
|
|
392
397
|
// Problem is when oldest parent is an empty join record and is not included
|
|
393
398
|
// which results in the oldest parent search returning -1 and parent heirarchy
|
|
394
399
|
// is thus messed up.
|
|
395
|
-
test('Bo#parseFromDatabase ', () => {
|
|
400
|
+
test('Bo#parseFromDatabase 10', () => {
|
|
396
401
|
let orders;
|
|
397
402
|
try {
|
|
398
403
|
// This failed when the bug was present
|
|
@@ -511,3 +516,70 @@ test('Bo#parseFromDatabase ', () => {
|
|
|
511
516
|
expect(orders.models[4].lineItems.models[0].productVariant.productVariantImages.models.length).toEqual(1);
|
|
512
517
|
expect(orders.models[4].lineItems.models[0].productVariant.productVariantImages.models[0].id).toEqual(829);
|
|
513
518
|
});
|
|
519
|
+
|
|
520
|
+
// Issue occcurs in nestClump
|
|
521
|
+
// Problem from early returning not logging bo so parent hierarcy was missing it
|
|
522
|
+
test('Bo#parseFromDatabase 11', () => {
|
|
523
|
+
let orders;
|
|
524
|
+
try {
|
|
525
|
+
// This failed when the bug was present
|
|
526
|
+
orders = OrderFull.createFromDatabase(eleven);
|
|
527
|
+
} catch (e) {
|
|
528
|
+
expect(e).not.toBeDefined();
|
|
529
|
+
}
|
|
530
|
+
expect(orders).toBeDefined();
|
|
531
|
+
// Lots of other assertions that are unrelated and shouldn't be here except
|
|
532
|
+
// I'm insecure about the lack of tests so just going at it cause I can.
|
|
533
|
+
// TODO add more later
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
// Issue occcurs in nestClump
|
|
537
|
+
// Problem when a table references another model twice (two columns)
|
|
538
|
+
test('Bo#parseFromDatabase 12', () => {
|
|
539
|
+
let prompt;
|
|
540
|
+
try {
|
|
541
|
+
// This failed when the bug was present
|
|
542
|
+
prompt = Prompt.createFromDatabase(twelve);
|
|
543
|
+
} catch (e) {
|
|
544
|
+
expect(e).not.toBeDefined();
|
|
545
|
+
}
|
|
546
|
+
expect(prompt).toBeDefined();
|
|
547
|
+
// Ideally the below should work
|
|
548
|
+
// expect(prompt.fromMember.id).toEqual(1);
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
// Issue occcurs in nestClump
|
|
552
|
+
// Problem when a table has records that are supposed to nest under root
|
|
553
|
+
// but nest under other stuff below it instead
|
|
554
|
+
// Member
|
|
555
|
+
// Recommendations [1]
|
|
556
|
+
// Brand
|
|
557
|
+
// Recommendations [1]
|
|
558
|
+
// Passion
|
|
559
|
+
// Recommendations [2]
|
|
560
|
+
// -- instead of correct --
|
|
561
|
+
// Member
|
|
562
|
+
// Recommendations[4]
|
|
563
|
+
// Brand
|
|
564
|
+
// Passion
|
|
565
|
+
test('Bo#parseFromDatabase 13', () => {
|
|
566
|
+
const members = Member.createFromDatabase(thirteen);
|
|
567
|
+
const member = members.models[0];
|
|
568
|
+
expect(member.recommendations.models.length).toEqual(4);
|
|
569
|
+
expect(member.recommendations.models[0].brand.id).toEqual(2);
|
|
570
|
+
expect(member.recommendations.models[0].product.id).toEqual(7);
|
|
571
|
+
expect(member.recommendations.models[0].category.id).toEqual(1);
|
|
572
|
+
expect(member.recommendations.models[0].recommendationAudiences.models[0].audience.id).toEqual(1);
|
|
573
|
+
expect(member.recommendations.models[1].brand.id).toEqual(2);
|
|
574
|
+
expect(member.recommendations.models[1].product.id).toEqual(1);
|
|
575
|
+
expect(member.recommendations.models[1].category.id).toEqual(2);
|
|
576
|
+
expect(member.recommendations.models[1].recommendationAudiences.models[0].audience.id).toEqual(1);
|
|
577
|
+
expect(member.recommendations.models[2].brand.id).toEqual(3);
|
|
578
|
+
expect(member.recommendations.models[2].product.id).toEqual(27);
|
|
579
|
+
expect(member.recommendations.models[2].category.id).toEqual(3);
|
|
580
|
+
expect(member.recommendations.models[2].recommendationAudiences.models[0].audience.id).toEqual(1);
|
|
581
|
+
expect(member.recommendations.models[3].brand.id).toEqual(6);
|
|
582
|
+
expect(member.recommendations.models[3].product.id).toEqual(75);
|
|
583
|
+
expect(member.recommendations.models[3].category.id).toEqual(4);
|
|
584
|
+
expect(member.recommendations.models[3].recommendationAudiences.models[0].audience.id).toEqual(1);
|
|
585
|
+
});
|