@nymphjs/nymph 1.0.0-beta.6 → 1.0.0-beta.61

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 (64) hide show
  1. package/CHANGELOG.md +277 -0
  2. package/README.md +13 -21
  3. package/dist/Entity.d.ts +269 -7
  4. package/dist/Entity.js +431 -89
  5. package/dist/Entity.js.map +1 -1
  6. package/dist/Entity.test.js +38 -16
  7. package/dist/Entity.test.js.map +1 -1
  8. package/dist/Entity.types.d.ts +225 -19
  9. package/dist/Nymph.d.ts +423 -11
  10. package/dist/Nymph.js +649 -156
  11. package/dist/Nymph.js.map +1 -1
  12. package/dist/Nymph.types.d.ts +31 -7
  13. package/dist/Nymph.types.js +2 -1
  14. package/dist/Nymph.types.js.map +1 -1
  15. package/dist/conf/d.d.ts +26 -0
  16. package/dist/conf/defaults.js +22 -0
  17. package/dist/conf/defaults.js.map +1 -1
  18. package/dist/driver/NymphDriver.d.ts +111 -36
  19. package/dist/driver/NymphDriver.js +169 -68
  20. package/dist/driver/NymphDriver.js.map +1 -1
  21. package/dist/driver/testArtifacts.d.ts +1 -1
  22. package/dist/driver/testArtifacts.js +285 -18
  23. package/dist/driver/testArtifacts.js.map +1 -1
  24. package/dist/errors/EntityInvalidDataError.d.ts +6 -0
  25. package/dist/errors/EntityInvalidDataError.js +6 -0
  26. package/dist/errors/EntityInvalidDataError.js.map +1 -1
  27. package/dist/errors/EntityUniqueConstraintError.d.ts +3 -0
  28. package/dist/errors/EntityUniqueConstraintError.js +11 -0
  29. package/dist/errors/EntityUniqueConstraintError.js.map +1 -0
  30. package/dist/errors/InvalidStateError.d.ts +3 -0
  31. package/dist/errors/InvalidStateError.js +11 -0
  32. package/dist/errors/InvalidStateError.js.map +1 -0
  33. package/dist/errors/QueryFailedError.js.map +1 -1
  34. package/dist/errors/index.d.ts +2 -0
  35. package/dist/errors/index.js +2 -0
  36. package/dist/errors/index.js.map +1 -1
  37. package/dist/testArtifacts.d.ts +17 -5
  38. package/dist/testArtifacts.js +23 -19
  39. package/dist/testArtifacts.js.map +1 -1
  40. package/dist/testMocks.d.ts +15 -10
  41. package/dist/testMocks.js +34 -11
  42. package/dist/testMocks.js.map +1 -1
  43. package/dist/utils.d.ts +1 -1
  44. package/dist/utils.js +21 -5
  45. package/dist/utils.js.map +1 -1
  46. package/package.json +16 -14
  47. package/src/Entity.test.ts +30 -10
  48. package/src/Entity.ts +406 -135
  49. package/src/Entity.types.ts +32 -66
  50. package/src/Nymph.ts +626 -196
  51. package/src/Nymph.types.ts +97 -26
  52. package/src/conf/d.ts +8 -0
  53. package/src/conf/defaults.ts +24 -0
  54. package/src/driver/NymphDriver.ts +187 -243
  55. package/src/driver/testArtifacts.ts +327 -146
  56. package/src/errors/EntityUniqueConstraintError.ts +6 -0
  57. package/src/errors/InvalidStateError.ts +6 -0
  58. package/src/errors/index.ts +4 -0
  59. package/src/nymphJoiProps.ts +2 -2
  60. package/src/testArtifacts.ts +18 -19
  61. package/src/testMocks.ts +64 -32
  62. package/src/utils.ts +22 -8
  63. package/tsconfig.json +1 -1
  64. 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';
3
- import Entity from './Entity';
4
- import { EntityConstructor, EntityData, EntityInterface } from './Entity.types';
2
+ import type { NymphDriver } from './driver';
3
+ import Entity, { type EntityInstanceType } from './Entity';
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
  */
@@ -72,20 +91,133 @@ 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[] = [];
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
+ [];
128
+
129
+ /**
130
+ * Initialize Nymph.
131
+ *
132
+ * @param config The Nymph configuration.
133
+ * @param driver The Nymph database driver.
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.
136
+ */
137
+ public constructor(
138
+ config: Partial<Config>,
139
+ driver: NymphDriver,
140
+ tilmeld?: TilmeldInterface,
141
+ parent?: Nymph,
142
+ ) {
143
+ this.config = { ...defaults, ...config };
144
+ this.driver = driver;
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
+ }
206
+ }
207
+
208
+ this.config.debugLog('nymph', 'Nymph loaded.');
209
+
210
+ if (tilmeld != null) {
211
+ this.tilmeld = tilmeld;
212
+ }
213
+
214
+ this.driver.init(this);
215
+ this.config.debugLog('nymph', 'Nymph driver loaded.');
216
+ if (this.tilmeld) {
217
+ this.tilmeld.init(this);
218
+ this.config.debugLog('nymph', 'Tilmeld loaded.');
219
+ }
220
+ }
89
221
 
90
222
  /**
91
223
  * Add your class to this instance.
@@ -97,106 +229,93 @@ export default class Nymph {
97
229
  * Because this creates a subclass, don't use the class
98
230
  * returned from `getEntityClass` to check with `instanceof`.
99
231
  */
100
- public addEntityClass<T extends EntityConstructor>(entityClass: T): T {
232
+ public addEntityClass<T extends EntityConstructor>(EntityClass: T): T {
233
+ if (EntityClass.class in this.entityClasses) {
234
+ this.config.debugLog(
235
+ 'nymph',
236
+ `Adding duplicate class "${EntityClass.class}". This may be a mistake.`,
237
+ );
238
+ }
239
+
240
+ // Check that it doesn't have the same etype as any other class.
241
+ for (const ExistingClass of Object.values(this.entityClasses)) {
242
+ if (
243
+ EntityClass.ETYPE === ExistingClass.ETYPE &&
244
+ EntityClass.class !== EntityClass.class
245
+ ) {
246
+ this.config.debugLog(
247
+ 'nymph',
248
+ `Adding class "${EntityClass.class}" with same etype as existing class "${ExistingClass.class}". This may be a mistake.`,
249
+ );
250
+ }
251
+ }
252
+
101
253
  const nymph = this;
102
- class NymphEntity extends entityClass {
254
+ this.entityClasses[EntityClass.class] = class extends EntityClass {
103
255
  static nymph: Nymph = nymph;
104
256
 
105
257
  constructor(...args: any[]) {
106
258
  super(...args);
107
259
  }
108
- }
109
- this.entityClasses[entityClass.class] = NymphEntity;
110
- return NymphEntity;
260
+ };
261
+ return this.entityClasses[EntityClass.class] as T;
111
262
  }
112
263
 
113
264
  /**
114
265
  * Get the class that uses the specified class name.
115
266
  */
116
- public getEntityClass(className: string): EntityConstructor {
117
- if (className in this.entityClasses) {
118
- return this.entityClasses[className];
267
+ public getEntityClass(className: string): EntityConstructor;
268
+ public getEntityClass<T extends EntityConstructor>(className: T): T;
269
+ public getEntityClass<T extends EntityConstructor = EntityConstructor>(
270
+ className: T | string,
271
+ ): T | EntityConstructor {
272
+ let key: string | null = null;
273
+ if (typeof className === 'string') {
274
+ key = className;
275
+ } else {
276
+ key = className.class;
277
+ }
278
+ if (key in this.entityClasses) {
279
+ return this.entityClasses[key];
119
280
  }
120
- throw new ClassNotAvailableError('Tried to use class: ' + className);
281
+ this.config.debugError('nymph', `Tried to use missing class "${key}".`);
282
+ throw new ClassNotAvailableError(`Tried to use missing class "${key}".`);
121
283
  }
122
284
 
123
285
  /**
124
- * Initialize Nymph.
286
+ * Get the class that uses the specified etype.
125
287
  *
126
- * @param config The Nymph configuration.
127
- * @param driver The Nymph database driver.
128
- * @param tilmeld The Tilmeld user/group manager instance, if you want to use it.
288
+ * Note that it is fine, though unusual, for two classes to use the same
289
+ * etype. However, this can lead to very hard to diagnose bugs, so is
290
+ * generally discouraged.
129
291
  */
130
- public constructor(
131
- config: Partial<Config>,
132
- driver: NymphDriver,
133
- tilmeld?: TilmeldInterface
134
- ) {
135
- this.config = { ...defaults, ...config };
136
- this.driver = driver;
137
-
138
- this.addEntityClass(Entity);
139
- this.Entity = this.getEntityClass('Entity') as typeof Entity;
140
-
141
- if (typeof tilmeld !== 'undefined') {
142
- this.tilmeld = tilmeld;
143
- }
144
-
145
- this.driver.init(this);
146
- if (this.tilmeld) {
147
- this.tilmeld.init(this);
292
+ public getEntityClassByEtype(etype: string): EntityConstructor {
293
+ for (const EntityClass of Object.values(this.entityClasses)) {
294
+ if (EntityClass.ETYPE === etype) {
295
+ return EntityClass;
296
+ }
148
297
  }
298
+ this.config.debugError(
299
+ 'nymph',
300
+ `Tried to use missing class by etype "${etype}".`,
301
+ );
302
+ throw new ClassNotAvailableError(
303
+ `Tried to use missing class by etype "${etype}".`,
304
+ );
149
305
  }
150
306
 
151
307
  /**
152
- * Get a clone of this instance with duplicate classes and event listeners.
308
+ * Get a clone of this instance with cloned classes and event listeners.
153
309
  *
154
310
  * @returns A clone of this instance.
155
311
  */
156
312
  public clone() {
157
- const nymph = new Nymph(this.config, this.driver, this.tilmeld?.clone());
158
- for (const name in this.entityClasses) {
159
- if (name === 'Entity' || (this.entityClasses[name] as any).skipOnClone) {
160
- continue;
161
- }
162
- nymph.addEntityClass(this.entityClasses[name]);
163
- }
164
-
165
- const events = [
166
- 'connect',
167
- 'disconnect',
168
- 'query',
169
- 'beforeGetEntity',
170
- 'beforeGetEntities',
171
- 'beforeSaveEntity',
172
- 'afterSaveEntity',
173
- 'beforeDeleteEntity',
174
- 'afterDeleteEntity',
175
- 'beforeDeleteEntityByID',
176
- 'afterDeleteEntityByID',
177
- 'beforeNewUID',
178
- 'afterNewUID',
179
- 'beforeSetUID',
180
- 'afterSetUID',
181
- 'beforeRenameUID',
182
- 'afterRenameUID',
183
- 'beforeDeleteUID',
184
- 'afterDeleteUID',
185
- ];
186
-
187
- for (let event of events) {
188
- const prop = event + 'Callbacks';
189
- // @ts-ignore: The callback should be the right type here.
190
- const callbacks = this[prop];
191
- for (let callback of callbacks) {
192
- if (callback.skipOnClone) {
193
- continue;
194
- }
195
- nymph.on(event as NymphEventType, callback);
196
- }
197
- }
198
-
199
- return nymph;
313
+ return new Nymph(
314
+ this.config,
315
+ this.driver.clone(),
316
+ this.tilmeld?.clone(),
317
+ this,
318
+ );
200
319
  }
201
320
 
202
321
  /**
@@ -205,13 +324,19 @@ export default class Nymph {
205
324
  * @returns Whether the instance is connected to the database.
206
325
  */
207
326
  public async connect(): Promise<boolean> {
208
- const result = this.driver.connect();
209
- for (let callback of this.connectCallbacks) {
210
- if (callback) {
211
- await callback(this, result);
327
+ try {
328
+ const result = this.driver.connect();
329
+ for (let callback of this.connectCallbacks) {
330
+ if (callback) {
331
+ await callback(this, result);
332
+ }
212
333
  }
334
+ this.config.debugLog('nymph', 'Driver connected.');
335
+ return await result;
336
+ } catch (e: any) {
337
+ this.config.debugError('nymph', `Failed to connect: ${e}`);
338
+ throw e;
213
339
  }
214
- return await result;
215
340
  }
216
341
 
217
342
  /**
@@ -220,13 +345,19 @@ export default class Nymph {
220
345
  * @returns Whether the instance is connected to the database.
221
346
  */
222
347
  public async disconnect(): Promise<boolean> {
223
- const result = this.driver.disconnect();
224
- for (let callback of this.disconnectCallbacks) {
225
- if (callback) {
226
- await callback(this, result);
348
+ try {
349
+ const result = this.driver.disconnect();
350
+ for (let callback of this.disconnectCallbacks) {
351
+ if (callback) {
352
+ await callback(this, result);
353
+ }
227
354
  }
355
+ this.config.debugLog('nymph', 'Driver disconnected.');
356
+ return await result;
357
+ } catch (e: any) {
358
+ this.config.debugError('nymph', `Failed to disconnect: ${e}`);
359
+ throw e;
228
360
  }
229
- return await result;
230
361
  }
231
362
 
232
363
  /**
@@ -250,28 +381,83 @@ export default class Nymph {
250
381
  * Transactions will nest as long as every name is unique. Internally, Nymph
251
382
  * uses names prefixed with "nymph-".
252
383
  *
253
- * @returns True on success, false on failure.
384
+ * @returns A new instance of Nymph that should be used for the transaction.
254
385
  */
255
386
  public async startTransaction(name: string): Promise<Nymph> {
256
- return await this.driver.startTransaction(name);
387
+ try {
388
+ for (let callback of this.beforeStartTransactionCallbacks) {
389
+ if (callback) {
390
+ await callback(this, name);
391
+ }
392
+ }
393
+ this.config.debugLog('nymph', `Starting transaction "${name}".`);
394
+ const result = await this.driver.startTransaction(name);
395
+ for (let callback of this.afterStartTransactionCallbacks) {
396
+ if (callback) {
397
+ await callback(this, name, result);
398
+ }
399
+ }
400
+ return result;
401
+ } catch (e: any) {
402
+ this.config.debugError('nymph', `Failed to start transaction: ${e}`);
403
+ throw e;
404
+ }
257
405
  }
258
406
 
259
407
  /**
260
408
  * Commit the named transaction.
261
409
  *
410
+ * After this is called, the transaction instance should be discarded.
411
+ *
262
412
  * @returns True on success, false on failure.
263
413
  */
264
414
  public async commit(name: string): Promise<boolean> {
265
- return await this.driver.commit(name);
415
+ try {
416
+ for (let callback of this.beforeCommitTransactionCallbacks) {
417
+ if (callback) {
418
+ await callback(this, name);
419
+ }
420
+ }
421
+ this.config.debugLog('nymph', `Committing transaction "${name}".`);
422
+ const result = await this.driver.commit(name);
423
+ for (let callback of this.afterCommitTransactionCallbacks) {
424
+ if (callback) {
425
+ await callback(this, name, result);
426
+ }
427
+ }
428
+ return result;
429
+ } catch (e: any) {
430
+ this.config.debugError('nymph', `Failed to commit transaction: ${e}`);
431
+ throw e;
432
+ }
266
433
  }
267
434
 
268
435
  /**
269
436
  * Rollback the named transaction.
270
437
  *
438
+ * After this is called, the transaction instance should be discarded.
439
+ *
271
440
  * @returns True on success, false on failure.
272
441
  */
273
442
  public async rollback(name: string): Promise<boolean> {
274
- return await this.driver.rollback(name);
443
+ try {
444
+ for (let callback of this.beforeRollbackTransactionCallbacks) {
445
+ if (callback) {
446
+ await callback(this, name);
447
+ }
448
+ }
449
+ this.config.debugLog('nymph', `Rolling back transaction "${name}".`);
450
+ const result = await this.driver.rollback(name);
451
+ for (let callback of this.afterRollbackTransactionCallbacks) {
452
+ if (callback) {
453
+ await callback(this, name, result);
454
+ }
455
+ }
456
+ return result;
457
+ } catch (e: any) {
458
+ this.config.debugError('nymph', `Failed to roll back transaction: ${e}`);
459
+ throw e;
460
+ }
275
461
  }
276
462
 
277
463
  /**
@@ -305,18 +491,33 @@ export default class Nymph {
305
491
  * @returns The UID's new value, or null on failure.
306
492
  */
307
493
  public async newUID(name: string): Promise<number | null> {
308
- for (let callback of this.beforeNewUIDCallbacks) {
309
- if (callback) {
310
- await callback(this, name);
494
+ try {
495
+ for (let callback of this.beforeNewUIDCallbacks) {
496
+ if (callback) {
497
+ await callback(this, name);
498
+ }
311
499
  }
312
- }
313
- const result = this.driver.newUID(name);
314
- for (let callback of this.afterNewUIDCallbacks) {
315
- if (callback) {
316
- await callback(this, result);
500
+ let result: Promise<number | null>;
501
+ try {
502
+ result = this.driver.newUID(name);
503
+ } catch (e: any) {
504
+ for (let callback of this.failedNewUIDCallbacks) {
505
+ if (callback) {
506
+ await callback(this, e);
507
+ }
508
+ }
509
+ throw e;
510
+ }
511
+ for (let callback of this.afterNewUIDCallbacks) {
512
+ if (callback) {
513
+ await callback(this, result);
514
+ }
317
515
  }
516
+ return await result;
517
+ } catch (e: any) {
518
+ this.config.debugError('nymph', `Failed to create UID "${name}": ${e}`);
519
+ throw e;
318
520
  }
319
- return await result;
320
521
  }
321
522
 
322
523
  /**
@@ -325,7 +526,12 @@ export default class Nymph {
325
526
  * @returns The UID's value, or null on failure and if it doesn't exist.
326
527
  */
327
528
  public async getUID(name: string): Promise<number | null> {
328
- return await this.driver.getUID(name);
529
+ try {
530
+ return await this.driver.getUID(name);
531
+ } catch (e: any) {
532
+ this.config.debugError('nymph', `Failed to get UID "${name}": ${e}`);
533
+ throw e;
534
+ }
329
535
  }
330
536
 
331
537
  /**
@@ -336,18 +542,33 @@ export default class Nymph {
336
542
  * @returns True on success, false on failure.
337
543
  */
338
544
  public async setUID(name: string, value: number): Promise<boolean> {
339
- for (let callback of this.beforeSetUIDCallbacks) {
340
- if (callback) {
341
- await callback(this, name, value);
545
+ try {
546
+ for (let callback of this.beforeSetUIDCallbacks) {
547
+ if (callback) {
548
+ await callback(this, name, value);
549
+ }
342
550
  }
343
- }
344
- const result = this.driver.setUID(name, value);
345
- for (let callback of this.afterSetUIDCallbacks) {
346
- if (callback) {
347
- await callback(this, result);
551
+ let result: Promise<boolean>;
552
+ try {
553
+ result = this.driver.setUID(name, value);
554
+ } catch (e: any) {
555
+ for (let callback of this.failedSetUIDCallbacks) {
556
+ if (callback) {
557
+ await callback(this, e);
558
+ }
559
+ }
560
+ throw e;
348
561
  }
562
+ for (let callback of this.afterSetUIDCallbacks) {
563
+ if (callback) {
564
+ await callback(this, result);
565
+ }
566
+ }
567
+ return await result;
568
+ } catch (e: any) {
569
+ this.config.debugError('nymph', `Failed to set UID "${name}": ${e}`);
570
+ throw e;
349
571
  }
350
- return await result;
351
572
  }
352
573
 
353
574
  /**
@@ -357,18 +578,33 @@ export default class Nymph {
357
578
  * @returns True on success, false on failure.
358
579
  */
359
580
  public async deleteUID(name: string): Promise<boolean> {
360
- for (let callback of this.beforeDeleteUIDCallbacks) {
361
- if (callback) {
362
- await callback(this, name);
581
+ try {
582
+ for (let callback of this.beforeDeleteUIDCallbacks) {
583
+ if (callback) {
584
+ await callback(this, name);
585
+ }
363
586
  }
364
- }
365
- const result = this.driver.deleteUID(name);
366
- for (let callback of this.afterDeleteUIDCallbacks) {
367
- if (callback) {
368
- await callback(this, result);
587
+ let result: Promise<boolean>;
588
+ try {
589
+ result = this.driver.deleteUID(name);
590
+ } catch (e: any) {
591
+ for (let callback of this.failedDeleteUIDCallbacks) {
592
+ if (callback) {
593
+ await callback(this, e);
594
+ }
595
+ }
596
+ throw e;
597
+ }
598
+ for (let callback of this.afterDeleteUIDCallbacks) {
599
+ if (callback) {
600
+ await callback(this, result);
601
+ }
369
602
  }
603
+ return await result;
604
+ } catch (e: any) {
605
+ this.config.debugError('nymph', `Failed to delete UID "${name}": ${e}`);
606
+ throw e;
370
607
  }
371
- return await result;
372
608
  }
373
609
 
374
610
  /**
@@ -379,18 +615,36 @@ export default class Nymph {
379
615
  * @returns True on success, false on failure.
380
616
  */
381
617
  public async renameUID(oldName: string, newName: string): Promise<boolean> {
382
- for (let callback of this.beforeRenameUIDCallbacks) {
383
- if (callback) {
384
- await callback(this, oldName, newName);
618
+ try {
619
+ for (let callback of this.beforeRenameUIDCallbacks) {
620
+ if (callback) {
621
+ await callback(this, oldName, newName);
622
+ }
385
623
  }
386
- }
387
- const result = this.driver.renameUID(oldName, newName);
388
- for (let callback of this.afterRenameUIDCallbacks) {
389
- if (callback) {
390
- await callback(this, result);
624
+ let result: Promise<boolean>;
625
+ try {
626
+ result = this.driver.renameUID(oldName, newName);
627
+ } catch (e: any) {
628
+ for (let callback of this.failedRenameUIDCallbacks) {
629
+ if (callback) {
630
+ await callback(this, e);
631
+ }
632
+ }
633
+ throw e;
391
634
  }
635
+ for (let callback of this.afterRenameUIDCallbacks) {
636
+ if (callback) {
637
+ await callback(this, result);
638
+ }
639
+ }
640
+ return await result;
641
+ } catch (e: any) {
642
+ this.config.debugError(
643
+ 'nymph',
644
+ `Failed to rename UID "${oldName}" to "${newName}": ${e}`,
645
+ );
646
+ throw e;
392
647
  }
393
- return await result;
394
648
  }
395
649
 
396
650
  /**
@@ -405,18 +659,33 @@ export default class Nymph {
405
659
  * @returns True on success, false on failure.
406
660
  */
407
661
  public async saveEntity(entity: EntityInterface): Promise<boolean> {
408
- for (let callback of this.beforeSaveEntityCallbacks) {
409
- if (callback) {
410
- await callback(this, entity);
662
+ try {
663
+ for (let callback of this.beforeSaveEntityCallbacks) {
664
+ if (callback) {
665
+ await callback(this, entity);
666
+ }
411
667
  }
412
- }
413
- const result = this.driver.saveEntity(entity);
414
- for (let callback of this.afterSaveEntityCallbacks) {
415
- if (callback) {
416
- await callback(this, result);
668
+ let result: Promise<boolean>;
669
+ try {
670
+ result = this.driver.saveEntity(entity);
671
+ } catch (e: any) {
672
+ for (let callback of this.failedSaveEntityCallbacks) {
673
+ if (callback) {
674
+ await callback(this, e);
675
+ }
676
+ }
677
+ throw e;
417
678
  }
679
+ for (let callback of this.afterSaveEntityCallbacks) {
680
+ if (callback) {
681
+ await callback(this, result);
682
+ }
683
+ }
684
+ return await result;
685
+ } catch (e: any) {
686
+ this.config.debugError('nymph', `Failed to save entity: ${e}`);
687
+ throw e;
418
688
  }
419
- return await result;
420
689
  }
421
690
 
422
691
  /**
@@ -429,8 +698,10 @@ export default class Nymph {
429
698
  * - offset - The offset from the oldest matching entity to start retrieving.
430
699
  * - reverse - If true, entities will be retrieved from newest to oldest.
431
700
  * Therefore, offset will be from the newest entity.
432
- * - sort - How to sort the entities. Accepts "cdate" or "mdate". Defaults to
433
- * "cdate".
701
+ * - sort - How to sort the entities. Accepts "cdate", "mdate", or the name of
702
+ * a top-level property. The method of sorting properties other than cdate
703
+ * and mdate is driver dependent. The only hard rule is that numbers should
704
+ * be sorted numerically (2 before 10). Defaults to "cdate".
434
705
  * - return - What to return. "entity", "guid", or "count". Defaults to
435
706
  * "entity".
436
707
  * - source - Will be 'client' if the query came from a REST call.
@@ -589,17 +860,22 @@ export default class Nymph {
589
860
  public async getEntities<T extends EntityConstructor = EntityConstructor>(
590
861
  options?: Options<T>,
591
862
  ...selectors: Selector[]
592
- ): Promise<ReturnType<T['factorySync']>[]>;
863
+ ): Promise<EntityInstanceType<T>[]>;
593
864
  public async getEntities<T extends EntityConstructor = EntityConstructor>(
594
865
  options: Options<T> = {},
595
866
  ...selectors: Selector[]
596
- ): Promise<ReturnType<T['factorySync']>[] | string[] | number> {
597
- for (let callback of this.beforeGetEntitiesCallbacks) {
598
- if (callback) {
599
- await callback(this, options, selectors);
867
+ ): Promise<EntityInstanceType<T>[] | string[] | number> {
868
+ try {
869
+ for (let callback of this.beforeGetEntitiesCallbacks) {
870
+ if (callback) {
871
+ await callback(this, options, selectors);
872
+ }
600
873
  }
874
+ return await this.driver.getEntities(options, ...selectors);
875
+ } catch (e: any) {
876
+ this.config.debugError('nymph', `Failed to get entities: ${e}`);
877
+ throw e;
601
878
  }
602
- return await this.driver.getEntities(options, ...selectors);
603
879
  }
604
880
 
605
881
  /**
@@ -626,40 +902,45 @@ export default class Nymph {
626
902
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
627
903
  options: Options<T>,
628
904
  ...selectors: Selector[]
629
- ): Promise<ReturnType<T['factorySync']> | null>;
905
+ ): Promise<EntityInstanceType<T> | null>;
630
906
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
631
907
  options: Options<T> & { return: 'guid' },
632
- guid: string
908
+ guid: string,
633
909
  ): Promise<string | null>;
634
910
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
635
911
  options: Options<T>,
636
- guid: string
637
- ): Promise<ReturnType<T['factorySync']> | null>;
912
+ guid: string,
913
+ ): Promise<EntityInstanceType<T> | null>;
638
914
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
639
915
  options: Options<T> = {},
640
916
  ...selectors: Selector[] | string[]
641
- ): Promise<ReturnType<T['factorySync']> | string | number | null> {
642
- // Set up options and selectors.
643
- if (typeof selectors[0] === 'string') {
644
- selectors = [{ type: '&', guid: selectors[0] }];
645
- }
646
- options.limit = 1;
647
- for (let callback of this.beforeGetEntityCallbacks) {
648
- if (callback) {
649
- await callback(this, options, selectors as Selector[]);
917
+ ): Promise<EntityInstanceType<T> | string | number | null> {
918
+ try {
919
+ // Set up options and selectors.
920
+ if (typeof selectors[0] === 'string') {
921
+ selectors = [{ type: '&', guid: selectors[0] }];
650
922
  }
923
+ options.limit = 1;
924
+ for (let callback of this.beforeGetEntityCallbacks) {
925
+ if (callback) {
926
+ await callback(this, options, selectors as Selector[]);
927
+ }
928
+ }
929
+ const entities = await this.driver.getEntities(
930
+ options,
931
+ ...(selectors as Selector[]),
932
+ );
933
+ if (options.return === 'count') {
934
+ return entities as unknown as number;
935
+ }
936
+ if (!entities || !entities.length) {
937
+ return null;
938
+ }
939
+ return entities[0];
940
+ } catch (e: any) {
941
+ this.config.debugError('nymph', `Failed to get entity: ${e}`);
942
+ throw e;
651
943
  }
652
- const entities = await this.driver.getEntities(
653
- options,
654
- ...(selectors as Selector[])
655
- );
656
- if (options.return === 'count') {
657
- return entities as unknown as number;
658
- }
659
- if (!entities || !entities.length) {
660
- return null;
661
- }
662
- return entities[0];
663
944
  }
664
945
 
665
946
  /**
@@ -669,18 +950,33 @@ export default class Nymph {
669
950
  * @returns True on success, false on failure.
670
951
  */
671
952
  public async deleteEntity(entity: EntityInterface): Promise<boolean> {
672
- for (let callback of this.beforeDeleteEntityCallbacks) {
673
- if (callback) {
674
- await callback(this, entity);
953
+ try {
954
+ for (let callback of this.beforeDeleteEntityCallbacks) {
955
+ if (callback) {
956
+ await callback(this, entity);
957
+ }
675
958
  }
676
- }
677
- const result = this.driver.deleteEntity(entity);
678
- for (let callback of this.afterDeleteEntityCallbacks) {
679
- if (callback) {
680
- await callback(this, result);
959
+ let result: Promise<boolean>;
960
+ try {
961
+ result = this.driver.deleteEntity(entity);
962
+ } catch (e: any) {
963
+ for (let callback of this.failedDeleteEntityCallbacks) {
964
+ if (callback) {
965
+ await callback(this, e);
966
+ }
967
+ }
968
+ throw e;
969
+ }
970
+ for (let callback of this.afterDeleteEntityCallbacks) {
971
+ if (callback) {
972
+ await callback(this, result);
973
+ }
681
974
  }
975
+ return await result;
976
+ } catch (e: any) {
977
+ this.config.debugError('nymph', `Failed to delete entity: ${e}`);
978
+ throw e;
682
979
  }
683
- return await result;
684
980
  }
685
981
 
686
982
  /**
@@ -692,20 +988,35 @@ export default class Nymph {
692
988
  */
693
989
  public async deleteEntityByID(
694
990
  guid: string,
695
- className?: string
991
+ className?: string,
696
992
  ): Promise<boolean> {
697
- for (let callback of this.beforeDeleteEntityByIDCallbacks) {
698
- if (callback) {
699
- await callback(this, guid, className);
993
+ try {
994
+ for (let callback of this.beforeDeleteEntityByIDCallbacks) {
995
+ if (callback) {
996
+ await callback(this, guid, className);
997
+ }
700
998
  }
701
- }
702
- const result = this.driver.deleteEntityByID(guid, className);
703
- for (let callback of this.afterDeleteEntityByIDCallbacks) {
704
- if (callback) {
705
- await callback(this, result);
999
+ let result: Promise<boolean>;
1000
+ try {
1001
+ result = this.driver.deleteEntityByID(guid, className);
1002
+ } catch (e: any) {
1003
+ for (let callback of this.failedDeleteEntityByIDCallbacks) {
1004
+ if (callback) {
1005
+ await callback(this, e);
1006
+ }
1007
+ }
1008
+ throw e;
706
1009
  }
1010
+ for (let callback of this.afterDeleteEntityByIDCallbacks) {
1011
+ if (callback) {
1012
+ await callback(this, result);
1013
+ }
1014
+ }
1015
+ return await result;
1016
+ } catch (e: any) {
1017
+ this.config.debugError('nymph', `Failed to delete entity by ID: ${e}`);
1018
+ throw e;
707
1019
  }
708
- return await result;
709
1020
  }
710
1021
 
711
1022
  /**
@@ -730,7 +1041,7 @@ export default class Nymph {
730
1041
  * # brackets ([]).
731
1042
  * # Properties are stored like this:
732
1043
  * # propname=JSON.stringify(value)
733
- * abilities=["system/all"]
1044
+ * abilities=["system/admin"]
734
1045
  * groups=[]
735
1046
  * inheritAbilities=false
736
1047
  * name="admin"
@@ -745,7 +1056,12 @@ export default class Nymph {
745
1056
  * @returns True on success, false on failure.
746
1057
  */
747
1058
  public async export(filename: string): Promise<boolean> {
748
- return await this.driver.export(filename);
1059
+ try {
1060
+ return await this.driver.export(filename);
1061
+ } catch (e: any) {
1062
+ this.config.debugError('nymph', `Failed to export: ${e}`);
1063
+ throw e;
1064
+ }
749
1065
  }
750
1066
 
751
1067
  /**
@@ -754,7 +1070,12 @@ export default class Nymph {
754
1070
  * @returns True on success, false on failure.
755
1071
  */
756
1072
  public async exportPrint(): Promise<boolean> {
757
- return await this.driver.exportPrint();
1073
+ try {
1074
+ return await this.driver.exportPrint();
1075
+ } catch (e: any) {
1076
+ this.config.debugError('nymph', `Failed to export: ${e}`);
1077
+ throw e;
1078
+ }
758
1079
  }
759
1080
 
760
1081
  /**
@@ -764,7 +1085,12 @@ export default class Nymph {
764
1085
  * @returns True on success, false on failure.
765
1086
  */
766
1087
  public async import(filename: string): Promise<boolean> {
767
- return await this.driver.import(filename);
1088
+ try {
1089
+ return await this.driver.import(filename);
1090
+ } catch (e: any) {
1091
+ this.config.debugError('nymph', `Failed to import: ${e}`);
1092
+ throw e;
1093
+ }
768
1094
  }
769
1095
 
770
1096
  public on<T extends NymphEventType>(
@@ -783,31 +1109,57 @@ export default class Nymph {
783
1109
  ? NymphBeforeSaveEntityCallback
784
1110
  : T extends 'afterSaveEntity'
785
1111
  ? NymphAfterSaveEntityCallback
1112
+ : T extends 'failedSaveEntity'
1113
+ ? NymphFailedSaveEntityCallback
786
1114
  : T extends 'beforeDeleteEntity'
787
1115
  ? NymphBeforeDeleteEntityCallback
788
1116
  : T extends 'afterDeleteEntity'
789
1117
  ? NymphAfterDeleteEntityCallback
1118
+ : T extends 'failedDeleteEntity'
1119
+ ? NymphFailedDeleteEntityCallback
790
1120
  : T extends 'beforeDeleteEntityByID'
791
1121
  ? NymphBeforeDeleteEntityByIDCallback
792
1122
  : T extends 'afterDeleteEntityByID'
793
1123
  ? NymphAfterDeleteEntityByIDCallback
1124
+ : T extends 'failedDeleteEntityByID'
1125
+ ? NymphFailedDeleteEntityByIDCallback
794
1126
  : T extends 'beforeNewUID'
795
1127
  ? NymphBeforeNewUIDCallback
796
1128
  : T extends 'afterNewUID'
797
1129
  ? NymphAfterNewUIDCallback
1130
+ : T extends 'failedNewUID'
1131
+ ? NymphFailedNewUIDCallback
798
1132
  : T extends 'beforeSetUID'
799
1133
  ? NymphBeforeSetUIDCallback
800
1134
  : T extends 'afterSetUID'
801
1135
  ? NymphAfterSetUIDCallback
1136
+ : T extends 'failedSetUID'
1137
+ ? NymphFailedSetUIDCallback
802
1138
  : T extends 'beforeRenameUID'
803
1139
  ? NymphBeforeRenameUIDCallback
804
1140
  : T extends 'afterRenameUID'
805
1141
  ? NymphAfterRenameUIDCallback
1142
+ : T extends 'failedRenameUID'
1143
+ ? NymphFailedRenameUIDCallback
806
1144
  : T extends 'beforeDeleteUID'
807
1145
  ? NymphBeforeDeleteUIDCallback
808
1146
  : T extends 'afterDeleteUID'
809
1147
  ? NymphAfterDeleteUIDCallback
810
- : never
1148
+ : T extends 'failedDeleteUID'
1149
+ ? NymphFailedDeleteUIDCallback
1150
+ : T extends 'beforeStartTransaction'
1151
+ ? NymphBeforeStartTransactionCallback
1152
+ : T extends 'afterStartTransaction'
1153
+ ? NymphAfterStartTransactionCallback
1154
+ : T extends 'beforeCommitTransaction'
1155
+ ? NymphBeforeCommitTransactionCallback
1156
+ : T extends 'afterCommitTransaction'
1157
+ ? NymphAfterCommitTransactionCallback
1158
+ : T extends 'beforeRollbackTransaction'
1159
+ ? NymphBeforeRollbackTransactionCallback
1160
+ : T extends 'afterRollbackTransaction'
1161
+ ? NymphAfterRollbackTransactionCallback
1162
+ : never,
811
1163
  ) {
812
1164
  const prop = (event + 'Callbacks') as T extends 'connect'
813
1165
  ? 'connectCallbacks'
@@ -823,30 +1175,56 @@ export default class Nymph {
823
1175
  ? 'beforeSaveEntityCallbacks'
824
1176
  : T extends 'afterSaveEntity'
825
1177
  ? 'afterSaveEntityCallbacks'
1178
+ : T extends 'failedSaveEntity'
1179
+ ? 'failedSaveEntityCallbacks'
826
1180
  : T extends 'beforeDeleteEntity'
827
1181
  ? 'beforeDeleteEntityCallbacks'
828
1182
  : T extends 'afterDeleteEntity'
829
1183
  ? 'afterDeleteEntityCallbacks'
1184
+ : T extends 'failedDeleteEntity'
1185
+ ? 'failedDeleteEntityCallbacks'
830
1186
  : T extends 'beforeDeleteEntityByID'
831
1187
  ? 'beforeDeleteEntityByIDCallbacks'
832
1188
  : T extends 'afterDeleteEntityByID'
833
1189
  ? 'afterDeleteEntityByIDCallbacks'
1190
+ : T extends 'failedDeleteEntityByID'
1191
+ ? 'failedDeleteEntityByIDCallbacks'
834
1192
  : T extends 'beforeNewUID'
835
1193
  ? 'beforeNewUIDCallbacks'
836
1194
  : T extends 'afterNewUID'
837
1195
  ? 'afterNewUIDCallbacks'
1196
+ : T extends 'failedNewUID'
1197
+ ? 'failedNewUIDCallbacks'
838
1198
  : T extends 'beforeSetUID'
839
1199
  ? 'beforeSetUIDCallbacks'
840
1200
  : T extends 'afterSetUID'
841
1201
  ? 'afterSetUIDCallbacks'
1202
+ : T extends 'failedSetUID'
1203
+ ? 'failedSetUIDCallbacks'
842
1204
  : T extends 'beforeRenameUID'
843
1205
  ? 'beforeRenameUIDCallbacks'
844
1206
  : T extends 'afterRenameUID'
845
1207
  ? 'afterRenameUIDCallbacks'
1208
+ : T extends 'failedRenameUID'
1209
+ ? 'failedRenameUIDCallbacks'
846
1210
  : T extends 'beforeDeleteUID'
847
1211
  ? 'beforeDeleteUIDCallbacks'
848
1212
  : T extends 'afterDeleteUID'
849
1213
  ? 'afterDeleteUIDCallbacks'
1214
+ : T extends 'failedDeleteUID'
1215
+ ? 'failedDeleteUIDCallbacks'
1216
+ : T extends 'beforeStartTransaction'
1217
+ ? 'beforeStartTransactionCallbacks'
1218
+ : T extends 'afterStartTransaction'
1219
+ ? 'afterStartTransactionCallbacks'
1220
+ : T extends 'beforeCommitTransaction'
1221
+ ? 'beforeCommitTransactionCallbacks'
1222
+ : T extends 'afterCommitTransaction'
1223
+ ? 'afterCommitTransactionCallbacks'
1224
+ : T extends 'beforeRollbackTransaction'
1225
+ ? 'beforeRollbackTransactionCallbacks'
1226
+ : T extends 'afterRollbackTransaction'
1227
+ ? 'afterRollbackTransactionCallbacks'
850
1228
  : never;
851
1229
  if (!(prop in this)) {
852
1230
  throw new Error('Invalid event type.');
@@ -872,31 +1250,57 @@ export default class Nymph {
872
1250
  ? NymphBeforeSaveEntityCallback
873
1251
  : T extends 'afterSaveEntity'
874
1252
  ? NymphAfterSaveEntityCallback
1253
+ : T extends 'failedSaveEntity'
1254
+ ? NymphFailedSaveEntityCallback
875
1255
  : T extends 'beforeDeleteEntity'
876
1256
  ? NymphBeforeDeleteEntityCallback
877
1257
  : T extends 'afterDeleteEntity'
878
1258
  ? NymphAfterDeleteEntityCallback
1259
+ : T extends 'failedDeleteEntity'
1260
+ ? NymphFailedDeleteEntityCallback
879
1261
  : T extends 'beforeDeleteEntityByID'
880
1262
  ? NymphBeforeDeleteEntityByIDCallback
881
1263
  : T extends 'afterDeleteEntityByID'
882
1264
  ? NymphAfterDeleteEntityByIDCallback
1265
+ : T extends 'failedDeleteEntityByID'
1266
+ ? NymphFailedDeleteEntityByIDCallback
883
1267
  : T extends 'beforeNewUID'
884
1268
  ? NymphBeforeNewUIDCallback
885
1269
  : T extends 'afterNewUID'
886
1270
  ? NymphAfterNewUIDCallback
1271
+ : T extends 'failedNewUID'
1272
+ ? NymphFailedNewUIDCallback
887
1273
  : T extends 'beforeSetUID'
888
1274
  ? NymphBeforeSetUIDCallback
889
1275
  : T extends 'afterSetUID'
890
1276
  ? NymphAfterSetUIDCallback
1277
+ : T extends 'failedSetUID'
1278
+ ? NymphFailedSetUIDCallback
891
1279
  : T extends 'beforeRenameUID'
892
1280
  ? NymphBeforeRenameUIDCallback
893
1281
  : T extends 'afterRenameUID'
894
1282
  ? NymphAfterRenameUIDCallback
1283
+ : T extends 'failedRenameUID'
1284
+ ? NymphFailedRenameUIDCallback
895
1285
  : T extends 'beforeDeleteUID'
896
1286
  ? NymphBeforeDeleteUIDCallback
897
1287
  : T extends 'afterDeleteUID'
898
1288
  ? NymphAfterDeleteUIDCallback
899
- : never
1289
+ : T extends 'failedDeleteUID'
1290
+ ? NymphFailedDeleteUIDCallback
1291
+ : T extends 'beforeStartTransaction'
1292
+ ? NymphBeforeStartTransactionCallback
1293
+ : T extends 'afterStartTransaction'
1294
+ ? NymphAfterStartTransactionCallback
1295
+ : T extends 'beforeCommitTransaction'
1296
+ ? NymphBeforeCommitTransactionCallback
1297
+ : T extends 'afterCommitTransaction'
1298
+ ? NymphAfterCommitTransactionCallback
1299
+ : T extends 'beforeRollbackTransaction'
1300
+ ? NymphBeforeRollbackTransactionCallback
1301
+ : T extends 'afterRollbackTransaction'
1302
+ ? NymphAfterRollbackTransactionCallback
1303
+ : never,
900
1304
  ) {
901
1305
  const prop = (event + 'Callbacks') as T extends 'connect'
902
1306
  ? 'connectCallbacks'
@@ -912,30 +1316,56 @@ export default class Nymph {
912
1316
  ? 'beforeGetEntitiesCallbacks'
913
1317
  : T extends 'afterSaveEntity'
914
1318
  ? 'afterSaveEntityCallbacks'
1319
+ : T extends 'failedSaveEntity'
1320
+ ? 'failedSaveEntityCallbacks'
915
1321
  : T extends 'beforeDeleteEntity'
916
1322
  ? 'beforeDeleteEntityCallbacks'
917
1323
  : T extends 'afterDeleteEntity'
918
1324
  ? 'afterDeleteEntityCallbacks'
1325
+ : T extends 'failedDeleteEntity'
1326
+ ? 'failedDeleteEntityCallbacks'
919
1327
  : T extends 'beforeDeleteEntityByID'
920
1328
  ? 'beforeDeleteEntityByIDCallbacks'
921
1329
  : T extends 'afterDeleteEntityByID'
922
1330
  ? 'afterDeleteEntityByIDCallbacks'
1331
+ : T extends 'failedDeleteEntityByID'
1332
+ ? 'failedDeleteEntityByIDCallbacks'
923
1333
  : T extends 'beforeNewUID'
924
1334
  ? 'beforeNewUIDCallbacks'
925
1335
  : T extends 'afterNewUID'
926
1336
  ? 'afterNewUIDCallbacks'
1337
+ : T extends 'failedNewUID'
1338
+ ? 'failedNewUIDCallbacks'
927
1339
  : T extends 'beforeSetUID'
928
1340
  ? 'beforeSetUIDCallbacks'
929
1341
  : T extends 'afterSetUID'
930
1342
  ? 'afterSetUIDCallbacks'
1343
+ : T extends 'failedSetUID'
1344
+ ? 'failedSetUIDCallbacks'
931
1345
  : T extends 'beforeRenameUID'
932
1346
  ? 'beforeRenameUIDCallbacks'
933
1347
  : T extends 'afterRenameUID'
934
1348
  ? 'afterRenameUIDCallbacks'
1349
+ : T extends 'failedRenameUID'
1350
+ ? 'failedRenameUIDCallbacks'
935
1351
  : T extends 'beforeDeleteUID'
936
1352
  ? 'beforeDeleteUIDCallbacks'
937
1353
  : T extends 'afterDeleteUID'
938
1354
  ? 'afterDeleteUIDCallbacks'
1355
+ : T extends 'failedDeleteUID'
1356
+ ? 'failedDeleteUIDCallbacks'
1357
+ : T extends 'beforeStartTransaction'
1358
+ ? 'beforeStartTransactionCallbacks'
1359
+ : T extends 'afterStartTransaction'
1360
+ ? 'afterStartTransactionCallbacks'
1361
+ : T extends 'beforeCommitTransaction'
1362
+ ? 'beforeCommitTransactionCallbacks'
1363
+ : T extends 'afterCommitTransaction'
1364
+ ? 'afterCommitTransactionCallbacks'
1365
+ : T extends 'beforeRollbackTransaction'
1366
+ ? 'beforeRollbackTransactionCallbacks'
1367
+ : T extends 'afterRollbackTransaction'
1368
+ ? 'afterRollbackTransactionCallbacks'
939
1369
  : never;
940
1370
  if (!(prop in this)) {
941
1371
  return false;