@onehat/data 1.19.41 → 1.20.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onehat/data",
3
- "version": "1.19.41",
3
+ "version": "1.20.1",
4
4
  "description": "JS data modeling package with adapters for many storage mediums.",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -47,6 +47,7 @@
47
47
  "moment": "^2.29.4",
48
48
  "natsort": "^2.0.3",
49
49
  "numeral": "^2.0.6",
50
+ "object-hash": "^3.0.0",
50
51
  "qs": "^6.11.2",
51
52
  "relative-time-parser": "^1.0.15",
52
53
  "uuid": "^9.0.1"
@@ -3,6 +3,7 @@
3
3
  import EventEmitter from '@onehat/events';
4
4
  import PropertyTypes from '../Property/index.js';
5
5
  import moment from 'moment';
6
+ import hash from 'object-hash';
6
7
  import _ from 'lodash';
7
8
 
8
9
  /**
@@ -104,6 +105,11 @@ class Entity extends EventEmitter {
104
105
  */
105
106
  this.properties = [];
106
107
 
108
+ /**
109
+ * @member {string} hash - A hash of this.submitValues, so we can detect changes
110
+ */
111
+ this.hash = null;
112
+
107
113
  /**
108
114
  * @member {boolean} isTree - Whether this Entity is a TreeNode
109
115
  */
@@ -254,11 +260,24 @@ class Entity extends EventEmitter {
254
260
  return this._proxy; // Return the Proxy, not 'this'
255
261
  }
256
262
 
263
+ /**
264
+ * Decorator for parent emit() method so we can rehash
265
+ */
266
+ emit(name) { // NOTE: Purposefully do not use an arrow-function, so we have access to arguments
267
+
268
+ if (!this.isDestroyed) {
269
+ this.rehash();
270
+ }
271
+
272
+ return super.emit(...arguments);
273
+ }
274
+
257
275
  initialize() {
258
276
  this.properties = this._createProperties();
259
277
  this._createMethods();
260
278
  this._createStatics();
261
279
  this.reset();
280
+ this.rehash();
262
281
  this.isInitialized = true;
263
282
  }
264
283
 
@@ -1022,47 +1041,6 @@ class Entity extends EventEmitter {
1022
1041
  return !_.isEqualWith(this._originalDataParsed, this.getParsedValues());
1023
1042
  }
1024
1043
 
1025
- /**
1026
- * Gets the a hash of the current submitValues.
1027
- * This allows easy detection of changes in data.
1028
- * @return {integer} hash
1029
- */
1030
- getHash = () => {
1031
- if (this.isDestroyed) {
1032
- throw Error('this.getHash is no longer valid. Entity has been destroyed.');
1033
- }
1034
-
1035
- const str = JSON.stringify(_.merge({}, this.submitValues, {
1036
- // include Entity state in hash
1037
- isDestroyed: this.isDestroyed,
1038
- isPhantom: this.isPhantom,
1039
- isDirty: this.isDirty,
1040
- isTempId: this.isTempId,
1041
- }));
1042
-
1043
- // from https://github.com/bryc/code/blob/master/jshash/experimental/cyrb53.js
1044
- const seed = 0;
1045
- let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
1046
- for (let i = 0, ch; i < str.length; i++) {
1047
- ch = str.charCodeAt(i);
1048
- h1 = Math.imul(h1 ^ ch, 2654435761);
1049
- h2 = Math.imul(h2 ^ ch, 1597334677);
1050
- }
1051
- h1 = Math.imul(h1 ^ (h1>>>16), 2246822507) ^ Math.imul(h2 ^ (h2>>>13), 3266489909);
1052
- h2 = Math.imul(h2 ^ (h2>>>16), 2246822507) ^ Math.imul(h1 ^ (h1>>>13), 3266489909);
1053
- const hash = 4294967296 * (2097151 & h2) + (h1>>>0);
1054
-
1055
- return hash;
1056
- }
1057
-
1058
- /**
1059
- * Getter of the hash for this Entity.
1060
- * @return {integer} hash
1061
- */
1062
- get hash() {
1063
- return this.getHash();
1064
- }
1065
-
1066
1044
  /**
1067
1045
  * Gets the original data object for this Entity.
1068
1046
  * This is either what was persisted to storage medium, or what was
@@ -1817,6 +1795,22 @@ class Entity extends EventEmitter {
1817
1795
  return true;
1818
1796
  }
1819
1797
 
1798
+ /**
1799
+ * Sets the hash of the current submitValues and state.
1800
+ * This allows easy detection of changes in data.
1801
+ * @return {integer} hash
1802
+ */
1803
+ rehash = () => {
1804
+ const toHash = JSON.stringify(_.merge({}, this.submitValues, {
1805
+ // include Entity state in hash
1806
+ isDestroyed: this.isDestroyed,
1807
+ isPhantom: this.isPhantom,
1808
+ isDirty: this.isDirty,
1809
+ isTempId: this.isTempId,
1810
+ }));
1811
+ this.hash = hash(toHash);
1812
+ }
1813
+
1820
1814
 
1821
1815
  /**
1822
1816
  * Destroy this object.
@@ -611,6 +611,7 @@ class OneBuildRepository extends AjaxRepository {
611
611
 
612
612
 
613
613
  // Don't emit events for root nodes...
614
+ this.rehash();
614
615
  this.emit('load', this);
615
616
  // this.emit('changeData', this.entities);
616
617
 
@@ -693,6 +694,7 @@ class OneBuildRepository extends AjaxRepository {
693
694
 
694
695
  this._setPaginationVars();
695
696
 
697
+ this.rehash();
696
698
  // this.emit('changeData', this.entities);
697
699
  this.emit('load', this);
698
700
 
@@ -773,6 +775,7 @@ class OneBuildRepository extends AjaxRepository {
773
775
 
774
776
  this._setPaginationVars();
775
777
 
778
+ this.rehash();
776
779
  // this.emit('changeData', this.entities);
777
780
  this.emit('load', this);
778
781
 
@@ -8,6 +8,7 @@ import {
8
8
  } from 'uuid';
9
9
  import moment from 'moment';
10
10
  import { waitUntil } from 'async-wait-until';
11
+ import hash from 'object-hash';
11
12
  import _ from 'lodash';
12
13
 
13
14
  /**
@@ -113,6 +114,11 @@ export default class Repository extends EventEmitter {
113
114
  */
114
115
  isShowingMore: false,
115
116
 
117
+ /**
118
+ * @member {string} hash - A hash of this.entities, so we can detect changes
119
+ */
120
+ hash: null,
121
+
116
122
  /**
117
123
  * @member {number} pageSize - Max number of entities per page
118
124
  * Example: For "Showing 21-30 of 45" This would be 10
@@ -284,6 +290,19 @@ export default class Repository extends EventEmitter {
284
290
  ]);
285
291
  }
286
292
 
293
+ /**
294
+ * Decorator for parent emit() method
295
+ * so we can rehash on changeData events
296
+ */
297
+ emit(name) { // NOTE: Purposefully do not use an arrow-function, so we have access to arguments
298
+
299
+ if (name === 'changeData') {
300
+ this.rehash();
301
+ }
302
+
303
+ return super.emit(...arguments);
304
+ }
305
+
287
306
  /**
288
307
  * Initializes the Repository.
289
308
  * - Applies default sorters
@@ -318,6 +337,7 @@ export default class Repository extends EventEmitter {
318
337
  if (init) {
319
338
  await init.call(this);
320
339
  }
340
+ this.rehash();
321
341
 
322
342
  this.isInitialized = true;
323
343
  this.emit('initialize');
@@ -2123,6 +2143,11 @@ export default class Repository extends EventEmitter {
2123
2143
  _.merge(this, options);
2124
2144
  }
2125
2145
 
2146
+ rehash = () => {
2147
+ const hashes = _.map(this.entities, (entity) => entity.hash);
2148
+ this.hash = hash(hashes);
2149
+ }
2150
+
2126
2151
  unmapData = (mappedData) => {
2127
2152
  const propertiesDef = this.schema?.model?.properties;
2128
2153
  if (!propertiesDef) {