@onehat/data 1.6.12 → 1.7.2

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.12",
3
+ "version": "1.7.2",
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
  },
@@ -377,6 +380,12 @@ class AjaxRepository extends Repository {
377
380
  if (this.debugMode) {
378
381
  console.log('load result ' + this.name, result);
379
382
  }
383
+
384
+ if (this.isDestroyed) {
385
+ // If this repository gets destroyed before it has a chance
386
+ // to process the Ajax request, just ignore the response.
387
+ return;
388
+ }
380
389
 
381
390
  const {
382
391
  root,
@@ -492,7 +501,7 @@ class AjaxRepository extends Repository {
492
501
  * @returns {promise} - Axios Promise.
493
502
  * @private
494
503
  */
495
- _doAdd(entity) {
504
+ _doAdd(entity) { // standard function notation
496
505
  if (!this.api.add) {
497
506
  throw new Error('No "add" api endpoint defined.');
498
507
  }
@@ -522,13 +531,57 @@ class AjaxRepository extends Repository {
522
531
  entity.loadOriginalData(root[0]);
523
532
  });
524
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 = {
552
+ entities: _.map(entities, entity => entity.submitValues),
553
+ };
554
+
555
+ return this._send(method, url, data)
556
+ .then(result => {
557
+ if (this.debugMode) {
558
+ console.log(this.api.batchAdd + ' result', result);
559
+ }
560
+ const {
561
+ root,
562
+ success,
563
+ total,
564
+ message
565
+ } = this._processServerResponse(result);
566
+
567
+ if (!success) {
568
+ throw new Error(message);
569
+ }
570
+
571
+ // Reload each entity with new data
572
+ // TODO: Check this
573
+ _.each(entities, (entity, ix) => {
574
+ entity.loadOriginalData(root[ix]);
575
+ });
576
+ });
577
+ }
525
578
 
526
579
  /**
527
580
  * Helper for save.
528
581
  * @returns {promise} - Axios Promise.
529
582
  * @private
530
583
  */
531
- _doEdit(entity) {
584
+ _doEdit(entity) { // standard function notation
532
585
  if (!this.api.edit) {
533
586
  throw new Error('No "edit" api endpoint defined.');
534
587
  }
@@ -559,12 +612,56 @@ class AjaxRepository extends Repository {
559
612
  });
560
613
  }
561
614
 
615
+ /**
616
+ * Helper for save.
617
+ * Edit multiple entities in storage medium
618
+ * @param {array} entities - Entities
619
+ * @returns {promise} - Axios Promise.
620
+ * @private
621
+ */
622
+ _doBatchEdit(entities) { // standard function notation
623
+ if (!this.api.batchEdit) {
624
+ throw new Error('No "batchEdit" api endpoint defined.');
625
+ }
626
+
627
+ this._operations.edit = true;
628
+
629
+ const method = this.methods.edit,
630
+ url = this.api.batchEdit,
631
+ data = {
632
+ entities: _.map(entities, entity => entity.submitValues),
633
+ };
634
+
635
+ return this._send(method, url, data)
636
+ .then(result => {
637
+ if (this.debugMode) {
638
+ console.log(this.api.batchEdit + ' result', result);
639
+ }
640
+ const {
641
+ root,
642
+ success,
643
+ total,
644
+ message
645
+ } = this._processServerResponse(result);
646
+
647
+ if (!success) {
648
+ throw new Error(message);
649
+ }
650
+
651
+ // Reload each entity with new data
652
+ // TODO: Check this
653
+ _.each(entities, (entity, ix) => {
654
+ entity.loadOriginalData(root[ix]);
655
+ });
656
+ });
657
+ }
658
+
562
659
  /**
563
660
  * Helper for save.
564
661
  * @returns {promise} - Axios Promise.
565
662
  * @private
566
663
  */
567
- _doDelete(entity) {
664
+ _doDelete(entity) { // standard function notation
568
665
  if (!this.api.delete) {
569
666
  throw new Error('No "delete" api endpoint defined.');
570
667
  }
@@ -598,9 +695,65 @@ class AjaxRepository extends Repository {
598
695
  });
599
696
  }
600
697
 
698
+ /**
699
+ * Helper for save.
700
+ * Delete multiple entities from storage medium
701
+ * @param {array} entities - Entities
702
+ * @returns {promise} - Axios Promise.
703
+ * @private
704
+ */
705
+ _doBatchDelete(entities) { // standard function notation
706
+ if (!this.api.batchDelete) {
707
+ throw new Error('No "batchDelete" api endpoint defined.');
708
+ }
709
+
710
+ this._operations.delete = true;
711
+
712
+ const method = this.methods.delete,
713
+ url = this.api.batchDelete,
714
+ ids = _.map(entities, entity => entity.id),
715
+ data = { ids, };
716
+
717
+ return this._send(method, url, data)
718
+ .then(result => {
719
+ if (this.debugMode) {
720
+ console.log(this.api.batchDelete + ' result', result);
721
+ }
722
+ const {
723
+ root,
724
+ success,
725
+ total,
726
+ message
727
+ } = this._processServerResponse(result);
728
+
729
+ if (!success) {
730
+ throw new Error(message);
731
+ }
732
+
733
+ // Delete it from this.entities
734
+ this.entities = _.filter(this.entities, (entity) => {
735
+ const deleteIt = ids.includes(entity.id);
736
+ if (deleteIt) {
737
+ entity.destroy();
738
+ }
739
+ return !deleteIt;
740
+ });
741
+ });
742
+ }
743
+
744
+ /**
745
+ * Helper for save.
746
+ * Tells repository to delete entity without ever having saved it
747
+ * to storage medium
748
+ * @private
749
+ */
601
750
  _doDeleteNonPersisted(entity) {
602
751
  this.entities = _.filter(this.entities, (item) => {
603
- return item !== entity;
752
+ const match = item === entity;
753
+ if (match) {
754
+ entity.destroy();
755
+ }
756
+ return !match;
604
757
  });
605
758
 
606
759
  return true;
@@ -681,19 +834,19 @@ class AjaxRepository extends Repository {
681
834
  */
682
835
  _finalizeSave = (promises) => {
683
836
  return this.axios.all(promises)
684
- .then(this.axios.spread((...batchOperationResults) => {
685
- // All requests are now complete
686
-
687
- this.isSaving = false;
688
- this.emit('save', batchOperationResults);
689
-
690
- // Do we need to reload?
691
- if (this._operations.add || this._operations.delete) {
692
- this.reload();
693
- } else {
694
- this.emit('changeData', this.entities);
695
- }
696
- }));
837
+ .then(this.axios.spread((...batchOperationResults) => {
838
+ // All requests are now complete
839
+
840
+ this.isSaving = false;
841
+ this.emit('save', batchOperationResults);
842
+
843
+ // Do we need to reload?
844
+ if (this._operations.add || this._operations.delete) {
845
+ this.reload();
846
+ } else {
847
+ this.emit('changeData', this.entities);
848
+ }
849
+ }));
697
850
  }
698
851
 
699
852
  }
@@ -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
- if (this.combineBatch) {
1257
+ if (_.size(entities) > 0) {
1258
+ if (this.combineBatch) {
1254
1259
 
1255
- // TODO: Implement combined batch processing
1256
- throw new Error('Combined batch processing not yet implemented');
1257
-
1258
- } else {
1259
- if (_.size(entities) > 0) {
1260
- let i;
1260
+ result = this.batchAsSynchronous ? await this._doBatchAdd(entities) : this._doBatchAdd(entities);
1261
+ results.push(result);
1262
+
1263
+ } else {
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,26 +1270,23 @@ 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
  }
1274
1277
  }
1275
-
1276
-
1277
1278
  break;
1278
1279
  case 'edit':
1279
1280
  entities = this.getDirty();
1280
- if (this.combineBatch) {
1281
+ if (_.size(entities) > 0) {
1282
+ if (this.combineBatch) {
1281
1283
 
1282
- // TODO: Implement combined batch processing
1283
- throw new Error('Combined batch processing not yet implemented');
1284
+ result = this.batchAsSynchronous ? await this._doBatchEdit(entities) : this._doBatchEdit(entities);
1285
+ results.push(result);
1284
1286
 
1285
- } else {
1286
- if (_.size(entities) > 0) {
1287
- let i;
1287
+ } else {
1288
1288
  for (i = 0; i < entities.length; i++) {
1289
- const entity = entities[i];
1289
+ entity = entities[i];
1290
1290
 
1291
1291
  if (entity.isDeleted) {
1292
1292
  // This entity is new, but it's also marked for deletion
@@ -1294,7 +1294,7 @@ export default class Repository extends EventEmitter {
1294
1294
  continue;
1295
1295
  }
1296
1296
 
1297
- const result = this.batchAsSynchronous ? await this._doEdit(entity) : this._doEdit(entity);
1297
+ result = this.batchAsSynchronous ? await this._doEdit(entity) : this._doEdit(entity);
1298
1298
  results.push(result);
1299
1299
  }
1300
1300
  }
@@ -1302,18 +1302,16 @@ export default class Repository extends EventEmitter {
1302
1302
  break;
1303
1303
  case 'delete':
1304
1304
  entities = this.getDeleted();
1305
- if (this.combineBatch) {
1305
+ if (_.size(entities) > 0) {
1306
+ if (this.combineBatch) {
1306
1307
 
1307
- // TODO: Implement combined batch processing
1308
- throw new Error('Combined batch processing not yet implemented');
1308
+ result = this.batchAsSynchronous ? await this._doBatchDelete(entities) : this._doBatchDelete(entities);
1309
+ results.push(result);
1309
1310
 
1310
- } else {
1311
- if (_.size(entities) > 0) {
1312
- let i;
1311
+ } else {
1313
1312
  for (i = 0; i < entities.length; i++) {
1314
- const entity = entities[i];
1313
+ entity = entities[i];
1315
1314
 
1316
- let result;
1317
1315
  if (!entity.isPersisted) {
1318
1316
  result = this.batchAsSynchronous ? await this._doDeleteNonPersisted(entity) : this._doDeleteNonPersisted(entity);
1319
1317
  } else {
@@ -1331,8 +1329,20 @@ export default class Repository extends EventEmitter {
1331
1329
  return await this._finalizeSave(results);
1332
1330
  }
1333
1331
 
1332
+
1333
+ /**
1334
+ * Helper for save.
1335
+ * Add multiple entities to storage medium
1336
+ * @param {array} entities - Entities
1337
+ * @private
1338
+ * @abstract
1339
+ */
1340
+ _doBatchAdd(entities) { // standard function notation
1341
+ throw new Error('_doBatchAdd must be implemented by Repository subclass');
1342
+ }
1343
+
1334
1344
  /**
1335
- * Helper for save().
1345
+ * Helper for save.
1336
1346
  * Add entity to storage medium
1337
1347
  * @param {object} entity - Entity
1338
1348
  * @private
@@ -1343,7 +1353,18 @@ export default class Repository extends EventEmitter {
1343
1353
  }
1344
1354
 
1345
1355
  /**
1346
- * Helper for save().
1356
+ * Helper for save.
1357
+ * Edit multiple entities in storage medium
1358
+ * @param {array} entities - Entities
1359
+ * @private
1360
+ * @abstract
1361
+ */
1362
+ _doBatchEdit(entities) { // standard function notation
1363
+ throw new Error('_doBatchEdit must be implemented by Repository subclass');
1364
+ }
1365
+
1366
+ /**
1367
+ * Helper for save.
1347
1368
  * Mark entity as saved
1348
1369
  * @param {object} entity - Entity
1349
1370
  * @private
@@ -1354,7 +1375,18 @@ export default class Repository extends EventEmitter {
1354
1375
  }
1355
1376
 
1356
1377
  /**
1357
- * Helper for save().
1378
+ * Helper for save.
1379
+ * Delete multiple entities from storage medium
1380
+ * @param {array} entities - Entities
1381
+ * @private
1382
+ * @abstract
1383
+ */
1384
+ _doBatchDelete(entities) { // standard function notation
1385
+ throw new Error('_doBatchDelete must be implemented by Repository subclass');
1386
+ }
1387
+
1388
+ /**
1389
+ * Helper for save.
1358
1390
  * Delete entity from storage medium
1359
1391
  * @param {object} entity - Entity
1360
1392
  * @private
@@ -1365,8 +1397,8 @@ export default class Repository extends EventEmitter {
1365
1397
  }
1366
1398
 
1367
1399
  /**
1368
- * Helper for save().
1369
- * Tells storage medium to delete entity without ever having saved it
1400
+ * Helper for save.
1401
+ * Tells repository to delete entity without ever having saved it
1370
1402
  * to storage medium
1371
1403
  * @private
1372
1404
  */