@onehat/data 1.6.13 → 1.7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onehat/data",
3
- "version": "1.6.13",
3
+ "version": "1.7.0",
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
@@ -257,15 +257,17 @@ class Entity extends EventEmitter {
257
257
  * This is mainly for updating Entity with new data
258
258
  * from remote storage medium.
259
259
  * Assumes (and sets) isPersisted === true.
260
+ * Assumes (and sets) isTempId === false.
260
261
  * @param {array} originalData - Raw data to load into entity.
261
262
  */
262
263
  loadOriginalData = (originalData) => {
263
264
  if (this.isDestroyed) {
264
265
  throw Error('this.loadOriginalData is no longer valid. Entity has been destroyed.');
265
266
  }
266
- this._originalData = originalData || {};
267
267
  this.isPersisted = true;
268
+ this._originalData = originalData || {};
268
269
  this.reset();
270
+ this.getIdProperty().isTempId = false;
269
271
  }
270
272
 
271
273
  /**
@@ -57,7 +57,6 @@ export default class IntegerProperty extends Property {
57
57
  }
58
58
  return id;
59
59
  }
60
-
61
60
 
62
61
  };
63
62
 
@@ -28,10 +28,13 @@ class AjaxRepository extends Repository {
28
28
  * @member {object} api - List of relative URIs to API endpoints.
29
29
  */
30
30
  api: {
31
- add: null,
32
31
  get: null,
32
+ add: null,
33
33
  edit: null,
34
34
  delete: null,
35
+ batchAdd: null,
36
+ batchEdit: null,
37
+ batchDelete: null,
35
38
  baseURL: '', // e.g. 'https://example.com/myapp/'
36
39
  },
37
40
 
@@ -39,8 +42,8 @@ class AjaxRepository extends Repository {
39
42
  * @member {object} methods - List of methods for all four CRUD operations
40
43
  */
41
44
  methods: {
42
- add: 'POST',
43
45
  get: 'GET',
46
+ add: 'POST',
44
47
  edit: 'POST',
45
48
  delete: 'POST',
46
49
  },
@@ -498,7 +501,7 @@ class AjaxRepository extends Repository {
498
501
  * @returns {promise} - Axios Promise.
499
502
  * @private
500
503
  */
501
- _doAdd(entity) {
504
+ _doAdd(entity) { // standard function notation
502
505
  if (!this.api.add) {
503
506
  throw new Error('No "add" api endpoint defined.');
504
507
  }
@@ -528,13 +531,55 @@ class AjaxRepository extends Repository {
528
531
  entity.loadOriginalData(root[0]);
529
532
  });
530
533
  }
534
+
535
+ /**
536
+ * Helper for save.
537
+ * Add multiple entities to storage medium
538
+ * @param {array} entities - Entities
539
+ * @returns {promise} - Axios Promise.
540
+ * @private
541
+ */
542
+ _doBatchAdd(entities) { // standard function notation
543
+ if (!this.api.batchAdd) {
544
+ throw new Error('No "batchAdd" api endpoint defined.');
545
+ }
546
+
547
+ this._operations.add = true;
548
+
549
+ const method = this.methods.add,
550
+ url = this.api.batchAdd,
551
+ data = _.map(entities, entity => entity.submitValues);
552
+
553
+ return this._send(method, url, data)
554
+ .then(result => {
555
+ if (this.debugMode) {
556
+ console.log(this.api.batchAdd + ' result', result);
557
+ }
558
+ const {
559
+ root,
560
+ success,
561
+ total,
562
+ message
563
+ } = this._processServerResponse(result);
564
+
565
+ if (!success) {
566
+ throw new Error(message);
567
+ }
568
+
569
+ // Reload each entity with new data
570
+ // TODO: Check this
571
+ _.each(entities, (entity, ix) => {
572
+ entity.loadOriginalData(root[ix]);
573
+ });
574
+ });
575
+ }
531
576
 
532
577
  /**
533
578
  * Helper for save.
534
579
  * @returns {promise} - Axios Promise.
535
580
  * @private
536
581
  */
537
- _doEdit(entity) {
582
+ _doEdit(entity) { // standard function notation
538
583
  if (!this.api.edit) {
539
584
  throw new Error('No "edit" api endpoint defined.');
540
585
  }
@@ -565,12 +610,54 @@ class AjaxRepository extends Repository {
565
610
  });
566
611
  }
567
612
 
613
+ /**
614
+ * Helper for save.
615
+ * Edit multiple entities in storage medium
616
+ * @param {array} entities - Entities
617
+ * @returns {promise} - Axios Promise.
618
+ * @private
619
+ */
620
+ _doBatchEdit(entities) { // standard function notation
621
+ if (!this.api.batchEdit) {
622
+ throw new Error('No "batchEdit" api endpoint defined.');
623
+ }
624
+
625
+ this._operations.edit = true;
626
+
627
+ const method = this.methods.edit,
628
+ url = this.api.batchEdit,
629
+ data = _.map(entities, entity => entity.submitValues);
630
+
631
+ return this._send(method, url, data)
632
+ .then(result => {
633
+ if (this.debugMode) {
634
+ console.log(this.api.batchEdit + ' result', result);
635
+ }
636
+ const {
637
+ root,
638
+ success,
639
+ total,
640
+ message
641
+ } = this._processServerResponse(result);
642
+
643
+ if (!success) {
644
+ throw new Error(message);
645
+ }
646
+
647
+ // Reload each entity with new data
648
+ // TODO: Check this
649
+ _.each(entities, (entity, ix) => {
650
+ entity.loadOriginalData(root[ix]);
651
+ });
652
+ });
653
+ }
654
+
568
655
  /**
569
656
  * Helper for save.
570
657
  * @returns {promise} - Axios Promise.
571
658
  * @private
572
659
  */
573
- _doDelete(entity) {
660
+ _doDelete(entity) { // standard function notation
574
661
  if (!this.api.delete) {
575
662
  throw new Error('No "delete" api endpoint defined.');
576
663
  }
@@ -604,9 +691,65 @@ class AjaxRepository extends Repository {
604
691
  });
605
692
  }
606
693
 
694
+ /**
695
+ * Helper for save.
696
+ * Delete multiple entities from storage medium
697
+ * @param {array} entities - Entities
698
+ * @returns {promise} - Axios Promise.
699
+ * @private
700
+ */
701
+ _doBatchDelete(entities) { // standard function notation
702
+ if (!this.api.batchDelete) {
703
+ throw new Error('No "batchDelete" api endpoint defined.');
704
+ }
705
+
706
+ this._operations.delete = true;
707
+
708
+ const method = this.methods.delete,
709
+ url = this.api.batchDelete,
710
+ ids = _.map(entities, entity => entity.id),
711
+ data = { ids, };
712
+
713
+ return this._send(method, url, data)
714
+ .then(result => {
715
+ if (this.debugMode) {
716
+ console.log(this.api.batchDelete + ' result', result);
717
+ }
718
+ const {
719
+ root,
720
+ success,
721
+ total,
722
+ message
723
+ } = this._processServerResponse(result);
724
+
725
+ if (!success) {
726
+ throw new Error(message);
727
+ }
728
+
729
+ // Delete it from this.entities
730
+ this.entities = _.filter(this.entities, (entity) => {
731
+ const deleteIt = ids.includes(entity.id);
732
+ if (deleteIt) {
733
+ entity.destroy();
734
+ }
735
+ return !deleteIt;
736
+ });
737
+ });
738
+ }
739
+
740
+ /**
741
+ * Helper for save.
742
+ * Tells repository to delete entity without ever having saved it
743
+ * to storage medium
744
+ * @private
745
+ */
607
746
  _doDeleteNonPersisted(entity) {
608
747
  this.entities = _.filter(this.entities, (item) => {
609
- return item !== entity;
748
+ const match = item === entity;
749
+ if (match) {
750
+ entity.destroy();
751
+ }
752
+ return !match;
610
753
  });
611
754
 
612
755
  return true;
@@ -687,19 +830,19 @@ class AjaxRepository extends Repository {
687
830
  */
688
831
  _finalizeSave = (promises) => {
689
832
  return this.axios.all(promises)
690
- .then(this.axios.spread((...batchOperationResults) => {
691
- // All requests are now complete
692
-
693
- this.isSaving = false;
694
- this.emit('save', batchOperationResults);
695
-
696
- // Do we need to reload?
697
- if (this._operations.add || this._operations.delete) {
698
- this.reload();
699
- } else {
700
- this.emit('changeData', this.entities);
701
- }
702
- }));
833
+ .then(this.axios.spread((...batchOperationResults) => {
834
+ // All requests are now complete
835
+
836
+ this.isSaving = false;
837
+ this.emit('save', batchOperationResults);
838
+
839
+ // Do we need to reload?
840
+ if (this._operations.add || this._operations.delete) {
841
+ this.reload();
842
+ } else {
843
+ this.emit('changeData', this.entities);
844
+ }
845
+ }));
703
846
  }
704
847
 
705
848
  }
@@ -35,10 +35,13 @@ class OneBuildRepository extends AjaxRepository {
35
35
  autoSave: true,
36
36
 
37
37
  api: {
38
- add: this.name + '/extAdd',
39
38
  get: this.name + '/get',
40
- edit: this.name + '/extEdit',
41
- delete: this.name + '/extDelete',
39
+ add: this.name + '/add',
40
+ edit: this.name + '/edit',
41
+ delete: this.name + '/delete',
42
+ batchAdd: this.name + '/batchAdd',
43
+ batchEdit: this.name + '/batchEdit',
44
+ batchDelete: this.name + '/batchDelete',
42
45
  },
43
46
 
44
47
  methods: {
@@ -51,6 +54,8 @@ class OneBuildRepository extends AjaxRepository {
51
54
  messageProperty: 'message',
52
55
 
53
56
  allowsMultiSort: true,
57
+ // batchAsSynchronous: true, // Add directly to schema for now
58
+ // combineBatch: true,
54
59
 
55
60
  // writer: {
56
61
  // type: 'json',
@@ -1243,23 +1243,26 @@ export default class Repository extends EventEmitter {
1243
1243
 
1244
1244
  const batchOrder = this.batchOrder.split(',');
1245
1245
 
1246
- let n;
1246
+ let n,
1247
+ i,
1248
+ entity,
1249
+ entities,
1250
+ operation,
1251
+ result;
1247
1252
  for (n = 0; n < batchOrder.length; n++) {
1248
- const operation = batchOrder[n];
1249
- let entities;
1253
+ operation = batchOrder[n];
1250
1254
  switch(operation) {
1251
1255
  case 'add':
1252
1256
  entities = this.getNonPersisted();
1253
1257
  if (this.combineBatch) {
1254
1258
 
1255
- // TODO: Implement combined batch processing
1256
- throw new Error('Combined batch processing not yet implemented');
1257
-
1259
+ result = this.batchAsSynchronous ? await this._doBatchAdd(entities) : this._doBatchAdd(entities);
1260
+ results.push(result);
1261
+
1258
1262
  } else {
1259
1263
  if (_.size(entities) > 0) {
1260
- let i;
1261
1264
  for (i = 0; i < entities.length; i++) {
1262
- const entity = entities[i];
1265
+ entity = entities[i];
1263
1266
 
1264
1267
  if (entity.isDeleted) {
1265
1268
  // This entity is new, but it's also marked for deletion
@@ -1267,7 +1270,7 @@ export default class Repository extends EventEmitter {
1267
1270
  continue;
1268
1271
  }
1269
1272
 
1270
- const result = this.batchAsSynchronous ? await this._doAdd(entity) : this._doAdd(entity);
1273
+ result = this.batchAsSynchronous ? await this._doAdd(entity) : this._doAdd(entity);
1271
1274
  results.push(result);
1272
1275
  }
1273
1276
  }
@@ -1279,14 +1282,13 @@ export default class Repository extends EventEmitter {
1279
1282
  entities = this.getDirty();
1280
1283
  if (this.combineBatch) {
1281
1284
 
1282
- // TODO: Implement combined batch processing
1283
- throw new Error('Combined batch processing not yet implemented');
1285
+ result = this.batchAsSynchronous ? await this._doBatchEdit(entities) : this._doBatchEdit(entities);
1286
+ results.push(result);
1284
1287
 
1285
1288
  } else {
1286
1289
  if (_.size(entities) > 0) {
1287
- let i;
1288
1290
  for (i = 0; i < entities.length; i++) {
1289
- const entity = entities[i];
1291
+ entity = entities[i];
1290
1292
 
1291
1293
  if (entity.isDeleted) {
1292
1294
  // This entity is new, but it's also marked for deletion
@@ -1294,7 +1296,7 @@ export default class Repository extends EventEmitter {
1294
1296
  continue;
1295
1297
  }
1296
1298
 
1297
- const result = this.batchAsSynchronous ? await this._doEdit(entity) : this._doEdit(entity);
1299
+ result = this.batchAsSynchronous ? await this._doEdit(entity) : this._doEdit(entity);
1298
1300
  results.push(result);
1299
1301
  }
1300
1302
  }
@@ -1304,16 +1306,14 @@ export default class Repository extends EventEmitter {
1304
1306
  entities = this.getDeleted();
1305
1307
  if (this.combineBatch) {
1306
1308
 
1307
- // TODO: Implement combined batch processing
1308
- throw new Error('Combined batch processing not yet implemented');
1309
+ result = this.batchAsSynchronous ? await this._doBatchDelete(entities) : this._doBatchDelete(entities);
1310
+ results.push(result);
1309
1311
 
1310
1312
  } else {
1311
1313
  if (_.size(entities) > 0) {
1312
- let i;
1313
1314
  for (i = 0; i < entities.length; i++) {
1314
- const entity = entities[i];
1315
+ entity = entities[i];
1315
1316
 
1316
- let result;
1317
1317
  if (!entity.isPersisted) {
1318
1318
  result = this.batchAsSynchronous ? await this._doDeleteNonPersisted(entity) : this._doDeleteNonPersisted(entity);
1319
1319
  } else {
@@ -1331,8 +1331,20 @@ export default class Repository extends EventEmitter {
1331
1331
  return await this._finalizeSave(results);
1332
1332
  }
1333
1333
 
1334
+
1335
+ /**
1336
+ * Helper for save.
1337
+ * Add multiple entities to storage medium
1338
+ * @param {array} entities - Entities
1339
+ * @private
1340
+ * @abstract
1341
+ */
1342
+ _doBatchAdd(entities) { // standard function notation
1343
+ throw new Error('_doBatchAdd must be implemented by Repository subclass');
1344
+ }
1345
+
1334
1346
  /**
1335
- * Helper for save().
1347
+ * Helper for save.
1336
1348
  * Add entity to storage medium
1337
1349
  * @param {object} entity - Entity
1338
1350
  * @private
@@ -1343,7 +1355,18 @@ export default class Repository extends EventEmitter {
1343
1355
  }
1344
1356
 
1345
1357
  /**
1346
- * Helper for save().
1358
+ * Helper for save.
1359
+ * Edit multiple entities in storage medium
1360
+ * @param {array} entities - Entities
1361
+ * @private
1362
+ * @abstract
1363
+ */
1364
+ _doBatchEdit(entities) { // standard function notation
1365
+ throw new Error('_doBatchEdit must be implemented by Repository subclass');
1366
+ }
1367
+
1368
+ /**
1369
+ * Helper for save.
1347
1370
  * Mark entity as saved
1348
1371
  * @param {object} entity - Entity
1349
1372
  * @private
@@ -1354,7 +1377,18 @@ export default class Repository extends EventEmitter {
1354
1377
  }
1355
1378
 
1356
1379
  /**
1357
- * Helper for save().
1380
+ * Helper for save.
1381
+ * Delete multiple entities from storage medium
1382
+ * @param {array} entities - Entities
1383
+ * @private
1384
+ * @abstract
1385
+ */
1386
+ _doBatchDelete(entities) { // standard function notation
1387
+ throw new Error('_doBatchDelete must be implemented by Repository subclass');
1388
+ }
1389
+
1390
+ /**
1391
+ * Helper for save.
1358
1392
  * Delete entity from storage medium
1359
1393
  * @param {object} entity - Entity
1360
1394
  * @private
@@ -1365,8 +1399,8 @@ export default class Repository extends EventEmitter {
1365
1399
  }
1366
1400
 
1367
1401
  /**
1368
- * Helper for save().
1369
- * Tells storage medium to delete entity without ever having saved it
1402
+ * Helper for save.
1403
+ * Tells repository to delete entity without ever having saved it
1370
1404
  * to storage medium
1371
1405
  * @private
1372
1406
  */