@nymphjs/nymph 1.0.0-beta.3 → 1.0.0-beta.30
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 +148 -0
- package/README.md +4 -2
- package/dist/Entity.d.ts +2 -0
- package/dist/Entity.js +43 -10
- package/dist/Entity.js.map +1 -1
- package/dist/Entity.test.js +17 -15
- package/dist/Entity.test.js.map +1 -1
- package/dist/Entity.types.d.ts +3 -1
- package/dist/Nymph.d.ts +22 -7
- package/dist/Nymph.js +214 -68
- package/dist/Nymph.js.map +1 -1
- package/dist/Nymph.types.d.ts +15 -2
- package/dist/Nymph.types.js.map +1 -1
- package/dist/driver/NymphDriver.d.ts +1 -0
- package/dist/driver/NymphDriver.js +2 -2
- package/dist/driver/NymphDriver.js.map +1 -1
- package/dist/driver/testArtifacts.js +204 -158
- package/dist/driver/testArtifacts.js.map +1 -1
- package/dist/testArtifacts.d.ts +7 -0
- package/dist/testArtifacts.js +14 -3
- package/dist/testArtifacts.js.map +1 -1
- package/dist/testMocks.d.ts +4 -1
- package/dist/testMocks.js +20 -8
- package/dist/testMocks.js.map +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +11 -5
- package/dist/utils.js.map +1 -1
- package/package.json +11 -11
- package/src/Entity.test.ts +14 -7
- package/src/Entity.ts +76 -19
- package/src/Entity.types.ts +13 -1
- package/src/Nymph.ts +385 -82
- package/src/Nymph.types.ts +70 -2
- package/src/driver/NymphDriver.ts +19 -4
- package/src/driver/testArtifacts.ts +120 -37
- package/src/testArtifacts.ts +20 -0
- package/src/testMocks.ts +27 -10
- package/src/utils.ts +21 -7
package/src/Nymph.types.ts
CHANGED
|
@@ -9,18 +9,31 @@ export type NymphEventType =
|
|
|
9
9
|
| 'beforeGetEntities'
|
|
10
10
|
| 'beforeSaveEntity'
|
|
11
11
|
| 'afterSaveEntity'
|
|
12
|
+
| 'failedSaveEntity'
|
|
12
13
|
| 'beforeDeleteEntity'
|
|
13
14
|
| 'afterDeleteEntity'
|
|
15
|
+
| 'failedDeleteEntity'
|
|
14
16
|
| 'beforeDeleteEntityByID'
|
|
15
17
|
| 'afterDeleteEntityByID'
|
|
18
|
+
| 'failedDeleteEntityByID'
|
|
16
19
|
| 'beforeNewUID'
|
|
17
20
|
| 'afterNewUID'
|
|
21
|
+
| 'failedNewUID'
|
|
18
22
|
| 'beforeSetUID'
|
|
19
23
|
| 'afterSetUID'
|
|
24
|
+
| 'failedSetUID'
|
|
20
25
|
| 'beforeRenameUID'
|
|
21
26
|
| 'afterRenameUID'
|
|
27
|
+
| 'failedRenameUID'
|
|
22
28
|
| 'beforeDeleteUID'
|
|
23
|
-
| 'afterDeleteUID'
|
|
29
|
+
| 'afterDeleteUID'
|
|
30
|
+
| 'failedDeleteUID'
|
|
31
|
+
| 'beforeStartTransaction'
|
|
32
|
+
| 'afterStartTransaction'
|
|
33
|
+
| 'beforeCommitTransaction'
|
|
34
|
+
| 'afterCommitTransaction'
|
|
35
|
+
| 'beforeRollbackTransaction'
|
|
36
|
+
| 'afterRollbackTransaction';
|
|
24
37
|
export type NymphConnectCallback = (
|
|
25
38
|
nymph: Nymph,
|
|
26
39
|
result: Promise<boolean>
|
|
@@ -63,6 +76,10 @@ export type NymphAfterSaveEntityCallback = (
|
|
|
63
76
|
nymph: Nymph,
|
|
64
77
|
result: Promise<boolean>
|
|
65
78
|
) => Promise<void>;
|
|
79
|
+
export type NymphFailedSaveEntityCallback = (
|
|
80
|
+
nymph: Nymph,
|
|
81
|
+
error: any
|
|
82
|
+
) => Promise<void>;
|
|
66
83
|
export type NymphBeforeDeleteEntityCallback = (
|
|
67
84
|
nymph: Nymph,
|
|
68
85
|
entity: EntityInterface
|
|
@@ -71,6 +88,10 @@ export type NymphAfterDeleteEntityCallback = (
|
|
|
71
88
|
nymph: Nymph,
|
|
72
89
|
result: Promise<boolean>
|
|
73
90
|
) => Promise<void>;
|
|
91
|
+
export type NymphFailedDeleteEntityCallback = (
|
|
92
|
+
nymph: Nymph,
|
|
93
|
+
error: any
|
|
94
|
+
) => Promise<void>;
|
|
74
95
|
export type NymphBeforeDeleteEntityByIDCallback = (
|
|
75
96
|
nymph: Nymph,
|
|
76
97
|
guid: string,
|
|
@@ -80,6 +101,10 @@ export type NymphAfterDeleteEntityByIDCallback = (
|
|
|
80
101
|
nymph: Nymph,
|
|
81
102
|
result: Promise<boolean>
|
|
82
103
|
) => Promise<void>;
|
|
104
|
+
export type NymphFailedDeleteEntityByIDCallback = (
|
|
105
|
+
nymph: Nymph,
|
|
106
|
+
error: any
|
|
107
|
+
) => Promise<void>;
|
|
83
108
|
export type NymphBeforeNewUIDCallback = (
|
|
84
109
|
nymph: Nymph,
|
|
85
110
|
name: string
|
|
@@ -88,6 +113,10 @@ export type NymphAfterNewUIDCallback = (
|
|
|
88
113
|
nymph: Nymph,
|
|
89
114
|
result: Promise<number | null>
|
|
90
115
|
) => Promise<void>;
|
|
116
|
+
export type NymphFailedNewUIDCallback = (
|
|
117
|
+
nymph: Nymph,
|
|
118
|
+
error: any
|
|
119
|
+
) => Promise<void>;
|
|
91
120
|
export type NymphBeforeSetUIDCallback = (
|
|
92
121
|
nymph: Nymph,
|
|
93
122
|
name: string,
|
|
@@ -97,6 +126,10 @@ export type NymphAfterSetUIDCallback = (
|
|
|
97
126
|
nymph: Nymph,
|
|
98
127
|
result: Promise<boolean>
|
|
99
128
|
) => Promise<void>;
|
|
129
|
+
export type NymphFailedSetUIDCallback = (
|
|
130
|
+
nymph: Nymph,
|
|
131
|
+
error: any
|
|
132
|
+
) => Promise<void>;
|
|
100
133
|
export type NymphBeforeRenameUIDCallback = (
|
|
101
134
|
nymph: Nymph,
|
|
102
135
|
oldName: string,
|
|
@@ -106,6 +139,10 @@ export type NymphAfterRenameUIDCallback = (
|
|
|
106
139
|
nymph: Nymph,
|
|
107
140
|
result: Promise<boolean>
|
|
108
141
|
) => Promise<void>;
|
|
142
|
+
export type NymphFailedRenameUIDCallback = (
|
|
143
|
+
nymph: Nymph,
|
|
144
|
+
error: any
|
|
145
|
+
) => Promise<void>;
|
|
109
146
|
export type NymphBeforeDeleteUIDCallback = (
|
|
110
147
|
nymph: Nymph,
|
|
111
148
|
name: string
|
|
@@ -114,13 +151,44 @@ export type NymphAfterDeleteUIDCallback = (
|
|
|
114
151
|
nymph: Nymph,
|
|
115
152
|
result: Promise<boolean>
|
|
116
153
|
) => Promise<void>;
|
|
154
|
+
export type NymphFailedDeleteUIDCallback = (
|
|
155
|
+
nymph: Nymph,
|
|
156
|
+
error: any
|
|
157
|
+
) => Promise<void>;
|
|
158
|
+
export type NymphBeforeStartTransactionCallback = (
|
|
159
|
+
nymph: Nymph,
|
|
160
|
+
name: string
|
|
161
|
+
) => Promise<void>;
|
|
162
|
+
export type NymphAfterStartTransactionCallback = (
|
|
163
|
+
nymph: Nymph,
|
|
164
|
+
name: string,
|
|
165
|
+
result: Nymph
|
|
166
|
+
) => Promise<void>;
|
|
167
|
+
export type NymphBeforeCommitTransactionCallback = (
|
|
168
|
+
nymph: Nymph,
|
|
169
|
+
name: string
|
|
170
|
+
) => Promise<void>;
|
|
171
|
+
export type NymphAfterCommitTransactionCallback = (
|
|
172
|
+
nymph: Nymph,
|
|
173
|
+
name: string,
|
|
174
|
+
result: boolean
|
|
175
|
+
) => Promise<void>;
|
|
176
|
+
export type NymphBeforeRollbackTransactionCallback = (
|
|
177
|
+
nymph: Nymph,
|
|
178
|
+
name: string
|
|
179
|
+
) => Promise<void>;
|
|
180
|
+
export type NymphAfterRollbackTransactionCallback = (
|
|
181
|
+
nymph: Nymph,
|
|
182
|
+
name: string,
|
|
183
|
+
result: boolean
|
|
184
|
+
) => Promise<void>;
|
|
117
185
|
|
|
118
186
|
export type Options<T extends EntityConstructor = EntityConstructor> = {
|
|
119
187
|
class?: T;
|
|
120
188
|
limit?: number;
|
|
121
189
|
offset?: number;
|
|
122
190
|
reverse?: boolean;
|
|
123
|
-
sort?: 'cdate' | 'mdate';
|
|
191
|
+
sort?: 'cdate' | 'mdate' | string;
|
|
124
192
|
return?: 'entity' | 'guid' | 'count';
|
|
125
193
|
source?: string;
|
|
126
194
|
skipCache?: boolean;
|
|
@@ -54,7 +54,18 @@ export default abstract class NymphDriver {
|
|
|
54
54
|
*/
|
|
55
55
|
private putDataCounter = 0;
|
|
56
56
|
|
|
57
|
+
/**
|
|
58
|
+
* This is used internally by Nymph. Don't call it yourself.
|
|
59
|
+
*
|
|
60
|
+
* @returns A clone of this instance.
|
|
61
|
+
*/
|
|
62
|
+
abstract clone(): NymphDriver;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Connect to the data store.
|
|
66
|
+
*/
|
|
57
67
|
abstract connect(): Promise<boolean>;
|
|
68
|
+
|
|
58
69
|
abstract isConnected(): boolean;
|
|
59
70
|
abstract startTransaction(name: string): Promise<Nymph>;
|
|
60
71
|
abstract commit(name: string): Promise<boolean>;
|
|
@@ -66,7 +77,12 @@ export default abstract class NymphDriver {
|
|
|
66
77
|
): Promise<boolean>;
|
|
67
78
|
abstract deleteEntityByID(guid: string, className?: string): Promise<boolean>;
|
|
68
79
|
abstract deleteUID(name: string): Promise<boolean>;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Disconnect from the data store.
|
|
83
|
+
*/
|
|
69
84
|
abstract disconnect(): Promise<boolean>;
|
|
85
|
+
|
|
70
86
|
protected abstract exportEntities(
|
|
71
87
|
writeLine: (line: string) => void
|
|
72
88
|
): Promise<void>;
|
|
@@ -609,10 +625,9 @@ export default abstract class NymphDriver {
|
|
|
609
625
|
for (let i = 0; i < tmpArr.length; i++) {
|
|
610
626
|
const name = tmpArr[i][0];
|
|
611
627
|
const [qrefOptions, ...qrefSelectors] = tmpArr[i][1];
|
|
612
|
-
const QrefEntityClass =
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
: qrefOptions.class ?? this.nymph.getEntityClass('Entity');
|
|
628
|
+
const QrefEntityClass = qrefOptions.class
|
|
629
|
+
? this.nymph.getEntityClass(qrefOptions.class)
|
|
630
|
+
: this.nymph.getEntityClass('Entity');
|
|
616
631
|
const newOptions = {
|
|
617
632
|
...qrefOptions,
|
|
618
633
|
class: QrefEntityClass,
|
|
@@ -3,16 +3,22 @@ import strtotime from 'locutus/php/datetime/strtotime';
|
|
|
3
3
|
import { guid } from '@nymphjs/guid';
|
|
4
4
|
|
|
5
5
|
import type Nymph from '../Nymph';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
TestBModel as TestBModelClass,
|
|
8
|
+
TestModel as TestModelClass,
|
|
9
|
+
TestModelData,
|
|
10
|
+
TestEmptyModel as TestEmptyModelClass,
|
|
11
|
+
} from '../testArtifacts';
|
|
7
12
|
|
|
8
13
|
export function QueriesTest(
|
|
9
14
|
nymph: Nymph,
|
|
10
15
|
it: (name: string, fn: () => void) => void
|
|
11
16
|
) {
|
|
12
|
-
nymph.addEntityClass(
|
|
13
|
-
nymph.addEntityClass(
|
|
17
|
+
const TestModel = nymph.addEntityClass(TestModelClass);
|
|
18
|
+
const TestBModel = nymph.addEntityClass(TestBModelClass);
|
|
19
|
+
const TestEmptyModel = nymph.addEntityClass(TestEmptyModelClass);
|
|
14
20
|
|
|
15
|
-
let testEntity:
|
|
21
|
+
let testEntity: TestModelClass & TestModelData;
|
|
16
22
|
let testGuid: string;
|
|
17
23
|
let refGuid: string;
|
|
18
24
|
let createdMultiple = false;
|
|
@@ -35,7 +41,10 @@ export function QueriesTest(
|
|
|
35
41
|
|
|
36
42
|
This one's email address is nice_hat-wednesday+newyork@im-a-hat.hat.
|
|
37
43
|
This one's phone number is (555) 555-1818.
|
|
38
|
-
This one's zip code is 92064
|
|
44
|
+
This one's zip code is 92064.
|
|
45
|
+
This one's favorite emojis are 🔥❤️😊😂⭐🤔
|
|
46
|
+
|
|
47
|
+
These hats are absolutely fantastic.`;
|
|
39
48
|
testEntity.number = 30;
|
|
40
49
|
testEntity.numberString = '30';
|
|
41
50
|
testEntity.timestamp = Date.now();
|
|
@@ -43,7 +52,7 @@ This one's zip code is 92064.`;
|
|
|
43
52
|
expect(testEntity.guid).not.toBeNull();
|
|
44
53
|
testGuid = testEntity.guid as string;
|
|
45
54
|
|
|
46
|
-
const entityReferenceTest:
|
|
55
|
+
const entityReferenceTest: TestModelClass & TestModelData = new TestModel();
|
|
47
56
|
entityReferenceTest.string = 'wrong';
|
|
48
57
|
entityReferenceTest.timestamp = strtotime('-2 days') * 1000;
|
|
49
58
|
expect(await entityReferenceTest.$save()).toEqual(true);
|
|
@@ -59,7 +68,7 @@ This one's zip code is 92064.`;
|
|
|
59
68
|
testEntity = nymph.driver.getEntitySync(
|
|
60
69
|
{ class: TestModel },
|
|
61
70
|
testGuid
|
|
62
|
-
) as
|
|
71
|
+
) as TestModelClass & TestModelData;
|
|
63
72
|
expect(testEntity).toBeInstanceOf(TestModel);
|
|
64
73
|
expect(testEntity.guid).toEqual(testGuid);
|
|
65
74
|
|
|
@@ -67,7 +76,7 @@ This one's zip code is 92064.`;
|
|
|
67
76
|
testEntity = (await nymph.getEntity(
|
|
68
77
|
{ class: TestModel },
|
|
69
78
|
testGuid
|
|
70
|
-
)) as
|
|
79
|
+
)) as TestModelClass & TestModelData;
|
|
71
80
|
expect(testEntity).toBeInstanceOf(TestModel);
|
|
72
81
|
expect(testEntity.guid).toEqual(testGuid);
|
|
73
82
|
}
|
|
@@ -80,6 +89,8 @@ This one's zip code is 92064.`;
|
|
|
80
89
|
for (let i = 0; i < 100; i++) {
|
|
81
90
|
const testEntity = await TestModel.factory();
|
|
82
91
|
testEntity.name = `Multi Test ${i}`;
|
|
92
|
+
// Reverse the number for sort testing.
|
|
93
|
+
testEntity.number = 100 - i;
|
|
83
94
|
testEntity.$removeTag('test');
|
|
84
95
|
testEntity.$addTag('multiTest');
|
|
85
96
|
expect(await testEntity.$save()).toEqual(true);
|
|
@@ -104,6 +115,13 @@ This one's zip code is 92064.`;
|
|
|
104
115
|
await createTestEntities();
|
|
105
116
|
});
|
|
106
117
|
|
|
118
|
+
it("doesn't create empty entity", async () => {
|
|
119
|
+
const testEntity = await TestEmptyModel.factory();
|
|
120
|
+
|
|
121
|
+
expect(await testEntity.$save()).toBeFalsy();
|
|
122
|
+
expect(testEntity.guid).toBeNull();
|
|
123
|
+
});
|
|
124
|
+
|
|
107
125
|
it('update mdate on save', async () => {
|
|
108
126
|
await createTestEntities();
|
|
109
127
|
|
|
@@ -191,12 +209,12 @@ This one's zip code is 92064.`;
|
|
|
191
209
|
testEntity = (await transaction.getEntity(
|
|
192
210
|
{ class: TestModel },
|
|
193
211
|
testGuid
|
|
194
|
-
)) as
|
|
212
|
+
)) as TestModelClass & TestModelData;
|
|
195
213
|
|
|
196
214
|
expect(testEntity.guid).toEqual(testGuid);
|
|
197
215
|
|
|
198
|
-
// Start a new transaction.
|
|
199
|
-
transaction = await nymph.startTransaction('test');
|
|
216
|
+
// Start a new transaction with a dot in the name.
|
|
217
|
+
transaction = await nymph.startTransaction('test.1');
|
|
200
218
|
testEntity.$nymph = transaction;
|
|
201
219
|
|
|
202
220
|
// Verify in a transaction.
|
|
@@ -207,7 +225,7 @@ This one's zip code is 92064.`;
|
|
|
207
225
|
expect(await testEntity.$save()).toEqual(true);
|
|
208
226
|
|
|
209
227
|
// Commit the transaction.
|
|
210
|
-
await transaction.commit('test');
|
|
228
|
+
await transaction.commit('test.1');
|
|
211
229
|
testEntity.$nymph = nymph;
|
|
212
230
|
|
|
213
231
|
// Verify not in a transaction.
|
|
@@ -1633,26 +1651,23 @@ This one's zip code is 92064.`;
|
|
|
1633
1651
|
expect(testEntity.$inArray(resultEntity)).toEqual(false);
|
|
1634
1652
|
});
|
|
1635
1653
|
|
|
1636
|
-
it('sort option', async () => {
|
|
1654
|
+
it('cdate and mdate sort option', async () => {
|
|
1637
1655
|
await createMultipleTestEntities();
|
|
1638
1656
|
|
|
1639
|
-
for (const sort of ['cdate', 'mdate']) {
|
|
1657
|
+
for (const sort of ['cdate', 'mdate'] as ('cdate' | 'mdate')[]) {
|
|
1640
1658
|
// Retrieving entities sorted...
|
|
1641
|
-
let resultEntities = await nymph.getEntities({
|
|
1642
|
-
class: TestModel,
|
|
1643
|
-
sort: sort as 'cdate' | 'mdate',
|
|
1644
|
-
});
|
|
1659
|
+
let resultEntities = await nymph.getEntities({ class: TestModel, sort });
|
|
1645
1660
|
expect(resultEntities.length).toBeGreaterThan(100);
|
|
1646
1661
|
for (let i = 0; i < resultEntities.length - 1; i++) {
|
|
1647
|
-
expect(
|
|
1648
|
-
resultEntities[i
|
|
1649
|
-
)
|
|
1662
|
+
expect(resultEntities[i + 1][sort]).toBeGreaterThan(
|
|
1663
|
+
resultEntities[i][sort] ?? 0
|
|
1664
|
+
);
|
|
1650
1665
|
}
|
|
1651
1666
|
|
|
1652
1667
|
// And test the same with guid return...
|
|
1653
1668
|
let resultGuids = await nymph.getEntities({
|
|
1654
1669
|
class: TestModel,
|
|
1655
|
-
sort
|
|
1670
|
+
sort,
|
|
1656
1671
|
return: 'guid',
|
|
1657
1672
|
});
|
|
1658
1673
|
expect(resultGuids.length).toBeGreaterThan(100);
|
|
@@ -1663,43 +1678,114 @@ This one's zip code is 92064.`;
|
|
|
1663
1678
|
// Retrieving entities reverse sorted...
|
|
1664
1679
|
resultEntities = await nymph.getEntities({
|
|
1665
1680
|
class: TestModel,
|
|
1666
|
-
sort
|
|
1681
|
+
sort,
|
|
1667
1682
|
reverse: true,
|
|
1668
1683
|
});
|
|
1669
1684
|
expect(resultEntities.length).toBeGreaterThan(100);
|
|
1670
1685
|
for (let i = 0; i < resultEntities.length - 1; i++) {
|
|
1671
|
-
expect(resultEntities[i + 1][sort
|
|
1672
|
-
resultEntities[i][sort
|
|
1686
|
+
expect(resultEntities[i + 1][sort]).toBeLessThan(
|
|
1687
|
+
resultEntities[i][sort] ?? 0
|
|
1673
1688
|
);
|
|
1674
1689
|
}
|
|
1675
1690
|
|
|
1676
1691
|
// And again with other selectors.
|
|
1677
1692
|
// Retrieving entities sorted...
|
|
1678
1693
|
resultEntities = await nymph.getEntities(
|
|
1679
|
-
{ class: TestModel, sort
|
|
1694
|
+
{ class: TestModel, sort },
|
|
1680
1695
|
{ type: '&', match: ['name', '^Multi Test '] }
|
|
1681
1696
|
);
|
|
1682
1697
|
expect(resultEntities.length).toEqual(100);
|
|
1683
1698
|
for (let i = 0; i < resultEntities.length - 1; i++) {
|
|
1684
|
-
expect(
|
|
1685
|
-
resultEntities[i
|
|
1686
|
-
)
|
|
1699
|
+
expect(resultEntities[i + 1][sort]).toBeGreaterThan(
|
|
1700
|
+
resultEntities[i][sort] ?? 0
|
|
1701
|
+
);
|
|
1687
1702
|
}
|
|
1688
1703
|
|
|
1689
1704
|
// Retrieving entities reverse sorted...
|
|
1690
1705
|
resultEntities = await nymph.getEntities(
|
|
1691
|
-
{ class: TestModel, sort
|
|
1706
|
+
{ class: TestModel, sort, reverse: true },
|
|
1692
1707
|
{ type: '&', match: ['name', '^Multi Test '] }
|
|
1693
1708
|
);
|
|
1694
1709
|
expect(resultEntities.length).toEqual(100);
|
|
1695
1710
|
for (let i = 0; i < resultEntities.length - 1; i++) {
|
|
1696
|
-
expect(resultEntities[i + 1][sort
|
|
1697
|
-
resultEntities[i][sort
|
|
1711
|
+
expect(resultEntities[i + 1][sort]).toBeLessThan(
|
|
1712
|
+
resultEntities[i][sort] ?? 0
|
|
1698
1713
|
);
|
|
1699
1714
|
}
|
|
1700
1715
|
}
|
|
1701
1716
|
});
|
|
1702
1717
|
|
|
1718
|
+
it('property sort option', async () => {
|
|
1719
|
+
await createMultipleTestEntities();
|
|
1720
|
+
|
|
1721
|
+
// Retrieving entities sorted...
|
|
1722
|
+
let resultEntities = await nymph.getEntities({
|
|
1723
|
+
class: TestModel,
|
|
1724
|
+
sort: 'number',
|
|
1725
|
+
});
|
|
1726
|
+
expect(resultEntities.length).toBeGreaterThan(100);
|
|
1727
|
+
for (let i = 0; i < resultEntities.length - 1; i++) {
|
|
1728
|
+
expect(resultEntities[i + 1].number ?? Infinity).toBeGreaterThanOrEqual(
|
|
1729
|
+
resultEntities[i].number ?? 0
|
|
1730
|
+
);
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
// And test the same with guid return...
|
|
1734
|
+
let resultGuids = await nymph.getEntities({
|
|
1735
|
+
class: TestModel,
|
|
1736
|
+
sort: 'number',
|
|
1737
|
+
return: 'guid',
|
|
1738
|
+
});
|
|
1739
|
+
expect(resultGuids.length).toBeGreaterThan(100);
|
|
1740
|
+
for (let i = 0; i < resultGuids.length - 1; i++) {
|
|
1741
|
+
expect(resultGuids[i]).toEqual(resultEntities[i].guid);
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
// Retrieving entities reverse sorted...
|
|
1745
|
+
resultEntities = await nymph.getEntities({
|
|
1746
|
+
class: TestModel,
|
|
1747
|
+
sort: 'number',
|
|
1748
|
+
reverse: true,
|
|
1749
|
+
});
|
|
1750
|
+
expect(resultEntities.length).toBeGreaterThan(100);
|
|
1751
|
+
for (let i = 0; i < resultEntities.length - 1; i++) {
|
|
1752
|
+
expect(resultEntities[i + 1].number ?? 0).toBeLessThanOrEqual(
|
|
1753
|
+
resultEntities[i].number ?? Infinity
|
|
1754
|
+
);
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1757
|
+
// And again with other selectors.
|
|
1758
|
+
// Retrieving entities sorted...
|
|
1759
|
+
resultEntities = await nymph.getEntities(
|
|
1760
|
+
{ class: TestModel, sort: 'number' },
|
|
1761
|
+
{ type: '&', match: ['name', '^Multi Test '] }
|
|
1762
|
+
);
|
|
1763
|
+
expect(resultEntities.length).toEqual(100);
|
|
1764
|
+
for (let i = 0; i < resultEntities.length - 1; i++) {
|
|
1765
|
+
expect(resultEntities[i + 1].number ?? Infinity).toBeGreaterThan(
|
|
1766
|
+
resultEntities[i].number ?? 0
|
|
1767
|
+
);
|
|
1768
|
+
expect(resultEntities[i].name).toEqual(
|
|
1769
|
+
`Multi Test ${100 - (resultEntities[i].number ?? 0)}`
|
|
1770
|
+
);
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1773
|
+
// Retrieving entities reverse sorted...
|
|
1774
|
+
resultEntities = await nymph.getEntities(
|
|
1775
|
+
{ class: TestModel, sort: 'number', reverse: true },
|
|
1776
|
+
{ type: '&', match: ['name', '^Multi Test '] }
|
|
1777
|
+
);
|
|
1778
|
+
expect(resultEntities.length).toEqual(100);
|
|
1779
|
+
for (let i = 0; i < resultEntities.length - 1; i++) {
|
|
1780
|
+
expect(resultEntities[i + 1].number ?? 0).toBeLessThan(
|
|
1781
|
+
resultEntities[i].number ?? Infinity
|
|
1782
|
+
);
|
|
1783
|
+
expect(resultEntities[i].name).toEqual(
|
|
1784
|
+
`Multi Test ${100 - (resultEntities[i].number ?? 0)}`
|
|
1785
|
+
);
|
|
1786
|
+
}
|
|
1787
|
+
});
|
|
1788
|
+
|
|
1703
1789
|
it('delete reference', async () => {
|
|
1704
1790
|
await createTestEntities();
|
|
1705
1791
|
|
|
@@ -1728,9 +1814,6 @@ export function UIDTest(
|
|
|
1728
1814
|
nymph: Nymph,
|
|
1729
1815
|
it: (name: string, fn: () => void) => void
|
|
1730
1816
|
) {
|
|
1731
|
-
nymph.addEntityClass(TestModel);
|
|
1732
|
-
nymph.addEntityClass(TestBModel);
|
|
1733
|
-
|
|
1734
1817
|
it('delete old test data', async () => {
|
|
1735
1818
|
expect(await nymph.deleteUID('TestUID')).toEqual(true);
|
|
1736
1819
|
expect(await nymph.deleteUID('NewUID')).toEqual(true);
|
|
@@ -1772,8 +1855,8 @@ export function ExportImportTest(
|
|
|
1772
1855
|
nymph: Nymph,
|
|
1773
1856
|
it: (name: string, fn: () => void) => void
|
|
1774
1857
|
) {
|
|
1775
|
-
nymph.addEntityClass(
|
|
1776
|
-
nymph.addEntityClass(
|
|
1858
|
+
const TestModel = nymph.addEntityClass(TestModelClass);
|
|
1859
|
+
const TestBModel = nymph.addEntityClass(TestBModelClass);
|
|
1777
1860
|
|
|
1778
1861
|
async function deleteTestData() {
|
|
1779
1862
|
let all = await nymph.getEntities({ class: TestModel });
|
package/src/testArtifacts.ts
CHANGED
|
@@ -86,3 +86,23 @@ export class TestBModel extends TestModel {
|
|
|
86
86
|
return super.factorySync(guid) as TestBModel & TestModelData;
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
+
|
|
90
|
+
export type TestEmptyModelData = {};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* This class is a test class that extends the Entity class.
|
|
94
|
+
*/
|
|
95
|
+
export class TestEmptyModel extends Entity<TestEmptyModelData> {
|
|
96
|
+
static ETYPE = 'test_empty_model';
|
|
97
|
+
static class = 'TestEmptyModel';
|
|
98
|
+
|
|
99
|
+
static async factory(
|
|
100
|
+
guid?: string
|
|
101
|
+
): Promise<TestEmptyModel & TestEmptyModelData> {
|
|
102
|
+
return (await super.factory(guid)) as TestEmptyModel & TestEmptyModelData;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
static factorySync(guid?: string): TestEmptyModel & TestEmptyModelData {
|
|
106
|
+
return super.factorySync(guid) as TestEmptyModel & TestEmptyModelData;
|
|
107
|
+
}
|
|
108
|
+
}
|
package/src/testMocks.ts
CHANGED
|
@@ -59,26 +59,43 @@ export class MockNymph {
|
|
|
59
59
|
private entityClasses: { [k: string]: EntityConstructor } = {};
|
|
60
60
|
public driver: MockNymphDriver;
|
|
61
61
|
public Tilmeld: any = undefined;
|
|
62
|
+
public Entity: typeof Entity;
|
|
62
63
|
|
|
63
64
|
public constructor() {
|
|
64
65
|
this.driver = new MockNymphDriver(this);
|
|
65
66
|
|
|
66
67
|
// class NymphEntity extends Entity {}
|
|
67
|
-
this.addEntityClass(Entity);
|
|
68
|
+
this.Entity = this.addEntityClass(Entity);
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
public addEntityClass(entityClass:
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
public addEntityClass<T extends EntityConstructor>(entityClass: T): T {
|
|
72
|
+
const nymph = this;
|
|
73
|
+
class NymphEntity extends entityClass {
|
|
74
|
+
static nymph: Nymph = nymph as unknown as Nymph;
|
|
75
|
+
|
|
76
|
+
constructor(...args: any[]) {
|
|
77
|
+
super(...args);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
this.entityClasses[entityClass.class] = NymphEntity;
|
|
81
|
+
return NymphEntity;
|
|
73
82
|
}
|
|
74
83
|
|
|
75
|
-
public getEntityClass(className:
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
84
|
+
public getEntityClass<T extends EntityConstructor>(className: T): T;
|
|
85
|
+
public getEntityClass(className: string): EntityConstructor;
|
|
86
|
+
public getEntityClass<T extends EntityConstructor = EntityConstructor>(
|
|
87
|
+
className: T | string
|
|
88
|
+
): T | EntityConstructor {
|
|
89
|
+
let key: string | null = null;
|
|
90
|
+
if (typeof className === 'string') {
|
|
91
|
+
key = className;
|
|
92
|
+
} else {
|
|
93
|
+
key = className.class;
|
|
94
|
+
}
|
|
95
|
+
if (key in this.entityClasses) {
|
|
96
|
+
return this.entityClasses[key];
|
|
80
97
|
}
|
|
81
|
-
throw new ClassNotAvailableError('Tried to use class: ' +
|
|
98
|
+
throw new ClassNotAvailableError('Tried to use class: ' + key);
|
|
82
99
|
}
|
|
83
100
|
|
|
84
101
|
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
package/src/utils.ts
CHANGED
|
@@ -17,7 +17,8 @@ export function uniqueStrings(array: string[]) {
|
|
|
17
17
|
|
|
18
18
|
export function classNamesToEntityConstructors(
|
|
19
19
|
nymph: Nymph,
|
|
20
|
-
selectors: Selector[]
|
|
20
|
+
selectors: Selector[],
|
|
21
|
+
enforceRestEnabledFlag = false
|
|
21
22
|
): Selector[] {
|
|
22
23
|
const newSelectors: Selector[] = [];
|
|
23
24
|
|
|
@@ -45,22 +46,35 @@ export function classNamesToEntityConstructors(
|
|
|
45
46
|
for (let i = 0; i < tmpArr.length; i++) {
|
|
46
47
|
const name = tmpArr[i][0];
|
|
47
48
|
const [qrefOptions, ...selectors] = tmpArr[i][1];
|
|
48
|
-
const QrefEntityClass =
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
const QrefEntityClass = qrefOptions.class
|
|
50
|
+
? nymph.getEntityClass(qrefOptions.class)
|
|
51
|
+
: nymph.getEntityClass('Entity');
|
|
52
|
+
if (enforceRestEnabledFlag && !QrefEntityClass.restEnabled) {
|
|
53
|
+
throw new Error('Not accessible.');
|
|
54
|
+
}
|
|
52
55
|
const options = { ...qrefOptions, class: QrefEntityClass };
|
|
53
56
|
if (!newSelector[key]) {
|
|
54
57
|
newSelector[key] = [];
|
|
55
58
|
}
|
|
56
59
|
(newSelector[key] as [string, [Options, ...Selector[]]][]).push([
|
|
57
60
|
name,
|
|
58
|
-
[
|
|
61
|
+
[
|
|
62
|
+
options,
|
|
63
|
+
...classNamesToEntityConstructors(
|
|
64
|
+
nymph,
|
|
65
|
+
selectors,
|
|
66
|
+
enforceRestEnabledFlag
|
|
67
|
+
),
|
|
68
|
+
],
|
|
59
69
|
]);
|
|
60
70
|
}
|
|
61
71
|
} else if (key === 'selector' || key === '!selector') {
|
|
62
72
|
const tmpArr = (Array.isArray(value) ? value : [value]) as Selector[];
|
|
63
|
-
newSelector[key] = classNamesToEntityConstructors(
|
|
73
|
+
newSelector[key] = classNamesToEntityConstructors(
|
|
74
|
+
nymph,
|
|
75
|
+
tmpArr,
|
|
76
|
+
enforceRestEnabledFlag
|
|
77
|
+
);
|
|
64
78
|
} else {
|
|
65
79
|
// @ts-ignore: ts doesn't know what value is here.
|
|
66
80
|
newSelector[key] = value;
|