@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.
- package/CHANGELOG.md +644 -0
- package/README.md +34 -24
- package/dist/Entity.d.ts +304 -15
- package/dist/Entity.js +609 -154
- package/dist/Entity.js.map +1 -1
- package/dist/Entity.test.js +75 -29
- package/dist/Entity.test.js.map +1 -1
- package/dist/Entity.types.d.ts +275 -28
- package/dist/Entity.types.js +1 -2
- package/dist/Nymph.d.ts +575 -11
- package/dist/Nymph.js +825 -288
- package/dist/Nymph.js.map +1 -1
- package/dist/Nymph.types.d.ts +117 -7
- package/dist/Nymph.types.js +47 -5
- package/dist/Nymph.types.js.map +1 -1
- package/dist/conf/defaults.d.ts +1 -1
- package/dist/conf/defaults.js +26 -3
- package/dist/conf/defaults.js.map +1 -1
- package/dist/conf/index.d.ts +50 -2
- package/dist/conf/index.js +2 -8
- package/dist/conf/index.js.map +1 -1
- package/dist/decorators/index.d.ts +1 -0
- package/dist/decorators/index.js +2 -0
- package/dist/decorators/index.js.map +1 -0
- package/dist/decorators/transactional.d.ts +12 -0
- package/dist/decorators/transactional.js +45 -0
- package/dist/decorators/transactional.js.map +1 -0
- package/dist/driver/NymphDriver.d.ts +209 -41
- package/dist/driver/NymphDriver.js +737 -242
- package/dist/driver/NymphDriver.js.map +1 -1
- package/dist/driver/index.d.ts +1 -2
- package/dist/driver/index.js +2 -23
- package/dist/driver/index.js.map +1 -1
- package/dist/driver/testArtifacts.d.ts +4 -4
- package/dist/driver/testArtifacts.js +2016 -1086
- package/dist/driver/testArtifacts.js.map +1 -1
- package/dist/errors/ClassNotAvailableError.js +1 -5
- package/dist/errors/ClassNotAvailableError.js.map +1 -1
- package/dist/errors/EntityConflictError.js +1 -5
- package/dist/errors/EntityConflictError.js.map +1 -1
- package/dist/errors/EntityInvalidDataError.d.ts +6 -0
- package/dist/errors/EntityInvalidDataError.js +8 -6
- package/dist/errors/EntityInvalidDataError.js.map +1 -1
- package/dist/errors/EntityIsSleepingReferenceError.js +1 -5
- package/dist/errors/EntityIsSleepingReferenceError.js.map +1 -1
- package/dist/errors/EntityUniqueConstraintError.d.ts +3 -0
- package/dist/errors/EntityUniqueConstraintError.js +7 -0
- package/dist/errors/EntityUniqueConstraintError.js.map +1 -0
- package/dist/errors/HttpError.d.ts +5 -0
- package/dist/errors/HttpError.js +11 -0
- package/dist/errors/HttpError.js.map +1 -0
- package/dist/errors/InvalidParametersError.js +1 -5
- package/dist/errors/InvalidParametersError.js.map +1 -1
- package/dist/errors/InvalidStateError.d.ts +3 -0
- package/dist/errors/InvalidStateError.js +7 -0
- package/dist/errors/InvalidStateError.js.map +1 -0
- package/dist/errors/MethodFailedError.d.ts +3 -0
- package/dist/errors/MethodFailedError.js +7 -0
- package/dist/errors/MethodFailedError.js.map +1 -0
- package/dist/errors/NotConfiguredError.js +1 -5
- package/dist/errors/NotConfiguredError.js.map +1 -1
- package/dist/errors/QueryFailedError.d.ts +2 -1
- package/dist/errors/QueryFailedError.js +5 -6
- package/dist/errors/QueryFailedError.js.map +1 -1
- package/dist/errors/UnableToConnectError.js +1 -5
- package/dist/errors/UnableToConnectError.js.map +1 -1
- package/dist/errors/index.d.ts +12 -8
- package/dist/errors/index.js +12 -24
- package/dist/errors/index.js.map +1 -1
- package/dist/helpers/index.d.ts +1 -0
- package/dist/helpers/index.js +2 -0
- package/dist/helpers/index.js.map +1 -0
- package/dist/helpers/transaction.d.ts +15 -0
- package/dist/helpers/transaction.js +47 -0
- package/dist/helpers/transaction.js.map +1 -0
- package/dist/index.d.ts +13 -11
- package/dist/index.js +16 -34
- package/dist/index.js.map +1 -1
- package/dist/nymphJoiProps.d.ts +1 -1
- package/dist/nymphJoiProps.js +10 -15
- package/dist/nymphJoiProps.js.map +1 -1
- package/dist/testArtifacts.d.ts +21 -6
- package/dist/testArtifacts.js +124 -50
- package/dist/testArtifacts.js.map +1 -1
- package/dist/testMocks.d.ts +27 -12
- package/dist/testMocks.js +44 -33
- package/dist/testMocks.js.map +1 -1
- package/dist/utils.d.ts +5 -5
- package/dist/utils.js +106 -68
- package/dist/utils.js.map +1 -1
- package/jest.config.js +31 -5
- package/package.json +43 -24
- package/src/Entity.test.ts +73 -23
- package/src/Entity.ts +555 -169
- package/src/Entity.types.ts +102 -90
- package/src/Nymph.ts +930 -517
- package/src/Nymph.types.ts +145 -39
- package/src/conf/defaults.ts +34 -1
- package/src/conf/index.ts +50 -2
- package/src/decorators/index.ts +1 -0
- package/src/decorators/transactional.ts +63 -0
- package/src/driver/NymphDriver.ts +987 -417
- package/src/driver/index.ts +1 -3
- package/src/driver/testArtifacts.ts +2699 -1628
- package/src/errors/EntityUniqueConstraintError.ts +6 -0
- package/src/errors/HttpError.ts +12 -0
- package/src/errors/InvalidStateError.ts +6 -0
- package/src/errors/MethodFailedError.ts +6 -0
- package/src/errors/QueryFailedError.ts +3 -1
- package/src/errors/index.ts +16 -8
- package/src/helpers/index.ts +1 -0
- package/src/helpers/transaction.ts +65 -0
- package/src/index.ts +13 -11
- package/src/nymphJoiProps.ts +2 -2
- package/src/testArtifacts.ts +69 -20
- package/src/testMocks.ts +107 -41
- package/src/utils.ts +102 -67
- package/tsconfig.json +6 -3
- package/typedoc.json +4 -0
- package/dist/conf/d.d.ts +0 -6
- package/dist/conf/d.js +0 -3
- package/dist/conf/d.js.map +0 -1
- package/src/conf/d.ts +0 -24
|
@@ -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
|
+
}
|
|
@@ -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() {
|
package/src/errors/index.ts
CHANGED
|
@@ -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 './
|
|
9
|
+
export * from './EntityUniqueConstraintError.js';
|
|
10
10
|
|
|
11
|
-
export * from './
|
|
11
|
+
export * from './HttpError.js';
|
|
12
12
|
|
|
13
|
-
export * from './
|
|
13
|
+
export * from './InvalidParametersError.js';
|
|
14
14
|
|
|
15
|
-
export * from './
|
|
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';
|
package/src/nymphJoiProps.ts
CHANGED
|
@@ -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
|
};
|
package/src/testArtifacts.ts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
42
|
+
constructor() {
|
|
43
|
+
super();
|
|
40
44
|
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
this.$addTag('test');
|
|
46
|
+
this.$data.boolean = true;
|
|
47
|
+
this.$data.uniques = [];
|
|
43
48
|
}
|
|
44
49
|
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
82
|
-
return (await super.factory(guid)) as TestBModel & TestModelData;
|
|
83
|
-
}
|
|
129
|
+
export type TestEmptyModelData = {};
|
|
84
130
|
|
|
85
|
-
|
|
86
|
-
|
|
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 {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
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
|
|
29
|
+
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
19
30
|
options: Options<T> & { return: 'guid' },
|
|
20
31
|
...selectors: Selector[]
|
|
21
|
-
): string | null
|
|
22
|
-
public
|
|
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
|
-
):
|
|
26
|
-
public
|
|
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
|
|
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
|
-
):
|
|
34
|
-
public
|
|
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
|
-
):
|
|
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
|
|
45
|
-
(options.class
|
|
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(
|
|
53
|
-
|
|
54
|
-
|
|
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>(
|
|
103
|
+
public addEntityClass<T extends EntityConstructor>(EntityClass: T): T {
|
|
72
104
|
const nymph = this;
|
|
73
|
-
class
|
|
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
|
-
|
|
81
|
-
return NymphEntity;
|
|
129
|
+
throw new ClassNotAvailableError(`Tried to use missing class "${key}".`);
|
|
82
130
|
}
|
|
83
131
|
|
|
84
|
-
public
|
|
85
|
-
|
|
86
|
-
|
|
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(
|
|
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<
|
|
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<
|
|
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<
|
|
170
|
+
): Promise<EntityInstanceType<T> | EntityObjectType<T> | string | null> {
|
|
111
171
|
// @ts-ignore: The selector type is correct here.
|
|
112
|
-
return this.driver.
|
|
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
|
-
|
|
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:
|
|
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(
|
|
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;
|