@nymphjs/nymph 1.0.0-beta.2 → 1.0.0-beta.21
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 +101 -0
- package/README.md +4 -2
- package/dist/Entity.js +41 -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 +1 -1
- package/dist/Nymph.d.ts +22 -8
- package/dist/Nymph.js +170 -32
- package/dist/Nymph.js.map +1 -1
- package/dist/Nymph.types.d.ts +16 -3
- package/dist/Nymph.types.js.map +1 -1
- package/dist/driver/NymphDriver.d.ts +8 -4
- package/dist/driver/NymphDriver.js +81 -64
- package/dist/driver/NymphDriver.js.map +1 -1
- package/dist/driver/testArtifacts.js +192 -155
- package/dist/driver/testArtifacts.js.map +1 -1
- package/dist/testArtifacts.js +2 -2
- package/dist/testArtifacts.js.map +1 -1
- package/dist/testMocks.d.ts +3 -1
- package/dist/testMocks.js +11 -6
- package/dist/testMocks.js.map +1 -1
- package/package.json +11 -11
- package/src/Entity.test.ts +14 -7
- package/src/Entity.ts +64 -19
- package/src/Entity.types.ts +1 -1
- package/src/Nymph.ts +331 -44
- package/src/Nymph.types.ts +82 -4
- package/src/driver/NymphDriver.ts +116 -74
- package/src/driver/testArtifacts.ts +104 -33
- package/src/testMocks.ts +14 -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>
|
|
@@ -29,12 +42,22 @@ export type NymphDisconnectCallback = (
|
|
|
29
42
|
nymph: Nymph,
|
|
30
43
|
result: Promise<boolean>
|
|
31
44
|
) => Promise<void>;
|
|
32
|
-
/**
|
|
45
|
+
/**
|
|
46
|
+
* The NymphQueryCallback will be called on both top level and qref queries.
|
|
47
|
+
*
|
|
48
|
+
* This is the only callback that is not asynchronous.
|
|
49
|
+
*
|
|
50
|
+
* This also isn't necessarily run on every "query". It is run before a database
|
|
51
|
+
* query for an entity, but it is not run during PubSub entity change
|
|
52
|
+
* propagation. Therefore, it shouldn't do anything _entity_ specific, instead
|
|
53
|
+
* it should be _query_ specific. For example, throw an error if the user is not
|
|
54
|
+
* permitted to run the query at all.
|
|
55
|
+
*/
|
|
33
56
|
export type NymphQueryCallback = (
|
|
34
57
|
nymph: Nymph,
|
|
35
58
|
options: Options,
|
|
36
59
|
selectors: FormattedSelector[]
|
|
37
|
-
) =>
|
|
60
|
+
) => void;
|
|
38
61
|
export type NymphBeforeGetEntityCallback = (
|
|
39
62
|
nymph: Nymph,
|
|
40
63
|
options: Options,
|
|
@@ -53,6 +76,10 @@ export type NymphAfterSaveEntityCallback = (
|
|
|
53
76
|
nymph: Nymph,
|
|
54
77
|
result: Promise<boolean>
|
|
55
78
|
) => Promise<void>;
|
|
79
|
+
export type NymphFailedSaveEntityCallback = (
|
|
80
|
+
nymph: Nymph,
|
|
81
|
+
error: any
|
|
82
|
+
) => Promise<void>;
|
|
56
83
|
export type NymphBeforeDeleteEntityCallback = (
|
|
57
84
|
nymph: Nymph,
|
|
58
85
|
entity: EntityInterface
|
|
@@ -61,6 +88,10 @@ export type NymphAfterDeleteEntityCallback = (
|
|
|
61
88
|
nymph: Nymph,
|
|
62
89
|
result: Promise<boolean>
|
|
63
90
|
) => Promise<void>;
|
|
91
|
+
export type NymphFailedDeleteEntityCallback = (
|
|
92
|
+
nymph: Nymph,
|
|
93
|
+
error: any
|
|
94
|
+
) => Promise<void>;
|
|
64
95
|
export type NymphBeforeDeleteEntityByIDCallback = (
|
|
65
96
|
nymph: Nymph,
|
|
66
97
|
guid: string,
|
|
@@ -70,6 +101,10 @@ export type NymphAfterDeleteEntityByIDCallback = (
|
|
|
70
101
|
nymph: Nymph,
|
|
71
102
|
result: Promise<boolean>
|
|
72
103
|
) => Promise<void>;
|
|
104
|
+
export type NymphFailedDeleteEntityByIDCallback = (
|
|
105
|
+
nymph: Nymph,
|
|
106
|
+
error: any
|
|
107
|
+
) => Promise<void>;
|
|
73
108
|
export type NymphBeforeNewUIDCallback = (
|
|
74
109
|
nymph: Nymph,
|
|
75
110
|
name: string
|
|
@@ -78,6 +113,10 @@ export type NymphAfterNewUIDCallback = (
|
|
|
78
113
|
nymph: Nymph,
|
|
79
114
|
result: Promise<number | null>
|
|
80
115
|
) => Promise<void>;
|
|
116
|
+
export type NymphFailedNewUIDCallback = (
|
|
117
|
+
nymph: Nymph,
|
|
118
|
+
error: any
|
|
119
|
+
) => Promise<void>;
|
|
81
120
|
export type NymphBeforeSetUIDCallback = (
|
|
82
121
|
nymph: Nymph,
|
|
83
122
|
name: string,
|
|
@@ -87,6 +126,10 @@ export type NymphAfterSetUIDCallback = (
|
|
|
87
126
|
nymph: Nymph,
|
|
88
127
|
result: Promise<boolean>
|
|
89
128
|
) => Promise<void>;
|
|
129
|
+
export type NymphFailedSetUIDCallback = (
|
|
130
|
+
nymph: Nymph,
|
|
131
|
+
error: any
|
|
132
|
+
) => Promise<void>;
|
|
90
133
|
export type NymphBeforeRenameUIDCallback = (
|
|
91
134
|
nymph: Nymph,
|
|
92
135
|
oldName: string,
|
|
@@ -96,6 +139,10 @@ export type NymphAfterRenameUIDCallback = (
|
|
|
96
139
|
nymph: Nymph,
|
|
97
140
|
result: Promise<boolean>
|
|
98
141
|
) => Promise<void>;
|
|
142
|
+
export type NymphFailedRenameUIDCallback = (
|
|
143
|
+
nymph: Nymph,
|
|
144
|
+
error: any
|
|
145
|
+
) => Promise<void>;
|
|
99
146
|
export type NymphBeforeDeleteUIDCallback = (
|
|
100
147
|
nymph: Nymph,
|
|
101
148
|
name: string
|
|
@@ -104,13 +151,44 @@ export type NymphAfterDeleteUIDCallback = (
|
|
|
104
151
|
nymph: Nymph,
|
|
105
152
|
result: Promise<boolean>
|
|
106
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>;
|
|
107
185
|
|
|
108
186
|
export type Options<T extends EntityConstructor = EntityConstructor> = {
|
|
109
187
|
class?: T;
|
|
110
188
|
limit?: number;
|
|
111
189
|
offset?: number;
|
|
112
190
|
reverse?: boolean;
|
|
113
|
-
sort?: 'cdate' | 'mdate';
|
|
191
|
+
sort?: 'cdate' | 'mdate' | string;
|
|
114
192
|
return?: 'entity' | 'guid' | 'count';
|
|
115
193
|
source?: string;
|
|
116
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>;
|
|
@@ -283,7 +299,7 @@ export default abstract class NymphDriver {
|
|
|
283
299
|
guid: string | null = null,
|
|
284
300
|
tags: string[] | null = null
|
|
285
301
|
) {
|
|
286
|
-
const formattedSelectors = this.formatSelectors(selectors);
|
|
302
|
+
const formattedSelectors = this.formatSelectors(selectors).selectors;
|
|
287
303
|
|
|
288
304
|
for (const curSelector of formattedSelectors) {
|
|
289
305
|
const type = curSelector.type;
|
|
@@ -575,8 +591,12 @@ export default abstract class NymphDriver {
|
|
|
575
591
|
public formatSelectors(
|
|
576
592
|
selectors: Selector[],
|
|
577
593
|
options: Options = {}
|
|
578
|
-
):
|
|
594
|
+
): {
|
|
595
|
+
selectors: FormattedSelector[];
|
|
596
|
+
qrefs: [Options, ...FormattedSelector[]][];
|
|
597
|
+
} {
|
|
579
598
|
const newSelectors: FormattedSelector[] = [];
|
|
599
|
+
const qrefs: [Options, ...FormattedSelector[]][] = [];
|
|
580
600
|
|
|
581
601
|
for (const curSelector of selectors) {
|
|
582
602
|
const newSelector: FormattedSelector = {
|
|
@@ -615,13 +635,18 @@ export default abstract class NymphDriver {
|
|
|
615
635
|
source: options.source,
|
|
616
636
|
};
|
|
617
637
|
const newSelectors = this.formatSelectors(qrefSelectors, options);
|
|
618
|
-
|
|
619
|
-
|
|
638
|
+
qrefs.push(
|
|
639
|
+
[newOptions, ...newSelectors.selectors],
|
|
640
|
+
...newSelectors.qrefs
|
|
641
|
+
);
|
|
642
|
+
formatArr[i] = [name, [newOptions, ...newSelectors.selectors]];
|
|
620
643
|
}
|
|
621
644
|
newSelector[key] = formatArr;
|
|
622
645
|
} else if (key === 'selector' || key === '!selector') {
|
|
623
646
|
const tmpArr = (Array.isArray(value) ? value : [value]) as Selector[];
|
|
624
|
-
|
|
647
|
+
const newSelectors = this.formatSelectors(tmpArr, options);
|
|
648
|
+
newSelector[key] = newSelectors.selectors;
|
|
649
|
+
qrefs.push(...newSelectors.qrefs);
|
|
625
650
|
} else if (!Array.isArray(value)) {
|
|
626
651
|
// @ts-ignore: ts doesn't know what value is here.
|
|
627
652
|
newSelector[key] = [[value]];
|
|
@@ -655,7 +680,7 @@ export default abstract class NymphDriver {
|
|
|
655
680
|
newSelectors.push(newSelector);
|
|
656
681
|
}
|
|
657
682
|
|
|
658
|
-
return newSelectors;
|
|
683
|
+
return { selectors: newSelectors, qrefs };
|
|
659
684
|
}
|
|
660
685
|
|
|
661
686
|
protected iterateSelectorsForQuery(
|
|
@@ -774,7 +799,7 @@ export default abstract class NymphDriver {
|
|
|
774
799
|
name: string;
|
|
775
800
|
svalue: string;
|
|
776
801
|
}
|
|
777
|
-
): { result: any; process: () => number };
|
|
802
|
+
): { result: any; process: () => number | Error };
|
|
778
803
|
protected getEntitesRowLike<T extends EntityConstructor = EntityConstructor>(
|
|
779
804
|
options: Options<T> & { return: 'guid' },
|
|
780
805
|
selectors: Selector[],
|
|
@@ -798,7 +823,7 @@ export default abstract class NymphDriver {
|
|
|
798
823
|
name: string;
|
|
799
824
|
svalue: string;
|
|
800
825
|
}
|
|
801
|
-
): { result: any; process: () => string[] };
|
|
826
|
+
): { result: any; process: () => string[] | Error };
|
|
802
827
|
protected getEntitesRowLike<T extends EntityConstructor = EntityConstructor>(
|
|
803
828
|
options: Options<T>,
|
|
804
829
|
selectors: Selector[],
|
|
@@ -822,7 +847,7 @@ export default abstract class NymphDriver {
|
|
|
822
847
|
name: string;
|
|
823
848
|
svalue: string;
|
|
824
849
|
}
|
|
825
|
-
): { result: any; process: () => ReturnType<T['factorySync']>[] };
|
|
850
|
+
): { result: any; process: () => ReturnType<T['factorySync']>[] | Error };
|
|
826
851
|
protected getEntitesRowLike<T extends EntityConstructor = EntityConstructor>(
|
|
827
852
|
options: Options<T>,
|
|
828
853
|
selectors: Selector[],
|
|
@@ -848,7 +873,7 @@ export default abstract class NymphDriver {
|
|
|
848
873
|
}
|
|
849
874
|
): {
|
|
850
875
|
result: any;
|
|
851
|
-
process: () => ReturnType<T['factorySync']>[] | string[] | number;
|
|
876
|
+
process: () => ReturnType<T['factorySync']>[] | string[] | number | Error;
|
|
852
877
|
} {
|
|
853
878
|
if (!this.isConnected()) {
|
|
854
879
|
throw new UnableToConnectError('not connected to DB');
|
|
@@ -918,78 +943,95 @@ export default abstract class NymphDriver {
|
|
|
918
943
|
}
|
|
919
944
|
}
|
|
920
945
|
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
946
|
+
try {
|
|
947
|
+
const formattedSelectors = this.formatSelectors(selectors, options);
|
|
948
|
+
this.nymph.runQueryCallbacks(options, formattedSelectors.selectors);
|
|
949
|
+
for (let qref of formattedSelectors.qrefs) {
|
|
950
|
+
const [options, ...selectors] = qref;
|
|
951
|
+
this.nymph.runQueryCallbacks(options, selectors);
|
|
952
|
+
}
|
|
953
|
+
const { result } = performQueryCallback(
|
|
954
|
+
options,
|
|
955
|
+
formattedSelectors.selectors,
|
|
956
|
+
etype
|
|
957
|
+
);
|
|
924
958
|
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
row = rowFetchCallback();
|
|
933
|
-
}
|
|
934
|
-
} else if (options.return === 'guid') {
|
|
935
|
-
while (row != null) {
|
|
936
|
-
(entities as string[]).push(getGUIDCallback(row));
|
|
937
|
-
row = rowFetchCallback();
|
|
938
|
-
}
|
|
939
|
-
} else {
|
|
940
|
-
while (row != null) {
|
|
941
|
-
const guid = getGUIDCallback(row);
|
|
942
|
-
const tagsAndDates = getTagsAndDatesCallback(row);
|
|
943
|
-
const tags = tagsAndDates.tags;
|
|
944
|
-
const cdate = tagsAndDates.cdate;
|
|
945
|
-
const mdate = tagsAndDates.mdate;
|
|
946
|
-
let dataNameAndSValue = getDataNameAndSValueCallback(row);
|
|
947
|
-
// Data.
|
|
948
|
-
const data: EntityData = {};
|
|
949
|
-
// Serialized data.
|
|
950
|
-
const sdata: SerializedEntityData = {};
|
|
951
|
-
if (dataNameAndSValue.name !== '') {
|
|
952
|
-
// This do will keep going and adding the data until the
|
|
953
|
-
// next entity is reached. $row will end on the next entity.
|
|
954
|
-
do {
|
|
955
|
-
dataNameAndSValue = getDataNameAndSValueCallback(row);
|
|
956
|
-
sdata[dataNameAndSValue.name] = dataNameAndSValue.svalue;
|
|
957
|
-
row = rowFetchCallback();
|
|
958
|
-
} while (row != null && getGUIDCallback(row) === guid);
|
|
959
|
-
} else {
|
|
960
|
-
// Make sure that $row is incremented :)
|
|
959
|
+
return {
|
|
960
|
+
result,
|
|
961
|
+
process: () => {
|
|
962
|
+
let row = rowFetchCallback();
|
|
963
|
+
if (options.return === 'count') {
|
|
964
|
+
while (row != null) {
|
|
965
|
+
count += getCountCallback(row);
|
|
961
966
|
row = rowFetchCallback();
|
|
962
967
|
}
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
if (options.skipAc != null) {
|
|
968
|
-
entity.$useSkipAc(!!options.skipAc);
|
|
969
|
-
}
|
|
970
|
-
entity.guid = guid;
|
|
971
|
-
entity.cdate = cdate;
|
|
972
|
-
entity.mdate = mdate;
|
|
973
|
-
entity.tags = tags;
|
|
974
|
-
this.putDataCounter++;
|
|
975
|
-
if (this.putDataCounter == 100) {
|
|
976
|
-
throw new Error('Infinite loop detected in Entity loading.');
|
|
968
|
+
} else if (options.return === 'guid') {
|
|
969
|
+
while (row != null) {
|
|
970
|
+
(entities as string[]).push(getGUIDCallback(row));
|
|
971
|
+
row = rowFetchCallback();
|
|
977
972
|
}
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
973
|
+
} else {
|
|
974
|
+
while (row != null) {
|
|
975
|
+
const guid = getGUIDCallback(row);
|
|
976
|
+
const tagsAndDates = getTagsAndDatesCallback(row);
|
|
977
|
+
const tags = tagsAndDates.tags;
|
|
978
|
+
const cdate = tagsAndDates.cdate;
|
|
979
|
+
const mdate = tagsAndDates.mdate;
|
|
980
|
+
let dataNameAndSValue = getDataNameAndSValueCallback(row);
|
|
981
|
+
// Data.
|
|
982
|
+
const data: EntityData = {};
|
|
983
|
+
// Serialized data.
|
|
984
|
+
const sdata: SerializedEntityData = {};
|
|
985
|
+
if (dataNameAndSValue.name !== '') {
|
|
986
|
+
// This do will keep going and adding the data until the
|
|
987
|
+
// next entity is reached. $row will end on the next entity.
|
|
988
|
+
do {
|
|
989
|
+
dataNameAndSValue = getDataNameAndSValueCallback(row);
|
|
990
|
+
sdata[dataNameAndSValue.name] = dataNameAndSValue.svalue;
|
|
991
|
+
row = rowFetchCallback();
|
|
992
|
+
} while (row != null && getGUIDCallback(row) === guid);
|
|
993
|
+
} else {
|
|
994
|
+
// Make sure that $row is incremented :)
|
|
995
|
+
row = rowFetchCallback();
|
|
996
|
+
}
|
|
997
|
+
const entity = EntityClass.factorySync() as ReturnType<
|
|
998
|
+
T['factorySync']
|
|
999
|
+
>;
|
|
1000
|
+
entity.$nymph = this.nymph;
|
|
1001
|
+
if (options.skipAc != null) {
|
|
1002
|
+
entity.$useSkipAc(!!options.skipAc);
|
|
1003
|
+
}
|
|
1004
|
+
entity.guid = guid;
|
|
1005
|
+
entity.cdate = cdate;
|
|
1006
|
+
entity.mdate = mdate;
|
|
1007
|
+
entity.tags = tags;
|
|
1008
|
+
this.putDataCounter++;
|
|
1009
|
+
if (this.putDataCounter == 100) {
|
|
1010
|
+
throw new Error('Infinite loop detected in Entity loading.');
|
|
1011
|
+
}
|
|
1012
|
+
entity.$putData(data, sdata);
|
|
1013
|
+
this.putDataCounter--;
|
|
1014
|
+
if (this.nymph.config.cache) {
|
|
1015
|
+
this.pushCache(guid, cdate, mdate, tags, data, sdata);
|
|
1016
|
+
}
|
|
1017
|
+
// @ts-ignore: ts doesn't know the return type here.
|
|
1018
|
+
entities.push(entity);
|
|
982
1019
|
}
|
|
983
|
-
// @ts-ignore: ts doesn't know the return type here.
|
|
984
|
-
entities.push(entity);
|
|
985
1020
|
}
|
|
986
|
-
}
|
|
987
1021
|
|
|
988
|
-
|
|
1022
|
+
freeResultCallback();
|
|
989
1023
|
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
1024
|
+
return options.return === 'count' ? count : entities;
|
|
1025
|
+
},
|
|
1026
|
+
};
|
|
1027
|
+
} catch (e: any) {
|
|
1028
|
+
return {
|
|
1029
|
+
result: Promise.resolve(e),
|
|
1030
|
+
process: () => {
|
|
1031
|
+
return e;
|
|
1032
|
+
},
|
|
1033
|
+
};
|
|
1034
|
+
}
|
|
993
1035
|
}
|
|
994
1036
|
|
|
995
1037
|
protected async saveEntityRowLike(
|
|
@@ -3,16 +3,20 @@ 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
|
+
} from '../testArtifacts';
|
|
7
11
|
|
|
8
12
|
export function QueriesTest(
|
|
9
13
|
nymph: Nymph,
|
|
10
14
|
it: (name: string, fn: () => void) => void
|
|
11
15
|
) {
|
|
12
|
-
nymph.addEntityClass(
|
|
13
|
-
nymph.addEntityClass(
|
|
16
|
+
const TestModel = nymph.addEntityClass(TestModelClass);
|
|
17
|
+
const TestBModel = nymph.addEntityClass(TestBModelClass);
|
|
14
18
|
|
|
15
|
-
let testEntity:
|
|
19
|
+
let testEntity: TestModelClass & TestModelData;
|
|
16
20
|
let testGuid: string;
|
|
17
21
|
let refGuid: string;
|
|
18
22
|
let createdMultiple = false;
|
|
@@ -43,7 +47,7 @@ This one's zip code is 92064.`;
|
|
|
43
47
|
expect(testEntity.guid).not.toBeNull();
|
|
44
48
|
testGuid = testEntity.guid as string;
|
|
45
49
|
|
|
46
|
-
const entityReferenceTest:
|
|
50
|
+
const entityReferenceTest: TestModelClass & TestModelData = new TestModel();
|
|
47
51
|
entityReferenceTest.string = 'wrong';
|
|
48
52
|
entityReferenceTest.timestamp = strtotime('-2 days') * 1000;
|
|
49
53
|
expect(await entityReferenceTest.$save()).toEqual(true);
|
|
@@ -59,7 +63,7 @@ This one's zip code is 92064.`;
|
|
|
59
63
|
testEntity = nymph.driver.getEntitySync(
|
|
60
64
|
{ class: TestModel },
|
|
61
65
|
testGuid
|
|
62
|
-
) as
|
|
66
|
+
) as TestModelClass & TestModelData;
|
|
63
67
|
expect(testEntity).toBeInstanceOf(TestModel);
|
|
64
68
|
expect(testEntity.guid).toEqual(testGuid);
|
|
65
69
|
|
|
@@ -67,7 +71,7 @@ This one's zip code is 92064.`;
|
|
|
67
71
|
testEntity = (await nymph.getEntity(
|
|
68
72
|
{ class: TestModel },
|
|
69
73
|
testGuid
|
|
70
|
-
)) as
|
|
74
|
+
)) as TestModelClass & TestModelData;
|
|
71
75
|
expect(testEntity).toBeInstanceOf(TestModel);
|
|
72
76
|
expect(testEntity.guid).toEqual(testGuid);
|
|
73
77
|
}
|
|
@@ -80,6 +84,8 @@ This one's zip code is 92064.`;
|
|
|
80
84
|
for (let i = 0; i < 100; i++) {
|
|
81
85
|
const testEntity = await TestModel.factory();
|
|
82
86
|
testEntity.name = `Multi Test ${i}`;
|
|
87
|
+
// Reverse the number for sort testing.
|
|
88
|
+
testEntity.number = 100 - i;
|
|
83
89
|
testEntity.$removeTag('test');
|
|
84
90
|
testEntity.$addTag('multiTest');
|
|
85
91
|
expect(await testEntity.$save()).toEqual(true);
|
|
@@ -191,7 +197,7 @@ This one's zip code is 92064.`;
|
|
|
191
197
|
testEntity = (await transaction.getEntity(
|
|
192
198
|
{ class: TestModel },
|
|
193
199
|
testGuid
|
|
194
|
-
)) as
|
|
200
|
+
)) as TestModelClass & TestModelData;
|
|
195
201
|
|
|
196
202
|
expect(testEntity.guid).toEqual(testGuid);
|
|
197
203
|
|
|
@@ -1633,26 +1639,23 @@ This one's zip code is 92064.`;
|
|
|
1633
1639
|
expect(testEntity.$inArray(resultEntity)).toEqual(false);
|
|
1634
1640
|
});
|
|
1635
1641
|
|
|
1636
|
-
it('sort option', async () => {
|
|
1642
|
+
it('cdate and mdate sort option', async () => {
|
|
1637
1643
|
await createMultipleTestEntities();
|
|
1638
1644
|
|
|
1639
|
-
for (const sort of ['cdate', 'mdate']) {
|
|
1645
|
+
for (const sort of ['cdate', 'mdate'] as ('cdate' | 'mdate')[]) {
|
|
1640
1646
|
// Retrieving entities sorted...
|
|
1641
|
-
let resultEntities = await nymph.getEntities({
|
|
1642
|
-
class: TestModel,
|
|
1643
|
-
sort: sort as 'cdate' | 'mdate',
|
|
1644
|
-
});
|
|
1647
|
+
let resultEntities = await nymph.getEntities({ class: TestModel, sort });
|
|
1645
1648
|
expect(resultEntities.length).toBeGreaterThan(100);
|
|
1646
1649
|
for (let i = 0; i < resultEntities.length - 1; i++) {
|
|
1647
|
-
expect(
|
|
1648
|
-
resultEntities[i
|
|
1649
|
-
)
|
|
1650
|
+
expect(resultEntities[i + 1][sort]).toBeGreaterThan(
|
|
1651
|
+
resultEntities[i][sort] ?? 0
|
|
1652
|
+
);
|
|
1650
1653
|
}
|
|
1651
1654
|
|
|
1652
1655
|
// And test the same with guid return...
|
|
1653
1656
|
let resultGuids = await nymph.getEntities({
|
|
1654
1657
|
class: TestModel,
|
|
1655
|
-
sort
|
|
1658
|
+
sort,
|
|
1656
1659
|
return: 'guid',
|
|
1657
1660
|
});
|
|
1658
1661
|
expect(resultGuids.length).toBeGreaterThan(100);
|
|
@@ -1663,43 +1666,114 @@ This one's zip code is 92064.`;
|
|
|
1663
1666
|
// Retrieving entities reverse sorted...
|
|
1664
1667
|
resultEntities = await nymph.getEntities({
|
|
1665
1668
|
class: TestModel,
|
|
1666
|
-
sort
|
|
1669
|
+
sort,
|
|
1667
1670
|
reverse: true,
|
|
1668
1671
|
});
|
|
1669
1672
|
expect(resultEntities.length).toBeGreaterThan(100);
|
|
1670
1673
|
for (let i = 0; i < resultEntities.length - 1; i++) {
|
|
1671
|
-
expect(resultEntities[i + 1][sort
|
|
1672
|
-
resultEntities[i][sort
|
|
1674
|
+
expect(resultEntities[i + 1][sort]).toBeLessThan(
|
|
1675
|
+
resultEntities[i][sort] ?? 0
|
|
1673
1676
|
);
|
|
1674
1677
|
}
|
|
1675
1678
|
|
|
1676
1679
|
// And again with other selectors.
|
|
1677
1680
|
// Retrieving entities sorted...
|
|
1678
1681
|
resultEntities = await nymph.getEntities(
|
|
1679
|
-
{ class: TestModel, sort
|
|
1682
|
+
{ class: TestModel, sort },
|
|
1680
1683
|
{ type: '&', match: ['name', '^Multi Test '] }
|
|
1681
1684
|
);
|
|
1682
1685
|
expect(resultEntities.length).toEqual(100);
|
|
1683
1686
|
for (let i = 0; i < resultEntities.length - 1; i++) {
|
|
1684
|
-
expect(
|
|
1685
|
-
resultEntities[i
|
|
1686
|
-
)
|
|
1687
|
+
expect(resultEntities[i + 1][sort]).toBeGreaterThan(
|
|
1688
|
+
resultEntities[i][sort] ?? 0
|
|
1689
|
+
);
|
|
1687
1690
|
}
|
|
1688
1691
|
|
|
1689
1692
|
// Retrieving entities reverse sorted...
|
|
1690
1693
|
resultEntities = await nymph.getEntities(
|
|
1691
|
-
{ class: TestModel, sort
|
|
1694
|
+
{ class: TestModel, sort, reverse: true },
|
|
1692
1695
|
{ type: '&', match: ['name', '^Multi Test '] }
|
|
1693
1696
|
);
|
|
1694
1697
|
expect(resultEntities.length).toEqual(100);
|
|
1695
1698
|
for (let i = 0; i < resultEntities.length - 1; i++) {
|
|
1696
|
-
expect(resultEntities[i + 1][sort
|
|
1697
|
-
resultEntities[i][sort
|
|
1699
|
+
expect(resultEntities[i + 1][sort]).toBeLessThan(
|
|
1700
|
+
resultEntities[i][sort] ?? 0
|
|
1698
1701
|
);
|
|
1699
1702
|
}
|
|
1700
1703
|
}
|
|
1701
1704
|
});
|
|
1702
1705
|
|
|
1706
|
+
it('property sort option', async () => {
|
|
1707
|
+
await createMultipleTestEntities();
|
|
1708
|
+
|
|
1709
|
+
// Retrieving entities sorted...
|
|
1710
|
+
let resultEntities = await nymph.getEntities({
|
|
1711
|
+
class: TestModel,
|
|
1712
|
+
sort: 'number',
|
|
1713
|
+
});
|
|
1714
|
+
expect(resultEntities.length).toBeGreaterThan(100);
|
|
1715
|
+
for (let i = 0; i < resultEntities.length - 1; i++) {
|
|
1716
|
+
expect(resultEntities[i + 1].number ?? Infinity).toBeGreaterThanOrEqual(
|
|
1717
|
+
resultEntities[i].number ?? 0
|
|
1718
|
+
);
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
// And test the same with guid return...
|
|
1722
|
+
let resultGuids = await nymph.getEntities({
|
|
1723
|
+
class: TestModel,
|
|
1724
|
+
sort: 'number',
|
|
1725
|
+
return: 'guid',
|
|
1726
|
+
});
|
|
1727
|
+
expect(resultGuids.length).toBeGreaterThan(100);
|
|
1728
|
+
for (let i = 0; i < resultGuids.length - 1; i++) {
|
|
1729
|
+
expect(resultGuids[i]).toEqual(resultEntities[i].guid);
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
// Retrieving entities reverse sorted...
|
|
1733
|
+
resultEntities = await nymph.getEntities({
|
|
1734
|
+
class: TestModel,
|
|
1735
|
+
sort: 'number',
|
|
1736
|
+
reverse: true,
|
|
1737
|
+
});
|
|
1738
|
+
expect(resultEntities.length).toBeGreaterThan(100);
|
|
1739
|
+
for (let i = 0; i < resultEntities.length - 1; i++) {
|
|
1740
|
+
expect(resultEntities[i + 1].number ?? 0).toBeLessThanOrEqual(
|
|
1741
|
+
resultEntities[i].number ?? Infinity
|
|
1742
|
+
);
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
// And again with other selectors.
|
|
1746
|
+
// Retrieving entities sorted...
|
|
1747
|
+
resultEntities = await nymph.getEntities(
|
|
1748
|
+
{ class: TestModel, sort: 'number' },
|
|
1749
|
+
{ type: '&', match: ['name', '^Multi Test '] }
|
|
1750
|
+
);
|
|
1751
|
+
expect(resultEntities.length).toEqual(100);
|
|
1752
|
+
for (let i = 0; i < resultEntities.length - 1; i++) {
|
|
1753
|
+
expect(resultEntities[i + 1].number ?? Infinity).toBeGreaterThan(
|
|
1754
|
+
resultEntities[i].number ?? 0
|
|
1755
|
+
);
|
|
1756
|
+
expect(resultEntities[i].name).toEqual(
|
|
1757
|
+
`Multi Test ${100 - (resultEntities[i].number ?? 0)}`
|
|
1758
|
+
);
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
// Retrieving entities reverse sorted...
|
|
1762
|
+
resultEntities = await nymph.getEntities(
|
|
1763
|
+
{ class: TestModel, sort: 'number', reverse: true },
|
|
1764
|
+
{ type: '&', match: ['name', '^Multi Test '] }
|
|
1765
|
+
);
|
|
1766
|
+
expect(resultEntities.length).toEqual(100);
|
|
1767
|
+
for (let i = 0; i < resultEntities.length - 1; i++) {
|
|
1768
|
+
expect(resultEntities[i + 1].number ?? 0).toBeLessThan(
|
|
1769
|
+
resultEntities[i].number ?? Infinity
|
|
1770
|
+
);
|
|
1771
|
+
expect(resultEntities[i].name).toEqual(
|
|
1772
|
+
`Multi Test ${100 - (resultEntities[i].number ?? 0)}`
|
|
1773
|
+
);
|
|
1774
|
+
}
|
|
1775
|
+
});
|
|
1776
|
+
|
|
1703
1777
|
it('delete reference', async () => {
|
|
1704
1778
|
await createTestEntities();
|
|
1705
1779
|
|
|
@@ -1728,9 +1802,6 @@ export function UIDTest(
|
|
|
1728
1802
|
nymph: Nymph,
|
|
1729
1803
|
it: (name: string, fn: () => void) => void
|
|
1730
1804
|
) {
|
|
1731
|
-
nymph.addEntityClass(TestModel);
|
|
1732
|
-
nymph.addEntityClass(TestBModel);
|
|
1733
|
-
|
|
1734
1805
|
it('delete old test data', async () => {
|
|
1735
1806
|
expect(await nymph.deleteUID('TestUID')).toEqual(true);
|
|
1736
1807
|
expect(await nymph.deleteUID('NewUID')).toEqual(true);
|
|
@@ -1772,8 +1843,8 @@ export function ExportImportTest(
|
|
|
1772
1843
|
nymph: Nymph,
|
|
1773
1844
|
it: (name: string, fn: () => void) => void
|
|
1774
1845
|
) {
|
|
1775
|
-
nymph.addEntityClass(
|
|
1776
|
-
nymph.addEntityClass(
|
|
1846
|
+
const TestModel = nymph.addEntityClass(TestModelClass);
|
|
1847
|
+
const TestBModel = nymph.addEntityClass(TestBModelClass);
|
|
1777
1848
|
|
|
1778
1849
|
async function deleteTestData() {
|
|
1779
1850
|
let all = await nymph.getEntities({ class: TestModel });
|