@onehat/data 1.13.5 → 1.13.6

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.13.5",
3
+ "version": "1.13.6",
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/OneHatData.js CHANGED
@@ -114,6 +114,23 @@ export class OneHatData extends EventEmitter {
114
114
  return this;
115
115
  }
116
116
 
117
+ /**
118
+ * Sets global error handler on all Repositories.
119
+ * Chainable.
120
+ * @param {function} handler - The global error handler
121
+ * @return this
122
+ */
123
+ setGlobalErrorHandler = (handler) => {
124
+ if (this.isDestroyed) {
125
+ throw new Error('this.setGlobalErrorHandler is no longer valid. OneHatData has been destroyed.');
126
+ }
127
+ const repositories = this.getAllRepositories();
128
+ _.each(repositories, (repository) => {
129
+ repository.setErrorHandler(handler);
130
+ });
131
+ return this;
132
+ }
133
+
117
134
 
118
135
  // ______ __
119
136
  // / ____/_______ ____ _/ /____
@@ -362,10 +362,12 @@ class AjaxRepository extends Repository {
362
362
  */
363
363
  load = async (params, callback = null) => {
364
364
  if (this.isDestroyed) {
365
- throw Error('this.load is no longer valid. Repository has been destroyed.');
365
+ this.throwError('this.load is no longer valid. Repository has been destroyed.');
366
+ return;
366
367
  }
367
368
  if (!this.api.get) {
368
- throw new Error('No "get" api endpoint defined.');
369
+ this.throwError('No "get" api endpoint defined.');
370
+ return;
369
371
  }
370
372
  this.emit('beforeLoad'); // TODO: canceling beforeLoad will cancel the load operation
371
373
  this.markLoading();
@@ -433,10 +435,12 @@ class AjaxRepository extends Repository {
433
435
  */
434
436
  reloadEntity = async (entity, callback = null) => {
435
437
  if (this.isDestroyed) {
436
- throw Error('this.reloadEntity is no longer valid. Repository has been destroyed.');
438
+ this.throwError('this.reloadEntity is no longer valid. Repository has been destroyed.');
439
+ return;
437
440
  }
438
441
  if (!this.api.get) {
439
- throw new Error('No "get" api endpoint defined.');
442
+ this.throwError('No "get" api endpoint defined.');
443
+ return;
440
444
  }
441
445
  this.emit('beforeLoad'); // TODO: canceling beforeLoad will cancel the load operation
442
446
  this.markLoading();
@@ -460,7 +464,8 @@ class AjaxRepository extends Repository {
460
464
  } = this._processServerResponse(result);
461
465
 
462
466
  if (!success) {
463
- throw Error(message);
467
+ this.throwError(message);
468
+ return;
464
469
  }
465
470
 
466
471
  const updatedData = root[0];
@@ -515,7 +520,8 @@ class AjaxRepository extends Repository {
515
520
  */
516
521
  _doAdd(entity) { // standard function notation
517
522
  if (!this.api.add) {
518
- throw new Error('No "add" api endpoint defined.');
523
+ this.throwError('No "add" api endpoint defined.');
524
+ return;
519
525
  }
520
526
 
521
527
  this._operations.add = true;
@@ -537,7 +543,8 @@ class AjaxRepository extends Repository {
537
543
  } = this._processServerResponse(result);
538
544
 
539
545
  if (!success) {
540
- throw new Error(message);
546
+ this.throwError(message);
547
+ return;
541
548
  }
542
549
 
543
550
  entity.loadOriginalData(root[0]);
@@ -553,7 +560,8 @@ class AjaxRepository extends Repository {
553
560
  */
554
561
  _doBatchAdd(entities) { // standard function notation
555
562
  if (!this.api.batchAdd) {
556
- throw new Error('No "batchAdd" api endpoint defined.');
563
+ this.throwError('No "batchAdd" api endpoint defined.');
564
+ return;
557
565
  }
558
566
 
559
567
  this._operations.add = true;
@@ -577,7 +585,8 @@ class AjaxRepository extends Repository {
577
585
  } = this._processServerResponse(result);
578
586
 
579
587
  if (!success) {
580
- throw new Error(message);
588
+ this.throwError(message);
589
+ return;
581
590
  }
582
591
 
583
592
  // Reload each entity with new data
@@ -595,7 +604,8 @@ class AjaxRepository extends Repository {
595
604
  */
596
605
  _doEdit(entity) { // standard function notation
597
606
  if (!this.api.edit) {
598
- throw new Error('No "edit" api endpoint defined.');
607
+ this.throwError('No "edit" api endpoint defined.');
608
+ return;
599
609
  }
600
610
 
601
611
  this._operations.edit = true;
@@ -617,7 +627,8 @@ class AjaxRepository extends Repository {
617
627
  } = this._processServerResponse(result);
618
628
 
619
629
  if (!success) {
620
- throw new Error(message);
630
+ this.throwError(message);
631
+ return;
621
632
  }
622
633
 
623
634
  entity.loadOriginalData(root[0]);
@@ -633,7 +644,8 @@ class AjaxRepository extends Repository {
633
644
  */
634
645
  _doBatchEdit(entities) { // standard function notation
635
646
  if (!this.api.batchEdit) {
636
- throw new Error('No "batchEdit" api endpoint defined.');
647
+ this.throwError('No "batchEdit" api endpoint defined.');
648
+ return;
637
649
  }
638
650
 
639
651
  this._operations.edit = true;
@@ -657,7 +669,8 @@ class AjaxRepository extends Repository {
657
669
  } = this._processServerResponse(result);
658
670
 
659
671
  if (!success) {
660
- throw new Error(message);
672
+ this.throwError(message);
673
+ return;
661
674
  }
662
675
 
663
676
  // Reload each entity with new data
@@ -675,7 +688,8 @@ class AjaxRepository extends Repository {
675
688
  */
676
689
  _doDelete(entity) { // standard function notation
677
690
  if (!this.api.delete) {
678
- throw new Error('No "delete" api endpoint defined.');
691
+ this.throwError('No "delete" api endpoint defined.');
692
+ return;
679
693
  }
680
694
 
681
695
  this._operations.delete = true;
@@ -697,7 +711,8 @@ class AjaxRepository extends Repository {
697
711
  } = this._processServerResponse(result);
698
712
 
699
713
  if (!success) {
700
- throw new Error(message);
714
+ this.throwError(message);
715
+ return;
701
716
  }
702
717
 
703
718
  // Delete it from this.entities
@@ -716,7 +731,8 @@ class AjaxRepository extends Repository {
716
731
  */
717
732
  _doBatchDelete(entities) { // standard function notation
718
733
  if (!this.api.batchDelete) {
719
- throw new Error('No "batchDelete" api endpoint defined.');
734
+ this.throwError('No "batchDelete" api endpoint defined.');
735
+ return;
720
736
  }
721
737
 
722
738
  this._operations.delete = true;
@@ -739,7 +755,8 @@ class AjaxRepository extends Repository {
739
755
  } = this._processServerResponse(result);
740
756
 
741
757
  if (!success) {
742
- throw new Error(message);
758
+ this.throwError(message);
759
+ return;
743
760
  }
744
761
 
745
762
  // Delete it from this.entities
@@ -779,7 +796,8 @@ class AjaxRepository extends Repository {
779
796
  _send = (method, url, data) => {
780
797
 
781
798
  if (!url) {
782
- throw new Error('No url submitted');
799
+ this.throwError('No url submitted');
800
+ return;
783
801
  }
784
802
 
785
803
  const options = {
@@ -68,16 +68,20 @@ class LocalFromRemoteRepository extends EventEmitter {
68
68
  super(...arguments);
69
69
 
70
70
  if (!config.local || !(config.local instanceof Repository)) {
71
- throw new Error('No local repository defined.');
71
+ this.throwError('No local repository defined.');
72
+ return;
72
73
  }
73
74
  if (!config.local.isLocal) {
74
- throw new Error('Local repository is not configured to be a local type.');
75
+ this.throwError('Local repository is not configured to be a local type.');
76
+ return;
75
77
  }
76
78
  if (!config.remote || !(config.remote instanceof Repository)) {
77
- throw new Error('No remote repository defined.');
79
+ this.throwError('No remote repository defined.');
80
+ return;
78
81
  }
79
82
  if (!config.remote.isRemote) {
80
- throw new Error('Remote repository is not configured to be a remote type.');
83
+ this.throwError('Remote repository is not configured to be a remote type.');
84
+ return;
81
85
  }
82
86
 
83
87
  const defaults = {
@@ -139,7 +143,8 @@ class LocalFromRemoteRepository extends EventEmitter {
139
143
  if (this.mode !== MODE_LOCAL_MIRROR &&
140
144
  this.mode !== MODE_REMOTE_WITH_OFFLINE &&
141
145
  this.mode !== MODE_COMMAND_QUEUE) {
142
- throw new Error('Mode not recognized.');
146
+ this.throwError('Mode not recognized.');
147
+ return;
143
148
  }
144
149
 
145
150
  this.registerEvents([
@@ -326,10 +331,12 @@ class LocalFromRemoteRepository extends EventEmitter {
326
331
  let command = this.commands[localItem.command];
327
332
 
328
333
  if (!command) {
329
- throw new Error('Command ' + localItem.command + ' not registered');
334
+ this.throwError('Command ' + localItem.command + ' not registered');
335
+ return;
330
336
  }
331
337
  if (!command.hasHandlers()) {
332
- throw new Error('No command handler registered for ' + localItem.command);
338
+ this.throwError('No command handler registered for ' + localItem.command);
339
+ return;
333
340
  }
334
341
 
335
342
  // local --> remote
@@ -365,7 +372,8 @@ class LocalFromRemoteRepository extends EventEmitter {
365
372
 
366
373
  case MODE_REMOTE_WITH_OFFLINE:
367
374
 
368
- throw new Error('Not implemented');
375
+ this.throwError('Not implemented');
376
+ return;
369
377
 
370
378
  // Load remote data into local
371
379
  // Local <-- Remote
@@ -92,7 +92,8 @@ class MemoryRepository extends Repository {
92
92
  load = async (data = null) => {
93
93
 
94
94
  if (this.isDestroyed) {
95
- throw Error('this.load is no longer valid. Repository has been destroyed.');
95
+ this.throwError('this.load is no longer valid. Repository has been destroyed.');
96
+ return;
96
97
  }
97
98
 
98
99
  this.emit('beforeLoad');
@@ -200,7 +201,8 @@ class MemoryRepository extends Repository {
200
201
  */
201
202
  _applySorters = () => {
202
203
  if (this.isDestroyed) {
203
- throw Error('this._applySorters is no longer valid. Repository has been destroyed.');
204
+ this.throwError('this._applySorters is no longer valid. Repository has been destroyed.');
205
+ return;
204
206
  }
205
207
  if (!this.hasSorters) {
206
208
  this.isSorted = false;
@@ -309,7 +311,8 @@ class MemoryRepository extends Repository {
309
311
  */
310
312
  _applyFilters = () => {
311
313
  if (this.isDestroyed) {
312
- throw Error('this._applyFilters is no longer valid. Repository has been destroyed.');
314
+ this.throwError('this._applyFilters is no longer valid. Repository has been destroyed.');
315
+ return;
313
316
  }
314
317
  if (!this.hasFilters) {
315
318
  this._filteredEntities = [];
@@ -358,7 +361,8 @@ class MemoryRepository extends Repository {
358
361
  */
359
362
  _doAdd(entity) { // standard function notation
360
363
  if (this.isDestroyed) {
361
- throw Error('this._doAdd is no longer valid. Repository has been destroyed.');
364
+ this.throwError('this._doAdd is no longer valid. Repository has been destroyed.');
365
+ return;
362
366
  }
363
367
 
364
368
  // Give it a non-temporary ID, if needed
@@ -407,7 +411,8 @@ class MemoryRepository extends Repository {
407
411
  */
408
412
  _doEdit(entity) { // standard function notation
409
413
  if (this.isDestroyed) {
410
- throw Error('this._doEdit is no longer valid. Repository has been destroyed.');
414
+ this.throwError('this._doEdit is no longer valid. Repository has been destroyed.');
415
+ return;
411
416
  }
412
417
 
413
418
  entity.markSaved();
@@ -422,7 +427,8 @@ class MemoryRepository extends Repository {
422
427
  */
423
428
  _doDelete(entity) { // standard function notation
424
429
  if (this.isDestroyed) {
425
- throw Error('this._doDelete is no longer valid. Repository has been destroyed.');
430
+ this.throwError('this._doDelete is no longer valid. Repository has been destroyed.');
431
+ return;
426
432
  }
427
433
  delete this._keyedEntities[entity.id];
428
434
  this.entities = _.filter(this.entities, (x) => x.id !== entity.id);
@@ -445,7 +451,8 @@ class MemoryRepository extends Repository {
445
451
  */
446
452
  getById = (id) => {
447
453
  if (this.isDestroyed) {
448
- throw Error('this.getById is no longer valid. Repository has been destroyed.');
454
+ this.throwError('this.getById is no longer valid. Repository has been destroyed.');
455
+ return;
449
456
  }
450
457
  return this._keyedEntities[id] ? this._keyedEntities[id] : null;
451
458
  }
@@ -458,7 +465,8 @@ class MemoryRepository extends Repository {
458
465
  */
459
466
  getIxById = (id) => {
460
467
  if (this.isDestroyed) {
461
- throw Error('this.getIxById is no longer valid. Repository has been destroyed.');
468
+ this.throwError('this.getIxById is no longer valid. Repository has been destroyed.');
469
+ return;
462
470
  }
463
471
 
464
472
  const ix = this.getEntitiesOnPage().findIndex((entity) => entity.id === id);
@@ -475,7 +483,8 @@ class MemoryRepository extends Repository {
475
483
  */
476
484
  getEntities = () => {
477
485
  if (this.isDestroyed) {
478
- throw Error('this.getEntities is no longer valid. Repository has been destroyed.');
486
+ this.throwError('this.getEntities is no longer valid. Repository has been destroyed.');
487
+ return;
479
488
  }
480
489
  return this._getActiveEntities();
481
490
  }
@@ -487,7 +496,8 @@ class MemoryRepository extends Repository {
487
496
  * /
488
497
  getAllData = () => {
489
498
  if (this.isDestroyed) {
490
- throw Error('this.getAllData is no longer valid. Repository has been destroyed.');
499
+ this.throwError('this.getAllData is no longer valid. Repository has been destroyed.');
500
+ return;
491
501
  }
492
502
  const entities = this._getActiveEntities();
493
503
  return _.map(entities, (entity) => {
@@ -528,7 +538,8 @@ class MemoryRepository extends Repository {
528
538
  */
529
539
  _paginate = (entities) => {
530
540
  if (this.isDestroyed) {
531
- throw Error('this._paginate is no longer valid. Repository has been destroyed.');
541
+ this.throwError('this._paginate is no longer valid. Repository has been destroyed.');
542
+ return;
532
543
  }
533
544
  if (!this.isPaginated) {
534
545
  return entities;
@@ -552,7 +563,8 @@ class MemoryRepository extends Repository {
552
563
  */
553
564
  _recalculate = () => {
554
565
  if (this.isDestroyed) {
555
- throw Error('this._recalculate is no longer valid. Repository has been destroyed.');
566
+ this.throwError('this._recalculate is no longer valid. Repository has been destroyed.');
567
+ return;
556
568
  }
557
569
  this._unsortedEntities = _.map(this._keyedEntities, item => item);
558
570
  this._sortedEntities = null;
@@ -589,7 +601,8 @@ class MemoryRepository extends Repository {
589
601
  */
590
602
  getGrandTotal = () => {
591
603
  if (this.isDestroyed) {
592
- throw Error('this.getGrandTotal is no longer valid. Repository has been destroyed.');
604
+ this.throwError('this.getGrandTotal is no longer valid. Repository has been destroyed.');
605
+ return;
593
606
  }
594
607
  return _.size(this._unsortedEntities);
595
608
  }
@@ -603,7 +616,8 @@ class MemoryRepository extends Repository {
603
616
  */
604
617
  _getActiveEntities = () => {
605
618
  if (this.isDestroyed) {
606
- throw Error('this._getActiveEntities is no longer valid. Repository has been destroyed.');
619
+ this.throwError('this._getActiveEntities is no longer valid. Repository has been destroyed.');
620
+ return;
607
621
  }
608
622
  if (this.hasFilters) {
609
623
  return this._filteredEntities;
@@ -43,7 +43,8 @@ class NullRepository extends Repository {
43
43
  */
44
44
  load = (data = this.data) => {
45
45
  if (this.isDestroyed) {
46
- throw Error('this.load is no longer valid. Repository has been destroyed.');
46
+ this.throwError('this.load is no longer valid. Repository has been destroyed.');
47
+ return;
47
48
  }
48
49
  this.emit('beforeLoad');
49
50
  this.markLoading();
@@ -96,7 +97,8 @@ class NullRepository extends Repository {
96
97
  */
97
98
  _doEdit(entity) { // standard function notation
98
99
  if (this.isDestroyed) {
99
- throw Error('this._doEdit is no longer valid. Repository has been destroyed.');
100
+ this.throwError('this._doEdit is no longer valid. Repository has been destroyed.');
101
+ return;
100
102
  }
101
103
  entity.markSaved();
102
104
  return {
@@ -303,7 +303,8 @@ class OfflineRepository extends MemoryRepository {
303
303
  */
304
304
  _getKeys = async () => {
305
305
  if (!this._getAllKeys) {
306
- throw new Error('Storage medium does not support _getAllKeys');
306
+ this.throwError('Storage medium does not support _getAllKeys');
307
+ return;
307
308
  }
308
309
  const re = new RegExp('^' + this.name + '-');
309
310
  let keys = await this._getAllKeys();
@@ -334,7 +335,8 @@ class OfflineRepository extends MemoryRepository {
334
335
  * @abstract
335
336
  */
336
337
  _storageGetValue = async (name) => {
337
- throw new Error('this._storageGetValue must be implemented by OfflineRepository subclass.');
338
+ this.throwError('this._storageGetValue must be implemented by OfflineRepository subclass.');
339
+ return;
338
340
  }
339
341
 
340
342
  /**
@@ -345,7 +347,8 @@ class OfflineRepository extends MemoryRepository {
345
347
  * @abstract
346
348
  */
347
349
  _storageSetValue = async (name, value) => {
348
- throw new Error('this._storageSetValue must be implemented by OfflineRepository subclass.');
350
+ this.throwError('this._storageSetValue must be implemented by OfflineRepository subclass.');
351
+ return;
349
352
  }
350
353
 
351
354
  /**
@@ -355,7 +358,8 @@ class OfflineRepository extends MemoryRepository {
355
358
  * @abstract
356
359
  */
357
360
  _storageDeleteValue = async (name) => {
358
- throw new Error('this._storageDeleteValue must be implemented by OfflineRepository subclass.');
361
+ this.throwError('this._storageDeleteValue must be implemented by OfflineRepository subclass.');
362
+ return;
359
363
  }
360
364
 
361
365
  /**
@@ -95,7 +95,8 @@ class OneBuildRepository extends AjaxRepository {
95
95
  _send = (method, url, data) => {
96
96
 
97
97
  if (!url) {
98
- throw new Error('No url submitted');
98
+ this.throwError('No url submitted');
99
+ return;
99
100
  }
100
101
 
101
102
  const options = {
@@ -264,7 +265,8 @@ class OneBuildRepository extends AjaxRepository {
264
265
 
265
266
  const response = result.data;
266
267
  if (!response.success) {
267
- throw new Error(response.data);
268
+ this.throwError(response.data);
269
+ return;
268
270
  }
269
271
 
270
272
  // Reload the repository, so updated sort_order values can be retrieved
@@ -301,7 +303,8 @@ class OneBuildRepository extends AjaxRepository {
301
303
 
302
304
  const response = result.data;
303
305
  if (!response.success) {
304
- throw new Error(response.data); // TODO: Fix back-end, so OneBuild submits the error message on response.message, not response.data
306
+ this.throwError(response.data); // TODO: Fix back-end, so OneBuild submits the error message on response.message, not response.data
307
+ return;
305
308
  }
306
309
 
307
310
  const userData = response.data;
@@ -330,7 +333,8 @@ class OneBuildRepository extends AjaxRepository {
330
333
  }
331
334
  const response = result.data;
332
335
  if (!response.success) {
333
- throw new Error(response.data);
336
+ this.throwError(response.data);
337
+ return;
334
338
  }
335
339
  return true;
336
340
  });
@@ -359,7 +363,8 @@ class OneBuildRepository extends AjaxRepository {
359
363
 
360
364
  const response = result.data;
361
365
  if (!response.success) {
362
- throw new Error(response.data);
366
+ this.throwError(response.data);
367
+ return;
363
368
  }
364
369
 
365
370
  return response;
@@ -31,7 +31,8 @@ export default class Repository extends EventEmitter {
31
31
  const { schema } = config;
32
32
 
33
33
  if (!schema || !schema.model) {
34
- throw new Error('Schema cannot be empty');
34
+ this.throwError('Schema cannot be empty');
35
+ return;
35
36
  }
36
37
 
37
38
  const defaults = {
@@ -290,7 +291,8 @@ export default class Repository extends EventEmitter {
290
291
  */
291
292
  _createMethods = () => {
292
293
  if (this.isDestroyed) {
293
- throw Error('this._createMethods is no longer valid. Repository has been destroyed.');
294
+ this.throwError('this._createMethods is no longer valid. Repository has been destroyed.');
295
+ return;
294
296
  }
295
297
  const methodDefinitions = this.schema.repository.methods || this.originalConfig.methods; // The latter is mainly for lfr repositories
296
298
  if (!_.isEmpty(methodDefinitions)) {
@@ -306,7 +308,8 @@ export default class Repository extends EventEmitter {
306
308
  */
307
309
  _createStatics = () => {
308
310
  if (this.isDestroyed) {
309
- throw Error('this._createStatics is no longer valid. Repository has been destroyed.');
311
+ this.throwError('this._createStatics is no longer valid. Repository has been destroyed.');
312
+ return;
310
313
  }
311
314
  const staticsDefinitions = this.schema.repository.statics || this.originalConfig.statics; // The latter is mainly for lfr repositories
312
315
  if (!_.isEmpty(staticsDefinitions)) {
@@ -328,7 +331,8 @@ export default class Repository extends EventEmitter {
328
331
  * @abstract
329
332
  */
330
333
  load = async () => {
331
- throw new Error('load must be implemented by Repository subclass');
334
+ this.throwError('load must be implemented by Repository subclass');
335
+ return;
332
336
  }
333
337
 
334
338
  /**
@@ -361,7 +365,8 @@ export default class Repository extends EventEmitter {
361
365
  * @abstract
362
366
  */
363
367
  reloadEntity = async (entity) => {
364
- throw new Error('reloadEntity must be implemented by Repository subclass');
368
+ this.throwError('reloadEntity must be implemented by Repository subclass');
369
+ return;
365
370
  }
366
371
 
367
372
  /**
@@ -370,7 +375,8 @@ export default class Repository extends EventEmitter {
370
375
  */
371
376
  setAutoSave = (isAutoSave) => {
372
377
  if (this.isDestroyed) {
373
- throw Error('this.setAutoSave is no longer valid. Repository has been destroyed.');
378
+ this.throwError('this.setAutoSave is no longer valid. Repository has been destroyed.');
379
+ return;
374
380
  }
375
381
  this.isAutoSave = isAutoSave
376
382
  }
@@ -381,7 +387,8 @@ export default class Repository extends EventEmitter {
381
387
  */
382
388
  setAutoLoad = (isAutoLoad) => {
383
389
  if (this.isDestroyed) {
384
- throw Error('this.setAutoLoad is no longer valid. Repository has been destroyed.');
390
+ this.throwError('this.setAutoLoad is no longer valid. Repository has been destroyed.');
391
+ return;
385
392
  }
386
393
  this.isAutoLoad = isAutoLoad
387
394
  }
@@ -398,7 +405,8 @@ export default class Repository extends EventEmitter {
398
405
  */
399
406
  get hasSorters() {
400
407
  if (this.isDestroyed) {
401
- throw Error('this.hasSorters is no longer valid. Repository has been destroyed.');
408
+ this.throwError('this.hasSorters is no longer valid. Repository has been destroyed.');
409
+ return;
402
410
  }
403
411
  return this.sorters.length > 0;
404
412
  }
@@ -408,7 +416,8 @@ export default class Repository extends EventEmitter {
408
416
  */
409
417
  clearSort = () => {
410
418
  if (this.isDestroyed) {
411
- throw Error('this.clearSort is no longer valid. Repository has been destroyed.');
419
+ this.throwError('this.clearSort is no longer valid. Repository has been destroyed.');
420
+ return;
412
421
  }
413
422
  this.setSorters([])
414
423
  }
@@ -445,7 +454,8 @@ export default class Repository extends EventEmitter {
445
454
  */
446
455
  sort = (arg1 = null, arg2 = 'ASC', arg3 = null) => {
447
456
  if (this.isDestroyed) {
448
- throw Error('this.sort is no longer valid. Repository has been destroyed.');
457
+ this.throwError('this.sort is no longer valid. Repository has been destroyed.');
458
+ return;
449
459
  }
450
460
  // Assemble sorting definition objects
451
461
  let sorters = [];
@@ -476,7 +486,8 @@ export default class Repository extends EventEmitter {
476
486
  */
477
487
  getDefaultSorters = () => {
478
488
  if (this.isDestroyed) {
479
- throw Error('this.getDefaultSorters is no longer valid. Repository has been destroyed.');
489
+ this.throwError('this.getDefaultSorters is no longer valid. Repository has been destroyed.');
490
+ return;
480
491
  }
481
492
  let sorters = [];
482
493
  if (this.schema?.model) {
@@ -505,10 +516,12 @@ export default class Repository extends EventEmitter {
505
516
  */
506
517
  setSorters = (sorters) => {
507
518
  if (this.isDestroyed) {
508
- throw Error('this.setSorters is no longer valid. Repository has been destroyed.');
519
+ this.throwError('this.setSorters is no longer valid. Repository has been destroyed.');
520
+ return;
509
521
  }
510
522
  if (!this.allowsMultiSort && sorters.length > 1) {
511
- throw Error('Cannot have more than one sorter at a time.');
523
+ this.throwError('Cannot have more than one sorter at a time.');
524
+ return;
512
525
  }
513
526
 
514
527
  let isChanged = false;
@@ -522,13 +535,15 @@ export default class Repository extends EventEmitter {
522
535
  }
523
536
  const propertyDefinition = _.find(this.schema.model.properties, (property) => property.name === sorter.name);
524
537
  if (!propertyDefinition) {
525
- throw new Error('Sorting property does not exist.');
538
+ this.throwError('Sorting property does not exist.');
539
+ return;
526
540
  }
527
541
  const propertyType = propertyDefinition.type;
528
542
  if (propertyType && PropertyTypes[propertyType]) {
529
543
  const propertyInstance = new PropertyTypes[propertyType]();
530
544
  if (!propertyInstance.isSortable) {
531
- throw new Error('Sorting property type is not sortable.');
545
+ this.throwError('Sorting property type is not sortable.');
546
+ return;
532
547
  }
533
548
  }
534
549
  });
@@ -554,7 +569,8 @@ export default class Repository extends EventEmitter {
554
569
  */
555
570
  get hasFilters() {
556
571
  if (this.isDestroyed) {
557
- throw Error('this.hasFilters is no longer valid. Repository has been destroyed.');
572
+ this.throwError('this.hasFilters is no longer valid. Repository has been destroyed.');
573
+ return;
558
574
  }
559
575
  return this.filters.length > 0;
560
576
  }
@@ -614,7 +630,8 @@ export default class Repository extends EventEmitter {
614
630
  */
615
631
  filter = (arg1 = null, arg2 = null, clearFirst = true) => {
616
632
  if (this.isDestroyed) {
617
- throw Error('this.filter is no longer valid. Repository has been destroyed.');
633
+ this.throwError('this.filter is no longer valid. Repository has been destroyed.');
634
+ return;
618
635
  }
619
636
 
620
637
  if (_.isNil(arg1)) {
@@ -719,7 +736,8 @@ export default class Repository extends EventEmitter {
719
736
  */
720
737
  _setFilters = (filters) => {
721
738
  if (this.isDestroyed) {
722
- throw Error('this._setFilters is no longer valid. Repository has been destroyed.');
739
+ this.throwError('this._setFilters is no longer valid. Repository has been destroyed.');
740
+ return;
723
741
  }
724
742
  let isChanged = false;
725
743
  if (!_.isEqual(this.filters, filters)) {
@@ -752,7 +770,8 @@ export default class Repository extends EventEmitter {
752
770
  */
753
771
  resetPagination = () => {
754
772
  if (this.isDestroyed) {
755
- throw Error('this.resetPagination is no longer valid. Repository has been destroyed.');
773
+ this.throwError('this.resetPagination is no longer valid. Repository has been destroyed.');
774
+ return;
756
775
  }
757
776
  this.setPage(1);
758
777
  }
@@ -763,7 +782,8 @@ export default class Repository extends EventEmitter {
763
782
  */
764
783
  setPageSize = (pageSize) => {
765
784
  if (this.isDestroyed) {
766
- throw Error('this.setPageSize is no longer valid. Repository has been destroyed.');
785
+ this.throwError('this.setPageSize is no longer valid. Repository has been destroyed.');
786
+ return;
767
787
  }
768
788
  if (!this.isPaginated) {
769
789
  return false;
@@ -792,7 +812,8 @@ export default class Repository extends EventEmitter {
792
812
  */
793
813
  setPage = (page) => {
794
814
  if (this.isDestroyed) {
795
- throw Error('this.setPage is no longer valid. Repository has been destroyed.');
815
+ this.throwError('this.setPage is no longer valid. Repository has been destroyed.');
816
+ return;
796
817
  }
797
818
  if (!this.isPaginated) {
798
819
  return false;
@@ -839,7 +860,8 @@ export default class Repository extends EventEmitter {
839
860
  */
840
861
  _setPaginationVars = () => {
841
862
  if (this.isDestroyed) {
842
- throw Error('this._setPaginationVars is no longer valid. Repository has been destroyed.');
863
+ this.throwError('this._setPaginationVars is no longer valid. Repository has been destroyed.');
864
+ return;
843
865
  }
844
866
  if (!this.isPaginated) {
845
867
  this.totalPages = 1;
@@ -935,7 +957,8 @@ export default class Repository extends EventEmitter {
935
957
  */
936
958
  add = async (data, isPersisted = false, originalIsMapped = false, isDelayedSave = false) => {
937
959
  if (this.isDestroyed) {
938
- throw Error('this.add is no longer valid. Repository has been destroyed.');
960
+ this.throwError('this.add is no longer valid. Repository has been destroyed.');
961
+ return;
939
962
  }
940
963
 
941
964
  // Does it already exist? If so, edit the existing
@@ -982,7 +1005,8 @@ export default class Repository extends EventEmitter {
982
1005
  */
983
1006
  createStandaloneEntity = async (data, isPersisted = false, originalIsMapped = false, isDelayedSave = false) => {
984
1007
  if (this.isDestroyed) {
985
- throw Error('this.createStandaloneEntity is no longer valid. Repository has been destroyed.');
1008
+ this.throwError('this.createStandaloneEntity is no longer valid. Repository has been destroyed.');
1009
+ return;
986
1010
  }
987
1011
 
988
1012
  const entity = Repository._createEntity(this.schema, data, this, isPersisted, originalIsMapped, isDelayedSave);
@@ -1046,7 +1070,8 @@ export default class Repository extends EventEmitter {
1046
1070
  */
1047
1071
  _relayEntityEvents = (entity) => {
1048
1072
  if (this.isDestroyed) {
1049
- throw Error('this._relayEntityEvents is no longer valid. Repository has been destroyed.');
1073
+ this.throwError('this._relayEntityEvents is no longer valid. Repository has been destroyed.');
1074
+ return;
1050
1075
  }
1051
1076
  this.relayEventsFrom(entity, [
1052
1077
  'change',
@@ -1146,7 +1171,8 @@ export default class Repository extends EventEmitter {
1146
1171
  */
1147
1172
  getByIx = (ix) => {
1148
1173
  if (this.isDestroyed) {
1149
- throw Error('this.getByIx is no longer valid. Repository has been destroyed.');
1174
+ this.throwError('this.getByIx is no longer valid. Repository has been destroyed.');
1175
+ return;
1150
1176
  }
1151
1177
  return this.entities[ix];
1152
1178
  }
@@ -1160,7 +1186,8 @@ export default class Repository extends EventEmitter {
1160
1186
  */
1161
1187
  getByRange = (startIx, endIx) => {
1162
1188
  if (this.isDestroyed) {
1163
- throw Error('this.getByRange is no longer valid. Repository has been destroyed.');
1189
+ this.throwError('this.getByRange is no longer valid. Repository has been destroyed.');
1190
+ return;
1164
1191
  }
1165
1192
  return _.slice(this.entities, startIx, endIx+1);
1166
1193
  }
@@ -1172,7 +1199,8 @@ export default class Repository extends EventEmitter {
1172
1199
  */
1173
1200
  getById = (id) => {
1174
1201
  if (this.isDestroyed) {
1175
- throw Error('this.getById is no longer valid. Repository has been destroyed.');
1202
+ this.throwError('this.getById is no longer valid. Repository has been destroyed.');
1203
+ return;
1176
1204
  }
1177
1205
  return this.getFirstBy(entity => entity.id === id);
1178
1206
  }
@@ -1184,7 +1212,8 @@ export default class Repository extends EventEmitter {
1184
1212
  */
1185
1213
  getIxById = (id) => {
1186
1214
  if (this.isDestroyed) {
1187
- throw Error('this.getIxById is no longer valid. Repository has been destroyed.');
1215
+ this.throwError('this.getIxById is no longer valid. Repository has been destroyed.');
1216
+ return;
1188
1217
  }
1189
1218
 
1190
1219
  const ix = this.entities.findIndex((entity) => entity.id === id);
@@ -1201,7 +1230,8 @@ export default class Repository extends EventEmitter {
1201
1230
  */
1202
1231
  getBy = (filter) => {
1203
1232
  if (this.isDestroyed) {
1204
- throw Error('this.getBy is no longer valid. Repository has been destroyed.');
1233
+ this.throwError('this.getBy is no longer valid. Repository has been destroyed.');
1234
+ return;
1205
1235
  }
1206
1236
  return _.filter(this.entities, filter);
1207
1237
  }
@@ -1217,7 +1247,8 @@ export default class Repository extends EventEmitter {
1217
1247
  */
1218
1248
  getFirstBy = (filter) => {
1219
1249
  if (this.isDestroyed) {
1220
- throw Error('this.getFirstBy is no longer valid. Repository has been destroyed.');
1250
+ this.throwError('this.getFirstBy is no longer valid. Repository has been destroyed.');
1251
+ return;
1221
1252
  }
1222
1253
  return _.find(this.entities, filter);
1223
1254
  }
@@ -1229,7 +1260,8 @@ export default class Repository extends EventEmitter {
1229
1260
  */
1230
1261
  getPhantom = (entities = null) => {
1231
1262
  if (this.isDestroyed) {
1232
- throw Error('this.getPhantom is no longer valid. Repository has been destroyed.');
1263
+ this.throwError('this.getPhantom is no longer valid. Repository has been destroyed.');
1264
+ return;
1233
1265
  }
1234
1266
  if (!entities) {
1235
1267
  entities = this.entities;
@@ -1244,7 +1276,8 @@ export default class Repository extends EventEmitter {
1244
1276
  */
1245
1277
  getNonPersisted = (entities = null) => {
1246
1278
  if (this.isDestroyed) {
1247
- throw Error('this.getDirty is no longer valid. Repository has been destroyed.');
1279
+ this.throwError('this.getDirty is no longer valid. Repository has been destroyed.');
1280
+ return;
1248
1281
  }
1249
1282
  if (!entities) {
1250
1283
  entities = this.entities;
@@ -1259,7 +1292,8 @@ export default class Repository extends EventEmitter {
1259
1292
  */
1260
1293
  getEntities = () => {
1261
1294
  if (this.isDestroyed) {
1262
- throw Error('this.getEntities is no longer valid. Repository has been destroyed.');
1295
+ this.throwError('this.getEntities is no longer valid. Repository has been destroyed.');
1296
+ return;
1263
1297
  }
1264
1298
  return this.entities;
1265
1299
  }
@@ -1273,7 +1307,8 @@ export default class Repository extends EventEmitter {
1273
1307
  */
1274
1308
  getEntitiesOnPage = () => {
1275
1309
  if (this.isDestroyed) {
1276
- throw Error('this.getPagedEntities is no longer valid. Repository has been destroyed.');
1310
+ this.throwError('this.getPagedEntities is no longer valid. Repository has been destroyed.');
1311
+ return;
1277
1312
  }
1278
1313
  const entities = this.getEntities();
1279
1314
  if (!this.isPaginated) {
@@ -1294,7 +1329,8 @@ export default class Repository extends EventEmitter {
1294
1329
  */
1295
1330
  getDirty = (entities = null) => {
1296
1331
  if (this.isDestroyed) {
1297
- throw Error('this.getDirty is no longer valid. Repository has been destroyed.');
1332
+ this.throwError('this.getDirty is no longer valid. Repository has been destroyed.');
1333
+ return;
1298
1334
  }
1299
1335
  if (!entities) {
1300
1336
  entities = this.entities;
@@ -1309,7 +1345,8 @@ export default class Repository extends EventEmitter {
1309
1345
  */
1310
1346
  getDeleted = (entities = null) => {
1311
1347
  if (this.isDestroyed) {
1312
- throw Error('this.getDeleted is no longer valid. Repository has been destroyed.');
1348
+ this.throwError('this.getDeleted is no longer valid. Repository has been destroyed.');
1349
+ return;
1313
1350
  }
1314
1351
  if (!entities) {
1315
1352
  entities = this.entities;
@@ -1324,7 +1361,8 @@ export default class Repository extends EventEmitter {
1324
1361
  */
1325
1362
  getStaged = (entities = null) => {
1326
1363
  if (this.isDestroyed) {
1327
- throw Error('this.getStaged is no longer valid. Repository has been destroyed.');
1364
+ this.throwError('this.getStaged is no longer valid. Repository has been destroyed.');
1365
+ return;
1328
1366
  }
1329
1367
  if (!entities) {
1330
1368
  entities = this.entities;
@@ -1338,7 +1376,8 @@ export default class Repository extends EventEmitter {
1338
1376
  */
1339
1377
  getSchema = () => {
1340
1378
  if (this.isDestroyed) {
1341
- throw Error('this.getSchema is no longer valid. Repository has been destroyed.');
1379
+ this.throwError('this.getSchema is no longer valid. Repository has been destroyed.');
1380
+ return;
1342
1381
  }
1343
1382
  return this.schema;
1344
1383
  }
@@ -1349,7 +1388,8 @@ export default class Repository extends EventEmitter {
1349
1388
  */
1350
1389
  getSortField = () => {
1351
1390
  if (this.isDestroyed) {
1352
- throw Error('this.getSortField is no longer valid. Repository has been destroyed.');
1391
+ this.throwError('this.getSortField is no longer valid. Repository has been destroyed.');
1392
+ return;
1353
1393
  }
1354
1394
  if (!this.allowsMultiSort || this.sorters.length < 1) {
1355
1395
  return null;
@@ -1363,7 +1403,8 @@ export default class Repository extends EventEmitter {
1363
1403
  */
1364
1404
  getSortDirection = () => {
1365
1405
  if (this.isDestroyed) {
1366
- throw Error('this.getSortDirection is no longer valid. Repository has been destroyed.');
1406
+ this.throwError('this.getSortDirection is no longer valid. Repository has been destroyed.');
1407
+ return;
1367
1408
  }
1368
1409
  if (!this.allowsMultiSort || this.sorters.length < 1) {
1369
1410
  return null;
@@ -1377,7 +1418,8 @@ export default class Repository extends EventEmitter {
1377
1418
  */
1378
1419
  getSortFn = () => {
1379
1420
  if (this.isDestroyed) {
1380
- throw Error('this.getSortDirection is no longer valid. Repository has been destroyed.');
1421
+ this.throwError('this.getSortDirection is no longer valid. Repository has been destroyed.');
1422
+ return;
1381
1423
  }
1382
1424
  if (!this.allowsMultiSort || this.sorters.length < 1) {
1383
1425
  return null;
@@ -1392,7 +1434,8 @@ export default class Repository extends EventEmitter {
1392
1434
  */
1393
1435
  getAssociatedRepository = (repositoryName) => {
1394
1436
  if (this.isDestroyed) {
1395
- throw Error('this.getAssociatedRepository is no longer valid. Repository has been destroyed.');
1437
+ this.throwError('this.getAssociatedRepository is no longer valid. Repository has been destroyed.');
1438
+ return;
1396
1439
  }
1397
1440
 
1398
1441
  const schema = this.getSchema();
@@ -1401,17 +1444,20 @@ export default class Repository extends EventEmitter {
1401
1444
  !schema.model.associations.belongsTo.includes(repositoryName) &&
1402
1445
  !schema.model.associations.belongsToMany.includes(repositoryName)
1403
1446
  ) {
1404
- throw Error(repositoryName + ' is not associated with this schema');
1447
+ this.throwError(repositoryName + ' is not associated with this schema');
1448
+ return;
1405
1449
  }
1406
1450
 
1407
1451
  const oneHatData = this.oneHatData;
1408
1452
  if (!oneHatData) {
1409
- throw Error('No global oneHatData object');
1453
+ this.throwError('No global oneHatData object');
1454
+ return;
1410
1455
  }
1411
1456
 
1412
1457
  const associatedRepository = oneHatData.getRepository(repositoryName);
1413
1458
  if (!associatedRepository) {
1414
- throw Error('Repository ' + repositoryName + ' cannot be found');
1459
+ this.throwError('Repository ' + repositoryName + ' cannot be found');
1460
+ return;
1415
1461
  }
1416
1462
 
1417
1463
  return associatedRepository;
@@ -1425,7 +1471,8 @@ export default class Repository extends EventEmitter {
1425
1471
  */
1426
1472
  isInRepository(idOrEntity) {
1427
1473
  if (this.isDestroyed) {
1428
- throw Error('this.isInRepository is no longer valid. Repository has been destroyed.');
1474
+ this.throwError('this.isInRepository is no longer valid. Repository has been destroyed.');
1475
+ return;
1429
1476
  }
1430
1477
  if (idOrEntity instanceof Entity) {
1431
1478
  return this.entities.indexOf(idOrEntity) !== -1;
@@ -1440,7 +1487,8 @@ export default class Repository extends EventEmitter {
1440
1487
  */
1441
1488
  get isDirty() {
1442
1489
  if (this.isDestroyed) {
1443
- throw Error('this.isDirty is no longer valid. Repository has been destroyed.');
1490
+ this.throwError('this.isDirty is no longer valid. Repository has been destroyed.');
1491
+ return;
1444
1492
  }
1445
1493
  return !!this.getDirty().length;
1446
1494
  }
@@ -1473,7 +1521,8 @@ export default class Repository extends EventEmitter {
1473
1521
  */
1474
1522
  save = async (entity = null, useStaged = false) => {
1475
1523
  if (this.isDestroyed) {
1476
- throw Error('this.save is no longer valid. Repository has been destroyed.');
1524
+ this.throwError('this.save is no longer valid. Repository has been destroyed.');
1525
+ return;
1477
1526
  }
1478
1527
 
1479
1528
  this.emit('beforeSave'); // So subclasses can prep anything needed for saving
@@ -1619,7 +1668,8 @@ export default class Repository extends EventEmitter {
1619
1668
  * @abstract
1620
1669
  */
1621
1670
  _doBatchAdd(entities) { // standard function notation
1622
- throw new Error('_doBatchAdd must be implemented by Repository subclass');
1671
+ this.throwError('_doBatchAdd must be implemented by Repository subclass');
1672
+ return;
1623
1673
  }
1624
1674
 
1625
1675
  /**
@@ -1630,7 +1680,8 @@ export default class Repository extends EventEmitter {
1630
1680
  * @abstract
1631
1681
  */
1632
1682
  _doAdd(entity) { // standard function notation
1633
- throw new Error('_doAdd must be implemented by Repository subclass');
1683
+ this.throwError('_doAdd must be implemented by Repository subclass');
1684
+ return;
1634
1685
  }
1635
1686
 
1636
1687
  /**
@@ -1641,7 +1692,8 @@ export default class Repository extends EventEmitter {
1641
1692
  * @abstract
1642
1693
  */
1643
1694
  _doBatchEdit(entities) { // standard function notation
1644
- throw new Error('_doBatchEdit must be implemented by Repository subclass');
1695
+ this.throwError('_doBatchEdit must be implemented by Repository subclass');
1696
+ return;
1645
1697
  }
1646
1698
 
1647
1699
  /**
@@ -1652,7 +1704,8 @@ export default class Repository extends EventEmitter {
1652
1704
  * @abstract
1653
1705
  */
1654
1706
  _doEdit(entity) { // standard function notation
1655
- throw new Error('_doEdit must be implemented by Repository subclass');
1707
+ this.throwError('_doEdit must be implemented by Repository subclass');
1708
+ return;
1656
1709
  }
1657
1710
 
1658
1711
  /**
@@ -1663,7 +1716,8 @@ export default class Repository extends EventEmitter {
1663
1716
  * @abstract
1664
1717
  */
1665
1718
  _doBatchDelete(entities) { // standard function notation
1666
- throw new Error('_doBatchDelete must be implemented by Repository subclass');
1719
+ this.throwError('_doBatchDelete must be implemented by Repository subclass');
1720
+ return;
1667
1721
  }
1668
1722
 
1669
1723
  /**
@@ -1674,7 +1728,8 @@ export default class Repository extends EventEmitter {
1674
1728
  * @abstract
1675
1729
  */
1676
1730
  _doDelete(entity) { // standard function notation
1677
- throw new Error('_doDelete must be implemented by Repository subclass');
1731
+ this.throwError('_doDelete must be implemented by Repository subclass');
1732
+ return;
1678
1733
  }
1679
1734
 
1680
1735
  /**
@@ -1710,7 +1765,8 @@ export default class Repository extends EventEmitter {
1710
1765
  */
1711
1766
  delete = async (entities) => {
1712
1767
  if (this.isDestroyed) {
1713
- throw Error('this.delete is no longer valid. Repository has been destroyed.');
1768
+ this.throwError('this.delete is no longer valid. Repository has been destroyed.');
1769
+ return;
1714
1770
  }
1715
1771
  if (!entities) {
1716
1772
  return false;
@@ -1873,6 +1929,26 @@ export default class Repository extends EventEmitter {
1873
1929
  _.merge(this, options);
1874
1930
  }
1875
1931
 
1932
+ /**
1933
+ * Set error handler for this repository
1934
+ * @param {function} handler - the error handler
1935
+ */
1936
+ setErrorHandler = (handler) => {
1937
+ this.errorHandler = handler;
1938
+ }
1939
+
1940
+
1941
+ /**
1942
+ * Either generates an exception, or handles it with the repository's errorHandler
1943
+ * @param {string|object|bool} error - the error message
1944
+ */
1945
+ throwError(obj) {
1946
+ if (this.errorHandler) {
1947
+ this.errorHandler(obj);
1948
+ } else {
1949
+ throw Error(obj);
1950
+ }
1951
+ }
1876
1952
 
1877
1953
  /**
1878
1954
  * Destroy this object.
@@ -1904,7 +1980,8 @@ export default class Repository extends EventEmitter {
1904
1980
  */
1905
1981
  getClassName = () => {
1906
1982
  if (this.isDestroyed) {
1907
- throw Error('this.getClassName is no longer valid. Repository has been destroyed.');
1983
+ this.throwError('this.getClassName is no longer valid. Repository has been destroyed.');
1984
+ return;
1908
1985
  }
1909
1986
  return this.__proto__.constructor.className;
1910
1987
  }
@@ -1919,7 +1996,8 @@ export default class Repository extends EventEmitter {
1919
1996
  */
1920
1997
  getType = () => {
1921
1998
  if (this.isDestroyed) {
1922
- throw Error('this.getClassName is no longer valid. Repository has been destroyed.');
1999
+ this.throwError('this.getClassName is no longer valid. Repository has been destroyed.');
2000
+ return;
1923
2001
  }
1924
2002
  return this.__proto__.constructor.type;
1925
2003
  }
@@ -1930,7 +2008,8 @@ export default class Repository extends EventEmitter {
1930
2008
 
1931
2009
  toString = () => {
1932
2010
  if (this.isDestroyed) {
1933
- throw Error('this.toString is no longer valid. Repository has been destroyed.');
2011
+ this.throwError('this.toString is no longer valid. Repository has been destroyed.');
2012
+ return;
1934
2013
  }
1935
2014
  return this.getClassName() + 'Repository {' + this.name + '} - ' + this.id;
1936
2015
  }