@nymphjs/nymph 1.0.0-beta.13 → 1.0.0-beta.130

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 (123) hide show
  1. package/CHANGELOG.md +644 -0
  2. package/README.md +34 -24
  3. package/dist/Entity.d.ts +304 -15
  4. package/dist/Entity.js +609 -154
  5. package/dist/Entity.js.map +1 -1
  6. package/dist/Entity.test.js +75 -29
  7. package/dist/Entity.test.js.map +1 -1
  8. package/dist/Entity.types.d.ts +275 -28
  9. package/dist/Entity.types.js +1 -2
  10. package/dist/Nymph.d.ts +575 -11
  11. package/dist/Nymph.js +825 -288
  12. package/dist/Nymph.js.map +1 -1
  13. package/dist/Nymph.types.d.ts +117 -7
  14. package/dist/Nymph.types.js +47 -5
  15. package/dist/Nymph.types.js.map +1 -1
  16. package/dist/conf/defaults.d.ts +1 -1
  17. package/dist/conf/defaults.js +26 -3
  18. package/dist/conf/defaults.js.map +1 -1
  19. package/dist/conf/index.d.ts +50 -2
  20. package/dist/conf/index.js +2 -8
  21. package/dist/conf/index.js.map +1 -1
  22. package/dist/decorators/index.d.ts +1 -0
  23. package/dist/decorators/index.js +2 -0
  24. package/dist/decorators/index.js.map +1 -0
  25. package/dist/decorators/transactional.d.ts +12 -0
  26. package/dist/decorators/transactional.js +45 -0
  27. package/dist/decorators/transactional.js.map +1 -0
  28. package/dist/driver/NymphDriver.d.ts +209 -41
  29. package/dist/driver/NymphDriver.js +737 -242
  30. package/dist/driver/NymphDriver.js.map +1 -1
  31. package/dist/driver/index.d.ts +1 -2
  32. package/dist/driver/index.js +2 -23
  33. package/dist/driver/index.js.map +1 -1
  34. package/dist/driver/testArtifacts.d.ts +4 -4
  35. package/dist/driver/testArtifacts.js +2016 -1086
  36. package/dist/driver/testArtifacts.js.map +1 -1
  37. package/dist/errors/ClassNotAvailableError.js +1 -5
  38. package/dist/errors/ClassNotAvailableError.js.map +1 -1
  39. package/dist/errors/EntityConflictError.js +1 -5
  40. package/dist/errors/EntityConflictError.js.map +1 -1
  41. package/dist/errors/EntityInvalidDataError.d.ts +6 -0
  42. package/dist/errors/EntityInvalidDataError.js +8 -6
  43. package/dist/errors/EntityInvalidDataError.js.map +1 -1
  44. package/dist/errors/EntityIsSleepingReferenceError.js +1 -5
  45. package/dist/errors/EntityIsSleepingReferenceError.js.map +1 -1
  46. package/dist/errors/EntityUniqueConstraintError.d.ts +3 -0
  47. package/dist/errors/EntityUniqueConstraintError.js +7 -0
  48. package/dist/errors/EntityUniqueConstraintError.js.map +1 -0
  49. package/dist/errors/HttpError.d.ts +5 -0
  50. package/dist/errors/HttpError.js +11 -0
  51. package/dist/errors/HttpError.js.map +1 -0
  52. package/dist/errors/InvalidParametersError.js +1 -5
  53. package/dist/errors/InvalidParametersError.js.map +1 -1
  54. package/dist/errors/InvalidStateError.d.ts +3 -0
  55. package/dist/errors/InvalidStateError.js +7 -0
  56. package/dist/errors/InvalidStateError.js.map +1 -0
  57. package/dist/errors/MethodFailedError.d.ts +3 -0
  58. package/dist/errors/MethodFailedError.js +7 -0
  59. package/dist/errors/MethodFailedError.js.map +1 -0
  60. package/dist/errors/NotConfiguredError.js +1 -5
  61. package/dist/errors/NotConfiguredError.js.map +1 -1
  62. package/dist/errors/QueryFailedError.d.ts +2 -1
  63. package/dist/errors/QueryFailedError.js +5 -6
  64. package/dist/errors/QueryFailedError.js.map +1 -1
  65. package/dist/errors/UnableToConnectError.js +1 -5
  66. package/dist/errors/UnableToConnectError.js.map +1 -1
  67. package/dist/errors/index.d.ts +12 -8
  68. package/dist/errors/index.js +12 -24
  69. package/dist/errors/index.js.map +1 -1
  70. package/dist/helpers/index.d.ts +1 -0
  71. package/dist/helpers/index.js +2 -0
  72. package/dist/helpers/index.js.map +1 -0
  73. package/dist/helpers/transaction.d.ts +15 -0
  74. package/dist/helpers/transaction.js +47 -0
  75. package/dist/helpers/transaction.js.map +1 -0
  76. package/dist/index.d.ts +13 -11
  77. package/dist/index.js +16 -34
  78. package/dist/index.js.map +1 -1
  79. package/dist/nymphJoiProps.d.ts +1 -1
  80. package/dist/nymphJoiProps.js +10 -15
  81. package/dist/nymphJoiProps.js.map +1 -1
  82. package/dist/testArtifacts.d.ts +21 -6
  83. package/dist/testArtifacts.js +124 -50
  84. package/dist/testArtifacts.js.map +1 -1
  85. package/dist/testMocks.d.ts +27 -12
  86. package/dist/testMocks.js +44 -33
  87. package/dist/testMocks.js.map +1 -1
  88. package/dist/utils.d.ts +5 -5
  89. package/dist/utils.js +106 -68
  90. package/dist/utils.js.map +1 -1
  91. package/jest.config.js +31 -5
  92. package/package.json +43 -24
  93. package/src/Entity.test.ts +73 -23
  94. package/src/Entity.ts +555 -169
  95. package/src/Entity.types.ts +102 -90
  96. package/src/Nymph.ts +930 -517
  97. package/src/Nymph.types.ts +145 -39
  98. package/src/conf/defaults.ts +34 -1
  99. package/src/conf/index.ts +50 -2
  100. package/src/decorators/index.ts +1 -0
  101. package/src/decorators/transactional.ts +63 -0
  102. package/src/driver/NymphDriver.ts +987 -417
  103. package/src/driver/index.ts +1 -3
  104. package/src/driver/testArtifacts.ts +2699 -1628
  105. package/src/errors/EntityUniqueConstraintError.ts +6 -0
  106. package/src/errors/HttpError.ts +12 -0
  107. package/src/errors/InvalidStateError.ts +6 -0
  108. package/src/errors/MethodFailedError.ts +6 -0
  109. package/src/errors/QueryFailedError.ts +3 -1
  110. package/src/errors/index.ts +16 -8
  111. package/src/helpers/index.ts +1 -0
  112. package/src/helpers/transaction.ts +65 -0
  113. package/src/index.ts +13 -11
  114. package/src/nymphJoiProps.ts +2 -2
  115. package/src/testArtifacts.ts +69 -20
  116. package/src/testMocks.ts +107 -41
  117. package/src/utils.ts +102 -67
  118. package/tsconfig.json +6 -3
  119. package/typedoc.json +4 -0
  120. package/dist/conf/d.d.ts +0 -6
  121. package/dist/conf/d.js +0 -3
  122. package/dist/conf/d.js.map +0 -1
  123. package/src/conf/d.ts +0 -24
@@ -0,0 +1,6 @@
1
+ export class EntityUniqueConstraintError extends Error {
2
+ constructor(message: string) {
3
+ super(message);
4
+ this.name = 'EntityUniqueConstraintError';
5
+ }
6
+ }
@@ -0,0 +1,12 @@
1
+ export class HttpError extends Error {
2
+ status?: number;
3
+ statusText?: string;
4
+
5
+ constructor(message: string, status?: number, statusText?: string) {
6
+ super(message);
7
+
8
+ this.name = 'HttpError';
9
+ this.status = status;
10
+ this.statusText = statusText;
11
+ }
12
+ }
@@ -0,0 +1,6 @@
1
+ export class InvalidStateError extends Error {
2
+ constructor(message: string) {
3
+ super(message);
4
+ this.name = 'InvalidStateError';
5
+ }
6
+ }
@@ -0,0 +1,6 @@
1
+ export class MethodFailedError extends Error {
2
+ constructor(message: string) {
3
+ super(message);
4
+ this.name = 'MethodFailedError';
5
+ }
6
+ }
@@ -1,10 +1,12 @@
1
1
  export class QueryFailedError extends Error {
2
2
  private query?: string;
3
+ public errorCode?: number;
3
4
 
4
- constructor(message: string, query?: string) {
5
+ constructor(message: string, query?: string, errorCode?: number) {
5
6
  super(message);
6
7
  this.name = 'QueryFailedError';
7
8
  this.query = query;
9
+ this.errorCode = errorCode;
8
10
  }
9
11
 
10
12
  public getQuery() {
@@ -1,15 +1,23 @@
1
- export * from './ClassNotAvailableError';
1
+ export * from './ClassNotAvailableError.js';
2
2
 
3
- export * from './EntityConflictError';
3
+ export * from './EntityConflictError.js';
4
4
 
5
- export * from './EntityInvalidDataError';
5
+ export * from './EntityInvalidDataError.js';
6
6
 
7
- export * from './EntityIsSleepingReferenceError';
7
+ export * from './EntityIsSleepingReferenceError.js';
8
8
 
9
- export * from './InvalidParametersError';
9
+ export * from './EntityUniqueConstraintError.js';
10
10
 
11
- export * from './NotConfiguredError';
11
+ export * from './HttpError.js';
12
12
 
13
- export * from './QueryFailedError';
13
+ export * from './InvalidParametersError.js';
14
14
 
15
- export * from './UnableToConnectError';
15
+ export * from './InvalidStateError.js';
16
+
17
+ export * from './MethodFailedError.js';
18
+
19
+ export * from './NotConfiguredError.js';
20
+
21
+ export * from './QueryFailedError.js';
22
+
23
+ export * from './UnableToConnectError.js';
@@ -0,0 +1 @@
1
+ export * from './transaction.js';
@@ -0,0 +1,65 @@
1
+ import Nymph from '../Nymph.js';
2
+
3
+ /**
4
+ * Run a function inside of a transaction.
5
+ *
6
+ * @param nymph The instance of Nymph to start the transaction on.
7
+ * @param name The name of the transaction.
8
+ * @param fn The function that runs inside the transaction. It is passed the
9
+ * transactional instance of Nymph. If it resolves, the transaction is
10
+ * committed, and if it throws, the transaction is rolled back.
11
+ * @param finallyFn An optional function to run after the transaction is
12
+ * committed or rolled back. It is passed the original instance
13
+ * of Nymph. It SHOULD NOT throw.
14
+ * @returns The return value of the function.
15
+ */
16
+ export async function transaction<T>(
17
+ nymph: Nymph,
18
+ name: string,
19
+ fn: (nymph: Nymph) => Promise<T>,
20
+ finallyFn?: (nymph: Nymph, committed?: boolean) => Promise<void>,
21
+ ): Promise<T> {
22
+ nymph.config.debugInfo('nymph:transaction', `Starting transaction ${name}`);
23
+ const tnymph = await nymph.startTransaction(name);
24
+ try {
25
+ const result = await fn(tnymph);
26
+
27
+ nymph.config.debugInfo(
28
+ 'nymph:transaction',
29
+ `Committing transaction ${name}`,
30
+ );
31
+ if (!(await tnymph.commit(name))) {
32
+ throw new Error('Transaction could not be committed.');
33
+ }
34
+
35
+ if (finallyFn) {
36
+ await finallyFn(nymph, true);
37
+ }
38
+
39
+ return result;
40
+ } catch (e: any) {
41
+ try {
42
+ nymph.config.debugInfo(
43
+ 'nymph:transaction',
44
+ `Rolling back transaction ${name}, reason: ${e.message}`,
45
+ );
46
+ await tnymph.rollback(name);
47
+ } catch (e: any) {
48
+ nymph.config.debugError(
49
+ 'nymph:transaction',
50
+ `Rollback of transaction ${name} failed, reason: ${e.message}`,
51
+ );
52
+ }
53
+ if (finallyFn) {
54
+ try {
55
+ await finallyFn(nymph, false);
56
+ } catch (e: any) {
57
+ nymph.config.debugError(
58
+ 'nymph:transaction',
59
+ `Finally function of transaction ${name} threw error: ${e.message}, this is a mistake and should be fixed, finally functions should never throw`,
60
+ );
61
+ }
62
+ }
63
+ throw e;
64
+ }
65
+ }
package/src/index.ts CHANGED
@@ -1,20 +1,22 @@
1
- export * from './conf';
2
- export * from './driver';
3
- export * from './errors';
1
+ export * from './conf/index.js';
2
+ export * from './driver/index.js';
3
+ export * from './errors/index.js';
4
+ export * from './decorators/index.js';
5
+ export * from './helpers/index.js';
4
6
 
5
- export * from './Entity.types';
7
+ export * from './Entity.types.js';
6
8
 
7
- export * from './Entity';
8
- import Entity from './Entity';
9
+ export * from './Entity.js';
10
+ import Entity from './Entity.js';
9
11
  export { Entity };
10
12
 
11
- export * from './Nymph.types';
13
+ export * from './Nymph.types.js';
12
14
 
13
- export * from './Nymph';
14
- import Nymph from './Nymph';
15
+ export * from './Nymph.js';
16
+ import Nymph from './Nymph.js';
15
17
  export { Nymph };
16
18
 
17
- import nymphJoiProps from './nymphJoiProps';
19
+ import nymphJoiProps from './nymphJoiProps.js';
18
20
  export { nymphJoiProps };
19
21
 
20
- export * from './utils';
22
+ export * from './utils.js';
@@ -4,7 +4,7 @@ export default {
4
4
  guid: Joi.alternatives()
5
5
  .try(
6
6
  Joi.any().only().allow(null),
7
- Joi.string().trim(false).length(24).hex()
7
+ Joi.string().trim(false).length(24).hex(),
8
8
  )
9
9
  .required(),
10
10
  cdate: Joi.alternatives()
@@ -18,7 +18,7 @@ export default {
18
18
  Joi.string().pattern(/[[\x01-\x1F\x7F]]/, {
19
19
  name: 'control characters',
20
20
  invert: true,
21
- })
21
+ }),
22
22
  )
23
23
  .required(),
24
24
  };
@@ -1,4 +1,6 @@
1
- import Entity from './Entity';
1
+ import Entity from './Entity.js';
2
+ import { transactional } from './decorators/index.js';
3
+ import { transaction } from './helpers/index.js';
2
4
 
3
5
  export type TestModelData = {
4
6
  name?: string;
@@ -7,6 +9,7 @@ export type TestModelData = {
7
9
  test?: string;
8
10
  array?: any[];
9
11
  match?: string;
12
+ search?: string;
10
13
  number?: number;
11
14
  numberString?: string;
12
15
  timestamp?: Number;
@@ -17,8 +20,10 @@ export type TestModelData = {
17
20
  [k: string]: TestModel & TestModelData;
18
21
  };
19
22
  parent?: TestModel & TestModelData;
20
- // For Import/Export Tests.
23
+ // For import/export tests.
21
24
  index?: string;
25
+ // For uniqueness tests.
26
+ uniques?: string[];
22
27
  };
23
28
 
24
29
  /**
@@ -34,21 +39,16 @@ export class TestModel extends Entity<TestModelData> {
34
39
  protected $protectedTags = ['test', 'notag'];
35
40
  protected $allowlistTags? = ['newtag'];
36
41
 
37
- static async factory(guid?: string): Promise<TestModel & TestModelData> {
38
- return (await super.factory(guid)) as TestModel & TestModelData;
39
- }
42
+ constructor() {
43
+ super();
40
44
 
41
- static factorySync(guid?: string): TestModel & TestModelData {
42
- return super.factorySync(guid) as TestModel & TestModelData;
45
+ this.$addTag('test');
46
+ this.$data.boolean = true;
47
+ this.$data.uniques = [];
43
48
  }
44
49
 
45
- constructor(guid?: string) {
46
- super(guid);
47
-
48
- if (this.guid == null) {
49
- this.$addTag('test');
50
- this.$data.boolean = true;
51
- }
50
+ public async $getUniques() {
51
+ return this.$data.uniques ?? [];
52
52
  }
53
53
 
54
54
  public $useProtectedData() {
@@ -69,6 +69,53 @@ export class TestModel extends Entity<TestModelData> {
69
69
  this.$protectedTags = $protectedTags;
70
70
  };
71
71
  }
72
+
73
+ @transactional
74
+ public async $testTransactionalDecorator(throwError: boolean) {
75
+ this.$data.string = 'this has been changed';
76
+
77
+ if (this.$data.reference) {
78
+ await this.$data.reference.$wake();
79
+ this.$data.reference.string = 'this has been changed too';
80
+ await this.$data.reference.$save();
81
+ }
82
+
83
+ await this.$save();
84
+
85
+ if (throwError) {
86
+ throw Error('An error.');
87
+ }
88
+
89
+ return 'Success.';
90
+ }
91
+
92
+ public async $testTransactionHelper(throwError: boolean) {
93
+ return await transaction(
94
+ this.$nymph,
95
+ 'test-transaction',
96
+ async (nymph) => {
97
+ this.$setNymph(nymph);
98
+ this.$data.string = 'this has been changed';
99
+
100
+ if (this.$data.reference) {
101
+ await this.$data.reference.$wake();
102
+ this.$data.reference.string = 'this has been changed too';
103
+ await this.$data.reference.$save();
104
+ }
105
+
106
+ await this.$save();
107
+
108
+ if (throwError) {
109
+ throw Error('An error.');
110
+ }
111
+
112
+ return 'Success.';
113
+ },
114
+ async (nymph) => {
115
+ this.$setNymph(nymph);
116
+ },
117
+ );
118
+ }
72
119
  }
73
120
 
74
121
  /**
@@ -77,12 +124,14 @@ export class TestModel extends Entity<TestModelData> {
77
124
  export class TestBModel extends TestModel {
78
125
  static ETYPE = 'test_b_model';
79
126
  static class = 'TestBModel';
127
+ }
80
128
 
81
- static async factory(guid?: string): Promise<TestBModel & TestModelData> {
82
- return (await super.factory(guid)) as TestBModel & TestModelData;
83
- }
129
+ export type TestEmptyModelData = {};
84
130
 
85
- static factorySync(guid?: string): TestBModel & TestModelData {
86
- return super.factorySync(guid) as TestBModel & TestModelData;
87
- }
131
+ /**
132
+ * This class is a test class that extends the Entity class.
133
+ */
134
+ export class TestEmptyModel extends Entity<TestEmptyModelData> {
135
+ static ETYPE = 'test_empty_model';
136
+ static class = 'TestEmptyModel';
88
137
  }
package/src/testMocks.ts CHANGED
@@ -1,10 +1,21 @@
1
1
  import { guid } from '@nymphjs/guid';
2
2
 
3
- import type Nymph from './Nymph';
4
- import { EntityConstructor, EntityInterface, EntityJson } from './Entity.types';
5
- import { Options, Selector } from './Nymph.types';
6
- import { ClassNotAvailableError } from './errors';
7
- import Entity from './Entity';
3
+ import type Nymph from './Nymph.js';
4
+ import type { EntityInstanceType, EntityObjectType } from './Entity.js';
5
+ import type {
6
+ EntityConstructor,
7
+ EntityInterface,
8
+ EntityJson,
9
+ } from './Entity.types.js';
10
+ import { Options, Selector } from './Nymph.types.js';
11
+ import { ClassNotAvailableError, EntityConflictError } from './errors/index.js';
12
+ import Entity from './Entity.js';
13
+ import {
14
+ classNamesToEntityConstructors,
15
+ entitiesToReferences,
16
+ entityConstructorsToClassNames,
17
+ referencesToEntities,
18
+ } from './utils.js';
8
19
 
9
20
  const entities: { [k: string]: EntityJson } = {};
10
21
 
@@ -15,43 +26,64 @@ export class MockNymphDriver {
15
26
  this.nymph = nymph;
16
27
  }
17
28
 
18
- public getEntitySync<T extends EntityConstructor = EntityConstructor>(
29
+ public async getEntity<T extends EntityConstructor = EntityConstructor>(
19
30
  options: Options<T> & { return: 'guid' },
20
31
  ...selectors: Selector[]
21
- ): string | null;
22
- public getEntitySync<T extends EntityConstructor = EntityConstructor>(
32
+ ): Promise<string | null>;
33
+ public async getEntity<T extends EntityConstructor = EntityConstructor>(
34
+ options: Options<T> & { return: 'object' },
35
+ ...selectors: Selector[]
36
+ ): Promise<EntityObjectType<T> | null>;
37
+ public async getEntity<T extends EntityConstructor = EntityConstructor>(
23
38
  options: Options<T>,
24
39
  ...selectors: Selector[]
25
- ): ReturnType<T['factorySync']> | null;
26
- public getEntitySync<T extends EntityConstructor = EntityConstructor>(
40
+ ): Promise<EntityInstanceType<T> | null>;
41
+ public async getEntity<T extends EntityConstructor = EntityConstructor>(
27
42
  options: Options<T> & { return: 'guid' },
28
- guid: string
29
- ): string | null;
30
- public getEntitySync<T extends EntityConstructor = EntityConstructor>(
43
+ guid: string,
44
+ ): Promise<string | null>;
45
+ public async getEntity<T extends EntityConstructor = EntityConstructor>(
46
+ options: Options<T> & { return: 'object' },
47
+ guid: string,
48
+ ): Promise<EntityObjectType<T> | null>;
49
+ public async getEntity<T extends EntityConstructor = EntityConstructor>(
31
50
  options: Options<T>,
32
- guid: string
33
- ): ReturnType<T['factorySync']> | null;
34
- public getEntitySync<T extends EntityConstructor = EntityConstructor>(
51
+ guid: string,
52
+ ): Promise<EntityInstanceType<T> | null>;
53
+ public async getEntity<T extends EntityConstructor = EntityConstructor>(
35
54
  options: Options<T> = {},
36
55
  ...selectors: Selector[] | string[]
37
- ): ReturnType<T['factorySync']> | string | null {
56
+ ): Promise<EntityInstanceType<T> | EntityObjectType<T> | string | null> {
38
57
  const guid =
39
58
  typeof selectors[0] === 'string' ? selectors[0] : selectors[0].guid;
40
59
  if (!options || !guid || typeof guid !== 'string' || !(guid in entities)) {
41
60
  return null;
42
61
  }
43
62
 
44
- const entity: EntityInterface = (
45
- (options.class as T) ?? this.nymph.getEntityClass('Entity')
63
+ const entity = (
64
+ (options.class ?? this.nymph.getEntityClass('Entity')) as T
46
65
  ).factorySync();
47
66
  const entityJson = entities[guid];
48
67
  entity.guid = guid;
49
68
  entity.cdate = entityJson.cdate;
50
69
  entity.mdate = entityJson.mdate;
51
70
  entity.tags = entityJson.tags;
52
- entity.$putData(entityJson.data, {});
53
-
54
- return entity as ReturnType<T['factorySync']>;
71
+ entity.$putData(
72
+ classNamesToEntityConstructors(
73
+ this.nymph as unknown as Nymph,
74
+ referencesToEntities(
75
+ entityJson.data,
76
+ this.nymph as unknown as Nymph,
77
+ !!options.skipAc,
78
+ false,
79
+ ),
80
+ false,
81
+ ),
82
+ {},
83
+ 'server',
84
+ );
85
+
86
+ return entity as EntityInstanceType<T>;
55
87
  }
56
88
  }
57
89
 
@@ -68,53 +100,79 @@ export class MockNymph {
68
100
  this.Entity = this.addEntityClass(Entity);
69
101
  }
70
102
 
71
- public addEntityClass<T extends EntityConstructor>(entityClass: T): T {
103
+ public addEntityClass<T extends EntityConstructor>(EntityClass: T): T {
72
104
  const nymph = this;
73
- class NymphEntity extends entityClass {
105
+ this.entityClasses[EntityClass.class] = class extends EntityClass {
74
106
  static nymph: Nymph = nymph as unknown as Nymph;
75
107
 
76
108
  constructor(...args: any[]) {
77
109
  super(...args);
78
110
  }
111
+ };
112
+ return this.entityClasses[EntityClass.class] as T;
113
+ }
114
+
115
+ public getEntityClass(className: string): EntityConstructor;
116
+ public getEntityClass<T extends EntityConstructor>(className: T): T;
117
+ public getEntityClass<T extends EntityConstructor = EntityConstructor>(
118
+ className: T | string,
119
+ ): T | EntityConstructor {
120
+ let key: string | null = null;
121
+ if (typeof className === 'string') {
122
+ key = className;
123
+ } else {
124
+ key = className.class;
125
+ }
126
+ if (key in this.entityClasses) {
127
+ return this.entityClasses[key];
79
128
  }
80
- this.entityClasses[entityClass.class] = NymphEntity;
81
- return NymphEntity;
129
+ throw new ClassNotAvailableError(`Tried to use missing class "${key}".`);
82
130
  }
83
131
 
84
- public getEntityClass(className: string): EntityConstructor {
85
- if (className in this.entityClasses) {
86
- return this.entityClasses[className];
132
+ public getEntityClassByEtype(etype: string): EntityConstructor {
133
+ for (const EntityClass of Object.values(this.entityClasses)) {
134
+ if (EntityClass.ETYPE === etype) {
135
+ return EntityClass;
136
+ }
87
137
  }
88
- throw new ClassNotAvailableError('Tried to use class: ' + className);
138
+ throw new ClassNotAvailableError(
139
+ `Tried to use missing class by etype "${etype}".`,
140
+ );
89
141
  }
90
142
 
91
143
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
92
144
  options: Options<T> & { return: 'guid' },
93
145
  ...selectors: Selector[]
94
146
  ): Promise<string | null>;
147
+ public async getEntity<T extends EntityConstructor = EntityConstructor>(
148
+ options: Options<T> & { return: 'object' },
149
+ ...selectors: Selector[]
150
+ ): Promise<EntityObjectType<T> | null>;
95
151
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
96
152
  options: Options<T>,
97
153
  ...selectors: Selector[]
98
- ): Promise<ReturnType<T['factorySync']> | null>;
154
+ ): Promise<EntityInstanceType<T> | null>;
99
155
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
100
156
  options: Options<T> & { return: 'guid' },
101
- guid: string
157
+ guid: string,
102
158
  ): Promise<string | null>;
159
+ public async getEntity<T extends EntityConstructor = EntityConstructor>(
160
+ options: Options<T> & { return: 'object' },
161
+ guid: string,
162
+ ): Promise<EntityObjectType<T> | null>;
103
163
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
104
164
  options: Options<T>,
105
- guid: string
106
- ): Promise<ReturnType<T['factorySync']> | null>;
165
+ guid: string,
166
+ ): Promise<EntityInstanceType<T> | null>;
107
167
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
108
168
  options: Options<T> = {},
109
169
  ...selectors: Selector[] | string[]
110
- ): Promise<ReturnType<T['factorySync']> | string | null> {
170
+ ): Promise<EntityInstanceType<T> | EntityObjectType<T> | string | null> {
111
171
  // @ts-ignore: The selector type is correct here.
112
- return this.driver.getEntitySync(options, ...selectors);
172
+ return await this.driver.getEntity(options, ...selectors);
113
173
  }
114
174
 
115
175
  public async saveEntity(entity: EntityInterface): Promise<boolean> {
116
- const className = (entity.constructor as any).class as string;
117
-
118
176
  if (entity.guid == null) {
119
177
  entity.guid = guid();
120
178
  entity.cdate = Date.now();
@@ -122,18 +180,26 @@ export class MockNymph {
122
180
  entity.guid in entities &&
123
181
  (entity.mdate ?? 0) < (entities[entity.guid].mdate ?? 0)
124
182
  ) {
125
- return false;
183
+ throw new EntityConflictError(
184
+ "Entity either doesn't exist or is newer in the DB.",
185
+ );
126
186
  }
127
187
 
128
188
  entity.mdate = Date.now();
129
189
 
130
190
  const entityJson: EntityJson = {
131
- class: className,
191
+ class: entity.constructor as EntityConstructor,
132
192
  guid: entity.guid,
133
193
  cdate: entity.cdate,
134
194
  mdate: entity.mdate,
135
195
  tags: [...entity.tags],
136
- data: JSON.parse(JSON.stringify(entity.$getData(true))),
196
+ data: JSON.parse(
197
+ JSON.stringify(
198
+ entityConstructorsToClassNames(
199
+ entitiesToReferences(entity.$getData(true), true),
200
+ ),
201
+ ),
202
+ ),
137
203
  };
138
204
 
139
205
  entities[entity.guid] = entityJson;