@onehat/data 1.4.12 → 1.5.1
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/cypress/integration/Entity.spec.js +77 -12
- package/cypress/integration/Property/Currency.spec.js +22 -0
- package/cypress/integration/Property/Property.spec.js +4 -0
- package/package.json +1 -1
- package/src/Entity.js +80 -1
- package/src/Property/Currency.js +7 -1
- package/src/Property/Property.js +11 -0
- package/src/Repository/Repository.js +14 -6
|
@@ -14,7 +14,7 @@ describe('Entity', function() {
|
|
|
14
14
|
properties: [
|
|
15
15
|
{ name: 'foo', type: 'int' },
|
|
16
16
|
{ name: 'bar' },
|
|
17
|
-
{ name: 'baz', mapping: 'baz.test.val', type: 'bool' },
|
|
17
|
+
{ name: 'baz', mapping: 'baz.test.val', type: 'bool', defaultValue: null, },
|
|
18
18
|
],
|
|
19
19
|
},
|
|
20
20
|
});
|
|
@@ -198,6 +198,17 @@ describe('Entity', function() {
|
|
|
198
198
|
expect(_.isEqual(this.entity.submitValues, expected)).to.be.true;
|
|
199
199
|
});
|
|
200
200
|
|
|
201
|
+
it('getSubmitValuesMapped & submitValuesMapped', function() {
|
|
202
|
+
const result = this.entity.getSubmitValuesMapped(),
|
|
203
|
+
expected = {
|
|
204
|
+
foo: 1,
|
|
205
|
+
bar: 'one',
|
|
206
|
+
'baz.test.val': true,
|
|
207
|
+
};
|
|
208
|
+
expect(_.isEqual(result, expected)).to.be.true;
|
|
209
|
+
expect(_.isEqual(this.entity.submitValuesMapped, expected)).to.be.true;
|
|
210
|
+
});
|
|
211
|
+
|
|
201
212
|
it('getDisplayValues & displayValues', function() {
|
|
202
213
|
const result = this.entity.getDisplayValues(),
|
|
203
214
|
expected = {
|
|
@@ -258,20 +269,74 @@ describe('Entity', function() {
|
|
|
258
269
|
});
|
|
259
270
|
|
|
260
271
|
it('getReverseMappedRawValue', function() {
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
const
|
|
272
|
+
const definition1 = {
|
|
273
|
+
name: 'foo',
|
|
274
|
+
mapping: 'a.b.c',
|
|
275
|
+
type: 'int',
|
|
276
|
+
},
|
|
277
|
+
Property1 = PropertyTypes[definition1.type];
|
|
278
|
+
const property1 = new Property1(definition1, 'fakeEntity');
|
|
279
|
+
|
|
280
|
+
property1.setValue('47');
|
|
281
|
+
|
|
282
|
+
const reverseMapped1 = Entity.getReverseMappedRawValue(property1),
|
|
283
|
+
expected1 = { a: { b: { c: '47' }, }, };
|
|
284
|
+
|
|
285
|
+
expect(_.isEqual(reverseMapped1, expected1)).to.be.true;
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
// Now, with no mapping
|
|
289
|
+
const definition2 = {
|
|
290
|
+
name: 'foo',
|
|
291
|
+
type: 'int',
|
|
292
|
+
},
|
|
293
|
+
Property2 = PropertyTypes[definition2.type];
|
|
294
|
+
const property2 = new Property2(definition2, 'fakeEntity');
|
|
268
295
|
|
|
269
|
-
|
|
296
|
+
property2.setValue('47');
|
|
270
297
|
|
|
271
|
-
const
|
|
272
|
-
|
|
298
|
+
const reverseMapped2 = Entity.getReverseMappedRawValue(property2),
|
|
299
|
+
expected2 = { foo: '47' };
|
|
273
300
|
|
|
274
|
-
expect(_.isEqual(
|
|
301
|
+
expect(_.isEqual(reverseMapped2, expected2)).to.be.true;
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it('getReverseMappedRawValues (check deep matches)', function() {
|
|
305
|
+
const schema = new Schema({
|
|
306
|
+
name: 'baz',
|
|
307
|
+
model: {
|
|
308
|
+
idProperty: 'foo',
|
|
309
|
+
displayProperty: 'bar',
|
|
310
|
+
properties: [
|
|
311
|
+
{ name: 'foo', type: 'int' },
|
|
312
|
+
{ name: 'bar' },
|
|
313
|
+
{ name: 'baz', mapping: 'baz.test.val', type: 'bool', defaultValue: null, },
|
|
314
|
+
{ name: 'baz2', mapping: 'baz.test2', type: 'bool', defaultValue: null, },
|
|
315
|
+
],
|
|
316
|
+
},
|
|
317
|
+
}),
|
|
318
|
+
data = {
|
|
319
|
+
foo: 1,
|
|
320
|
+
bar: 'one',
|
|
321
|
+
baz: {
|
|
322
|
+
test: {
|
|
323
|
+
val: true,
|
|
324
|
+
},
|
|
325
|
+
test2: false,
|
|
326
|
+
},
|
|
327
|
+
},
|
|
328
|
+
entity = new Entity(schema, data);
|
|
329
|
+
entity.initialize();
|
|
330
|
+
|
|
331
|
+
const result = entity.getReverseMappedRawValues();
|
|
332
|
+
expect(_.isEqual(result, data)).to.be.true;
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it('build a new entity from an existing one using getDataForNewEntity', function() {
|
|
336
|
+
const entity = new Entity(this.schema, this.entity.getDataForNewEntity());
|
|
337
|
+
entity.initialize();
|
|
338
|
+
|
|
339
|
+
expect(_.isEqual(entity.submitValues, this.entity.submitValues)).to.be.true;
|
|
275
340
|
});
|
|
276
341
|
|
|
277
342
|
it('getChanged', function() {
|
|
@@ -60,6 +60,28 @@ describe('CurrencyProperty', function() {
|
|
|
60
60
|
expect(formatted).to.be.eq('$1,234.56');
|
|
61
61
|
});
|
|
62
62
|
|
|
63
|
+
it('omitZeros', function() {
|
|
64
|
+
this.property.setValue('1234.56');
|
|
65
|
+
expect(this.property.displayValue).to.be.eq('$1,234.56');
|
|
66
|
+
|
|
67
|
+
this.property.setValue('1234.50');
|
|
68
|
+
expect(this.property.displayValue).to.be.eq('$1,234.50');
|
|
69
|
+
|
|
70
|
+
this.property.setValue('1234.00');
|
|
71
|
+
expect(this.property.displayValue).to.be.eq('$1,234.00');
|
|
72
|
+
|
|
73
|
+
this.property.omitZeros = true;
|
|
74
|
+
|
|
75
|
+
this.property.setValue('1234.56');
|
|
76
|
+
expect(this.property.displayValue).to.be.eq('$1,234.56');
|
|
77
|
+
|
|
78
|
+
this.property.setValue('1234.50');
|
|
79
|
+
expect(this.property.displayValue).to.be.eq('$1,234.50');
|
|
80
|
+
|
|
81
|
+
this.property.setValue('1234.00');
|
|
82
|
+
expect(this.property.displayValue).to.be.eq('$1,234');
|
|
83
|
+
});
|
|
84
|
+
|
|
63
85
|
it('submitValue', function() {
|
|
64
86
|
this.property.setValue(123.156);
|
|
65
87
|
const formatted = this.property.submitValue;
|
|
@@ -108,6 +108,10 @@ describe('Property', function() {
|
|
|
108
108
|
const property = entity.getProperty('bar');
|
|
109
109
|
expect(property.isDisplayProperty).to.be.true;
|
|
110
110
|
});
|
|
111
|
+
|
|
112
|
+
it('getMapping', function() {
|
|
113
|
+
expect(this.property.getMapping()).to.be.eq('id');
|
|
114
|
+
});
|
|
111
115
|
|
|
112
116
|
});
|
|
113
117
|
|
package/package.json
CHANGED
package/src/Entity.js
CHANGED
|
@@ -32,8 +32,10 @@ class Entity extends EventEmitter {
|
|
|
32
32
|
* @constructor
|
|
33
33
|
* @param {Schema} schema - Schema object
|
|
34
34
|
* @param {object} rawData - Raw data object. Keys are Property names, Values are Property values.
|
|
35
|
+
* @param {Repository} repository
|
|
36
|
+
* @param {boolean} - Has rawData already been mapped according to schema?
|
|
35
37
|
*/
|
|
36
|
-
constructor(schema, rawData = {}, repository = null) {
|
|
38
|
+
constructor(schema, rawData = {}, repository = null, originalIsMapped = false) {
|
|
37
39
|
super(...arguments);
|
|
38
40
|
|
|
39
41
|
if (!schema) {
|
|
@@ -86,6 +88,12 @@ class Entity extends EventEmitter {
|
|
|
86
88
|
*/
|
|
87
89
|
this._originalDataParsed = null;
|
|
88
90
|
|
|
91
|
+
/**
|
|
92
|
+
* @member {boolean} originalIsMapped - Has the original data already been mapped according to schema?
|
|
93
|
+
* @private
|
|
94
|
+
*/
|
|
95
|
+
this.originalIsMapped = originalIsMapped;
|
|
96
|
+
|
|
89
97
|
/**
|
|
90
98
|
* @member {Object} properties - Object of all Properties, keyed by id (for quick access)
|
|
91
99
|
* These properties are actually created in the initialize() function.
|
|
@@ -204,6 +212,11 @@ class Entity extends EventEmitter {
|
|
|
204
212
|
throw new Error('PropertyType ' + type + ' does not exist.');
|
|
205
213
|
}
|
|
206
214
|
|
|
215
|
+
if (this.originalIsMapped) {
|
|
216
|
+
// Data has already been mapped according to schema, so alter definition
|
|
217
|
+
definition = _.clone(definition); // Clone it so you don't alter original in schema
|
|
218
|
+
definition.mapping = definition.name;
|
|
219
|
+
}
|
|
207
220
|
const Property = PropertyTypes[type],
|
|
208
221
|
property = new Property(definition, this._proxy);
|
|
209
222
|
|
|
@@ -444,6 +457,36 @@ class Entity extends EventEmitter {
|
|
|
444
457
|
return this.getSubmitValues();
|
|
445
458
|
}
|
|
446
459
|
|
|
460
|
+
/**
|
|
461
|
+
* Gets an object of properties/values for this Entity,
|
|
462
|
+
* and returns them with the mapped names
|
|
463
|
+
* Values are the "submit" values, not the "raw" or "parsed" or "display" values.
|
|
464
|
+
* @return {object} propertyValues
|
|
465
|
+
*/
|
|
466
|
+
getSubmitValuesMapped = () => {
|
|
467
|
+
if (this.isDestroyed) {
|
|
468
|
+
throw Error('this.getSubmitValuesMapped is no longer valid. Entity has been destroyed.');
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
let propertyValues = {};
|
|
472
|
+
_.forOwn(this.properties, (property) => {
|
|
473
|
+
const name = property.hasMapping ? property.getMapping() : property.name;
|
|
474
|
+
propertyValues[name] = property.getSubmitValue();
|
|
475
|
+
});
|
|
476
|
+
return propertyValues;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Gets "submit" values for this Entity, and returns them with the mapped names
|
|
481
|
+
* @return {object} values
|
|
482
|
+
*/
|
|
483
|
+
get submitValuesMapped() {
|
|
484
|
+
if (this.isDestroyed) {
|
|
485
|
+
throw Error('this.submitValuesMapped is no longer valid. Entity has been destroyed.');
|
|
486
|
+
}
|
|
487
|
+
return this.getSubmitValuesMapped();
|
|
488
|
+
}
|
|
489
|
+
|
|
447
490
|
/**
|
|
448
491
|
* Gets an object of values for this Entity,
|
|
449
492
|
* Values are the "display" values, not the "raw" or "parsed" or "submit" values.
|
|
@@ -556,6 +599,11 @@ class Entity extends EventEmitter {
|
|
|
556
599
|
* @static
|
|
557
600
|
*/
|
|
558
601
|
static getReverseMappedRawValue(property) {
|
|
602
|
+
if (!property.hasMapping) {
|
|
603
|
+
const obj = {};
|
|
604
|
+
obj[property.name] = property.rawValue;
|
|
605
|
+
return obj;
|
|
606
|
+
}
|
|
559
607
|
const mapStack = property.mapping.split('.'),
|
|
560
608
|
rawValue = property.getRawValue();
|
|
561
609
|
|
|
@@ -578,6 +626,37 @@ class Entity extends EventEmitter {
|
|
|
578
626
|
return value;
|
|
579
627
|
}
|
|
580
628
|
|
|
629
|
+
/**
|
|
630
|
+
* Builds up an object of original values for this entity, from which another entity could be easily created
|
|
631
|
+
* @return {object} value - An object representing the 'path' to the raw value.
|
|
632
|
+
* e.g. With a mapping of 'a.b.c' and a property rawValue of '47', the
|
|
633
|
+
* following object will be returned:{ a: { b: { c: '47' }, }, }
|
|
634
|
+
*/
|
|
635
|
+
getReverseMappedRawValues = () => {
|
|
636
|
+
if (this.isDestroyed) {
|
|
637
|
+
throw Error('this.getReverseMappedRawValues is no longer valid. Entity has been destroyed.');
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
let propertyValues = {};
|
|
641
|
+
_.forOwn(this.properties, (property) => {
|
|
642
|
+
const reverseMapped = Entity.getReverseMappedRawValue(property);
|
|
643
|
+
_.merge(propertyValues, reverseMapped);
|
|
644
|
+
});
|
|
645
|
+
return propertyValues;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
/**
|
|
649
|
+
* Convenience function
|
|
650
|
+
* Build a new entity with this data
|
|
651
|
+
*/
|
|
652
|
+
getDataForNewEntity = () => {
|
|
653
|
+
if (this.isDestroyed) {
|
|
654
|
+
throw Error('this.getDataForNewEntity is no longer valid. Entity has been destroyed.');
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
return this.getReverseMappedRawValues();
|
|
658
|
+
}
|
|
659
|
+
|
|
581
660
|
/**
|
|
582
661
|
* Gets the values that have changed since last time saved
|
|
583
662
|
* @return {array|boolean} diff - Array of property names that have changed, or false
|
package/src/Property/Currency.js
CHANGED
|
@@ -26,6 +26,7 @@ export default class CurrencyProperty extends Property {
|
|
|
26
26
|
},
|
|
27
27
|
submitAsString: true, // NOTE, we want to use the accounting.toFixed() method by default
|
|
28
28
|
defaultValue: 0.00,
|
|
29
|
+
omitZeros: false, // Should we omit any .00 at the end?
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
_.merge(this, defaults, config);
|
|
@@ -45,7 +46,12 @@ export default class CurrencyProperty extends Property {
|
|
|
45
46
|
if (this.isDestroyed) {
|
|
46
47
|
throw Error('this.getDisplayValue is no longer valid. Property has been destroyed.');
|
|
47
48
|
}
|
|
48
|
-
|
|
49
|
+
|
|
50
|
+
let ret = accounting.formatMoney(this.parsedValue, this.displayOptions)
|
|
51
|
+
if (this.omitZeros && ret.match(/\.00$/)) {
|
|
52
|
+
ret = ret.replace(/\.00$/, '');
|
|
53
|
+
}
|
|
54
|
+
return ret;
|
|
49
55
|
}
|
|
50
56
|
|
|
51
57
|
getSubmitValue = () => {
|
package/src/Property/Property.js
CHANGED
|
@@ -405,6 +405,17 @@ export default class Property extends EventEmitter {
|
|
|
405
405
|
return this.__proto__.constructor.className;
|
|
406
406
|
}
|
|
407
407
|
|
|
408
|
+
/**
|
|
409
|
+
* Gets the mapped name of this Property.
|
|
410
|
+
* @return {string} name
|
|
411
|
+
*/
|
|
412
|
+
getMapping = () => {
|
|
413
|
+
if (this.isDestroyed) {
|
|
414
|
+
throw Error('this.getMapping is no longer valid. Property has been destroyed.');
|
|
415
|
+
}
|
|
416
|
+
return this.mapping;
|
|
417
|
+
}
|
|
418
|
+
|
|
408
419
|
/**
|
|
409
420
|
* Destroy this object.
|
|
410
421
|
* - Removes all circular references to parent objects
|
|
@@ -847,10 +847,11 @@ export default class Repository extends EventEmitter {
|
|
|
847
847
|
* Creates a single new Entity in storage medium.
|
|
848
848
|
* @param {object} data - Either raw data object or Entity. If raw data, keys are Property names, Values are Property values.
|
|
849
849
|
* @param {boolean} isPersisted - Whether the new entity should be marked as already being persisted in storage medium.
|
|
850
|
+
* @param {boolean} originalIsMapped - Has data already been mapped according to schema?
|
|
850
851
|
* @return {object} entity - new Entity object
|
|
851
852
|
* @fires add
|
|
852
853
|
*/
|
|
853
|
-
add = async (data, isPersisted) => {
|
|
854
|
+
add = async (data, isPersisted = false, originalIsMapped = false) => {
|
|
854
855
|
if (this.isDestroyed) {
|
|
855
856
|
throw Error('this.add is no longer valid. Repository has been destroyed.');
|
|
856
857
|
}
|
|
@@ -858,7 +859,7 @@ export default class Repository extends EventEmitter {
|
|
|
858
859
|
let entity = data;
|
|
859
860
|
if (!(data instanceof Entity)) {
|
|
860
861
|
// Create the new entity
|
|
861
|
-
entity = Repository._createEntity(this.schema, data, this, isPersisted);
|
|
862
|
+
entity = Repository._createEntity(this.schema, data, this, isPersisted, originalIsMapped);
|
|
862
863
|
}
|
|
863
864
|
this._relayEntityEvents(entity);
|
|
864
865
|
this.entities.push(entity);
|
|
@@ -877,20 +878,27 @@ export default class Repository extends EventEmitter {
|
|
|
877
878
|
return entity;
|
|
878
879
|
}
|
|
879
880
|
|
|
881
|
+
/**
|
|
882
|
+
* Convenience function to add entity with mapped data.
|
|
883
|
+
*/
|
|
884
|
+
addMapped = (data, isPersisted = false) => {
|
|
885
|
+
return this.add(data, isPersisted, true);
|
|
886
|
+
}
|
|
887
|
+
|
|
880
888
|
/**
|
|
881
889
|
* Convenience function to create multiple new Entities in storage medium.
|
|
882
890
|
* @param {array} data - Array of data objects or Entities.
|
|
883
891
|
* @param {boolean} isPersisted - Whether the new entities should be marked as already being persisted in storage medium.
|
|
884
892
|
* @return {array} entities - new Entity objects
|
|
885
893
|
*/
|
|
886
|
-
addMultiple = async (allData, isPersisted) => {
|
|
894
|
+
addMultiple = async (allData, isPersisted = false, originalIsMapped = false) => {
|
|
887
895
|
|
|
888
896
|
let entities = [],
|
|
889
897
|
i;
|
|
890
898
|
|
|
891
899
|
for (i = 0; i < allData.length; i++) {
|
|
892
900
|
const data = allData[i],
|
|
893
|
-
entity = await this.add(data, isPersisted);
|
|
901
|
+
entity = await this.add(data, isPersisted, originalIsMapped);
|
|
894
902
|
entities.push(entity);
|
|
895
903
|
};
|
|
896
904
|
|
|
@@ -907,8 +915,8 @@ export default class Repository extends EventEmitter {
|
|
|
907
915
|
* @return {object} entity - new Entity object
|
|
908
916
|
* @private
|
|
909
917
|
*/
|
|
910
|
-
static _createEntity = (schema, rawData, repository = null, isPersisted = false) => {
|
|
911
|
-
const entity = new Entity(schema, rawData, repository);
|
|
918
|
+
static _createEntity = (schema, rawData, repository = null, isPersisted = false, originalIsMapped = false) => {
|
|
919
|
+
const entity = new Entity(schema, rawData, repository, originalIsMapped);
|
|
912
920
|
entity.initialize();
|
|
913
921
|
entity.isPersisted = isPersisted;
|
|
914
922
|
return entity;
|