@nymphjs/nymph 1.0.0-beta.7 → 1.0.0-beta.71

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 (65) hide show
  1. package/CHANGELOG.md +324 -0
  2. package/README.md +13 -21
  3. package/dist/Entity.d.ts +269 -7
  4. package/dist/Entity.js +491 -105
  5. package/dist/Entity.js.map +1 -1
  6. package/dist/Entity.test.js +39 -17
  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 +685 -176
  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 +129 -38
  19. package/dist/driver/NymphDriver.js +264 -131
  20. package/dist/driver/NymphDriver.js.map +1 -1
  21. package/dist/driver/testArtifacts.d.ts +1 -1
  22. package/dist/driver/testArtifacts.js +336 -42
  23. package/dist/driver/testArtifacts.js.map +1 -1
  24. package/dist/errors/EntityInvalidDataError.d.ts +6 -0
  25. package/dist/errors/EntityInvalidDataError.js +7 -1
  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 +1 -0
  34. package/dist/errors/QueryFailedError.js.map +1 -1
  35. package/dist/errors/index.d.ts +2 -0
  36. package/dist/errors/index.js +2 -0
  37. package/dist/errors/index.js.map +1 -1
  38. package/dist/testArtifacts.d.ts +17 -5
  39. package/dist/testArtifacts.js +31 -27
  40. package/dist/testArtifacts.js.map +1 -1
  41. package/dist/testMocks.d.ts +15 -10
  42. package/dist/testMocks.js +37 -13
  43. package/dist/testMocks.js.map +1 -1
  44. package/dist/utils.d.ts +1 -1
  45. package/dist/utils.js +21 -5
  46. package/dist/utils.js.map +1 -1
  47. package/package.json +16 -14
  48. package/src/Entity.test.ts +32 -11
  49. package/src/Entity.ts +423 -134
  50. package/src/Entity.types.ts +32 -66
  51. package/src/Nymph.ts +618 -195
  52. package/src/Nymph.types.ts +97 -26
  53. package/src/conf/d.ts +8 -0
  54. package/src/conf/defaults.ts +24 -0
  55. package/src/driver/NymphDriver.ts +281 -311
  56. package/src/driver/testArtifacts.ts +384 -173
  57. package/src/errors/EntityUniqueConstraintError.ts +6 -0
  58. package/src/errors/InvalidStateError.ts +6 -0
  59. package/src/errors/index.ts +4 -0
  60. package/src/nymphJoiProps.ts +2 -2
  61. package/src/testArtifacts.ts +18 -19
  62. package/src/testMocks.ts +64 -32
  63. package/src/utils.ts +22 -8
  64. package/tsconfig.json +3 -3
  65. 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, 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,109 +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;
119
277
  }
120
- throw new ClassNotAvailableError('Tried to use class: ' + className);
278
+ if (key in this.entityClasses) {
279
+ return this.entityClasses[key];
280
+ }
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.Entity = this.addEntityClass(Entity);
139
-
140
- if (typeof tilmeld !== 'undefined') {
141
- this.tilmeld = tilmeld;
142
- }
143
-
144
- this.driver.init(this);
145
- if (this.tilmeld) {
146
- 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
+ }
147
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
+ );
148
305
  }
149
306
 
150
307
  /**
151
- * 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.
152
309
  *
153
310
  * @returns A clone of this instance.
154
311
  */
155
312
  public clone() {
156
- const nymph = new Nymph(
313
+ return new Nymph(
157
314
  this.config,
158
315
  this.driver.clone(),
159
- this.tilmeld?.clone()
316
+ this.tilmeld?.clone(),
317
+ this,
160
318
  );
161
- for (const name in this.entityClasses) {
162
- if (name === 'Entity' || (this.entityClasses[name] as any).skipOnClone) {
163
- continue;
164
- }
165
- nymph.addEntityClass(this.entityClasses[name]);
166
- }
167
-
168
- const events = [
169
- 'connect',
170
- 'disconnect',
171
- 'query',
172
- 'beforeGetEntity',
173
- 'beforeGetEntities',
174
- 'beforeSaveEntity',
175
- 'afterSaveEntity',
176
- 'beforeDeleteEntity',
177
- 'afterDeleteEntity',
178
- 'beforeDeleteEntityByID',
179
- 'afterDeleteEntityByID',
180
- 'beforeNewUID',
181
- 'afterNewUID',
182
- 'beforeSetUID',
183
- 'afterSetUID',
184
- 'beforeRenameUID',
185
- 'afterRenameUID',
186
- 'beforeDeleteUID',
187
- 'afterDeleteUID',
188
- ];
189
-
190
- for (let event of events) {
191
- const prop = event + 'Callbacks';
192
- // @ts-ignore: The callback should be the right type here.
193
- const callbacks = this[prop];
194
- for (let callback of callbacks) {
195
- if (callback.skipOnClone) {
196
- continue;
197
- }
198
- nymph.on(event as NymphEventType, callback);
199
- }
200
- }
201
-
202
- return nymph;
203
319
  }
204
320
 
205
321
  /**
@@ -208,13 +324,19 @@ export default class Nymph {
208
324
  * @returns Whether the instance is connected to the database.
209
325
  */
210
326
  public async connect(): Promise<boolean> {
211
- const result = this.driver.connect();
212
- for (let callback of this.connectCallbacks) {
213
- if (callback) {
214
- 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
+ }
215
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;
216
339
  }
217
- return await result;
218
340
  }
219
341
 
220
342
  /**
@@ -223,13 +345,19 @@ export default class Nymph {
223
345
  * @returns Whether the instance is connected to the database.
224
346
  */
225
347
  public async disconnect(): Promise<boolean> {
226
- const result = this.driver.disconnect();
227
- for (let callback of this.disconnectCallbacks) {
228
- if (callback) {
229
- 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
+ }
230
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;
231
360
  }
232
- return await result;
233
361
  }
234
362
 
235
363
  /**
@@ -256,7 +384,24 @@ export default class Nymph {
256
384
  * @returns A new instance of Nymph that should be used for the transaction.
257
385
  */
258
386
  public async startTransaction(name: string): Promise<Nymph> {
259
- 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
+ }
260
405
  }
261
406
 
262
407
  /**
@@ -267,7 +412,24 @@ export default class Nymph {
267
412
  * @returns True on success, false on failure.
268
413
  */
269
414
  public async commit(name: string): Promise<boolean> {
270
- 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
+ }
271
433
  }
272
434
 
273
435
  /**
@@ -278,7 +440,24 @@ export default class Nymph {
278
440
  * @returns True on success, false on failure.
279
441
  */
280
442
  public async rollback(name: string): Promise<boolean> {
281
- 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
+ }
282
461
  }
283
462
 
284
463
  /**
@@ -312,18 +491,33 @@ export default class Nymph {
312
491
  * @returns The UID's new value, or null on failure.
313
492
  */
314
493
  public async newUID(name: string): Promise<number | null> {
315
- for (let callback of this.beforeNewUIDCallbacks) {
316
- if (callback) {
317
- await callback(this, name);
494
+ try {
495
+ for (let callback of this.beforeNewUIDCallbacks) {
496
+ if (callback) {
497
+ await callback(this, name);
498
+ }
318
499
  }
319
- }
320
- const result = this.driver.newUID(name);
321
- for (let callback of this.afterNewUIDCallbacks) {
322
- if (callback) {
323
- 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
+ }
324
515
  }
516
+ return await result;
517
+ } catch (e: any) {
518
+ this.config.debugError('nymph', `Failed to create UID "${name}": ${e}`);
519
+ throw e;
325
520
  }
326
- return await result;
327
521
  }
328
522
 
329
523
  /**
@@ -332,7 +526,12 @@ export default class Nymph {
332
526
  * @returns The UID's value, or null on failure and if it doesn't exist.
333
527
  */
334
528
  public async getUID(name: string): Promise<number | null> {
335
- 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
+ }
336
535
  }
337
536
 
338
537
  /**
@@ -343,18 +542,33 @@ export default class Nymph {
343
542
  * @returns True on success, false on failure.
344
543
  */
345
544
  public async setUID(name: string, value: number): Promise<boolean> {
346
- for (let callback of this.beforeSetUIDCallbacks) {
347
- if (callback) {
348
- await callback(this, name, value);
545
+ try {
546
+ for (let callback of this.beforeSetUIDCallbacks) {
547
+ if (callback) {
548
+ await callback(this, name, value);
549
+ }
349
550
  }
350
- }
351
- const result = this.driver.setUID(name, value);
352
- for (let callback of this.afterSetUIDCallbacks) {
353
- if (callback) {
354
- 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;
561
+ }
562
+ for (let callback of this.afterSetUIDCallbacks) {
563
+ if (callback) {
564
+ await callback(this, result);
565
+ }
355
566
  }
567
+ return await result;
568
+ } catch (e: any) {
569
+ this.config.debugError('nymph', `Failed to set UID "${name}": ${e}`);
570
+ throw e;
356
571
  }
357
- return await result;
358
572
  }
359
573
 
360
574
  /**
@@ -364,18 +578,33 @@ export default class Nymph {
364
578
  * @returns True on success, false on failure.
365
579
  */
366
580
  public async deleteUID(name: string): Promise<boolean> {
367
- for (let callback of this.beforeDeleteUIDCallbacks) {
368
- if (callback) {
369
- await callback(this, name);
581
+ try {
582
+ for (let callback of this.beforeDeleteUIDCallbacks) {
583
+ if (callback) {
584
+ await callback(this, name);
585
+ }
370
586
  }
371
- }
372
- const result = this.driver.deleteUID(name);
373
- for (let callback of this.afterDeleteUIDCallbacks) {
374
- if (callback) {
375
- 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;
376
597
  }
598
+ for (let callback of this.afterDeleteUIDCallbacks) {
599
+ if (callback) {
600
+ await callback(this, result);
601
+ }
602
+ }
603
+ return await result;
604
+ } catch (e: any) {
605
+ this.config.debugError('nymph', `Failed to delete UID "${name}": ${e}`);
606
+ throw e;
377
607
  }
378
- return await result;
379
608
  }
380
609
 
381
610
  /**
@@ -386,18 +615,36 @@ export default class Nymph {
386
615
  * @returns True on success, false on failure.
387
616
  */
388
617
  public async renameUID(oldName: string, newName: string): Promise<boolean> {
389
- for (let callback of this.beforeRenameUIDCallbacks) {
390
- if (callback) {
391
- await callback(this, oldName, newName);
618
+ try {
619
+ for (let callback of this.beforeRenameUIDCallbacks) {
620
+ if (callback) {
621
+ await callback(this, oldName, newName);
622
+ }
392
623
  }
393
- }
394
- const result = this.driver.renameUID(oldName, newName);
395
- for (let callback of this.afterRenameUIDCallbacks) {
396
- if (callback) {
397
- 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;
634
+ }
635
+ for (let callback of this.afterRenameUIDCallbacks) {
636
+ if (callback) {
637
+ await callback(this, result);
638
+ }
398
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;
399
647
  }
400
- return await result;
401
648
  }
402
649
 
403
650
  /**
@@ -412,18 +659,33 @@ export default class Nymph {
412
659
  * @returns True on success, false on failure.
413
660
  */
414
661
  public async saveEntity(entity: EntityInterface): Promise<boolean> {
415
- for (let callback of this.beforeSaveEntityCallbacks) {
416
- if (callback) {
417
- await callback(this, entity);
662
+ try {
663
+ for (let callback of this.beforeSaveEntityCallbacks) {
664
+ if (callback) {
665
+ await callback(this, entity);
666
+ }
418
667
  }
419
- }
420
- const result = this.driver.saveEntity(entity);
421
- for (let callback of this.afterSaveEntityCallbacks) {
422
- if (callback) {
423
- 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;
678
+ }
679
+ for (let callback of this.afterSaveEntityCallbacks) {
680
+ if (callback) {
681
+ await callback(this, result);
682
+ }
424
683
  }
684
+ return await result;
685
+ } catch (e: any) {
686
+ this.config.debugError('nymph', `Failed to save entity: ${e}`);
687
+ throw e;
425
688
  }
426
- return await result;
427
689
  }
428
690
 
429
691
  /**
@@ -436,8 +698,10 @@ export default class Nymph {
436
698
  * - offset - The offset from the oldest matching entity to start retrieving.
437
699
  * - reverse - If true, entities will be retrieved from newest to oldest.
438
700
  * Therefore, offset will be from the newest entity.
439
- * - sort - How to sort the entities. Accepts "cdate" or "mdate". Defaults to
440
- * "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".
441
705
  * - return - What to return. "entity", "guid", or "count". Defaults to
442
706
  * "entity".
443
707
  * - source - Will be 'client' if the query came from a REST call.
@@ -596,17 +860,22 @@ export default class Nymph {
596
860
  public async getEntities<T extends EntityConstructor = EntityConstructor>(
597
861
  options?: Options<T>,
598
862
  ...selectors: Selector[]
599
- ): Promise<ReturnType<T['factorySync']>[]>;
863
+ ): Promise<EntityInstanceType<T>[]>;
600
864
  public async getEntities<T extends EntityConstructor = EntityConstructor>(
601
865
  options: Options<T> = {},
602
866
  ...selectors: Selector[]
603
- ): Promise<ReturnType<T['factorySync']>[] | string[] | number> {
604
- for (let callback of this.beforeGetEntitiesCallbacks) {
605
- if (callback) {
606
- 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
+ }
607
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;
608
878
  }
609
- return await this.driver.getEntities(options, ...selectors);
610
879
  }
611
880
 
612
881
  /**
@@ -633,40 +902,45 @@ export default class Nymph {
633
902
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
634
903
  options: Options<T>,
635
904
  ...selectors: Selector[]
636
- ): Promise<ReturnType<T['factorySync']> | null>;
905
+ ): Promise<EntityInstanceType<T> | null>;
637
906
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
638
907
  options: Options<T> & { return: 'guid' },
639
- guid: string
908
+ guid: string,
640
909
  ): Promise<string | null>;
641
910
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
642
911
  options: Options<T>,
643
- guid: string
644
- ): Promise<ReturnType<T['factorySync']> | null>;
912
+ guid: string,
913
+ ): Promise<EntityInstanceType<T> | null>;
645
914
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
646
915
  options: Options<T> = {},
647
916
  ...selectors: Selector[] | string[]
648
- ): Promise<ReturnType<T['factorySync']> | string | number | null> {
649
- // Set up options and selectors.
650
- if (typeof selectors[0] === 'string') {
651
- selectors = [{ type: '&', guid: selectors[0] }];
652
- }
653
- options.limit = 1;
654
- for (let callback of this.beforeGetEntityCallbacks) {
655
- if (callback) {
656
- 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] }];
657
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;
658
943
  }
659
- const entities = await this.driver.getEntities(
660
- options,
661
- ...(selectors as Selector[])
662
- );
663
- if (options.return === 'count') {
664
- return entities as unknown as number;
665
- }
666
- if (!entities || !entities.length) {
667
- return null;
668
- }
669
- return entities[0];
670
944
  }
671
945
 
672
946
  /**
@@ -676,18 +950,33 @@ export default class Nymph {
676
950
  * @returns True on success, false on failure.
677
951
  */
678
952
  public async deleteEntity(entity: EntityInterface): Promise<boolean> {
679
- for (let callback of this.beforeDeleteEntityCallbacks) {
680
- if (callback) {
681
- await callback(this, entity);
953
+ try {
954
+ for (let callback of this.beforeDeleteEntityCallbacks) {
955
+ if (callback) {
956
+ await callback(this, entity);
957
+ }
682
958
  }
683
- }
684
- const result = this.driver.deleteEntity(entity);
685
- for (let callback of this.afterDeleteEntityCallbacks) {
686
- if (callback) {
687
- 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
+ }
688
974
  }
975
+ return await result;
976
+ } catch (e: any) {
977
+ this.config.debugError('nymph', `Failed to delete entity: ${e}`);
978
+ throw e;
689
979
  }
690
- return await result;
691
980
  }
692
981
 
693
982
  /**
@@ -699,20 +988,35 @@ export default class Nymph {
699
988
  */
700
989
  public async deleteEntityByID(
701
990
  guid: string,
702
- className?: string
991
+ className?: string,
703
992
  ): Promise<boolean> {
704
- for (let callback of this.beforeDeleteEntityByIDCallbacks) {
705
- if (callback) {
706
- await callback(this, guid, className);
993
+ try {
994
+ for (let callback of this.beforeDeleteEntityByIDCallbacks) {
995
+ if (callback) {
996
+ await callback(this, guid, className);
997
+ }
707
998
  }
708
- }
709
- const result = this.driver.deleteEntityByID(guid, className);
710
- for (let callback of this.afterDeleteEntityByIDCallbacks) {
711
- if (callback) {
712
- 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;
713
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;
714
1019
  }
715
- return await result;
716
1020
  }
717
1021
 
718
1022
  /**
@@ -737,7 +1041,7 @@ export default class Nymph {
737
1041
  * # brackets ([]).
738
1042
  * # Properties are stored like this:
739
1043
  * # propname=JSON.stringify(value)
740
- * abilities=["system/all"]
1044
+ * abilities=["system/admin"]
741
1045
  * groups=[]
742
1046
  * inheritAbilities=false
743
1047
  * name="admin"
@@ -752,7 +1056,12 @@ export default class Nymph {
752
1056
  * @returns True on success, false on failure.
753
1057
  */
754
1058
  public async export(filename: string): Promise<boolean> {
755
- 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
+ }
756
1065
  }
757
1066
 
758
1067
  /**
@@ -761,7 +1070,12 @@ export default class Nymph {
761
1070
  * @returns True on success, false on failure.
762
1071
  */
763
1072
  public async exportPrint(): Promise<boolean> {
764
- 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
+ }
765
1079
  }
766
1080
 
767
1081
  /**
@@ -771,7 +1085,12 @@ export default class Nymph {
771
1085
  * @returns True on success, false on failure.
772
1086
  */
773
1087
  public async import(filename: string): Promise<boolean> {
774
- 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
+ }
775
1094
  }
776
1095
 
777
1096
  public on<T extends NymphEventType>(
@@ -790,31 +1109,57 @@ export default class Nymph {
790
1109
  ? NymphBeforeSaveEntityCallback
791
1110
  : T extends 'afterSaveEntity'
792
1111
  ? NymphAfterSaveEntityCallback
1112
+ : T extends 'failedSaveEntity'
1113
+ ? NymphFailedSaveEntityCallback
793
1114
  : T extends 'beforeDeleteEntity'
794
1115
  ? NymphBeforeDeleteEntityCallback
795
1116
  : T extends 'afterDeleteEntity'
796
1117
  ? NymphAfterDeleteEntityCallback
1118
+ : T extends 'failedDeleteEntity'
1119
+ ? NymphFailedDeleteEntityCallback
797
1120
  : T extends 'beforeDeleteEntityByID'
798
1121
  ? NymphBeforeDeleteEntityByIDCallback
799
1122
  : T extends 'afterDeleteEntityByID'
800
1123
  ? NymphAfterDeleteEntityByIDCallback
1124
+ : T extends 'failedDeleteEntityByID'
1125
+ ? NymphFailedDeleteEntityByIDCallback
801
1126
  : T extends 'beforeNewUID'
802
1127
  ? NymphBeforeNewUIDCallback
803
1128
  : T extends 'afterNewUID'
804
1129
  ? NymphAfterNewUIDCallback
1130
+ : T extends 'failedNewUID'
1131
+ ? NymphFailedNewUIDCallback
805
1132
  : T extends 'beforeSetUID'
806
1133
  ? NymphBeforeSetUIDCallback
807
1134
  : T extends 'afterSetUID'
808
1135
  ? NymphAfterSetUIDCallback
1136
+ : T extends 'failedSetUID'
1137
+ ? NymphFailedSetUIDCallback
809
1138
  : T extends 'beforeRenameUID'
810
1139
  ? NymphBeforeRenameUIDCallback
811
1140
  : T extends 'afterRenameUID'
812
1141
  ? NymphAfterRenameUIDCallback
1142
+ : T extends 'failedRenameUID'
1143
+ ? NymphFailedRenameUIDCallback
813
1144
  : T extends 'beforeDeleteUID'
814
1145
  ? NymphBeforeDeleteUIDCallback
815
1146
  : T extends 'afterDeleteUID'
816
1147
  ? NymphAfterDeleteUIDCallback
817
- : 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,
818
1163
  ) {
819
1164
  const prop = (event + 'Callbacks') as T extends 'connect'
820
1165
  ? 'connectCallbacks'
@@ -830,30 +1175,56 @@ export default class Nymph {
830
1175
  ? 'beforeSaveEntityCallbacks'
831
1176
  : T extends 'afterSaveEntity'
832
1177
  ? 'afterSaveEntityCallbacks'
1178
+ : T extends 'failedSaveEntity'
1179
+ ? 'failedSaveEntityCallbacks'
833
1180
  : T extends 'beforeDeleteEntity'
834
1181
  ? 'beforeDeleteEntityCallbacks'
835
1182
  : T extends 'afterDeleteEntity'
836
1183
  ? 'afterDeleteEntityCallbacks'
1184
+ : T extends 'failedDeleteEntity'
1185
+ ? 'failedDeleteEntityCallbacks'
837
1186
  : T extends 'beforeDeleteEntityByID'
838
1187
  ? 'beforeDeleteEntityByIDCallbacks'
839
1188
  : T extends 'afterDeleteEntityByID'
840
1189
  ? 'afterDeleteEntityByIDCallbacks'
1190
+ : T extends 'failedDeleteEntityByID'
1191
+ ? 'failedDeleteEntityByIDCallbacks'
841
1192
  : T extends 'beforeNewUID'
842
1193
  ? 'beforeNewUIDCallbacks'
843
1194
  : T extends 'afterNewUID'
844
1195
  ? 'afterNewUIDCallbacks'
1196
+ : T extends 'failedNewUID'
1197
+ ? 'failedNewUIDCallbacks'
845
1198
  : T extends 'beforeSetUID'
846
1199
  ? 'beforeSetUIDCallbacks'
847
1200
  : T extends 'afterSetUID'
848
1201
  ? 'afterSetUIDCallbacks'
1202
+ : T extends 'failedSetUID'
1203
+ ? 'failedSetUIDCallbacks'
849
1204
  : T extends 'beforeRenameUID'
850
1205
  ? 'beforeRenameUIDCallbacks'
851
1206
  : T extends 'afterRenameUID'
852
1207
  ? 'afterRenameUIDCallbacks'
1208
+ : T extends 'failedRenameUID'
1209
+ ? 'failedRenameUIDCallbacks'
853
1210
  : T extends 'beforeDeleteUID'
854
1211
  ? 'beforeDeleteUIDCallbacks'
855
1212
  : T extends 'afterDeleteUID'
856
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'
857
1228
  : never;
858
1229
  if (!(prop in this)) {
859
1230
  throw new Error('Invalid event type.');
@@ -879,31 +1250,57 @@ export default class Nymph {
879
1250
  ? NymphBeforeSaveEntityCallback
880
1251
  : T extends 'afterSaveEntity'
881
1252
  ? NymphAfterSaveEntityCallback
1253
+ : T extends 'failedSaveEntity'
1254
+ ? NymphFailedSaveEntityCallback
882
1255
  : T extends 'beforeDeleteEntity'
883
1256
  ? NymphBeforeDeleteEntityCallback
884
1257
  : T extends 'afterDeleteEntity'
885
1258
  ? NymphAfterDeleteEntityCallback
1259
+ : T extends 'failedDeleteEntity'
1260
+ ? NymphFailedDeleteEntityCallback
886
1261
  : T extends 'beforeDeleteEntityByID'
887
1262
  ? NymphBeforeDeleteEntityByIDCallback
888
1263
  : T extends 'afterDeleteEntityByID'
889
1264
  ? NymphAfterDeleteEntityByIDCallback
1265
+ : T extends 'failedDeleteEntityByID'
1266
+ ? NymphFailedDeleteEntityByIDCallback
890
1267
  : T extends 'beforeNewUID'
891
1268
  ? NymphBeforeNewUIDCallback
892
1269
  : T extends 'afterNewUID'
893
1270
  ? NymphAfterNewUIDCallback
1271
+ : T extends 'failedNewUID'
1272
+ ? NymphFailedNewUIDCallback
894
1273
  : T extends 'beforeSetUID'
895
1274
  ? NymphBeforeSetUIDCallback
896
1275
  : T extends 'afterSetUID'
897
1276
  ? NymphAfterSetUIDCallback
1277
+ : T extends 'failedSetUID'
1278
+ ? NymphFailedSetUIDCallback
898
1279
  : T extends 'beforeRenameUID'
899
1280
  ? NymphBeforeRenameUIDCallback
900
1281
  : T extends 'afterRenameUID'
901
1282
  ? NymphAfterRenameUIDCallback
1283
+ : T extends 'failedRenameUID'
1284
+ ? NymphFailedRenameUIDCallback
902
1285
  : T extends 'beforeDeleteUID'
903
1286
  ? NymphBeforeDeleteUIDCallback
904
1287
  : T extends 'afterDeleteUID'
905
1288
  ? NymphAfterDeleteUIDCallback
906
- : 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,
907
1304
  ) {
908
1305
  const prop = (event + 'Callbacks') as T extends 'connect'
909
1306
  ? 'connectCallbacks'
@@ -919,30 +1316,56 @@ export default class Nymph {
919
1316
  ? 'beforeGetEntitiesCallbacks'
920
1317
  : T extends 'afterSaveEntity'
921
1318
  ? 'afterSaveEntityCallbacks'
1319
+ : T extends 'failedSaveEntity'
1320
+ ? 'failedSaveEntityCallbacks'
922
1321
  : T extends 'beforeDeleteEntity'
923
1322
  ? 'beforeDeleteEntityCallbacks'
924
1323
  : T extends 'afterDeleteEntity'
925
1324
  ? 'afterDeleteEntityCallbacks'
1325
+ : T extends 'failedDeleteEntity'
1326
+ ? 'failedDeleteEntityCallbacks'
926
1327
  : T extends 'beforeDeleteEntityByID'
927
1328
  ? 'beforeDeleteEntityByIDCallbacks'
928
1329
  : T extends 'afterDeleteEntityByID'
929
1330
  ? 'afterDeleteEntityByIDCallbacks'
1331
+ : T extends 'failedDeleteEntityByID'
1332
+ ? 'failedDeleteEntityByIDCallbacks'
930
1333
  : T extends 'beforeNewUID'
931
1334
  ? 'beforeNewUIDCallbacks'
932
1335
  : T extends 'afterNewUID'
933
1336
  ? 'afterNewUIDCallbacks'
1337
+ : T extends 'failedNewUID'
1338
+ ? 'failedNewUIDCallbacks'
934
1339
  : T extends 'beforeSetUID'
935
1340
  ? 'beforeSetUIDCallbacks'
936
1341
  : T extends 'afterSetUID'
937
1342
  ? 'afterSetUIDCallbacks'
1343
+ : T extends 'failedSetUID'
1344
+ ? 'failedSetUIDCallbacks'
938
1345
  : T extends 'beforeRenameUID'
939
1346
  ? 'beforeRenameUIDCallbacks'
940
1347
  : T extends 'afterRenameUID'
941
1348
  ? 'afterRenameUIDCallbacks'
1349
+ : T extends 'failedRenameUID'
1350
+ ? 'failedRenameUIDCallbacks'
942
1351
  : T extends 'beforeDeleteUID'
943
1352
  ? 'beforeDeleteUIDCallbacks'
944
1353
  : T extends 'afterDeleteUID'
945
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'
946
1369
  : never;
947
1370
  if (!(prop in this)) {
948
1371
  return false;