@onehat/data 1.7.11 → 1.7.15

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.
@@ -580,6 +580,21 @@ describe('Entity', function() {
580
580
  this.entity.markStaged(false);
581
581
  expect(this.entity.isStaged).to.be.false;
582
582
  });
583
+
584
+ it('setValue changed lastModified', function() {
585
+ let earlyLastModified,
586
+ lateLastModified;
587
+
588
+ earlyLastModified = this.entity.lastModified;
589
+ this.entity.setValue('foo', '125');
590
+ lateLastModified = this.entity.lastModified;
591
+ expect(earlyLastModified < lateLastModified).to.be.true;
592
+
593
+ earlyLastModified = this.entity.lastModified;
594
+ this.entity.foo = '126';
595
+ lateLastModified = this.entity.lastModified;
596
+ expect(earlyLastModified < lateLastModified).to.be.true;
597
+ });
583
598
  });
584
599
 
585
600
  describe('events', function() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onehat/data",
3
- "version": "1.7.11",
3
+ "version": "1.7.15",
4
4
  "description": "JS data modeling package with adapters for many storage mediums.",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
package/src/Entity.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  import EventEmitter from '@onehat/events';
4
4
  import PropertyTypes from './Property';
5
+ import moment from 'moment';
5
6
  import _ from 'lodash';
6
7
 
7
8
  /**
@@ -129,6 +130,11 @@ class Entity extends EventEmitter {
129
130
  */
130
131
  this.isDestroyed = false;
131
132
 
133
+ /**
134
+ * @member {string} lastModified - Last time this entity was modified
135
+ */
136
+ this.lastModified = null;
137
+
132
138
  // This ES6 Proxy allows us to create magic getters and setters for all property values.
133
139
  // However, these getters and setters are *not* available within the Entity itself.
134
140
  this._proxy = new Proxy(this, {
@@ -325,6 +331,7 @@ class Entity extends EventEmitter {
325
331
  if (this.isDeleted) {
326
332
  this.undelete();
327
333
  }
334
+ this.setLastModified();
328
335
 
329
336
  this.emit('reset', this._proxy);
330
337
  }
@@ -399,6 +406,10 @@ class Entity extends EventEmitter {
399
406
  }
400
407
  return value;
401
408
  }
409
+
410
+ setLastModified = () => {
411
+ this.lastModified = moment(new Date()).format('YYYY-MM-DD HH:mm:ss.SSSS');
412
+ }
402
413
 
403
414
 
404
415
  // ______ __ __
@@ -990,6 +1001,7 @@ class Entity extends EventEmitter {
990
1001
  }
991
1002
 
992
1003
  idProperty.isTempId = false;
1004
+ this.setLastModified();
993
1005
 
994
1006
  return isChanged;
995
1007
  }
@@ -1034,6 +1046,7 @@ class Entity extends EventEmitter {
1034
1046
  }
1035
1047
  property.resumeEvents();
1036
1048
  });
1049
+ this.setLastModified();
1037
1050
 
1038
1051
  if (isChanged) {
1039
1052
  this._recalculateDependentProperties();
@@ -362,7 +362,7 @@ class AjaxRepository extends Repository {
362
362
  throw new Error('No "get" api endpoint defined.');
363
363
  }
364
364
  this.emit('beforeLoad'); // TODO: canceling beforeLoad will cancel the load operation
365
- this.isLoading = true;
365
+ this.markLoading();
366
366
 
367
367
 
368
368
  if (!_.isNil(params) && _.isObject(params)) {
@@ -407,9 +407,9 @@ class AjaxRepository extends Repository {
407
407
  // Set the total records that pass filter
408
408
  this.total = total;
409
409
  this._setPaginationVars();
410
-
411
- this.isLoading = false;
412
- this.isLoaded = true;
410
+
411
+ this.markLoaded();
412
+
413
413
  this.emit('changeData', this.entities);
414
414
  this.emit('load', this);
415
415
  })
@@ -432,7 +432,7 @@ class AjaxRepository extends Repository {
432
432
  throw new Error('No "get" api endpoint defined.');
433
433
  }
434
434
  this.emit('beforeLoad'); // TODO: canceling beforeLoad will cancel the load operation
435
- this.isLoading = true;
435
+ this.markLoading();
436
436
 
437
437
  const params = this._getReloadEntityParams(entity);
438
438
  if (this.debugMode) {
@@ -460,8 +460,8 @@ class AjaxRepository extends Repository {
460
460
  entity.loadOriginalData(updatedData, true);
461
461
  entity.emit('reload', entity);
462
462
 
463
- this.isLoading = false;
464
- this.isLoaded = true;
463
+ this.markLoaded();
464
+
465
465
  this.emit('changeData', this.entities);
466
466
  this.emit('load', this);
467
467
  this.emit('reloadEntity', entity);
@@ -95,7 +95,7 @@ class MemoryRepository extends Repository {
95
95
  }
96
96
 
97
97
  this.emit('beforeLoad');
98
- this.isLoading = true;
98
+ this.markLoading();
99
99
 
100
100
 
101
101
  const isDirectLoad = !_.isNil(data);
@@ -143,8 +143,7 @@ class MemoryRepository extends Repository {
143
143
  await this._saveToStorage(entities);
144
144
  }
145
145
 
146
- this.isLoading = false;
147
- this.isLoaded = true;
146
+ this.markLoaded();
148
147
  this._recalculate(); // fires changeData if needed
149
148
  this.emit('load', entities, this);
150
149
  return entities;
@@ -444,6 +443,21 @@ class MemoryRepository extends Repository {
444
443
  })
445
444
  }
446
445
  /* */
446
+
447
+ removeEntity(entity) { // standard function notation
448
+ const id = entity.id;
449
+
450
+ super.removeEntity(entity);
451
+
452
+ if (this.hasSorters) {
453
+ this._applySorters();
454
+ }
455
+ if (this.hasFilters) {
456
+ this._applyFilters();
457
+ }
458
+ delete this._keyedEntities[id];
459
+ }
460
+
447
461
 
448
462
 
449
463
 
@@ -46,7 +46,7 @@ class NullRepository extends Repository {
46
46
  throw Error('this.load is no longer valid. Repository has been destroyed.');
47
47
  }
48
48
  this.emit('beforeLoad');
49
- this.isLoading = true;
49
+ this.markLoading();
50
50
 
51
51
  if (data) {
52
52
  let entities = data;
@@ -65,8 +65,7 @@ class NullRepository extends Repository {
65
65
 
66
66
  this._updateSize();
67
67
 
68
- this.isLoading = false;
69
- this.isLoaded = true;
68
+ this.markLoaded();
70
69
  this.emit('changeData', this.entities);
71
70
  this.emit('load', this);
72
71
  }
@@ -5,6 +5,7 @@ import Entity from '../Entity';
5
5
  import {
6
6
  v4 as uuid,
7
7
  } from 'uuid';
8
+ import moment from 'moment';
8
9
  import _ from 'lodash';
9
10
 
10
11
  /**
@@ -194,6 +195,11 @@ export default class Repository extends EventEmitter {
194
195
  */
195
196
  this.isLoading = false;
196
197
 
198
+ /**
199
+ * @member {string} lastLoaded - Last time this repository was loaded
200
+ */
201
+ this.lastLoaded = null;
202
+
197
203
  /**
198
204
  * @member {Boolean} isSaving - State: whether or not entities are currently being saved
199
205
  */
@@ -266,9 +272,10 @@ export default class Repository extends EventEmitter {
266
272
  }
267
273
 
268
274
  this._createMethods();
275
+ this._createStatics();
269
276
 
270
- if (this.schema.repository.initialize) {
271
- this.schema.repository.initialize();
277
+ if (this.schema.repository.init) {
278
+ await this.schema.repository.init.call(this);
272
279
  }
273
280
 
274
281
  this.isInitialized = true;
@@ -291,6 +298,22 @@ export default class Repository extends EventEmitter {
291
298
  }
292
299
  }
293
300
 
301
+ /**
302
+ * Creates the static properties for this Repository, based on Schema.
303
+ * @private
304
+ */
305
+ _createStatics = () => {
306
+ if (this.isDestroyed) {
307
+ throw Error('this._createStatics is no longer valid. Entity has been destroyed.');
308
+ }
309
+ const staticsDefinitions = this.schema.repository.statics;
310
+ if (!_.isEmpty(staticsDefinitions)) {
311
+ _.each(staticsDefinitions, (value, key) => {
312
+ this[key] = value;
313
+ });
314
+ }
315
+ }
316
+
294
317
 
295
318
  // __ __
296
319
  // / / ____ ____ _____/ /
@@ -306,6 +329,22 @@ export default class Repository extends EventEmitter {
306
329
  throw new Error('load must be implemented by Repository subclass');
307
330
  }
308
331
 
332
+ /**
333
+ * Marks this repository as loading
334
+ */
335
+ markLoading = () => {
336
+ this.isLoading = true;
337
+ }
338
+
339
+ /**
340
+ * Marks this repository as loaded
341
+ */
342
+ markLoaded = () => {
343
+ this.isLoading = false;
344
+ this.isLoaded = true;
345
+ this.lastLoaded = moment(new Date()).format('YYYY-MM-DD HH:mm:ss.SSSS');
346
+ }
347
+
309
348
  /**
310
349
  * Reload data from storage medium, using previous settings.
311
350
  * Subclasses may override this to provide additional
@@ -1255,49 +1294,6 @@ export default class Repository extends EventEmitter {
1255
1294
  return associatedRepository;
1256
1295
  }
1257
1296
 
1258
- /**
1259
- * Gets the Schema object
1260
- * @return {Schema} schema
1261
- */
1262
- getSchema = () => {
1263
- if (this.isDestroyed) {
1264
- throw Error('this.getSchema is no longer valid. Entity has been destroyed.');
1265
- }
1266
- return this.schema;
1267
- }
1268
-
1269
- /**
1270
- * Gets the associated Repository
1271
- * @param {string} repositoryName - Name of the Repository to retrieve
1272
- * @return {boolean} hasProperty
1273
- */
1274
- getAssociatedRepository = (repositoryName) => {
1275
- if (this.isDestroyed) {
1276
- throw Error('this.getAssociatedRepository is no longer valid. Entity has been destroyed.');
1277
- }
1278
-
1279
- const schema = this.getSchema();
1280
- if (!schema.model.associations.hasOne.includes(repositoryName) &&
1281
- !schema.model.associations.hasMany.includes(repositoryName) &&
1282
- !schema.model.associations.belongsTo.includes(repositoryName) &&
1283
- !schema.model.associations.belongsToMany.includes(repositoryName)
1284
- ) {
1285
- throw Error(repositoryName + ' is not associated with this schema');
1286
- }
1287
-
1288
- const oneHatData = this.oneHatData;
1289
- if (!oneHatData) {
1290
- throw Error('No global oneHatData object');
1291
- }
1292
-
1293
- const associatedRepository = oneHatData.getRepository(repositoryName);
1294
- if (!associatedRepository) {
1295
- throw Error('Repository ' + repositoryName + ' cannot be found');
1296
- }
1297
-
1298
- return associatedRepository;
1299
- }
1300
-
1301
1297
  /**
1302
1298
  * Utility function.
1303
1299
  * Detects if entity is in the current page of the storage medium.
@@ -1621,7 +1617,7 @@ export default class Repository extends EventEmitter {
1621
1617
  * Mainly used for phantom Entities
1622
1618
  * Helper for delete()
1623
1619
  */
1624
- removeEntity = async (entity) => {
1620
+ removeEntity(entity) { // standard function notation so it can be called by child class
1625
1621
  this.entities = _.filter(this.entities, e => e !== entity);
1626
1622
  entity.destroy();
1627
1623
  }