@nymphjs/nymph 1.0.0-beta.10 → 1.0.0-beta.100

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 (96) hide show
  1. package/CHANGELOG.md +483 -0
  2. package/README.md +10 -20
  3. package/dist/Entity.d.ts +293 -10
  4. package/dist/Entity.js +563 -148
  5. package/dist/Entity.js.map +1 -1
  6. package/dist/Entity.test.js +52 -13
  7. package/dist/Entity.test.js.map +1 -1
  8. package/dist/Entity.types.d.ts +256 -23
  9. package/dist/Entity.types.js +1 -2
  10. package/dist/Nymph.d.ts +496 -12
  11. package/dist/Nymph.js +752 -179
  12. package/dist/Nymph.js.map +1 -1
  13. package/dist/Nymph.types.d.ts +77 -8
  14. package/dist/Nymph.types.js +3 -5
  15. package/dist/Nymph.types.js.map +1 -1
  16. package/dist/conf/d.d.ts +43 -0
  17. package/dist/conf/d.js +1 -2
  18. package/dist/conf/defaults.d.ts +1 -1
  19. package/dist/conf/defaults.js +26 -3
  20. package/dist/conf/defaults.js.map +1 -1
  21. package/dist/conf/index.d.ts +2 -2
  22. package/dist/conf/index.js +2 -8
  23. package/dist/conf/index.js.map +1 -1
  24. package/dist/driver/NymphDriver.d.ts +174 -40
  25. package/dist/driver/NymphDriver.js +469 -239
  26. package/dist/driver/NymphDriver.js.map +1 -1
  27. package/dist/driver/index.d.ts +2 -2
  28. package/dist/driver/index.js +3 -23
  29. package/dist/driver/index.js.map +1 -1
  30. package/dist/driver/testArtifacts.d.ts +2 -2
  31. package/dist/driver/testArtifacts.js +814 -92
  32. package/dist/driver/testArtifacts.js.map +1 -1
  33. package/dist/errors/ClassNotAvailableError.js +1 -5
  34. package/dist/errors/ClassNotAvailableError.js.map +1 -1
  35. package/dist/errors/EntityConflictError.js +1 -5
  36. package/dist/errors/EntityConflictError.js.map +1 -1
  37. package/dist/errors/EntityInvalidDataError.d.ts +6 -0
  38. package/dist/errors/EntityInvalidDataError.js +8 -6
  39. package/dist/errors/EntityInvalidDataError.js.map +1 -1
  40. package/dist/errors/EntityIsSleepingReferenceError.js +1 -5
  41. package/dist/errors/EntityIsSleepingReferenceError.js.map +1 -1
  42. package/dist/errors/EntityUniqueConstraintError.d.ts +3 -0
  43. package/dist/errors/EntityUniqueConstraintError.js +7 -0
  44. package/dist/errors/EntityUniqueConstraintError.js.map +1 -0
  45. package/dist/errors/InvalidParametersError.js +1 -5
  46. package/dist/errors/InvalidParametersError.js.map +1 -1
  47. package/dist/errors/InvalidStateError.d.ts +3 -0
  48. package/dist/errors/InvalidStateError.js +7 -0
  49. package/dist/errors/InvalidStateError.js.map +1 -0
  50. package/dist/errors/NotConfiguredError.js +1 -5
  51. package/dist/errors/NotConfiguredError.js.map +1 -1
  52. package/dist/errors/QueryFailedError.js +2 -5
  53. package/dist/errors/QueryFailedError.js.map +1 -1
  54. package/dist/errors/UnableToConnectError.js +1 -5
  55. package/dist/errors/UnableToConnectError.js.map +1 -1
  56. package/dist/errors/index.d.ts +10 -8
  57. package/dist/errors/index.js +10 -24
  58. package/dist/errors/index.js.map +1 -1
  59. package/dist/index.d.ts +11 -11
  60. package/dist/index.js +14 -34
  61. package/dist/index.js.map +1 -1
  62. package/dist/nymphJoiProps.js +10 -15
  63. package/dist/nymphJoiProps.js.map +1 -1
  64. package/dist/testArtifacts.d.ts +19 -6
  65. package/dist/testArtifacts.js +32 -37
  66. package/dist/testArtifacts.js.map +1 -1
  67. package/dist/testMocks.d.ts +27 -12
  68. package/dist/testMocks.js +40 -29
  69. package/dist/testMocks.js.map +1 -1
  70. package/dist/utils.d.ts +4 -4
  71. package/dist/utils.js +40 -29
  72. package/dist/utils.js.map +1 -1
  73. package/jest.config.js +11 -2
  74. package/package.json +23 -19
  75. package/src/Entity.test.ts +50 -7
  76. package/src/Entity.ts +483 -147
  77. package/src/Entity.types.ts +72 -74
  78. package/src/Nymph.ts +868 -322
  79. package/src/Nymph.types.ts +146 -27
  80. package/src/conf/d.ts +25 -0
  81. package/src/conf/defaults.ts +34 -1
  82. package/src/conf/index.ts +2 -2
  83. package/src/driver/NymphDriver.ts +562 -414
  84. package/src/driver/index.ts +2 -2
  85. package/src/driver/testArtifacts.ts +954 -185
  86. package/src/errors/EntityUniqueConstraintError.ts +6 -0
  87. package/src/errors/InvalidStateError.ts +6 -0
  88. package/src/errors/index.ts +12 -8
  89. package/src/index.ts +11 -11
  90. package/src/nymphJoiProps.ts +2 -2
  91. package/src/testArtifacts.ts +20 -20
  92. package/src/testMocks.ts +76 -35
  93. package/src/type/locutus.d.ts +3 -0
  94. package/src/utils.ts +39 -18
  95. package/tsconfig.json +5 -3
  96. package/typedoc.json +4 -0
package/src/Nymph.ts CHANGED
@@ -1,8 +1,18 @@
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';
5
- import { ClassNotAvailableError } from './errors';
1
+ import { Config, ConfigDefaults as defaults } from './conf/index.js';
2
+ import type { NymphDriver } from './driver/index.js';
3
+ import Entity, {
4
+ type EntityInstanceType,
5
+ type EntityObjectType,
6
+ } from './Entity.js';
7
+ import type {
8
+ EntityConstructor,
9
+ EntityInterface,
10
+ SerializedEntityData,
11
+ } from './Entity.types.js';
12
+ import {
13
+ ClassNotAvailableError,
14
+ InvalidParametersError,
15
+ } from './errors/index.js';
6
16
  import type {
7
17
  Selector,
8
18
  Options,
@@ -12,23 +22,36 @@ import type {
12
22
  NymphBeforeGetEntitiesCallback,
13
23
  NymphBeforeSaveEntityCallback,
14
24
  NymphAfterSaveEntityCallback,
25
+ NymphFailedSaveEntityCallback,
15
26
  NymphBeforeDeleteEntityCallback,
16
27
  NymphAfterDeleteEntityCallback,
28
+ NymphFailedDeleteEntityCallback,
17
29
  NymphBeforeDeleteEntityByIDCallback,
18
30
  NymphAfterDeleteEntityByIDCallback,
31
+ NymphFailedDeleteEntityByIDCallback,
19
32
  NymphBeforeNewUIDCallback,
20
33
  NymphAfterNewUIDCallback,
34
+ NymphFailedNewUIDCallback,
21
35
  NymphBeforeSetUIDCallback,
22
36
  NymphAfterSetUIDCallback,
37
+ NymphFailedSetUIDCallback,
23
38
  NymphBeforeRenameUIDCallback,
24
39
  NymphAfterRenameUIDCallback,
40
+ NymphFailedRenameUIDCallback,
25
41
  NymphBeforeDeleteUIDCallback,
26
42
  NymphAfterDeleteUIDCallback,
43
+ NymphFailedDeleteUIDCallback,
44
+ NymphBeforeStartTransactionCallback,
45
+ NymphAfterStartTransactionCallback,
46
+ NymphBeforeCommitTransactionCallback,
47
+ NymphAfterCommitTransactionCallback,
48
+ NymphBeforeRollbackTransactionCallback,
49
+ NymphAfterRollbackTransactionCallback,
27
50
  NymphEventType,
28
51
  NymphQueryCallback,
29
52
  FormattedSelector,
30
53
  TilmeldInterface,
31
- } from './Nymph.types';
54
+ } from './Nymph.types.js';
32
55
 
33
56
  /**
34
57
  * An object relational mapper for Node.js.
@@ -41,10 +64,16 @@ import type {
41
64
  */
42
65
  export default class Nymph {
43
66
  /**
44
- * The PubSub config.
67
+ * The Nymph config.
45
68
  */
46
69
  public config: Config;
47
70
 
71
+ /**
72
+ * The Nymph instance that this one was cloned from, or null if it's not a
73
+ * clone.
74
+ */
75
+ public parent: Nymph | null;
76
+
48
77
  /**
49
78
  * The Nymph database driver.
50
79
  */
@@ -72,20 +101,40 @@ export default class Nymph {
72
101
  private beforeGetEntitiesCallbacks: NymphBeforeGetEntitiesCallback[] = [];
73
102
  private beforeSaveEntityCallbacks: NymphBeforeSaveEntityCallback[] = [];
74
103
  private afterSaveEntityCallbacks: NymphAfterSaveEntityCallback[] = [];
104
+ private failedSaveEntityCallbacks: NymphFailedSaveEntityCallback[] = [];
75
105
  private beforeDeleteEntityCallbacks: NymphBeforeDeleteEntityCallback[] = [];
76
106
  private afterDeleteEntityCallbacks: NymphAfterDeleteEntityCallback[] = [];
107
+ private failedDeleteEntityCallbacks: NymphFailedDeleteEntityCallback[] = [];
77
108
  private beforeDeleteEntityByIDCallbacks: NymphBeforeDeleteEntityByIDCallback[] =
78
109
  [];
79
110
  private afterDeleteEntityByIDCallbacks: NymphAfterDeleteEntityByIDCallback[] =
80
111
  [];
112
+ private failedDeleteEntityByIDCallbacks: NymphFailedDeleteEntityByIDCallback[] =
113
+ [];
81
114
  private beforeNewUIDCallbacks: NymphBeforeNewUIDCallback[] = [];
82
115
  private afterNewUIDCallbacks: NymphAfterNewUIDCallback[] = [];
116
+ private failedNewUIDCallbacks: NymphFailedNewUIDCallback[] = [];
83
117
  private beforeSetUIDCallbacks: NymphBeforeSetUIDCallback[] = [];
84
118
  private afterSetUIDCallbacks: NymphAfterSetUIDCallback[] = [];
119
+ private failedSetUIDCallbacks: NymphFailedSetUIDCallback[] = [];
85
120
  private beforeRenameUIDCallbacks: NymphBeforeRenameUIDCallback[] = [];
86
121
  private afterRenameUIDCallbacks: NymphAfterRenameUIDCallback[] = [];
122
+ private failedRenameUIDCallbacks: NymphFailedRenameUIDCallback[] = [];
87
123
  private beforeDeleteUIDCallbacks: NymphBeforeDeleteUIDCallback[] = [];
88
124
  private afterDeleteUIDCallbacks: NymphAfterDeleteUIDCallback[] = [];
125
+ private failedDeleteUIDCallbacks: NymphFailedDeleteUIDCallback[] = [];
126
+ private beforeStartTransactionCallbacks: NymphBeforeStartTransactionCallback[] =
127
+ [];
128
+ private afterStartTransactionCallbacks: NymphAfterStartTransactionCallback[] =
129
+ [];
130
+ private beforeCommitTransactionCallbacks: NymphBeforeCommitTransactionCallback[] =
131
+ [];
132
+ private afterCommitTransactionCallbacks: NymphAfterCommitTransactionCallback[] =
133
+ [];
134
+ private beforeRollbackTransactionCallbacks: NymphBeforeRollbackTransactionCallback[] =
135
+ [];
136
+ private afterRollbackTransactionCallbacks: NymphAfterRollbackTransactionCallback[] =
137
+ [];
89
138
 
90
139
  /**
91
140
  * Initialize Nymph.
@@ -93,24 +142,90 @@ export default class Nymph {
93
142
  * @param config The Nymph configuration.
94
143
  * @param driver The Nymph database driver.
95
144
  * @param tilmeld The Tilmeld user/group manager instance, if you want to use it.
145
+ * @param parent Used internally by Nymph. Don't set this.
96
146
  */
97
147
  public constructor(
98
148
  config: Partial<Config>,
99
149
  driver: NymphDriver,
100
- tilmeld?: TilmeldInterface
150
+ tilmeld?: TilmeldInterface,
151
+ parent?: Nymph,
101
152
  ) {
102
153
  this.config = { ...defaults, ...config };
103
154
  this.driver = driver;
155
+ this.parent = parent ?? null;
104
156
 
105
157
  this.Entity = this.addEntityClass(Entity);
106
158
 
107
- if (typeof tilmeld !== 'undefined') {
159
+ if (parent) {
160
+ for (const name in parent.entityClasses) {
161
+ if (
162
+ name === 'Entity' ||
163
+ (parent.entityClasses[name] as any).skipOnClone
164
+ ) {
165
+ continue;
166
+ }
167
+ this.addEntityClass(parent.entityClasses[name]);
168
+ }
169
+
170
+ const events = [
171
+ 'connect',
172
+ 'disconnect',
173
+ 'query',
174
+ 'beforeGetEntity',
175
+ 'beforeGetEntities',
176
+ 'beforeSaveEntity',
177
+ 'afterSaveEntity',
178
+ 'failedSaveEntity',
179
+ 'beforeDeleteEntity',
180
+ 'afterDeleteEntity',
181
+ 'failedDeleteEntity',
182
+ 'beforeDeleteEntityByID',
183
+ 'afterDeleteEntityByID',
184
+ 'failedDeleteEntityByID',
185
+ 'beforeNewUID',
186
+ 'afterNewUID',
187
+ 'failedNewUID',
188
+ 'beforeSetUID',
189
+ 'afterSetUID',
190
+ 'failedSetUID',
191
+ 'beforeRenameUID',
192
+ 'afterRenameUID',
193
+ 'failedRenameUID',
194
+ 'beforeDeleteUID',
195
+ 'afterDeleteUID',
196
+ 'failedDeleteUID',
197
+ 'beforeStartTransaction',
198
+ 'afterStartTransaction',
199
+ 'beforeCommitTransaction',
200
+ 'afterCommitTransaction',
201
+ 'beforeRollbackTransaction',
202
+ 'afterRollbackTransaction',
203
+ ];
204
+
205
+ for (let event of events) {
206
+ const prop = event + 'Callbacks';
207
+ // @ts-ignore: The callback should be the right type here.
208
+ const callbacks = parent[prop];
209
+ for (let callback of callbacks) {
210
+ if (callback.skipOnClone) {
211
+ continue;
212
+ }
213
+ this.on(event as NymphEventType, callback);
214
+ }
215
+ }
216
+ }
217
+
218
+ this.config.debugInfo('nymph', 'Nymph loaded.');
219
+
220
+ if (tilmeld != null) {
108
221
  this.tilmeld = tilmeld;
109
222
  }
110
223
 
111
224
  this.driver.init(this);
225
+ this.config.debugInfo('nymph', 'Nymph driver loaded.');
112
226
  if (this.tilmeld) {
113
227
  this.tilmeld.init(this);
228
+ this.config.debugInfo('nymph', 'Tilmeld loaded.');
114
229
  }
115
230
  }
116
231
 
@@ -124,82 +239,93 @@ export default class Nymph {
124
239
  * Because this creates a subclass, don't use the class
125
240
  * returned from `getEntityClass` to check with `instanceof`.
126
241
  */
127
- public addEntityClass<T extends EntityConstructor>(entityClass: T): T {
242
+ public addEntityClass<T extends EntityConstructor>(EntityClass: T): T {
243
+ if (EntityClass.class in this.entityClasses) {
244
+ this.config.debugLog(
245
+ 'nymph',
246
+ `Adding duplicate class "${EntityClass.class}". This may be a mistake.`,
247
+ );
248
+ }
249
+
250
+ // Check that it doesn't have the same etype as any other class.
251
+ for (const ExistingClass of Object.values(this.entityClasses)) {
252
+ if (
253
+ EntityClass.ETYPE === ExistingClass.ETYPE &&
254
+ EntityClass.class !== EntityClass.class
255
+ ) {
256
+ this.config.debugLog(
257
+ 'nymph',
258
+ `Adding class "${EntityClass.class}" with same etype as existing class "${ExistingClass.class}". This may be a mistake.`,
259
+ );
260
+ }
261
+ }
262
+
128
263
  const nymph = this;
129
- class NymphEntity extends entityClass {
264
+ this.entityClasses[EntityClass.class] = class extends EntityClass {
130
265
  static nymph: Nymph = nymph;
131
266
 
132
267
  constructor(...args: any[]) {
133
268
  super(...args);
134
269
  }
135
- }
136
- this.entityClasses[entityClass.class] = NymphEntity;
137
- return NymphEntity;
270
+ };
271
+ return this.entityClasses[EntityClass.class] as T;
138
272
  }
139
273
 
140
274
  /**
141
275
  * Get the class that uses the specified class name.
142
276
  */
143
- public getEntityClass(className: string): EntityConstructor {
144
- if (className in this.entityClasses) {
145
- return this.entityClasses[className];
277
+ public getEntityClass(className: string): EntityConstructor;
278
+ public getEntityClass<T extends EntityConstructor>(className: T): T;
279
+ public getEntityClass<T extends EntityConstructor = EntityConstructor>(
280
+ className: T | string,
281
+ ): T | EntityConstructor {
282
+ let key: string | null = null;
283
+ if (typeof className === 'string') {
284
+ key = className;
285
+ } else {
286
+ key = className.class;
287
+ }
288
+ if (key in this.entityClasses) {
289
+ return this.entityClasses[key];
290
+ }
291
+ this.config.debugError('nymph', `Tried to use missing class "${key}".`);
292
+ throw new ClassNotAvailableError(`Tried to use missing class "${key}".`);
293
+ }
294
+
295
+ /**
296
+ * Get the class that uses the specified etype.
297
+ *
298
+ * Note that it is fine, though unusual, for two classes to use the same
299
+ * etype. However, this can lead to very hard to diagnose bugs, so is
300
+ * generally discouraged.
301
+ */
302
+ public getEntityClassByEtype(etype: string): EntityConstructor {
303
+ for (const EntityClass of Object.values(this.entityClasses)) {
304
+ if (EntityClass.ETYPE === etype) {
305
+ return EntityClass;
306
+ }
146
307
  }
147
- throw new ClassNotAvailableError('Tried to use class: ' + className);
308
+ this.config.debugError(
309
+ 'nymph',
310
+ `Tried to use missing class by etype "${etype}".`,
311
+ );
312
+ throw new ClassNotAvailableError(
313
+ `Tried to use missing class by etype "${etype}".`,
314
+ );
148
315
  }
149
316
 
150
317
  /**
151
- * Get a clone of this instance with duplicate classes and event listeners.
318
+ * Get a clone of this instance with cloned classes and event listeners.
152
319
  *
153
320
  * @returns A clone of this instance.
154
321
  */
155
322
  public clone() {
156
- const nymph = new Nymph(
323
+ return new Nymph(
157
324
  this.config,
158
325
  this.driver.clone(),
159
- this.tilmeld?.clone()
326
+ this.tilmeld?.clone(),
327
+ this,
160
328
  );
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
329
  }
204
330
 
205
331
  /**
@@ -208,13 +334,19 @@ export default class Nymph {
208
334
  * @returns Whether the instance is connected to the database.
209
335
  */
210
336
  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);
337
+ try {
338
+ const result = this.driver.connect();
339
+ for (let callback of this.connectCallbacks) {
340
+ if (callback) {
341
+ await callback(this, result);
342
+ }
215
343
  }
344
+ this.config.debugInfo('nymph', 'Driver connected.');
345
+ return await result;
346
+ } catch (e: any) {
347
+ this.config.debugError('nymph', `Failed to connect: ${e}`);
348
+ throw e;
216
349
  }
217
- return await result;
218
350
  }
219
351
 
220
352
  /**
@@ -223,13 +355,19 @@ export default class Nymph {
223
355
  * @returns Whether the instance is connected to the database.
224
356
  */
225
357
  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);
358
+ try {
359
+ const result = this.driver.disconnect();
360
+ for (let callback of this.disconnectCallbacks) {
361
+ if (callback) {
362
+ await callback(this, result);
363
+ }
230
364
  }
365
+ this.config.debugInfo('nymph', 'Driver disconnected.');
366
+ return await result;
367
+ } catch (e: any) {
368
+ this.config.debugError('nymph', `Failed to disconnect: ${e}`);
369
+ throw e;
231
370
  }
232
- return await result;
233
371
  }
234
372
 
235
373
  /**
@@ -256,7 +394,24 @@ export default class Nymph {
256
394
  * @returns A new instance of Nymph that should be used for the transaction.
257
395
  */
258
396
  public async startTransaction(name: string): Promise<Nymph> {
259
- return await this.driver.startTransaction(name);
397
+ try {
398
+ for (let callback of this.beforeStartTransactionCallbacks) {
399
+ if (callback) {
400
+ await callback(this, name);
401
+ }
402
+ }
403
+ this.config.debugLog('nymph', `Starting transaction "${name}".`);
404
+ const result = await this.driver.startTransaction(name);
405
+ for (let callback of this.afterStartTransactionCallbacks) {
406
+ if (callback) {
407
+ await callback(this, name, result);
408
+ }
409
+ }
410
+ return result;
411
+ } catch (e: any) {
412
+ this.config.debugError('nymph', `Failed to start transaction: ${e}`);
413
+ throw e;
414
+ }
260
415
  }
261
416
 
262
417
  /**
@@ -267,7 +422,24 @@ export default class Nymph {
267
422
  * @returns True on success, false on failure.
268
423
  */
269
424
  public async commit(name: string): Promise<boolean> {
270
- return await this.driver.commit(name);
425
+ try {
426
+ for (let callback of this.beforeCommitTransactionCallbacks) {
427
+ if (callback) {
428
+ await callback(this, name);
429
+ }
430
+ }
431
+ this.config.debugLog('nymph', `Committing transaction "${name}".`);
432
+ const result = await this.driver.commit(name);
433
+ for (let callback of this.afterCommitTransactionCallbacks) {
434
+ if (callback) {
435
+ await callback(this, name, result);
436
+ }
437
+ }
438
+ return result;
439
+ } catch (e: any) {
440
+ this.config.debugError('nymph', `Failed to commit transaction: ${e}`);
441
+ throw e;
442
+ }
271
443
  }
272
444
 
273
445
  /**
@@ -278,7 +450,24 @@ export default class Nymph {
278
450
  * @returns True on success, false on failure.
279
451
  */
280
452
  public async rollback(name: string): Promise<boolean> {
281
- return await this.driver.rollback(name);
453
+ try {
454
+ for (let callback of this.beforeRollbackTransactionCallbacks) {
455
+ if (callback) {
456
+ await callback(this, name);
457
+ }
458
+ }
459
+ this.config.debugLog('nymph', `Rolling back transaction "${name}".`);
460
+ const result = await this.driver.rollback(name);
461
+ for (let callback of this.afterRollbackTransactionCallbacks) {
462
+ if (callback) {
463
+ await callback(this, name, result);
464
+ }
465
+ }
466
+ return result;
467
+ } catch (e: any) {
468
+ this.config.debugError('nymph', `Failed to roll back transaction: ${e}`);
469
+ throw e;
470
+ }
282
471
  }
283
472
 
284
473
  /**
@@ -312,18 +501,33 @@ export default class Nymph {
312
501
  * @returns The UID's new value, or null on failure.
313
502
  */
314
503
  public async newUID(name: string): Promise<number | null> {
315
- for (let callback of this.beforeNewUIDCallbacks) {
316
- if (callback) {
317
- await callback(this, name);
504
+ try {
505
+ for (let callback of this.beforeNewUIDCallbacks) {
506
+ if (callback) {
507
+ await callback(this, name);
508
+ }
318
509
  }
319
- }
320
- const result = this.driver.newUID(name);
321
- for (let callback of this.afterNewUIDCallbacks) {
322
- if (callback) {
323
- await callback(this, result);
510
+ let result: Promise<number | null>;
511
+ try {
512
+ result = this.driver.newUID(name);
513
+ } catch (e: any) {
514
+ for (let callback of this.failedNewUIDCallbacks) {
515
+ if (callback) {
516
+ await callback(this, e);
517
+ }
518
+ }
519
+ throw e;
324
520
  }
521
+ for (let callback of this.afterNewUIDCallbacks) {
522
+ if (callback) {
523
+ await callback(this, result);
524
+ }
525
+ }
526
+ return await result;
527
+ } catch (e: any) {
528
+ this.config.debugError('nymph', `Failed to create UID "${name}": ${e}`);
529
+ throw e;
325
530
  }
326
- return await result;
327
531
  }
328
532
 
329
533
  /**
@@ -332,7 +536,12 @@ export default class Nymph {
332
536
  * @returns The UID's value, or null on failure and if it doesn't exist.
333
537
  */
334
538
  public async getUID(name: string): Promise<number | null> {
335
- return await this.driver.getUID(name);
539
+ try {
540
+ return await this.driver.getUID(name);
541
+ } catch (e: any) {
542
+ this.config.debugError('nymph', `Failed to get UID "${name}": ${e}`);
543
+ throw e;
544
+ }
336
545
  }
337
546
 
338
547
  /**
@@ -343,18 +552,33 @@ export default class Nymph {
343
552
  * @returns True on success, false on failure.
344
553
  */
345
554
  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);
555
+ try {
556
+ for (let callback of this.beforeSetUIDCallbacks) {
557
+ if (callback) {
558
+ await callback(this, name, value);
559
+ }
349
560
  }
350
- }
351
- const result = this.driver.setUID(name, value);
352
- for (let callback of this.afterSetUIDCallbacks) {
353
- if (callback) {
354
- await callback(this, result);
561
+ let result: Promise<boolean>;
562
+ try {
563
+ result = this.driver.setUID(name, value);
564
+ } catch (e: any) {
565
+ for (let callback of this.failedSetUIDCallbacks) {
566
+ if (callback) {
567
+ await callback(this, e);
568
+ }
569
+ }
570
+ throw e;
571
+ }
572
+ for (let callback of this.afterSetUIDCallbacks) {
573
+ if (callback) {
574
+ await callback(this, result);
575
+ }
355
576
  }
577
+ return await result;
578
+ } catch (e: any) {
579
+ this.config.debugError('nymph', `Failed to set UID "${name}": ${e}`);
580
+ throw e;
356
581
  }
357
- return await result;
358
582
  }
359
583
 
360
584
  /**
@@ -364,18 +588,33 @@ export default class Nymph {
364
588
  * @returns True on success, false on failure.
365
589
  */
366
590
  public async deleteUID(name: string): Promise<boolean> {
367
- for (let callback of this.beforeDeleteUIDCallbacks) {
368
- if (callback) {
369
- await callback(this, name);
591
+ try {
592
+ for (let callback of this.beforeDeleteUIDCallbacks) {
593
+ if (callback) {
594
+ await callback(this, name);
595
+ }
370
596
  }
371
- }
372
- const result = this.driver.deleteUID(name);
373
- for (let callback of this.afterDeleteUIDCallbacks) {
374
- if (callback) {
375
- await callback(this, result);
597
+ let result: Promise<boolean>;
598
+ try {
599
+ result = this.driver.deleteUID(name);
600
+ } catch (e: any) {
601
+ for (let callback of this.failedDeleteUIDCallbacks) {
602
+ if (callback) {
603
+ await callback(this, e);
604
+ }
605
+ }
606
+ throw e;
376
607
  }
608
+ for (let callback of this.afterDeleteUIDCallbacks) {
609
+ if (callback) {
610
+ await callback(this, result);
611
+ }
612
+ }
613
+ return await result;
614
+ } catch (e: any) {
615
+ this.config.debugError('nymph', `Failed to delete UID "${name}": ${e}`);
616
+ throw e;
377
617
  }
378
- return await result;
379
618
  }
380
619
 
381
620
  /**
@@ -386,18 +625,36 @@ export default class Nymph {
386
625
  * @returns True on success, false on failure.
387
626
  */
388
627
  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);
628
+ try {
629
+ for (let callback of this.beforeRenameUIDCallbacks) {
630
+ if (callback) {
631
+ await callback(this, oldName, newName);
632
+ }
392
633
  }
393
- }
394
- const result = this.driver.renameUID(oldName, newName);
395
- for (let callback of this.afterRenameUIDCallbacks) {
396
- if (callback) {
397
- await callback(this, result);
634
+ let result: Promise<boolean>;
635
+ try {
636
+ result = this.driver.renameUID(oldName, newName);
637
+ } catch (e: any) {
638
+ for (let callback of this.failedRenameUIDCallbacks) {
639
+ if (callback) {
640
+ await callback(this, e);
641
+ }
642
+ }
643
+ throw e;
398
644
  }
645
+ for (let callback of this.afterRenameUIDCallbacks) {
646
+ if (callback) {
647
+ await callback(this, result);
648
+ }
649
+ }
650
+ return await result;
651
+ } catch (e: any) {
652
+ this.config.debugError(
653
+ 'nymph',
654
+ `Failed to rename UID "${oldName}" to "${newName}": ${e}`,
655
+ );
656
+ throw e;
399
657
  }
400
- return await result;
401
658
  }
402
659
 
403
660
  /**
@@ -412,18 +669,33 @@ export default class Nymph {
412
669
  * @returns True on success, false on failure.
413
670
  */
414
671
  public async saveEntity(entity: EntityInterface): Promise<boolean> {
415
- for (let callback of this.beforeSaveEntityCallbacks) {
416
- if (callback) {
417
- await callback(this, entity);
672
+ try {
673
+ for (let callback of this.beforeSaveEntityCallbacks) {
674
+ if (callback) {
675
+ await callback(this, entity);
676
+ }
418
677
  }
419
- }
420
- const result = this.driver.saveEntity(entity);
421
- for (let callback of this.afterSaveEntityCallbacks) {
422
- if (callback) {
423
- await callback(this, result);
678
+ let result: Promise<boolean>;
679
+ try {
680
+ result = this.driver.saveEntity(entity);
681
+ } catch (e: any) {
682
+ for (let callback of this.failedSaveEntityCallbacks) {
683
+ if (callback) {
684
+ await callback(this, e);
685
+ }
686
+ }
687
+ throw e;
688
+ }
689
+ for (let callback of this.afterSaveEntityCallbacks) {
690
+ if (callback) {
691
+ await callback(this, result);
692
+ }
424
693
  }
694
+ return await result;
695
+ } catch (e: any) {
696
+ this.config.debugError('nymph', `Failed to save entity: ${e}`);
697
+ throw e;
425
698
  }
426
- return await result;
427
699
  }
428
700
 
429
701
  /**
@@ -436,10 +708,12 @@ export default class Nymph {
436
708
  * - offset - The offset from the oldest matching entity to start retrieving.
437
709
  * - reverse - If true, entities will be retrieved from newest to oldest.
438
710
  * Therefore, offset will be from the newest entity.
439
- * - sort - How to sort the entities. Accepts "cdate" or "mdate". Defaults to
440
- * "cdate".
441
- * - return - What to return. "entity", "guid", or "count". Defaults to
442
- * "entity".
711
+ * - sort - How to sort the entities. Accepts "cdate", "mdate", or the name of
712
+ * a top-level property. The method of sorting properties other than cdate
713
+ * and mdate is driver dependent. The only hard rule is that numbers should
714
+ * be sorted numerically (2 before 10). Defaults to "cdate".
715
+ * - return - What to return. "entity", "object", "guid", or "count". Defaults
716
+ * to "entity".
443
717
  * - source - Will be 'client' if the query came from a REST call.
444
718
  * - skipCache - If true, Nymph will skip the cache and retrieve the entity
445
719
  * from the DB.
@@ -472,6 +746,11 @@ export default class Nymph {
472
746
  * - contain - An array with a name, then value. True if the named property
473
747
  * contains the value (its JSON string is found within the property's JSON
474
748
  * string).
749
+ * - search - An array with a name, then search query. True if the named
750
+ * property matches the query. Use single quotes to find sequential terms.
751
+ * Use double quotes to find exact terms. Use "or" as the or operator. Use
752
+ * "-" before a term as the negation operator. Stop words and punctuation
753
+ * are stripped. Case insensitive.
475
754
  * - match - An array with a name, then regular expression. True if the
476
755
  * named property matches. Uses POSIX RegExp. Case sensitive. Must *not* be
477
756
  * surrounded by any delimiters.
@@ -593,20 +872,37 @@ export default class Nymph {
593
872
  options: Options<T> & { return: 'guid' },
594
873
  ...selectors: Selector[]
595
874
  ): Promise<string[]>;
875
+ public async getEntities<T extends EntityConstructor = EntityConstructor>(
876
+ options: Options<T> & { return: 'object' },
877
+ ...selectors: Selector[]
878
+ ): Promise<EntityObjectType<T>[]>;
596
879
  public async getEntities<T extends EntityConstructor = EntityConstructor>(
597
880
  options?: Options<T>,
598
881
  ...selectors: Selector[]
599
- ): Promise<ReturnType<T['factorySync']>[]>;
882
+ ): Promise<EntityInstanceType<T>[]>;
600
883
  public async getEntities<T extends EntityConstructor = EntityConstructor>(
601
884
  options: Options<T> = {},
602
885
  ...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);
886
+ ): Promise<
887
+ EntityInstanceType<T>[] | EntityObjectType<T>[] | string[] | number
888
+ > {
889
+ if (options.source === 'client' && options.return === 'object') {
890
+ throw new InvalidParametersError(
891
+ 'Object return type not allowed from client.',
892
+ );
893
+ }
894
+
895
+ try {
896
+ for (let callback of this.beforeGetEntitiesCallbacks) {
897
+ if (callback) {
898
+ await callback(this, options, selectors);
899
+ }
607
900
  }
901
+ return await this.driver.getEntities(options, ...selectors);
902
+ } catch (e: any) {
903
+ this.config.debugError('nymph', `Failed to get entities: ${e}`);
904
+ throw e;
608
905
  }
609
- return await this.driver.getEntities(options, ...selectors);
610
906
  }
611
907
 
612
908
  /**
@@ -630,43 +926,64 @@ export default class Nymph {
630
926
  options: Options<T> & { return: 'guid' },
631
927
  ...selectors: Selector[]
632
928
  ): Promise<string | null>;
929
+ public async getEntity<T extends EntityConstructor = EntityConstructor>(
930
+ options: Options<T> & { return: 'object' },
931
+ ...selectors: Selector[]
932
+ ): Promise<EntityObjectType<T> | null>;
633
933
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
634
934
  options: Options<T>,
635
935
  ...selectors: Selector[]
636
- ): Promise<ReturnType<T['factorySync']> | null>;
936
+ ): Promise<EntityInstanceType<T> | null>;
637
937
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
638
938
  options: Options<T> & { return: 'guid' },
639
- guid: string
939
+ guid: string,
640
940
  ): Promise<string | null>;
941
+ public async getEntity<T extends EntityConstructor = EntityConstructor>(
942
+ options: Options<T> & { return: 'object' },
943
+ guid: string,
944
+ ): Promise<EntityObjectType<T> | null>;
641
945
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
642
946
  options: Options<T>,
643
- guid: string
644
- ): Promise<ReturnType<T['factorySync']> | null>;
947
+ guid: string,
948
+ ): Promise<EntityInstanceType<T> | null>;
645
949
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
646
950
  options: Options<T> = {},
647
951
  ...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] }];
952
+ ): Promise<
953
+ EntityInstanceType<T> | EntityObjectType<T> | string | number | null
954
+ > {
955
+ if (options.source === 'client' && options.return === 'object') {
956
+ throw new InvalidParametersError(
957
+ 'Object return type not allowed from client.',
958
+ );
652
959
  }
653
- options.limit = 1;
654
- for (let callback of this.beforeGetEntityCallbacks) {
655
- if (callback) {
656
- await callback(this, options, selectors as Selector[]);
960
+
961
+ try {
962
+ // Set up options and selectors.
963
+ if (typeof selectors[0] === 'string') {
964
+ selectors = [{ type: '&', guid: selectors[0] }];
657
965
  }
966
+ options.limit = 1;
967
+ for (let callback of this.beforeGetEntityCallbacks) {
968
+ if (callback) {
969
+ await callback(this, options, selectors as Selector[]);
970
+ }
971
+ }
972
+ const entities = await this.driver.getEntities(
973
+ options,
974
+ ...(selectors as Selector[]),
975
+ );
976
+ if (options.return === 'count') {
977
+ return entities as unknown as number;
978
+ }
979
+ if (!entities || !entities.length) {
980
+ return null;
981
+ }
982
+ return entities[0];
983
+ } catch (e: any) {
984
+ this.config.debugError('nymph', `Failed to get entity: ${e}`);
985
+ throw e;
658
986
  }
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
987
  }
671
988
 
672
989
  /**
@@ -676,18 +993,33 @@ export default class Nymph {
676
993
  * @returns True on success, false on failure.
677
994
  */
678
995
  public async deleteEntity(entity: EntityInterface): Promise<boolean> {
679
- for (let callback of this.beforeDeleteEntityCallbacks) {
680
- if (callback) {
681
- await callback(this, entity);
996
+ try {
997
+ for (let callback of this.beforeDeleteEntityCallbacks) {
998
+ if (callback) {
999
+ await callback(this, entity);
1000
+ }
682
1001
  }
683
- }
684
- const result = this.driver.deleteEntity(entity);
685
- for (let callback of this.afterDeleteEntityCallbacks) {
686
- if (callback) {
687
- await callback(this, result);
1002
+ let result: Promise<boolean>;
1003
+ try {
1004
+ result = this.driver.deleteEntity(entity);
1005
+ } catch (e: any) {
1006
+ for (let callback of this.failedDeleteEntityCallbacks) {
1007
+ if (callback) {
1008
+ await callback(this, e);
1009
+ }
1010
+ }
1011
+ throw e;
688
1012
  }
1013
+ for (let callback of this.afterDeleteEntityCallbacks) {
1014
+ if (callback) {
1015
+ await callback(this, result);
1016
+ }
1017
+ }
1018
+ return await result;
1019
+ } catch (e: any) {
1020
+ this.config.debugError('nymph', `Failed to delete entity: ${e}`);
1021
+ throw e;
689
1022
  }
690
- return await result;
691
1023
  }
692
1024
 
693
1025
  /**
@@ -699,20 +1031,35 @@ export default class Nymph {
699
1031
  */
700
1032
  public async deleteEntityByID(
701
1033
  guid: string,
702
- className?: string
1034
+ className?: string,
703
1035
  ): Promise<boolean> {
704
- for (let callback of this.beforeDeleteEntityByIDCallbacks) {
705
- if (callback) {
706
- await callback(this, guid, className);
1036
+ try {
1037
+ for (let callback of this.beforeDeleteEntityByIDCallbacks) {
1038
+ if (callback) {
1039
+ await callback(this, guid, className);
1040
+ }
707
1041
  }
708
- }
709
- const result = this.driver.deleteEntityByID(guid, className);
710
- for (let callback of this.afterDeleteEntityByIDCallbacks) {
711
- if (callback) {
712
- await callback(this, result);
1042
+ let result: Promise<boolean>;
1043
+ try {
1044
+ result = this.driver.deleteEntityByID(guid, className);
1045
+ } catch (e: any) {
1046
+ for (let callback of this.failedDeleteEntityByIDCallbacks) {
1047
+ if (callback) {
1048
+ await callback(this, e);
1049
+ }
1050
+ }
1051
+ throw e;
1052
+ }
1053
+ for (let callback of this.afterDeleteEntityByIDCallbacks) {
1054
+ if (callback) {
1055
+ await callback(this, result);
1056
+ }
713
1057
  }
1058
+ return await result;
1059
+ } catch (e: any) {
1060
+ this.config.debugError('nymph', `Failed to delete entity by ID: ${e}`);
1061
+ throw e;
714
1062
  }
715
- return await result;
716
1063
  }
717
1064
 
718
1065
  /**
@@ -737,7 +1084,7 @@ export default class Nymph {
737
1084
  * # brackets ([]).
738
1085
  * # Properties are stored like this:
739
1086
  * # propname=JSON.stringify(value)
740
- * abilities=["system/all"]
1087
+ * abilities=["system/admin"]
741
1088
  * groups=[]
742
1089
  * inheritAbilities=false
743
1090
  * name="admin"
@@ -752,7 +1099,12 @@ export default class Nymph {
752
1099
  * @returns True on success, false on failure.
753
1100
  */
754
1101
  public async export(filename: string): Promise<boolean> {
755
- return await this.driver.export(filename);
1102
+ try {
1103
+ return await this.driver.export(filename);
1104
+ } catch (e: any) {
1105
+ this.config.debugError('nymph', `Failed to export: ${e}`);
1106
+ throw e;
1107
+ }
756
1108
  }
757
1109
 
758
1110
  /**
@@ -761,7 +1113,12 @@ export default class Nymph {
761
1113
  * @returns True on success, false on failure.
762
1114
  */
763
1115
  public async exportPrint(): Promise<boolean> {
764
- return await this.driver.exportPrint();
1116
+ try {
1117
+ return await this.driver.exportPrint();
1118
+ } catch (e: any) {
1119
+ this.config.debugError('nymph', `Failed to export: ${e}`);
1120
+ throw e;
1121
+ }
765
1122
  }
766
1123
 
767
1124
  /**
@@ -771,7 +1128,92 @@ export default class Nymph {
771
1128
  * @returns True on success, false on failure.
772
1129
  */
773
1130
  public async import(filename: string): Promise<boolean> {
774
- return await this.driver.import(filename);
1131
+ try {
1132
+ return await this.driver.import(filename);
1133
+ } catch (e: any) {
1134
+ this.config.debugError('nymph', `Failed to import: ${e}`);
1135
+ throw e;
1136
+ }
1137
+ }
1138
+
1139
+ /**
1140
+ * Import a single entity.
1141
+ *
1142
+ * @param entity The entity data to import.
1143
+ */
1144
+ public async importEntity(entity: {
1145
+ guid: string;
1146
+ cdate: number;
1147
+ mdate: number;
1148
+ tags: string[];
1149
+ sdata: SerializedEntityData;
1150
+ etype: string;
1151
+ }) {
1152
+ try {
1153
+ return await this.driver.importEntity(entity);
1154
+ } catch (e: any) {
1155
+ this.config.debugError('nymph', `Failed to import: ${e}`);
1156
+ throw e;
1157
+ }
1158
+ }
1159
+
1160
+ /**
1161
+ * Import a single entity's tokens.
1162
+ *
1163
+ * This does not update any of the actual data, only the tokens used for full
1164
+ * text search.
1165
+ *
1166
+ * Be careful with this function, since you can overwrite existing tokens with
1167
+ * data that is out of sync. The DB _should_ prevent you from inserting tokens
1168
+ * for an entity that doesn't exist, but it _won't_ prevent you from inserting
1169
+ * tokens for properties that don't exist on an entity.
1170
+ *
1171
+ * @param entity The entity data to import.
1172
+ */
1173
+ public async importEntityTokens(entity: {
1174
+ guid: string;
1175
+ cdate: number;
1176
+ mdate: number;
1177
+ tags: string[];
1178
+ sdata: SerializedEntityData;
1179
+ etype: string;
1180
+ }) {
1181
+ try {
1182
+ return await this.driver.importEntityTokens(entity);
1183
+ } catch (e: any) {
1184
+ this.config.debugError('nymph', `Failed to import: ${e}`);
1185
+ throw e;
1186
+ }
1187
+ }
1188
+
1189
+ /**
1190
+ * Detect whether the database needs to be migrated.
1191
+ *
1192
+ * If not false (so, one of the string values), the database should be
1193
+ * exported with an old version of Nymph, then imported into a fresh database
1194
+ * with this version.
1195
+ *
1196
+ * 'json' means the data tables are missing the JSON field, and the DB
1197
+ * **must** be exported and imported to fix it.
1198
+ *
1199
+ * 'tokens' means the FTS token tables are missing, and you can get away with
1200
+ * a live migration with `liveMigration('tokenTables')` and doing
1201
+ * `importEntityTokens(entity)` for each entity.
1202
+ */
1203
+ public async needsMigration() {
1204
+ return await this.driver.needsMigration();
1205
+ }
1206
+
1207
+ /**
1208
+ * Perform a live migration on the DB.
1209
+ *
1210
+ * A 'tokenTables' migration will simply add the missing token tables. It will
1211
+ * **not** fill them. You must use `importEntityTokens` on each entity after
1212
+ * running this to fill the token tables and enable full text search matching
1213
+ * on existing entities.
1214
+ */
1215
+ public async liveMigration(migrationType: 'tokenTables') {
1216
+ return await this.driver.liveMigration(migrationType);
775
1217
  }
776
1218
 
777
1219
  public on<T extends NymphEventType>(
@@ -779,82 +1221,134 @@ export default class Nymph {
779
1221
  callback: T extends 'connect'
780
1222
  ? NymphConnectCallback
781
1223
  : T extends 'disconnect'
782
- ? NymphDisconnectCallback
783
- : T extends 'query'
784
- ? NymphQueryCallback
785
- : T extends 'beforeGetEntity'
786
- ? NymphBeforeGetEntityCallback
787
- : T extends 'beforeGetEntities'
788
- ? NymphBeforeGetEntitiesCallback
789
- : T extends 'beforeSaveEntity'
790
- ? NymphBeforeSaveEntityCallback
791
- : T extends 'afterSaveEntity'
792
- ? NymphAfterSaveEntityCallback
793
- : T extends 'beforeDeleteEntity'
794
- ? NymphBeforeDeleteEntityCallback
795
- : T extends 'afterDeleteEntity'
796
- ? NymphAfterDeleteEntityCallback
797
- : T extends 'beforeDeleteEntityByID'
798
- ? NymphBeforeDeleteEntityByIDCallback
799
- : T extends 'afterDeleteEntityByID'
800
- ? NymphAfterDeleteEntityByIDCallback
801
- : T extends 'beforeNewUID'
802
- ? NymphBeforeNewUIDCallback
803
- : T extends 'afterNewUID'
804
- ? NymphAfterNewUIDCallback
805
- : T extends 'beforeSetUID'
806
- ? NymphBeforeSetUIDCallback
807
- : T extends 'afterSetUID'
808
- ? NymphAfterSetUIDCallback
809
- : T extends 'beforeRenameUID'
810
- ? NymphBeforeRenameUIDCallback
811
- : T extends 'afterRenameUID'
812
- ? NymphAfterRenameUIDCallback
813
- : T extends 'beforeDeleteUID'
814
- ? NymphBeforeDeleteUIDCallback
815
- : T extends 'afterDeleteUID'
816
- ? NymphAfterDeleteUIDCallback
817
- : never
1224
+ ? NymphDisconnectCallback
1225
+ : T extends 'query'
1226
+ ? NymphQueryCallback
1227
+ : T extends 'beforeGetEntity'
1228
+ ? NymphBeforeGetEntityCallback
1229
+ : T extends 'beforeGetEntities'
1230
+ ? NymphBeforeGetEntitiesCallback
1231
+ : T extends 'beforeSaveEntity'
1232
+ ? NymphBeforeSaveEntityCallback
1233
+ : T extends 'afterSaveEntity'
1234
+ ? NymphAfterSaveEntityCallback
1235
+ : T extends 'failedSaveEntity'
1236
+ ? NymphFailedSaveEntityCallback
1237
+ : T extends 'beforeDeleteEntity'
1238
+ ? NymphBeforeDeleteEntityCallback
1239
+ : T extends 'afterDeleteEntity'
1240
+ ? NymphAfterDeleteEntityCallback
1241
+ : T extends 'failedDeleteEntity'
1242
+ ? NymphFailedDeleteEntityCallback
1243
+ : T extends 'beforeDeleteEntityByID'
1244
+ ? NymphBeforeDeleteEntityByIDCallback
1245
+ : T extends 'afterDeleteEntityByID'
1246
+ ? NymphAfterDeleteEntityByIDCallback
1247
+ : T extends 'failedDeleteEntityByID'
1248
+ ? NymphFailedDeleteEntityByIDCallback
1249
+ : T extends 'beforeNewUID'
1250
+ ? NymphBeforeNewUIDCallback
1251
+ : T extends 'afterNewUID'
1252
+ ? NymphAfterNewUIDCallback
1253
+ : T extends 'failedNewUID'
1254
+ ? NymphFailedNewUIDCallback
1255
+ : T extends 'beforeSetUID'
1256
+ ? NymphBeforeSetUIDCallback
1257
+ : T extends 'afterSetUID'
1258
+ ? NymphAfterSetUIDCallback
1259
+ : T extends 'failedSetUID'
1260
+ ? NymphFailedSetUIDCallback
1261
+ : T extends 'beforeRenameUID'
1262
+ ? NymphBeforeRenameUIDCallback
1263
+ : T extends 'afterRenameUID'
1264
+ ? NymphAfterRenameUIDCallback
1265
+ : T extends 'failedRenameUID'
1266
+ ? NymphFailedRenameUIDCallback
1267
+ : T extends 'beforeDeleteUID'
1268
+ ? NymphBeforeDeleteUIDCallback
1269
+ : T extends 'afterDeleteUID'
1270
+ ? NymphAfterDeleteUIDCallback
1271
+ : T extends 'failedDeleteUID'
1272
+ ? NymphFailedDeleteUIDCallback
1273
+ : T extends 'beforeStartTransaction'
1274
+ ? NymphBeforeStartTransactionCallback
1275
+ : T extends 'afterStartTransaction'
1276
+ ? NymphAfterStartTransactionCallback
1277
+ : T extends 'beforeCommitTransaction'
1278
+ ? NymphBeforeCommitTransactionCallback
1279
+ : T extends 'afterCommitTransaction'
1280
+ ? NymphAfterCommitTransactionCallback
1281
+ : T extends 'beforeRollbackTransaction'
1282
+ ? NymphBeforeRollbackTransactionCallback
1283
+ : T extends 'afterRollbackTransaction'
1284
+ ? NymphAfterRollbackTransactionCallback
1285
+ : never,
818
1286
  ) {
819
1287
  const prop = (event + 'Callbacks') as T extends 'connect'
820
1288
  ? 'connectCallbacks'
821
1289
  : T extends 'disconnect'
822
- ? 'disconnectCallbacks'
823
- : T extends 'query'
824
- ? 'queryCallbacks'
825
- : T extends 'beforeGetEntity'
826
- ? 'beforeGetEntityCallbacks'
827
- : T extends 'beforeGetEntities'
828
- ? 'beforeGetEntitiesCallbacks'
829
- : T extends 'beforeSaveEntity'
830
- ? 'beforeSaveEntityCallbacks'
831
- : T extends 'afterSaveEntity'
832
- ? 'afterSaveEntityCallbacks'
833
- : T extends 'beforeDeleteEntity'
834
- ? 'beforeDeleteEntityCallbacks'
835
- : T extends 'afterDeleteEntity'
836
- ? 'afterDeleteEntityCallbacks'
837
- : T extends 'beforeDeleteEntityByID'
838
- ? 'beforeDeleteEntityByIDCallbacks'
839
- : T extends 'afterDeleteEntityByID'
840
- ? 'afterDeleteEntityByIDCallbacks'
841
- : T extends 'beforeNewUID'
842
- ? 'beforeNewUIDCallbacks'
843
- : T extends 'afterNewUID'
844
- ? 'afterNewUIDCallbacks'
845
- : T extends 'beforeSetUID'
846
- ? 'beforeSetUIDCallbacks'
847
- : T extends 'afterSetUID'
848
- ? 'afterSetUIDCallbacks'
849
- : T extends 'beforeRenameUID'
850
- ? 'beforeRenameUIDCallbacks'
851
- : T extends 'afterRenameUID'
852
- ? 'afterRenameUIDCallbacks'
853
- : T extends 'beforeDeleteUID'
854
- ? 'beforeDeleteUIDCallbacks'
855
- : T extends 'afterDeleteUID'
856
- ? 'afterDeleteUIDCallbacks'
857
- : never;
1290
+ ? 'disconnectCallbacks'
1291
+ : T extends 'query'
1292
+ ? 'queryCallbacks'
1293
+ : T extends 'beforeGetEntity'
1294
+ ? 'beforeGetEntityCallbacks'
1295
+ : T extends 'beforeGetEntities'
1296
+ ? 'beforeGetEntitiesCallbacks'
1297
+ : T extends 'beforeSaveEntity'
1298
+ ? 'beforeSaveEntityCallbacks'
1299
+ : T extends 'afterSaveEntity'
1300
+ ? 'afterSaveEntityCallbacks'
1301
+ : T extends 'failedSaveEntity'
1302
+ ? 'failedSaveEntityCallbacks'
1303
+ : T extends 'beforeDeleteEntity'
1304
+ ? 'beforeDeleteEntityCallbacks'
1305
+ : T extends 'afterDeleteEntity'
1306
+ ? 'afterDeleteEntityCallbacks'
1307
+ : T extends 'failedDeleteEntity'
1308
+ ? 'failedDeleteEntityCallbacks'
1309
+ : T extends 'beforeDeleteEntityByID'
1310
+ ? 'beforeDeleteEntityByIDCallbacks'
1311
+ : T extends 'afterDeleteEntityByID'
1312
+ ? 'afterDeleteEntityByIDCallbacks'
1313
+ : T extends 'failedDeleteEntityByID'
1314
+ ? 'failedDeleteEntityByIDCallbacks'
1315
+ : T extends 'beforeNewUID'
1316
+ ? 'beforeNewUIDCallbacks'
1317
+ : T extends 'afterNewUID'
1318
+ ? 'afterNewUIDCallbacks'
1319
+ : T extends 'failedNewUID'
1320
+ ? 'failedNewUIDCallbacks'
1321
+ : T extends 'beforeSetUID'
1322
+ ? 'beforeSetUIDCallbacks'
1323
+ : T extends 'afterSetUID'
1324
+ ? 'afterSetUIDCallbacks'
1325
+ : T extends 'failedSetUID'
1326
+ ? 'failedSetUIDCallbacks'
1327
+ : T extends 'beforeRenameUID'
1328
+ ? 'beforeRenameUIDCallbacks'
1329
+ : T extends 'afterRenameUID'
1330
+ ? 'afterRenameUIDCallbacks'
1331
+ : T extends 'failedRenameUID'
1332
+ ? 'failedRenameUIDCallbacks'
1333
+ : T extends 'beforeDeleteUID'
1334
+ ? 'beforeDeleteUIDCallbacks'
1335
+ : T extends 'afterDeleteUID'
1336
+ ? 'afterDeleteUIDCallbacks'
1337
+ : T extends 'failedDeleteUID'
1338
+ ? 'failedDeleteUIDCallbacks'
1339
+ : T extends 'beforeStartTransaction'
1340
+ ? 'beforeStartTransactionCallbacks'
1341
+ : T extends 'afterStartTransaction'
1342
+ ? 'afterStartTransactionCallbacks'
1343
+ : T extends 'beforeCommitTransaction'
1344
+ ? 'beforeCommitTransactionCallbacks'
1345
+ : T extends 'afterCommitTransaction'
1346
+ ? 'afterCommitTransactionCallbacks'
1347
+ : T extends 'beforeRollbackTransaction'
1348
+ ? 'beforeRollbackTransactionCallbacks'
1349
+ : T extends 'afterRollbackTransaction'
1350
+ ? 'afterRollbackTransactionCallbacks'
1351
+ : never;
858
1352
  if (!(prop in this)) {
859
1353
  throw new Error('Invalid event type.');
860
1354
  }
@@ -868,82 +1362,134 @@ export default class Nymph {
868
1362
  callback: T extends 'connect'
869
1363
  ? NymphConnectCallback
870
1364
  : T extends 'disconnect'
871
- ? NymphDisconnectCallback
872
- : T extends 'query'
873
- ? NymphQueryCallback
874
- : T extends 'beforeGetEntity'
875
- ? NymphBeforeGetEntityCallback
876
- : T extends 'beforeGetEntities'
877
- ? NymphBeforeGetEntitiesCallback
878
- : T extends 'beforeSaveEntity'
879
- ? NymphBeforeSaveEntityCallback
880
- : T extends 'afterSaveEntity'
881
- ? NymphAfterSaveEntityCallback
882
- : T extends 'beforeDeleteEntity'
883
- ? NymphBeforeDeleteEntityCallback
884
- : T extends 'afterDeleteEntity'
885
- ? NymphAfterDeleteEntityCallback
886
- : T extends 'beforeDeleteEntityByID'
887
- ? NymphBeforeDeleteEntityByIDCallback
888
- : T extends 'afterDeleteEntityByID'
889
- ? NymphAfterDeleteEntityByIDCallback
890
- : T extends 'beforeNewUID'
891
- ? NymphBeforeNewUIDCallback
892
- : T extends 'afterNewUID'
893
- ? NymphAfterNewUIDCallback
894
- : T extends 'beforeSetUID'
895
- ? NymphBeforeSetUIDCallback
896
- : T extends 'afterSetUID'
897
- ? NymphAfterSetUIDCallback
898
- : T extends 'beforeRenameUID'
899
- ? NymphBeforeRenameUIDCallback
900
- : T extends 'afterRenameUID'
901
- ? NymphAfterRenameUIDCallback
902
- : T extends 'beforeDeleteUID'
903
- ? NymphBeforeDeleteUIDCallback
904
- : T extends 'afterDeleteUID'
905
- ? NymphAfterDeleteUIDCallback
906
- : never
1365
+ ? NymphDisconnectCallback
1366
+ : T extends 'query'
1367
+ ? NymphQueryCallback
1368
+ : T extends 'beforeGetEntity'
1369
+ ? NymphBeforeGetEntityCallback
1370
+ : T extends 'beforeGetEntities'
1371
+ ? NymphBeforeGetEntitiesCallback
1372
+ : T extends 'beforeSaveEntity'
1373
+ ? NymphBeforeSaveEntityCallback
1374
+ : T extends 'afterSaveEntity'
1375
+ ? NymphAfterSaveEntityCallback
1376
+ : T extends 'failedSaveEntity'
1377
+ ? NymphFailedSaveEntityCallback
1378
+ : T extends 'beforeDeleteEntity'
1379
+ ? NymphBeforeDeleteEntityCallback
1380
+ : T extends 'afterDeleteEntity'
1381
+ ? NymphAfterDeleteEntityCallback
1382
+ : T extends 'failedDeleteEntity'
1383
+ ? NymphFailedDeleteEntityCallback
1384
+ : T extends 'beforeDeleteEntityByID'
1385
+ ? NymphBeforeDeleteEntityByIDCallback
1386
+ : T extends 'afterDeleteEntityByID'
1387
+ ? NymphAfterDeleteEntityByIDCallback
1388
+ : T extends 'failedDeleteEntityByID'
1389
+ ? NymphFailedDeleteEntityByIDCallback
1390
+ : T extends 'beforeNewUID'
1391
+ ? NymphBeforeNewUIDCallback
1392
+ : T extends 'afterNewUID'
1393
+ ? NymphAfterNewUIDCallback
1394
+ : T extends 'failedNewUID'
1395
+ ? NymphFailedNewUIDCallback
1396
+ : T extends 'beforeSetUID'
1397
+ ? NymphBeforeSetUIDCallback
1398
+ : T extends 'afterSetUID'
1399
+ ? NymphAfterSetUIDCallback
1400
+ : T extends 'failedSetUID'
1401
+ ? NymphFailedSetUIDCallback
1402
+ : T extends 'beforeRenameUID'
1403
+ ? NymphBeforeRenameUIDCallback
1404
+ : T extends 'afterRenameUID'
1405
+ ? NymphAfterRenameUIDCallback
1406
+ : T extends 'failedRenameUID'
1407
+ ? NymphFailedRenameUIDCallback
1408
+ : T extends 'beforeDeleteUID'
1409
+ ? NymphBeforeDeleteUIDCallback
1410
+ : T extends 'afterDeleteUID'
1411
+ ? NymphAfterDeleteUIDCallback
1412
+ : T extends 'failedDeleteUID'
1413
+ ? NymphFailedDeleteUIDCallback
1414
+ : T extends 'beforeStartTransaction'
1415
+ ? NymphBeforeStartTransactionCallback
1416
+ : T extends 'afterStartTransaction'
1417
+ ? NymphAfterStartTransactionCallback
1418
+ : T extends 'beforeCommitTransaction'
1419
+ ? NymphBeforeCommitTransactionCallback
1420
+ : T extends 'afterCommitTransaction'
1421
+ ? NymphAfterCommitTransactionCallback
1422
+ : T extends 'beforeRollbackTransaction'
1423
+ ? NymphBeforeRollbackTransactionCallback
1424
+ : T extends 'afterRollbackTransaction'
1425
+ ? NymphAfterRollbackTransactionCallback
1426
+ : never,
907
1427
  ) {
908
1428
  const prop = (event + 'Callbacks') as T extends 'connect'
909
1429
  ? 'connectCallbacks'
910
1430
  : T extends 'disconnect'
911
- ? 'disconnectCallbacks'
912
- : T extends 'query'
913
- ? 'queryCallbacks'
914
- : T extends 'beforeSaveEntity'
915
- ? 'beforeSaveEntityCallbacks'
916
- : T extends 'beforeGetEntity'
917
- ? 'beforeGetEntityCallbacks'
918
- : T extends 'beforeGetEntities'
919
- ? 'beforeGetEntitiesCallbacks'
920
- : T extends 'afterSaveEntity'
921
- ? 'afterSaveEntityCallbacks'
922
- : T extends 'beforeDeleteEntity'
923
- ? 'beforeDeleteEntityCallbacks'
924
- : T extends 'afterDeleteEntity'
925
- ? 'afterDeleteEntityCallbacks'
926
- : T extends 'beforeDeleteEntityByID'
927
- ? 'beforeDeleteEntityByIDCallbacks'
928
- : T extends 'afterDeleteEntityByID'
929
- ? 'afterDeleteEntityByIDCallbacks'
930
- : T extends 'beforeNewUID'
931
- ? 'beforeNewUIDCallbacks'
932
- : T extends 'afterNewUID'
933
- ? 'afterNewUIDCallbacks'
934
- : T extends 'beforeSetUID'
935
- ? 'beforeSetUIDCallbacks'
936
- : T extends 'afterSetUID'
937
- ? 'afterSetUIDCallbacks'
938
- : T extends 'beforeRenameUID'
939
- ? 'beforeRenameUIDCallbacks'
940
- : T extends 'afterRenameUID'
941
- ? 'afterRenameUIDCallbacks'
942
- : T extends 'beforeDeleteUID'
943
- ? 'beforeDeleteUIDCallbacks'
944
- : T extends 'afterDeleteUID'
945
- ? 'afterDeleteUIDCallbacks'
946
- : never;
1431
+ ? 'disconnectCallbacks'
1432
+ : T extends 'query'
1433
+ ? 'queryCallbacks'
1434
+ : T extends 'beforeSaveEntity'
1435
+ ? 'beforeSaveEntityCallbacks'
1436
+ : T extends 'beforeGetEntity'
1437
+ ? 'beforeGetEntityCallbacks'
1438
+ : T extends 'beforeGetEntities'
1439
+ ? 'beforeGetEntitiesCallbacks'
1440
+ : T extends 'afterSaveEntity'
1441
+ ? 'afterSaveEntityCallbacks'
1442
+ : T extends 'failedSaveEntity'
1443
+ ? 'failedSaveEntityCallbacks'
1444
+ : T extends 'beforeDeleteEntity'
1445
+ ? 'beforeDeleteEntityCallbacks'
1446
+ : T extends 'afterDeleteEntity'
1447
+ ? 'afterDeleteEntityCallbacks'
1448
+ : T extends 'failedDeleteEntity'
1449
+ ? 'failedDeleteEntityCallbacks'
1450
+ : T extends 'beforeDeleteEntityByID'
1451
+ ? 'beforeDeleteEntityByIDCallbacks'
1452
+ : T extends 'afterDeleteEntityByID'
1453
+ ? 'afterDeleteEntityByIDCallbacks'
1454
+ : T extends 'failedDeleteEntityByID'
1455
+ ? 'failedDeleteEntityByIDCallbacks'
1456
+ : T extends 'beforeNewUID'
1457
+ ? 'beforeNewUIDCallbacks'
1458
+ : T extends 'afterNewUID'
1459
+ ? 'afterNewUIDCallbacks'
1460
+ : T extends 'failedNewUID'
1461
+ ? 'failedNewUIDCallbacks'
1462
+ : T extends 'beforeSetUID'
1463
+ ? 'beforeSetUIDCallbacks'
1464
+ : T extends 'afterSetUID'
1465
+ ? 'afterSetUIDCallbacks'
1466
+ : T extends 'failedSetUID'
1467
+ ? 'failedSetUIDCallbacks'
1468
+ : T extends 'beforeRenameUID'
1469
+ ? 'beforeRenameUIDCallbacks'
1470
+ : T extends 'afterRenameUID'
1471
+ ? 'afterRenameUIDCallbacks'
1472
+ : T extends 'failedRenameUID'
1473
+ ? 'failedRenameUIDCallbacks'
1474
+ : T extends 'beforeDeleteUID'
1475
+ ? 'beforeDeleteUIDCallbacks'
1476
+ : T extends 'afterDeleteUID'
1477
+ ? 'afterDeleteUIDCallbacks'
1478
+ : T extends 'failedDeleteUID'
1479
+ ? 'failedDeleteUIDCallbacks'
1480
+ : T extends 'beforeStartTransaction'
1481
+ ? 'beforeStartTransactionCallbacks'
1482
+ : T extends 'afterStartTransaction'
1483
+ ? 'afterStartTransactionCallbacks'
1484
+ : T extends 'beforeCommitTransaction'
1485
+ ? 'beforeCommitTransactionCallbacks'
1486
+ : T extends 'afterCommitTransaction'
1487
+ ? 'afterCommitTransactionCallbacks'
1488
+ : T extends 'beforeRollbackTransaction'
1489
+ ? 'beforeRollbackTransactionCallbacks'
1490
+ : T extends 'afterRollbackTransaction'
1491
+ ? 'afterRollbackTransactionCallbacks'
1492
+ : never;
947
1493
  if (!(prop in this)) {
948
1494
  return false;
949
1495
  }