@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.
@@ -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
@@ -1,6 +1,5 @@
1
1
  import { defineConfig } from "cypress";
2
2
  import webpackPreprocessor from "@cypress/webpack-preprocessor";
3
- import Webpack from "webpack";
4
3
 
5
4
  export default defineConfig({
6
5
  e2e: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onehat/data",
3
- "version": "1.17.3",
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.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.19.6",
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.13.0",
64
+ "cypress": "12.15.0",
65
65
  "ink-docstrap": "^1.3.2",
66
66
  "joi": "^17.9.2",
67
67
  "jsdoc": "^4.0.2",
@@ -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, originalIsMapped = false, isDelayedSave = false, isRemotePhantomMode = false) {
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
- const [dependentProperties, nonDependentProperties] = _.partition(this.properties, (property) => {
1219
- return property.hasDepends;
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 this.setValues(mappedData);
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
@@ -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 this.axios.all(promises)
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
- // TODO: Load root nodes (and possibly their children)
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, originalIsMapped = false, isDelayedSave = 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, originalIsMapped, isDelayedSave, this.isRemotePhantomMode);
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, originalIsMapped = false, isDelayedSave = 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, originalIsMapped, isDelayedSave, this.isRemotePhantomMode);
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, originalIsMapped = 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, originalIsMapped);
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, originalIsMapped = false, isDelayedSave = false, isRemotePhantomMode = false) => {
1085
- const entity = new Entity(schema, rawData, repository, originalIsMapped, isDelayedSave, isRemotePhantomMode);
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;