@nymphjs/nymph 1.0.0-beta.5 → 1.0.0-beta.50

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.
Files changed (50) hide show
  1. package/CHANGELOG.md +231 -0
  2. package/README.md +15 -15
  3. package/dist/Entity.d.ts +24 -3
  4. package/dist/Entity.js +194 -86
  5. package/dist/Entity.js.map +1 -1
  6. package/dist/Entity.test.js +34 -17
  7. package/dist/Entity.test.js.map +1 -1
  8. package/dist/Entity.types.d.ts +3 -1
  9. package/dist/Nymph.d.ts +22 -7
  10. package/dist/Nymph.js +214 -68
  11. package/dist/Nymph.js.map +1 -1
  12. package/dist/Nymph.types.d.ts +18 -5
  13. package/dist/Nymph.types.js +1 -1
  14. package/dist/Nymph.types.js.map +1 -1
  15. package/dist/driver/NymphDriver.d.ts +1 -22
  16. package/dist/driver/NymphDriver.js +85 -105
  17. package/dist/driver/NymphDriver.js.map +1 -1
  18. package/dist/driver/testArtifacts.js +208 -159
  19. package/dist/driver/testArtifacts.js.map +1 -1
  20. package/dist/errors/InvalidStateError.d.ts +3 -0
  21. package/dist/errors/InvalidStateError.js +11 -0
  22. package/dist/errors/InvalidStateError.js.map +1 -0
  23. package/dist/errors/QueryFailedError.js.map +1 -1
  24. package/dist/errors/index.d.ts +1 -0
  25. package/dist/errors/index.js +1 -0
  26. package/dist/errors/index.js.map +1 -1
  27. package/dist/testArtifacts.d.ts +10 -3
  28. package/dist/testArtifacts.js +20 -11
  29. package/dist/testArtifacts.js.map +1 -1
  30. package/dist/testMocks.d.ts +10 -7
  31. package/dist/testMocks.js +22 -10
  32. package/dist/testMocks.js.map +1 -1
  33. package/dist/utils.d.ts +1 -1
  34. package/dist/utils.js +11 -5
  35. package/dist/utils.js.map +1 -1
  36. package/package.json +15 -15
  37. package/src/Entity.test.ts +33 -11
  38. package/src/Entity.ts +303 -127
  39. package/src/Entity.types.ts +13 -1
  40. package/src/Nymph.ts +392 -88
  41. package/src/Nymph.types.ts +95 -24
  42. package/src/driver/NymphDriver.ts +203 -282
  43. package/src/driver/testArtifacts.ts +238 -157
  44. package/src/errors/InvalidStateError.ts +6 -0
  45. package/src/errors/index.ts +2 -0
  46. package/src/nymphJoiProps.ts +2 -2
  47. package/src/testArtifacts.ts +28 -10
  48. package/src/testMocks.ts +42 -25
  49. package/src/utils.ts +22 -8
  50. package/typedoc.json +4 -0
package/src/Nymph.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Config, ConfigDefaults as defaults } from './conf';
2
- import { NymphDriver } from './driver';
2
+ import type { NymphDriver } from './driver';
3
3
  import Entity from './Entity';
4
- import { EntityConstructor, EntityData, EntityInterface } from './Entity.types';
4
+ import type { EntityConstructor, EntityInterface } from './Entity.types';
5
5
  import { ClassNotAvailableError } from './errors';
6
6
  import type {
7
7
  Selector,
@@ -12,18 +12,31 @@ import type {
12
12
  NymphBeforeGetEntitiesCallback,
13
13
  NymphBeforeSaveEntityCallback,
14
14
  NymphAfterSaveEntityCallback,
15
+ NymphFailedSaveEntityCallback,
15
16
  NymphBeforeDeleteEntityCallback,
16
17
  NymphAfterDeleteEntityCallback,
18
+ NymphFailedDeleteEntityCallback,
17
19
  NymphBeforeDeleteEntityByIDCallback,
18
20
  NymphAfterDeleteEntityByIDCallback,
21
+ NymphFailedDeleteEntityByIDCallback,
19
22
  NymphBeforeNewUIDCallback,
20
23
  NymphAfterNewUIDCallback,
24
+ NymphFailedNewUIDCallback,
21
25
  NymphBeforeSetUIDCallback,
22
26
  NymphAfterSetUIDCallback,
27
+ NymphFailedSetUIDCallback,
23
28
  NymphBeforeRenameUIDCallback,
24
29
  NymphAfterRenameUIDCallback,
30
+ NymphFailedRenameUIDCallback,
25
31
  NymphBeforeDeleteUIDCallback,
26
32
  NymphAfterDeleteUIDCallback,
33
+ NymphFailedDeleteUIDCallback,
34
+ NymphBeforeStartTransactionCallback,
35
+ NymphAfterStartTransactionCallback,
36
+ NymphBeforeCommitTransactionCallback,
37
+ NymphAfterCommitTransactionCallback,
38
+ NymphBeforeRollbackTransactionCallback,
39
+ NymphAfterRollbackTransactionCallback,
27
40
  NymphEventType,
28
41
  NymphQueryCallback,
29
42
  FormattedSelector,
@@ -41,10 +54,16 @@ import type {
41
54
  */
42
55
  export default class Nymph {
43
56
  /**
44
- * The PubSub config.
57
+ * The Nymph config.
45
58
  */
46
59
  public config: Config;
47
60
 
61
+ /**
62
+ * The Nymph instance that this one was cloned from, or null if it's not a
63
+ * clone.
64
+ */
65
+ public parent: Nymph | null;
66
+
48
67
  /**
49
68
  * The Nymph database driver.
50
69
  */
@@ -63,7 +82,7 @@ export default class Nymph {
63
82
  /**
64
83
  * The entity class for this instance of Nymph.
65
84
  */
66
- public Entity: typeof Entity = Entity;
85
+ public Entity: typeof Entity;
67
86
 
68
87
  private connectCallbacks: NymphConnectCallback[] = [];
69
88
  private disconnectCallbacks: NymphDisconnectCallback[] = [];
@@ -72,34 +91,40 @@ export default class Nymph {
72
91
  private beforeGetEntitiesCallbacks: NymphBeforeGetEntitiesCallback[] = [];
73
92
  private beforeSaveEntityCallbacks: NymphBeforeSaveEntityCallback[] = [];
74
93
  private afterSaveEntityCallbacks: NymphAfterSaveEntityCallback[] = [];
94
+ private failedSaveEntityCallbacks: NymphFailedSaveEntityCallback[] = [];
75
95
  private beforeDeleteEntityCallbacks: NymphBeforeDeleteEntityCallback[] = [];
76
96
  private afterDeleteEntityCallbacks: NymphAfterDeleteEntityCallback[] = [];
97
+ private failedDeleteEntityCallbacks: NymphFailedDeleteEntityCallback[] = [];
77
98
  private beforeDeleteEntityByIDCallbacks: NymphBeforeDeleteEntityByIDCallback[] =
78
99
  [];
79
100
  private afterDeleteEntityByIDCallbacks: NymphAfterDeleteEntityByIDCallback[] =
80
101
  [];
102
+ private failedDeleteEntityByIDCallbacks: NymphFailedDeleteEntityByIDCallback[] =
103
+ [];
81
104
  private beforeNewUIDCallbacks: NymphBeforeNewUIDCallback[] = [];
82
105
  private afterNewUIDCallbacks: NymphAfterNewUIDCallback[] = [];
106
+ private failedNewUIDCallbacks: NymphFailedNewUIDCallback[] = [];
83
107
  private beforeSetUIDCallbacks: NymphBeforeSetUIDCallback[] = [];
84
108
  private afterSetUIDCallbacks: NymphAfterSetUIDCallback[] = [];
109
+ private failedSetUIDCallbacks: NymphFailedSetUIDCallback[] = [];
85
110
  private beforeRenameUIDCallbacks: NymphBeforeRenameUIDCallback[] = [];
86
111
  private afterRenameUIDCallbacks: NymphAfterRenameUIDCallback[] = [];
112
+ private failedRenameUIDCallbacks: NymphFailedRenameUIDCallback[] = [];
87
113
  private beforeDeleteUIDCallbacks: NymphBeforeDeleteUIDCallback[] = [];
88
114
  private afterDeleteUIDCallbacks: NymphAfterDeleteUIDCallback[] = [];
89
-
90
- public addEntityClass(entityClass: EntityConstructor) {
91
- this.entityClasses[entityClass.class] = entityClass;
92
- entityClass.nymph = this;
93
- }
94
-
95
- public getEntityClass(className: string): EntityConstructor {
96
- if (className in this.entityClasses) {
97
- const EntityClass = this.entityClasses[className];
98
- EntityClass.nymph = this;
99
- return EntityClass;
100
- }
101
- throw new ClassNotAvailableError('Tried to use class: ' + className);
102
- }
115
+ private failedDeleteUIDCallbacks: NymphFailedDeleteUIDCallback[] = [];
116
+ private beforeStartTransactionCallbacks: NymphBeforeStartTransactionCallback[] =
117
+ [];
118
+ private afterStartTransactionCallbacks: NymphAfterStartTransactionCallback[] =
119
+ [];
120
+ private beforeCommitTransactionCallbacks: NymphBeforeCommitTransactionCallback[] =
121
+ [];
122
+ private afterCommitTransactionCallbacks: NymphAfterCommitTransactionCallback[] =
123
+ [];
124
+ private beforeRollbackTransactionCallbacks: NymphBeforeRollbackTransactionCallback[] =
125
+ [];
126
+ private afterRollbackTransactionCallbacks: NymphAfterRollbackTransactionCallback[] =
127
+ [];
103
128
 
104
129
  /**
105
130
  * Initialize Nymph.
@@ -107,22 +132,82 @@ export default class Nymph {
107
132
  * @param config The Nymph configuration.
108
133
  * @param driver The Nymph database driver.
109
134
  * @param tilmeld The Tilmeld user/group manager instance, if you want to use it.
135
+ * @param parent Used internally by Nymph. Don't set this.
110
136
  */
111
137
  public constructor(
112
138
  config: Partial<Config>,
113
139
  driver: NymphDriver,
114
- tilmeld?: TilmeldInterface
140
+ tilmeld?: TilmeldInterface,
141
+ parent?: Nymph,
115
142
  ) {
116
143
  this.config = { ...defaults, ...config };
117
144
  this.driver = driver;
118
- if (typeof tilmeld !== 'undefined') {
119
- this.tilmeld = tilmeld;
145
+ this.parent = parent ?? null;
146
+
147
+ this.Entity = this.addEntityClass(Entity);
148
+
149
+ if (parent) {
150
+ for (const name in parent.entityClasses) {
151
+ if (
152
+ name === 'Entity' ||
153
+ (parent.entityClasses[name] as any).skipOnClone
154
+ ) {
155
+ continue;
156
+ }
157
+ this.addEntityClass(parent.entityClasses[name]);
158
+ }
159
+
160
+ const events = [
161
+ 'connect',
162
+ 'disconnect',
163
+ 'query',
164
+ 'beforeGetEntity',
165
+ 'beforeGetEntities',
166
+ 'beforeSaveEntity',
167
+ 'afterSaveEntity',
168
+ 'failedSaveEntity',
169
+ 'beforeDeleteEntity',
170
+ 'afterDeleteEntity',
171
+ 'failedDeleteEntity',
172
+ 'beforeDeleteEntityByID',
173
+ 'afterDeleteEntityByID',
174
+ 'failedDeleteEntityByID',
175
+ 'beforeNewUID',
176
+ 'afterNewUID',
177
+ 'failedNewUID',
178
+ 'beforeSetUID',
179
+ 'afterSetUID',
180
+ 'failedSetUID',
181
+ 'beforeRenameUID',
182
+ 'afterRenameUID',
183
+ 'failedRenameUID',
184
+ 'beforeDeleteUID',
185
+ 'afterDeleteUID',
186
+ 'failedDeleteUID',
187
+ 'beforeStartTransaction',
188
+ 'afterStartTransaction',
189
+ 'beforeCommitTransaction',
190
+ 'afterCommitTransaction',
191
+ 'beforeRollbackTransaction',
192
+ 'afterRollbackTransaction',
193
+ ];
194
+
195
+ for (let event of events) {
196
+ const prop = event + 'Callbacks';
197
+ // @ts-ignore: The callback should be the right type here.
198
+ const callbacks = parent[prop];
199
+ for (let callback of callbacks) {
200
+ if (callback.skipOnClone) {
201
+ continue;
202
+ }
203
+ this.on(event as NymphEventType, callback);
204
+ }
205
+ }
120
206
  }
121
207
 
122
- class NymphEntity<T extends EntityData = EntityData> extends Entity<T> {}
123
- NymphEntity.nymph = this;
124
- this.Entity = NymphEntity;
125
- this.addEntityClass(NymphEntity);
208
+ if (tilmeld != null) {
209
+ this.tilmeld = tilmeld;
210
+ }
126
211
 
127
212
  this.driver.init(this);
128
213
  if (this.tilmeld) {
@@ -131,54 +216,60 @@ export default class Nymph {
131
216
  }
132
217
 
133
218
  /**
134
- * Get a clone of this instance with duplicate classes and event listeners.
219
+ * Add your class to this instance.
135
220
  *
136
- * @returns A clone of this instance.
221
+ * This will create a class that extends your class within this instance of
222
+ * Nymph and return it. You can then use this class's constructor and methods,
223
+ * which will use this instance of Nymph.
224
+ *
225
+ * Because this creates a subclass, don't use the class
226
+ * returned from `getEntityClass` to check with `instanceof`.
137
227
  */
138
- public clone() {
139
- const nymph = new Nymph(this.config, this.driver, this.tilmeld?.clone());
140
- for (const name in this.entityClasses) {
141
- if (name === 'Entity' || (this.entityClasses[name] as any).skipOnClone) {
142
- continue;
143
- }
144
- nymph.addEntityClass(this.entityClasses[name]);
145
- }
146
-
147
- const events = [
148
- 'connect',
149
- 'disconnect',
150
- 'query',
151
- 'beforeGetEntity',
152
- 'beforeGetEntities',
153
- 'beforeSaveEntity',
154
- 'afterSaveEntity',
155
- 'beforeDeleteEntity',
156
- 'afterDeleteEntity',
157
- 'beforeDeleteEntityByID',
158
- 'afterDeleteEntityByID',
159
- 'beforeNewUID',
160
- 'afterNewUID',
161
- 'beforeSetUID',
162
- 'afterSetUID',
163
- 'beforeRenameUID',
164
- 'afterRenameUID',
165
- 'beforeDeleteUID',
166
- 'afterDeleteUID',
167
- ];
168
-
169
- for (let event of events) {
170
- const prop = event + 'Callbacks';
171
- // @ts-ignore: The callback should be the right type here.
172
- const callbacks = this[prop];
173
- for (let callback of callbacks) {
174
- if (callback.skipOnClone) {
175
- continue;
176
- }
177
- nymph.on(event as NymphEventType, callback);
228
+ public addEntityClass<T extends EntityConstructor>(entityClass: T): T {
229
+ const nymph = this;
230
+ class NymphEntity extends entityClass {
231
+ static nymph: Nymph = nymph;
232
+
233
+ constructor(...args: any[]) {
234
+ super(...args);
178
235
  }
179
236
  }
237
+ this.entityClasses[entityClass.class] = NymphEntity;
238
+ return NymphEntity;
239
+ }
180
240
 
181
- return nymph;
241
+ /**
242
+ * Get the class that uses the specified class name.
243
+ */
244
+ public getEntityClass<T extends EntityConstructor>(className: T): T;
245
+ public getEntityClass(className: string): EntityConstructor;
246
+ public getEntityClass<T extends EntityConstructor = EntityConstructor>(
247
+ className: T | string,
248
+ ): T | EntityConstructor {
249
+ let key: string | null = null;
250
+ if (typeof className === 'string') {
251
+ key = className;
252
+ } else {
253
+ key = className.class;
254
+ }
255
+ if (key in this.entityClasses) {
256
+ return this.entityClasses[key];
257
+ }
258
+ throw new ClassNotAvailableError('Tried to use class: ' + key);
259
+ }
260
+
261
+ /**
262
+ * Get a clone of this instance with cloned classes and event listeners.
263
+ *
264
+ * @returns A clone of this instance.
265
+ */
266
+ public clone() {
267
+ return new Nymph(
268
+ this.config,
269
+ this.driver.clone(),
270
+ this.tilmeld?.clone(),
271
+ this,
272
+ );
182
273
  }
183
274
 
184
275
  /**
@@ -232,28 +323,65 @@ export default class Nymph {
232
323
  * Transactions will nest as long as every name is unique. Internally, Nymph
233
324
  * uses names prefixed with "nymph-".
234
325
  *
235
- * @returns True on success, false on failure.
326
+ * @returns A new instance of Nymph that should be used for the transaction.
236
327
  */
237
328
  public async startTransaction(name: string): Promise<Nymph> {
238
- return await this.driver.startTransaction(name);
329
+ for (let callback of this.beforeStartTransactionCallbacks) {
330
+ if (callback) {
331
+ await callback(this, name);
332
+ }
333
+ }
334
+ const result = await this.driver.startTransaction(name);
335
+ for (let callback of this.afterStartTransactionCallbacks) {
336
+ if (callback) {
337
+ await callback(this, name, result);
338
+ }
339
+ }
340
+ return result;
239
341
  }
240
342
 
241
343
  /**
242
344
  * Commit the named transaction.
243
345
  *
346
+ * After this is called, the transaction instance should be discarded.
347
+ *
244
348
  * @returns True on success, false on failure.
245
349
  */
246
350
  public async commit(name: string): Promise<boolean> {
247
- return await this.driver.commit(name);
351
+ for (let callback of this.beforeCommitTransactionCallbacks) {
352
+ if (callback) {
353
+ await callback(this, name);
354
+ }
355
+ }
356
+ const result = await this.driver.commit(name);
357
+ for (let callback of this.afterCommitTransactionCallbacks) {
358
+ if (callback) {
359
+ await callback(this, name, result);
360
+ }
361
+ }
362
+ return result;
248
363
  }
249
364
 
250
365
  /**
251
366
  * Rollback the named transaction.
252
367
  *
368
+ * After this is called, the transaction instance should be discarded.
369
+ *
253
370
  * @returns True on success, false on failure.
254
371
  */
255
372
  public async rollback(name: string): Promise<boolean> {
256
- return await this.driver.rollback(name);
373
+ for (let callback of this.beforeRollbackTransactionCallbacks) {
374
+ if (callback) {
375
+ await callback(this, name);
376
+ }
377
+ }
378
+ const result = await this.driver.rollback(name);
379
+ for (let callback of this.afterRollbackTransactionCallbacks) {
380
+ if (callback) {
381
+ await callback(this, name, result);
382
+ }
383
+ }
384
+ return result;
257
385
  }
258
386
 
259
387
  /**
@@ -292,7 +420,17 @@ export default class Nymph {
292
420
  await callback(this, name);
293
421
  }
294
422
  }
295
- const result = this.driver.newUID(name);
423
+ let result: Promise<number | null>;
424
+ try {
425
+ result = this.driver.newUID(name);
426
+ } catch (e: any) {
427
+ for (let callback of this.failedNewUIDCallbacks) {
428
+ if (callback) {
429
+ await callback(this, e);
430
+ }
431
+ }
432
+ throw e;
433
+ }
296
434
  for (let callback of this.afterNewUIDCallbacks) {
297
435
  if (callback) {
298
436
  await callback(this, result);
@@ -323,7 +461,17 @@ export default class Nymph {
323
461
  await callback(this, name, value);
324
462
  }
325
463
  }
326
- const result = this.driver.setUID(name, value);
464
+ let result: Promise<boolean>;
465
+ try {
466
+ result = this.driver.setUID(name, value);
467
+ } catch (e: any) {
468
+ for (let callback of this.failedSetUIDCallbacks) {
469
+ if (callback) {
470
+ await callback(this, e);
471
+ }
472
+ }
473
+ throw e;
474
+ }
327
475
  for (let callback of this.afterSetUIDCallbacks) {
328
476
  if (callback) {
329
477
  await callback(this, result);
@@ -344,7 +492,17 @@ export default class Nymph {
344
492
  await callback(this, name);
345
493
  }
346
494
  }
347
- const result = this.driver.deleteUID(name);
495
+ let result: Promise<boolean>;
496
+ try {
497
+ result = this.driver.deleteUID(name);
498
+ } catch (e: any) {
499
+ for (let callback of this.failedDeleteUIDCallbacks) {
500
+ if (callback) {
501
+ await callback(this, e);
502
+ }
503
+ }
504
+ throw e;
505
+ }
348
506
  for (let callback of this.afterDeleteUIDCallbacks) {
349
507
  if (callback) {
350
508
  await callback(this, result);
@@ -366,7 +524,17 @@ export default class Nymph {
366
524
  await callback(this, oldName, newName);
367
525
  }
368
526
  }
369
- const result = this.driver.renameUID(oldName, newName);
527
+ let result: Promise<boolean>;
528
+ try {
529
+ result = this.driver.renameUID(oldName, newName);
530
+ } catch (e: any) {
531
+ for (let callback of this.failedRenameUIDCallbacks) {
532
+ if (callback) {
533
+ await callback(this, e);
534
+ }
535
+ }
536
+ throw e;
537
+ }
370
538
  for (let callback of this.afterRenameUIDCallbacks) {
371
539
  if (callback) {
372
540
  await callback(this, result);
@@ -392,7 +560,17 @@ export default class Nymph {
392
560
  await callback(this, entity);
393
561
  }
394
562
  }
395
- const result = this.driver.saveEntity(entity);
563
+ let result: Promise<boolean>;
564
+ try {
565
+ result = this.driver.saveEntity(entity);
566
+ } catch (e: any) {
567
+ for (let callback of this.failedSaveEntityCallbacks) {
568
+ if (callback) {
569
+ await callback(this, e);
570
+ }
571
+ }
572
+ throw e;
573
+ }
396
574
  for (let callback of this.afterSaveEntityCallbacks) {
397
575
  if (callback) {
398
576
  await callback(this, result);
@@ -411,8 +589,10 @@ export default class Nymph {
411
589
  * - offset - The offset from the oldest matching entity to start retrieving.
412
590
  * - reverse - If true, entities will be retrieved from newest to oldest.
413
591
  * Therefore, offset will be from the newest entity.
414
- * - sort - How to sort the entities. Accepts "cdate" or "mdate". Defaults to
415
- * "cdate".
592
+ * - sort - How to sort the entities. Accepts "cdate", "mdate", or the name of
593
+ * a top-level property. The method of sorting properties other than cdate
594
+ * and mdate is driver dependent. The only hard rule is that numbers should
595
+ * be sorted numerically (2 before 10). Defaults to "cdate".
416
596
  * - return - What to return. "entity", "guid", or "count". Defaults to
417
597
  * "entity".
418
598
  * - source - Will be 'client' if the query came from a REST call.
@@ -611,11 +791,11 @@ export default class Nymph {
611
791
  ): Promise<ReturnType<T['factorySync']> | null>;
612
792
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
613
793
  options: Options<T> & { return: 'guid' },
614
- guid: string
794
+ guid: string,
615
795
  ): Promise<string | null>;
616
796
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
617
797
  options: Options<T>,
618
- guid: string
798
+ guid: string,
619
799
  ): Promise<ReturnType<T['factorySync']> | null>;
620
800
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
621
801
  options: Options<T> = {},
@@ -633,7 +813,7 @@ export default class Nymph {
633
813
  }
634
814
  const entities = await this.driver.getEntities(
635
815
  options,
636
- ...(selectors as Selector[])
816
+ ...(selectors as Selector[]),
637
817
  );
638
818
  if (options.return === 'count') {
639
819
  return entities as unknown as number;
@@ -656,7 +836,17 @@ export default class Nymph {
656
836
  await callback(this, entity);
657
837
  }
658
838
  }
659
- const result = this.driver.deleteEntity(entity);
839
+ let result: Promise<boolean>;
840
+ try {
841
+ result = this.driver.deleteEntity(entity);
842
+ } catch (e: any) {
843
+ for (let callback of this.failedDeleteEntityCallbacks) {
844
+ if (callback) {
845
+ await callback(this, e);
846
+ }
847
+ }
848
+ throw e;
849
+ }
660
850
  for (let callback of this.afterDeleteEntityCallbacks) {
661
851
  if (callback) {
662
852
  await callback(this, result);
@@ -674,14 +864,24 @@ export default class Nymph {
674
864
  */
675
865
  public async deleteEntityByID(
676
866
  guid: string,
677
- className?: string
867
+ className?: string,
678
868
  ): Promise<boolean> {
679
869
  for (let callback of this.beforeDeleteEntityByIDCallbacks) {
680
870
  if (callback) {
681
871
  await callback(this, guid, className);
682
872
  }
683
873
  }
684
- const result = this.driver.deleteEntityByID(guid, className);
874
+ let result: Promise<boolean>;
875
+ try {
876
+ result = this.driver.deleteEntityByID(guid, className);
877
+ } catch (e: any) {
878
+ for (let callback of this.failedDeleteEntityByIDCallbacks) {
879
+ if (callback) {
880
+ await callback(this, e);
881
+ }
882
+ }
883
+ throw e;
884
+ }
685
885
  for (let callback of this.afterDeleteEntityByIDCallbacks) {
686
886
  if (callback) {
687
887
  await callback(this, result);
@@ -712,7 +912,7 @@ export default class Nymph {
712
912
  * # brackets ([]).
713
913
  * # Properties are stored like this:
714
914
  * # propname=JSON.stringify(value)
715
- * abilities=["system/all"]
915
+ * abilities=["system/admin"]
716
916
  * groups=[]
717
917
  * inheritAbilities=false
718
918
  * name="admin"
@@ -765,31 +965,57 @@ export default class Nymph {
765
965
  ? NymphBeforeSaveEntityCallback
766
966
  : T extends 'afterSaveEntity'
767
967
  ? NymphAfterSaveEntityCallback
968
+ : T extends 'failedSaveEntity'
969
+ ? NymphFailedSaveEntityCallback
768
970
  : T extends 'beforeDeleteEntity'
769
971
  ? NymphBeforeDeleteEntityCallback
770
972
  : T extends 'afterDeleteEntity'
771
973
  ? NymphAfterDeleteEntityCallback
974
+ : T extends 'failedDeleteEntity'
975
+ ? NymphFailedDeleteEntityCallback
772
976
  : T extends 'beforeDeleteEntityByID'
773
977
  ? NymphBeforeDeleteEntityByIDCallback
774
978
  : T extends 'afterDeleteEntityByID'
775
979
  ? NymphAfterDeleteEntityByIDCallback
980
+ : T extends 'failedDeleteEntityByID'
981
+ ? NymphFailedDeleteEntityByIDCallback
776
982
  : T extends 'beforeNewUID'
777
983
  ? NymphBeforeNewUIDCallback
778
984
  : T extends 'afterNewUID'
779
985
  ? NymphAfterNewUIDCallback
986
+ : T extends 'failedNewUID'
987
+ ? NymphFailedNewUIDCallback
780
988
  : T extends 'beforeSetUID'
781
989
  ? NymphBeforeSetUIDCallback
782
990
  : T extends 'afterSetUID'
783
991
  ? NymphAfterSetUIDCallback
992
+ : T extends 'failedSetUID'
993
+ ? NymphFailedSetUIDCallback
784
994
  : T extends 'beforeRenameUID'
785
995
  ? NymphBeforeRenameUIDCallback
786
996
  : T extends 'afterRenameUID'
787
997
  ? NymphAfterRenameUIDCallback
998
+ : T extends 'failedRenameUID'
999
+ ? NymphFailedRenameUIDCallback
788
1000
  : T extends 'beforeDeleteUID'
789
1001
  ? NymphBeforeDeleteUIDCallback
790
1002
  : T extends 'afterDeleteUID'
791
1003
  ? NymphAfterDeleteUIDCallback
792
- : never
1004
+ : T extends 'failedDeleteUID'
1005
+ ? NymphFailedDeleteUIDCallback
1006
+ : T extends 'beforeStartTransaction'
1007
+ ? NymphBeforeStartTransactionCallback
1008
+ : T extends 'afterStartTransaction'
1009
+ ? NymphAfterStartTransactionCallback
1010
+ : T extends 'beforeCommitTransaction'
1011
+ ? NymphBeforeCommitTransactionCallback
1012
+ : T extends 'afterCommitTransaction'
1013
+ ? NymphAfterCommitTransactionCallback
1014
+ : T extends 'beforeRollbackTransaction'
1015
+ ? NymphBeforeRollbackTransactionCallback
1016
+ : T extends 'afterRollbackTransaction'
1017
+ ? NymphAfterRollbackTransactionCallback
1018
+ : never,
793
1019
  ) {
794
1020
  const prop = (event + 'Callbacks') as T extends 'connect'
795
1021
  ? 'connectCallbacks'
@@ -805,30 +1031,56 @@ export default class Nymph {
805
1031
  ? 'beforeSaveEntityCallbacks'
806
1032
  : T extends 'afterSaveEntity'
807
1033
  ? 'afterSaveEntityCallbacks'
1034
+ : T extends 'failedSaveEntity'
1035
+ ? 'failedSaveEntityCallbacks'
808
1036
  : T extends 'beforeDeleteEntity'
809
1037
  ? 'beforeDeleteEntityCallbacks'
810
1038
  : T extends 'afterDeleteEntity'
811
1039
  ? 'afterDeleteEntityCallbacks'
1040
+ : T extends 'failedDeleteEntity'
1041
+ ? 'failedDeleteEntityCallbacks'
812
1042
  : T extends 'beforeDeleteEntityByID'
813
1043
  ? 'beforeDeleteEntityByIDCallbacks'
814
1044
  : T extends 'afterDeleteEntityByID'
815
1045
  ? 'afterDeleteEntityByIDCallbacks'
1046
+ : T extends 'failedDeleteEntityByID'
1047
+ ? 'failedDeleteEntityByIDCallbacks'
816
1048
  : T extends 'beforeNewUID'
817
1049
  ? 'beforeNewUIDCallbacks'
818
1050
  : T extends 'afterNewUID'
819
1051
  ? 'afterNewUIDCallbacks'
1052
+ : T extends 'failedNewUID'
1053
+ ? 'failedNewUIDCallbacks'
820
1054
  : T extends 'beforeSetUID'
821
1055
  ? 'beforeSetUIDCallbacks'
822
1056
  : T extends 'afterSetUID'
823
1057
  ? 'afterSetUIDCallbacks'
1058
+ : T extends 'failedSetUID'
1059
+ ? 'failedSetUIDCallbacks'
824
1060
  : T extends 'beforeRenameUID'
825
1061
  ? 'beforeRenameUIDCallbacks'
826
1062
  : T extends 'afterRenameUID'
827
1063
  ? 'afterRenameUIDCallbacks'
1064
+ : T extends 'failedRenameUID'
1065
+ ? 'failedRenameUIDCallbacks'
828
1066
  : T extends 'beforeDeleteUID'
829
1067
  ? 'beforeDeleteUIDCallbacks'
830
1068
  : T extends 'afterDeleteUID'
831
1069
  ? 'afterDeleteUIDCallbacks'
1070
+ : T extends 'failedDeleteUID'
1071
+ ? 'failedDeleteUIDCallbacks'
1072
+ : T extends 'beforeStartTransaction'
1073
+ ? 'beforeStartTransactionCallbacks'
1074
+ : T extends 'afterStartTransaction'
1075
+ ? 'afterStartTransactionCallbacks'
1076
+ : T extends 'beforeCommitTransaction'
1077
+ ? 'beforeCommitTransactionCallbacks'
1078
+ : T extends 'afterCommitTransaction'
1079
+ ? 'afterCommitTransactionCallbacks'
1080
+ : T extends 'beforeRollbackTransaction'
1081
+ ? 'beforeRollbackTransactionCallbacks'
1082
+ : T extends 'afterRollbackTransaction'
1083
+ ? 'afterRollbackTransactionCallbacks'
832
1084
  : never;
833
1085
  if (!(prop in this)) {
834
1086
  throw new Error('Invalid event type.');
@@ -854,31 +1106,57 @@ export default class Nymph {
854
1106
  ? NymphBeforeSaveEntityCallback
855
1107
  : T extends 'afterSaveEntity'
856
1108
  ? NymphAfterSaveEntityCallback
1109
+ : T extends 'failedSaveEntity'
1110
+ ? NymphFailedSaveEntityCallback
857
1111
  : T extends 'beforeDeleteEntity'
858
1112
  ? NymphBeforeDeleteEntityCallback
859
1113
  : T extends 'afterDeleteEntity'
860
1114
  ? NymphAfterDeleteEntityCallback
1115
+ : T extends 'failedDeleteEntity'
1116
+ ? NymphFailedDeleteEntityCallback
861
1117
  : T extends 'beforeDeleteEntityByID'
862
1118
  ? NymphBeforeDeleteEntityByIDCallback
863
1119
  : T extends 'afterDeleteEntityByID'
864
1120
  ? NymphAfterDeleteEntityByIDCallback
1121
+ : T extends 'failedDeleteEntityByID'
1122
+ ? NymphFailedDeleteEntityByIDCallback
865
1123
  : T extends 'beforeNewUID'
866
1124
  ? NymphBeforeNewUIDCallback
867
1125
  : T extends 'afterNewUID'
868
1126
  ? NymphAfterNewUIDCallback
1127
+ : T extends 'failedNewUID'
1128
+ ? NymphFailedNewUIDCallback
869
1129
  : T extends 'beforeSetUID'
870
1130
  ? NymphBeforeSetUIDCallback
871
1131
  : T extends 'afterSetUID'
872
1132
  ? NymphAfterSetUIDCallback
1133
+ : T extends 'failedSetUID'
1134
+ ? NymphFailedSetUIDCallback
873
1135
  : T extends 'beforeRenameUID'
874
1136
  ? NymphBeforeRenameUIDCallback
875
1137
  : T extends 'afterRenameUID'
876
1138
  ? NymphAfterRenameUIDCallback
1139
+ : T extends 'failedRenameUID'
1140
+ ? NymphFailedRenameUIDCallback
877
1141
  : T extends 'beforeDeleteUID'
878
1142
  ? NymphBeforeDeleteUIDCallback
879
1143
  : T extends 'afterDeleteUID'
880
1144
  ? NymphAfterDeleteUIDCallback
881
- : never
1145
+ : T extends 'failedDeleteUID'
1146
+ ? NymphFailedDeleteUIDCallback
1147
+ : T extends 'beforeStartTransaction'
1148
+ ? NymphBeforeStartTransactionCallback
1149
+ : T extends 'afterStartTransaction'
1150
+ ? NymphAfterStartTransactionCallback
1151
+ : T extends 'beforeCommitTransaction'
1152
+ ? NymphBeforeCommitTransactionCallback
1153
+ : T extends 'afterCommitTransaction'
1154
+ ? NymphAfterCommitTransactionCallback
1155
+ : T extends 'beforeRollbackTransaction'
1156
+ ? NymphBeforeRollbackTransactionCallback
1157
+ : T extends 'afterRollbackTransaction'
1158
+ ? NymphAfterRollbackTransactionCallback
1159
+ : never,
882
1160
  ) {
883
1161
  const prop = (event + 'Callbacks') as T extends 'connect'
884
1162
  ? 'connectCallbacks'
@@ -894,30 +1172,56 @@ export default class Nymph {
894
1172
  ? 'beforeGetEntitiesCallbacks'
895
1173
  : T extends 'afterSaveEntity'
896
1174
  ? 'afterSaveEntityCallbacks'
1175
+ : T extends 'failedSaveEntity'
1176
+ ? 'failedSaveEntityCallbacks'
897
1177
  : T extends 'beforeDeleteEntity'
898
1178
  ? 'beforeDeleteEntityCallbacks'
899
1179
  : T extends 'afterDeleteEntity'
900
1180
  ? 'afterDeleteEntityCallbacks'
1181
+ : T extends 'failedDeleteEntity'
1182
+ ? 'failedDeleteEntityCallbacks'
901
1183
  : T extends 'beforeDeleteEntityByID'
902
1184
  ? 'beforeDeleteEntityByIDCallbacks'
903
1185
  : T extends 'afterDeleteEntityByID'
904
1186
  ? 'afterDeleteEntityByIDCallbacks'
1187
+ : T extends 'failedDeleteEntityByID'
1188
+ ? 'failedDeleteEntityByIDCallbacks'
905
1189
  : T extends 'beforeNewUID'
906
1190
  ? 'beforeNewUIDCallbacks'
907
1191
  : T extends 'afterNewUID'
908
1192
  ? 'afterNewUIDCallbacks'
1193
+ : T extends 'failedNewUID'
1194
+ ? 'failedNewUIDCallbacks'
909
1195
  : T extends 'beforeSetUID'
910
1196
  ? 'beforeSetUIDCallbacks'
911
1197
  : T extends 'afterSetUID'
912
1198
  ? 'afterSetUIDCallbacks'
1199
+ : T extends 'failedSetUID'
1200
+ ? 'failedSetUIDCallbacks'
913
1201
  : T extends 'beforeRenameUID'
914
1202
  ? 'beforeRenameUIDCallbacks'
915
1203
  : T extends 'afterRenameUID'
916
1204
  ? 'afterRenameUIDCallbacks'
1205
+ : T extends 'failedRenameUID'
1206
+ ? 'failedRenameUIDCallbacks'
917
1207
  : T extends 'beforeDeleteUID'
918
1208
  ? 'beforeDeleteUIDCallbacks'
919
1209
  : T extends 'afterDeleteUID'
920
1210
  ? 'afterDeleteUIDCallbacks'
1211
+ : T extends 'failedDeleteUID'
1212
+ ? 'failedDeleteUIDCallbacks'
1213
+ : T extends 'beforeStartTransaction'
1214
+ ? 'beforeStartTransactionCallbacks'
1215
+ : T extends 'afterStartTransaction'
1216
+ ? 'afterStartTransactionCallbacks'
1217
+ : T extends 'beforeCommitTransaction'
1218
+ ? 'beforeCommitTransactionCallbacks'
1219
+ : T extends 'afterCommitTransaction'
1220
+ ? 'afterCommitTransactionCallbacks'
1221
+ : T extends 'beforeRollbackTransaction'
1222
+ ? 'beforeRollbackTransactionCallbacks'
1223
+ : T extends 'afterRollbackTransaction'
1224
+ ? 'afterRollbackTransactionCallbacks'
921
1225
  : never;
922
1226
  if (!(prop in this)) {
923
1227
  return false;