@onehat/data 1.17.3 → 1.18.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/cypress/e2e/Entity.cy.js +23 -0
- package/cypress/e2e/Repository/Repository.cy.js +4 -0
- package/cypress.config.js +0 -1
- package/package.json +4 -4
- package/src/Entity/Entity.js +44 -13
- package/src/Repository/Ajax.js +1 -15
- package/src/Repository/OneBuild.js +79 -2
- package/src/Repository/Repository.js +8 -12
package/cypress/e2e/Entity.cy.js
CHANGED
|
@@ -542,6 +542,23 @@ describe('Entity', function() {
|
|
|
542
542
|
expect(this.entity.isDirty).to.be.true;
|
|
543
543
|
});
|
|
544
544
|
|
|
545
|
+
it('getMappedData', function() {
|
|
546
|
+
|
|
547
|
+
const mapped = this.entity.getMappedData({
|
|
548
|
+
foo: 2,
|
|
549
|
+
bar: 'two',
|
|
550
|
+
baz: {
|
|
551
|
+
test: {
|
|
552
|
+
val: false,
|
|
553
|
+
},
|
|
554
|
+
},
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
expect(mapped.foo).to.be.eq(2);
|
|
558
|
+
expect(mapped.bar).to.be.eq('two');
|
|
559
|
+
expect(mapped.baz).to.be.eq(false);
|
|
560
|
+
});
|
|
561
|
+
|
|
545
562
|
it('setId', function() {
|
|
546
563
|
expect(this.entity.foo).to.be.eq(1);
|
|
547
564
|
expect(this.entity.isTempId).to.be.false;
|
|
@@ -640,11 +657,17 @@ describe('Entity', function() {
|
|
|
640
657
|
lateLastModified;
|
|
641
658
|
|
|
642
659
|
earlyLastModified = this.entity.lastModified;
|
|
660
|
+
cy.wait(100);
|
|
661
|
+
|
|
643
662
|
this.entity.setValue('foo', '125');
|
|
644
663
|
lateLastModified = this.entity.lastModified;
|
|
645
664
|
expect(earlyLastModified < lateLastModified).to.be.true;
|
|
646
665
|
|
|
666
|
+
cy.wait(100);
|
|
667
|
+
|
|
647
668
|
earlyLastModified = this.entity.lastModified;
|
|
669
|
+
|
|
670
|
+
cy.wait(100);
|
|
648
671
|
this.entity.foo = '126';
|
|
649
672
|
lateLastModified = this.entity.lastModified;
|
|
650
673
|
expect(earlyLastModified < lateLastModified).to.be.true;
|
|
@@ -1214,6 +1214,10 @@ describe('Repository Base', function() {
|
|
|
1214
1214
|
child = await id4.getLastChild();
|
|
1215
1215
|
expect(child).to.be.null;
|
|
1216
1216
|
|
|
1217
|
+
// getPath
|
|
1218
|
+
const path = id4.getPath();
|
|
1219
|
+
expect(path).to.be.eq('1/2/4');
|
|
1220
|
+
|
|
1217
1221
|
destoryRepository(repository);
|
|
1218
1222
|
})();
|
|
1219
1223
|
});
|
package/cypress.config.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onehat/data",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.18.0",
|
|
4
4
|
"description": "JS data modeling package with adapters for many storage mediums.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"accounting-js": "^1.1.1",
|
|
41
41
|
"axios": "^1.4.0",
|
|
42
42
|
"chrono-node": "^2.6.3",
|
|
43
|
-
"fast-xml-parser": "^4.2.
|
|
43
|
+
"fast-xml-parser": "^4.2.4",
|
|
44
44
|
"he": "^1.2.0",
|
|
45
45
|
"js-base64": "^3.7.5",
|
|
46
46
|
"lodash": "^4.17.21",
|
|
@@ -55,13 +55,13 @@
|
|
|
55
55
|
"@babel/core": "^7.22.1",
|
|
56
56
|
"@babel/node": "^7.22.1",
|
|
57
57
|
"@babel/plugin-transform-class-properties": "^7.22.3",
|
|
58
|
-
"@babel/plugin-transform-runtime": "^7.
|
|
58
|
+
"@babel/plugin-transform-runtime": "^7.22.4",
|
|
59
59
|
"@babel/preset-env": "^7.22.4",
|
|
60
60
|
"@babel/register": "^7.21.0",
|
|
61
61
|
"@babel/runtime": "^7.22.3",
|
|
62
62
|
"@cypress/webpack-preprocessor": "^5.17.1",
|
|
63
63
|
"babel-loader": "^9.1.2",
|
|
64
|
-
"cypress": "12.
|
|
64
|
+
"cypress": "12.15.0",
|
|
65
65
|
"ink-docstrap": "^1.3.2",
|
|
66
66
|
"joi": "^17.9.2",
|
|
67
67
|
"jsdoc": "^4.0.2",
|
package/src/Entity/Entity.js
CHANGED
|
@@ -32,10 +32,9 @@ class Entity extends EventEmitter {
|
|
|
32
32
|
* @param {Schema} schema - Schema object
|
|
33
33
|
* @param {object} rawData - Raw data object. Keys are Property names, Values are Property values.
|
|
34
34
|
* @param {Repository} repository
|
|
35
|
-
* @param {boolean} originalIsMapped - Has data already been mapped according to schema?
|
|
36
35
|
* @param {boolean} isDelayedSave - Should the repository skip autosave when immediately adding the record?
|
|
37
36
|
*/
|
|
38
|
-
constructor(schema, rawData = {}, repository = null,
|
|
37
|
+
constructor(schema, rawData = {}, repository = null, isDelayedSave = false, isRemotePhantomMode = false) {
|
|
39
38
|
super(...arguments);
|
|
40
39
|
|
|
41
40
|
if (!schema) {
|
|
@@ -89,12 +88,14 @@ class Entity extends EventEmitter {
|
|
|
89
88
|
* @private
|
|
90
89
|
*/
|
|
91
90
|
this._originalDataParsed = null;
|
|
92
|
-
|
|
91
|
+
|
|
93
92
|
/**
|
|
94
93
|
* @member {boolean} originalIsMapped - Has the original data already been mapped according to schema?
|
|
94
|
+
* The attribute is no longer used. this._originalData should always be UNmapped.
|
|
95
95
|
* @private
|
|
96
|
+
* @deprecated
|
|
96
97
|
*/
|
|
97
|
-
this.originalIsMapped = originalIsMapped;
|
|
98
|
+
// this.originalIsMapped = originalIsMapped;
|
|
98
99
|
|
|
99
100
|
/**
|
|
100
101
|
* @member {Object} properties - Object of all Properties, keyed by id (for quick access)
|
|
@@ -339,11 +340,6 @@ class Entity extends EventEmitter {
|
|
|
339
340
|
throw new Error('PropertyType ' + type + ' does not exist.');
|
|
340
341
|
}
|
|
341
342
|
|
|
342
|
-
if (this.originalIsMapped) {
|
|
343
|
-
// Data has already been mapped according to schema, so alter definition
|
|
344
|
-
definition = _.clone(definition); // Clone it so you don't alter original in schema
|
|
345
|
-
definition.mapping = definition.name;
|
|
346
|
-
}
|
|
347
343
|
const
|
|
348
344
|
Property = PropertyTypes[type],
|
|
349
345
|
property = new Property(definition, this._proxy);
|
|
@@ -383,6 +379,7 @@ class Entity extends EventEmitter {
|
|
|
383
379
|
throw Error('this.loadOriginalData is no longer valid. Entity has been destroyed.');
|
|
384
380
|
}
|
|
385
381
|
this.isPersisted = true;
|
|
382
|
+
|
|
386
383
|
this._originalData = originalData || {};
|
|
387
384
|
this.reset();
|
|
388
385
|
this.getIdProperty().isTempId = false;
|
|
@@ -1215,9 +1212,16 @@ class Entity extends EventEmitter {
|
|
|
1215
1212
|
throw Error('this.setRawValues is no longer valid. Entity has been destroyed.');
|
|
1216
1213
|
}
|
|
1217
1214
|
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1215
|
+
return this.setValues(this.getMappedData(rawData));
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
/**
|
|
1219
|
+
* Maps the data, according to schema
|
|
1220
|
+
* @param {object} rawData - Raw data object, prior to mapping,
|
|
1221
|
+
* @returns {object} mappedData
|
|
1222
|
+
*/
|
|
1223
|
+
getMappedData = (rawData) => {
|
|
1224
|
+
|
|
1221
1225
|
const mappedData = {};
|
|
1222
1226
|
function setMappedValue(property) {
|
|
1223
1227
|
let rawValue;
|
|
@@ -1232,10 +1236,14 @@ class Entity extends EventEmitter {
|
|
|
1232
1236
|
mappedData[property.name] = rawValue;
|
|
1233
1237
|
}
|
|
1234
1238
|
|
|
1239
|
+
const [dependentProperties, nonDependentProperties] = _.partition(this.properties, (property) => {
|
|
1240
|
+
return property.hasDepends;
|
|
1241
|
+
});
|
|
1242
|
+
|
|
1235
1243
|
_.each(nonDependentProperties, setMappedValue);
|
|
1236
1244
|
_.each(dependentProperties, setMappedValue);
|
|
1237
1245
|
|
|
1238
|
-
return
|
|
1246
|
+
return mappedData;
|
|
1239
1247
|
}
|
|
1240
1248
|
|
|
1241
1249
|
/**
|
|
@@ -1773,6 +1781,29 @@ class Entity extends EventEmitter {
|
|
|
1773
1781
|
return child;
|
|
1774
1782
|
}
|
|
1775
1783
|
|
|
1784
|
+
/**
|
|
1785
|
+
* Gets the path to this node.
|
|
1786
|
+
* @return {string} path
|
|
1787
|
+
*/
|
|
1788
|
+
getPath = () => {
|
|
1789
|
+
this.ensureTree();
|
|
1790
|
+
if (this.isDestroyed) {
|
|
1791
|
+
throw Error('this.getPath is no longer valid. TreeNode has been destroyed.');
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
const parentIds = [];
|
|
1795
|
+
let parent = this;
|
|
1796
|
+
while(parent.hasParent) { // stops at root
|
|
1797
|
+
parentIds.push(parent.id);
|
|
1798
|
+
parent = parent.parent;
|
|
1799
|
+
}
|
|
1800
|
+
if (parent.id !== this.id) {
|
|
1801
|
+
parentIds.push(parent.id); // add root id
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1804
|
+
return parentIds.reverse().join('/');
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1776
1807
|
/**
|
|
1777
1808
|
* Helper to make sure this Repository is a tree
|
|
1778
1809
|
* @private
|
package/src/Repository/Ajax.js
CHANGED
|
@@ -559,10 +559,6 @@ class AjaxRepository extends Repository {
|
|
|
559
559
|
url = this.api.add,
|
|
560
560
|
data = entity.getSubmitValues();
|
|
561
561
|
|
|
562
|
-
if (entity.isRemotePhantomMode) {
|
|
563
|
-
data.isRemotePhantom = true;
|
|
564
|
-
}
|
|
565
|
-
|
|
566
562
|
return this._send(method, url, data)
|
|
567
563
|
.then(result => {
|
|
568
564
|
if (this.debugMode) {
|
|
@@ -610,9 +606,6 @@ class AjaxRepository extends Repository {
|
|
|
610
606
|
data = {
|
|
611
607
|
entities: _.map(entities, entity => {
|
|
612
608
|
const values = entity.submitValues;
|
|
613
|
-
if (entity.isRemotePhantomMode) {
|
|
614
|
-
values.isRemotePhantom = true;
|
|
615
|
-
}
|
|
616
609
|
entity.isSaving = true;
|
|
617
610
|
return values;
|
|
618
611
|
}),
|
|
@@ -672,10 +665,6 @@ class AjaxRepository extends Repository {
|
|
|
672
665
|
url = this.api.edit,
|
|
673
666
|
data = entity.getSubmitValues();
|
|
674
667
|
|
|
675
|
-
if (entity.isRemotePhantomMode) {
|
|
676
|
-
data.isRemotePhantom = false;
|
|
677
|
-
}
|
|
678
|
-
|
|
679
668
|
return this._send(method, url, data)
|
|
680
669
|
.then(result => {
|
|
681
670
|
if (this.debugMode) {
|
|
@@ -723,9 +712,6 @@ class AjaxRepository extends Repository {
|
|
|
723
712
|
data = {
|
|
724
713
|
entities: _.map(entities, entity => {
|
|
725
714
|
const values = entity.submitValues;
|
|
726
|
-
if (entity.isRemotePhantomMode) {
|
|
727
|
-
values.isRemotePhantom = false;
|
|
728
|
-
}
|
|
729
715
|
entity.isSaving = true;
|
|
730
716
|
return values;
|
|
731
717
|
}),
|
|
@@ -971,7 +957,7 @@ class AjaxRepository extends Repository {
|
|
|
971
957
|
if (!promises.length) {
|
|
972
958
|
return;
|
|
973
959
|
}
|
|
974
|
-
return
|
|
960
|
+
return Promise.all(promises)
|
|
975
961
|
.then(this.axios.spread((...batchOperationResults) => {
|
|
976
962
|
// All requests are now complete
|
|
977
963
|
|
|
@@ -414,12 +414,16 @@ class OneBuildRepository extends AjaxRepository {
|
|
|
414
414
|
/**
|
|
415
415
|
* Gets the root nodes of this tree.
|
|
416
416
|
*/
|
|
417
|
-
getRootNodes = async (getChildren = false, depth) => {
|
|
417
|
+
getRootNodes = async (getChildren = false, depth, getChildParams) => {
|
|
418
418
|
this.ensureTree();
|
|
419
419
|
if (this.isDestroyed) {
|
|
420
420
|
this.throwError('this.setRootNode is no longer valid. Repository has been destroyed.');
|
|
421
421
|
return;
|
|
422
422
|
}
|
|
423
|
+
if (!this.isOnline) {
|
|
424
|
+
this.throwError('Offline');
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
423
427
|
|
|
424
428
|
// Clear all entities, if any exist
|
|
425
429
|
_.each(this.entities, (entity) => {
|
|
@@ -427,11 +431,84 @@ class OneBuildRepository extends AjaxRepository {
|
|
|
427
431
|
});
|
|
428
432
|
this.entities = [];
|
|
429
433
|
|
|
430
|
-
|
|
434
|
+
|
|
435
|
+
const data = {
|
|
436
|
+
url: this.name + '/getRootNodes',
|
|
437
|
+
data: qs.stringify({
|
|
438
|
+
getChildren,
|
|
439
|
+
depth,
|
|
440
|
+
conditions: getChildParams ? getChildParams() : null
|
|
441
|
+
}),
|
|
442
|
+
method: 'POST',
|
|
443
|
+
baseURL: this.api.baseURL,
|
|
444
|
+
};
|
|
431
445
|
|
|
446
|
+
if (this.debugMode) {
|
|
447
|
+
console.log('getRootNodes', data);
|
|
448
|
+
}
|
|
432
449
|
|
|
450
|
+
return this.axios(data)
|
|
451
|
+
.then((result) => {
|
|
452
|
+
if (this.debugMode) {
|
|
453
|
+
console.log('getRootNodes response', result);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const response = result.data;
|
|
457
|
+
if (!response.success) {
|
|
458
|
+
this.throwError(response.data);
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// TODO: Load up the repository with these root nodes
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
});
|
|
433
467
|
}
|
|
434
468
|
|
|
469
|
+
/**
|
|
470
|
+
* Searches all nodes for the supplied text.
|
|
471
|
+
* This basically takes the search query and returns whatever the server sends
|
|
472
|
+
*/
|
|
473
|
+
searchTree = async (q) => {
|
|
474
|
+
this.ensureTree();
|
|
475
|
+
if (this.isDestroyed) {
|
|
476
|
+
this.throwError('this.searchTree is no longer valid. Repository has been destroyed.');
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
if (!this.isOnline) {
|
|
480
|
+
this.throwError('Offline');
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
const data = {
|
|
485
|
+
url: this.name + '/searchTree',
|
|
486
|
+
data: qs.stringify({
|
|
487
|
+
q,
|
|
488
|
+
}),
|
|
489
|
+
method: 'POST',
|
|
490
|
+
baseURL: this.api.baseURL,
|
|
491
|
+
};
|
|
492
|
+
|
|
493
|
+
if (this.debugMode) {
|
|
494
|
+
console.log('searchTree', data);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
return this.axios(data)
|
|
498
|
+
.then((result) => {
|
|
499
|
+
if (this.debugMode) {
|
|
500
|
+
console.log('searchTree response', result);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
const response = result.data;
|
|
504
|
+
if (!response.success) {
|
|
505
|
+
this.throwError(response.data);
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
return response.data;
|
|
510
|
+
});
|
|
511
|
+
}
|
|
435
512
|
/**
|
|
436
513
|
* Loads the children of the supplied treeNode
|
|
437
514
|
*/
|
|
@@ -965,12 +965,11 @@ export default class Repository extends EventEmitter {
|
|
|
965
965
|
* Creates a single new Entity in storage medium.
|
|
966
966
|
* @param {object} data - Either raw data object or Entity. If raw data, keys are Property names, Values are Property values.
|
|
967
967
|
* @param {boolean} isPersisted - Whether the new entity should be marked as already being persisted in storage medium.
|
|
968
|
-
* @param {boolean} originalIsMapped - Has data already been mapped according to schema?
|
|
969
968
|
* @param {boolean} isDelayedSave - Should the repository skip autosave when immediately adding the record?
|
|
970
969
|
* @return {object} entity - new Entity object
|
|
971
970
|
* @fires add
|
|
972
971
|
*/
|
|
973
|
-
add = async (data, isPersisted = false,
|
|
972
|
+
add = async (data, isPersisted = false, isDelayedSave = false) => {
|
|
974
973
|
if (this.isDestroyed) {
|
|
975
974
|
this.throwError('this.add is no longer valid. Repository has been destroyed.');
|
|
976
975
|
return;
|
|
@@ -992,7 +991,7 @@ export default class Repository extends EventEmitter {
|
|
|
992
991
|
let entity = data;
|
|
993
992
|
if (!(data instanceof Entity)) {
|
|
994
993
|
// Create the new entity
|
|
995
|
-
entity = Repository._createEntity(this.schema, data, this, isPersisted,
|
|
994
|
+
entity = Repository._createEntity(this.schema, data, this, isPersisted, isDelayedSave, this.isRemotePhantomMode);
|
|
996
995
|
}
|
|
997
996
|
this._relayEntityEvents(entity);
|
|
998
997
|
this.entities.unshift(entity); // Add to *beginning* of entities array, so the phantom record will appear at the beginning of the current page
|
|
@@ -1016,11 +1015,10 @@ export default class Repository extends EventEmitter {
|
|
|
1016
1015
|
* Used when we want to work with an entity, but don't want that entity to appear in a repository.
|
|
1017
1016
|
* @param {object} data - Either raw data object or Entity. If raw data, keys are Property names, Values are Property values.
|
|
1018
1017
|
* @param {boolean} isPersisted - Whether the new entity should be marked as already being persisted in storage medium.
|
|
1019
|
-
* @param {boolean} originalIsMapped - Has data already been mapped according to schema?
|
|
1020
1018
|
* @param {boolean} isDelayedSave - Should the repository skip autosave when immediately adding the record?
|
|
1021
1019
|
* @return {object} entity - new Entity object
|
|
1022
1020
|
*/
|
|
1023
|
-
createStandaloneEntity = async (data, isPersisted = false,
|
|
1021
|
+
createStandaloneEntity = async (data, isPersisted = false, isDelayedSave = false) => {
|
|
1024
1022
|
if (this.isDestroyed) {
|
|
1025
1023
|
this.throwError('this.createStandaloneEntity is no longer valid. Repository has been destroyed.');
|
|
1026
1024
|
return;
|
|
@@ -1030,7 +1028,7 @@ export default class Repository extends EventEmitter {
|
|
|
1030
1028
|
return;
|
|
1031
1029
|
}
|
|
1032
1030
|
|
|
1033
|
-
const entity = Repository._createEntity(this.schema, data, this, isPersisted,
|
|
1031
|
+
const entity = Repository._createEntity(this.schema, data, this, isPersisted, isDelayedSave, this.isRemotePhantomMode);
|
|
1034
1032
|
|
|
1035
1033
|
if (entity.isPhantom) {
|
|
1036
1034
|
entity.createTempId();
|
|
@@ -1050,10 +1048,9 @@ export default class Repository extends EventEmitter {
|
|
|
1050
1048
|
* Convenience function to create multiple new Entities in storage medium.
|
|
1051
1049
|
* @param {array} data - Array of data objects or Entities.
|
|
1052
1050
|
* @param {boolean} isPersisted - Whether the new entities should be marked as already being persisted in storage medium.
|
|
1053
|
-
* @param {boolean} originalIsMapped - Has data already been mapped according to schema?
|
|
1054
1051
|
* @return {array} entities - new Entity objects
|
|
1055
1052
|
*/
|
|
1056
|
-
addMultiple = async (allData, isPersisted = false
|
|
1053
|
+
addMultiple = async (allData, isPersisted = false) => {
|
|
1057
1054
|
|
|
1058
1055
|
let entities = [],
|
|
1059
1056
|
i,
|
|
@@ -1062,7 +1059,7 @@ export default class Repository extends EventEmitter {
|
|
|
1062
1059
|
|
|
1063
1060
|
for (i = 0; i < allData.length; i++) {
|
|
1064
1061
|
data = allData[i];
|
|
1065
|
-
entity = await this.add(data, isPersisted
|
|
1062
|
+
entity = await this.add(data, isPersisted);
|
|
1066
1063
|
entities.push(entity);
|
|
1067
1064
|
};
|
|
1068
1065
|
|
|
@@ -1076,13 +1073,12 @@ export default class Repository extends EventEmitter {
|
|
|
1076
1073
|
* @param {object} rawData - Raw data object. Keys are Property names, Values are Property values.
|
|
1077
1074
|
* @param {boolean} repository - Optional repository to connect the entity to.
|
|
1078
1075
|
* @param {boolean} isPersisted - Whether the new entity should be marked as already being persisted in storage medium.
|
|
1079
|
-
* @param {boolean} originalIsMapped - Has data already been mapped according to schema?
|
|
1080
1076
|
* @param {boolean} isDelayedSave - Should the repository skip autosave when immediately adding the record?
|
|
1081
1077
|
* @return {object} entity - new Entity object
|
|
1082
1078
|
* @private
|
|
1083
1079
|
*/
|
|
1084
|
-
static _createEntity = (schema, rawData, repository = null, isPersisted = false,
|
|
1085
|
-
const entity = new Entity(schema, rawData, repository,
|
|
1080
|
+
static _createEntity = (schema, rawData, repository = null, isPersisted = false, isDelayedSave = false, isRemotePhantomMode = false) => {
|
|
1081
|
+
const entity = new Entity(schema, rawData, repository, isDelayedSave, isRemotePhantomMode);
|
|
1086
1082
|
entity.initialize();
|
|
1087
1083
|
entity.isPersisted = isPersisted;
|
|
1088
1084
|
return entity;
|