@nymphjs/nymph 1.0.0-beta.90 → 1.0.0-beta.92
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 +10 -0
- package/dist/Entity.d.ts +2 -1
- package/dist/Entity.js.map +1 -1
- package/dist/Entity.types.d.ts +7 -0
- package/dist/Nymph.d.ts +12 -3
- package/dist/Nymph.js +7 -1
- package/dist/Nymph.js.map +1 -1
- package/dist/Nymph.types.d.ts +8 -3
- package/dist/Nymph.types.js.map +1 -1
- package/dist/driver/NymphDriver.d.ts +33 -6
- package/dist/driver/NymphDriver.js +108 -51
- package/dist/driver/NymphDriver.js.map +1 -1
- package/dist/driver/testArtifacts.js +43 -0
- package/dist/driver/testArtifacts.js.map +1 -1
- package/dist/testMocks.d.ts +13 -1
- package/dist/testMocks.js.map +1 -1
- package/package.json +3 -3
- package/src/Entity.ts +4 -0
- package/src/Entity.types.ts +8 -0
- package/src/Nymph.ts +40 -6
- package/src/Nymph.types.ts +8 -3
- package/src/driver/NymphDriver.ts +166 -71
- package/src/driver/testArtifacts.ts +55 -0
- package/src/testMocks.ts +19 -3
package/src/Entity.types.ts
CHANGED
|
@@ -22,6 +22,14 @@ export type SerializedEntityData = {
|
|
|
22
22
|
[k: string]: string;
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
+
export type EntityObject = {
|
|
26
|
+
guid: string | null;
|
|
27
|
+
cdate: number | null;
|
|
28
|
+
mdate: number | null;
|
|
29
|
+
tags: string[];
|
|
30
|
+
[k: string]: any;
|
|
31
|
+
};
|
|
32
|
+
|
|
25
33
|
export type EntityJson = {
|
|
26
34
|
class: string;
|
|
27
35
|
guid: string | null;
|
package/src/Nymph.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { Config, ConfigDefaults as defaults } from './conf/index.js';
|
|
2
2
|
import type { NymphDriver } from './driver/index.js';
|
|
3
|
-
import Entity, {
|
|
3
|
+
import Entity, {
|
|
4
|
+
type EntityInstanceType,
|
|
5
|
+
type EntityObjectType,
|
|
6
|
+
} from './Entity.js';
|
|
4
7
|
import type { EntityConstructor, EntityInterface } from './Entity.types.js';
|
|
5
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
ClassNotAvailableError,
|
|
10
|
+
InvalidParametersError,
|
|
11
|
+
} from './errors/index.js';
|
|
6
12
|
import type {
|
|
7
13
|
Selector,
|
|
8
14
|
Options,
|
|
@@ -702,8 +708,8 @@ export default class Nymph {
|
|
|
702
708
|
* a top-level property. The method of sorting properties other than cdate
|
|
703
709
|
* and mdate is driver dependent. The only hard rule is that numbers should
|
|
704
710
|
* be sorted numerically (2 before 10). Defaults to "cdate".
|
|
705
|
-
* - return - What to return. "entity", "guid", or "count". Defaults
|
|
706
|
-
* "entity".
|
|
711
|
+
* - return - What to return. "entity", "object", "guid", or "count". Defaults
|
|
712
|
+
* to "entity".
|
|
707
713
|
* - source - Will be 'client' if the query came from a REST call.
|
|
708
714
|
* - skipCache - If true, Nymph will skip the cache and retrieve the entity
|
|
709
715
|
* from the DB.
|
|
@@ -857,6 +863,10 @@ export default class Nymph {
|
|
|
857
863
|
options: Options<T> & { return: 'guid' },
|
|
858
864
|
...selectors: Selector[]
|
|
859
865
|
): Promise<string[]>;
|
|
866
|
+
public async getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
867
|
+
options: Options<T> & { return: 'object' },
|
|
868
|
+
...selectors: Selector[]
|
|
869
|
+
): Promise<EntityObjectType<T>[]>;
|
|
860
870
|
public async getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
861
871
|
options?: Options<T>,
|
|
862
872
|
...selectors: Selector[]
|
|
@@ -864,7 +874,15 @@ export default class Nymph {
|
|
|
864
874
|
public async getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
865
875
|
options: Options<T> = {},
|
|
866
876
|
...selectors: Selector[]
|
|
867
|
-
): Promise<
|
|
877
|
+
): Promise<
|
|
878
|
+
EntityInstanceType<T>[] | EntityObjectType<T>[] | string[] | number
|
|
879
|
+
> {
|
|
880
|
+
if (options.source === 'client' && options.return === 'object') {
|
|
881
|
+
throw new InvalidParametersError(
|
|
882
|
+
'Object return type not allowed from client.',
|
|
883
|
+
);
|
|
884
|
+
}
|
|
885
|
+
|
|
868
886
|
try {
|
|
869
887
|
for (let callback of this.beforeGetEntitiesCallbacks) {
|
|
870
888
|
if (callback) {
|
|
@@ -899,6 +917,10 @@ export default class Nymph {
|
|
|
899
917
|
options: Options<T> & { return: 'guid' },
|
|
900
918
|
...selectors: Selector[]
|
|
901
919
|
): Promise<string | null>;
|
|
920
|
+
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
921
|
+
options: Options<T> & { return: 'object' },
|
|
922
|
+
...selectors: Selector[]
|
|
923
|
+
): Promise<EntityObjectType<T> | null>;
|
|
902
924
|
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
903
925
|
options: Options<T>,
|
|
904
926
|
...selectors: Selector[]
|
|
@@ -907,6 +929,10 @@ export default class Nymph {
|
|
|
907
929
|
options: Options<T> & { return: 'guid' },
|
|
908
930
|
guid: string,
|
|
909
931
|
): Promise<string | null>;
|
|
932
|
+
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
933
|
+
options: Options<T> & { return: 'object' },
|
|
934
|
+
guid: string,
|
|
935
|
+
): Promise<EntityObjectType<T> | null>;
|
|
910
936
|
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
911
937
|
options: Options<T>,
|
|
912
938
|
guid: string,
|
|
@@ -914,7 +940,15 @@ export default class Nymph {
|
|
|
914
940
|
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
915
941
|
options: Options<T> = {},
|
|
916
942
|
...selectors: Selector[] | string[]
|
|
917
|
-
): Promise<
|
|
943
|
+
): Promise<
|
|
944
|
+
EntityInstanceType<T> | EntityObjectType<T> | string | number | null
|
|
945
|
+
> {
|
|
946
|
+
if (options.source === 'client' && options.return === 'object') {
|
|
947
|
+
throw new InvalidParametersError(
|
|
948
|
+
'Object return type not allowed from client.',
|
|
949
|
+
);
|
|
950
|
+
}
|
|
951
|
+
|
|
918
952
|
try {
|
|
919
953
|
// Set up options and selectors.
|
|
920
954
|
if (typeof selectors[0] === 'string') {
|
package/src/Nymph.types.ts
CHANGED
|
@@ -208,10 +208,15 @@ export type Options<T extends EntityConstructor = EntityConstructor> = {
|
|
|
208
208
|
*/
|
|
209
209
|
sort?: 'cdate' | 'mdate' | string;
|
|
210
210
|
/**
|
|
211
|
-
* What to return, the entities with their data, just the
|
|
212
|
-
* count.
|
|
211
|
+
* What to return, the entities with their data, just the entity data, just
|
|
212
|
+
* the GUIDs, or just a count.
|
|
213
|
+
*
|
|
214
|
+
* 'object' is only available on the server, as there are substantial security
|
|
215
|
+
* implications with using it. It returns the full entity data as a simple
|
|
216
|
+
* object. You should only use it for operations where instantiating the
|
|
217
|
+
* entities has an unacceptable performance cost.
|
|
213
218
|
*/
|
|
214
|
-
return?: 'entity' | 'guid' | 'count';
|
|
219
|
+
return?: 'entity' | 'object' | 'guid' | 'count';
|
|
215
220
|
/**
|
|
216
221
|
* Will be 'client' if the query came from a REST request or the PubSub
|
|
217
222
|
* server. (Mainly used in Tilmeld for access control.)
|
|
@@ -5,7 +5,7 @@ import strtotime from 'locutus/php/datetime/strtotime.js';
|
|
|
5
5
|
|
|
6
6
|
import type Nymph from '../Nymph.js';
|
|
7
7
|
import type { Selector, Options, FormattedSelector } from '../Nymph.types.js';
|
|
8
|
-
import
|
|
8
|
+
import type { EntityInstanceType, EntityObjectType } from '../Entity.js';
|
|
9
9
|
import type {
|
|
10
10
|
EntityConstructor,
|
|
11
11
|
EntityData,
|
|
@@ -108,6 +108,10 @@ export default abstract class NymphDriver {
|
|
|
108
108
|
options: Options<T> & { return: 'guid' },
|
|
109
109
|
...selectors: Selector[]
|
|
110
110
|
): Promise<string[]>;
|
|
111
|
+
abstract getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
112
|
+
options: Options<T> & { return: 'object' },
|
|
113
|
+
...selectors: Selector[]
|
|
114
|
+
): Promise<EntityObjectType<T>[]>;
|
|
111
115
|
abstract getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
112
116
|
options?: Options<T>,
|
|
113
117
|
...selectors: Selector[]
|
|
@@ -115,7 +119,9 @@ export default abstract class NymphDriver {
|
|
|
115
119
|
abstract getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
116
120
|
options?: Options<T>,
|
|
117
121
|
...selectors: Selector[]
|
|
118
|
-
): Promise<
|
|
122
|
+
): Promise<
|
|
123
|
+
EntityInstanceType<T>[] | EntityObjectType<T>[] | string[] | number
|
|
124
|
+
>;
|
|
119
125
|
abstract getUID(name: string): Promise<number | null>;
|
|
120
126
|
abstract importEntity(entity: {
|
|
121
127
|
guid: string;
|
|
@@ -796,6 +802,30 @@ export default abstract class NymphDriver {
|
|
|
796
802
|
svalue: string;
|
|
797
803
|
},
|
|
798
804
|
): { result: any; process: () => string[] | Error };
|
|
805
|
+
protected getEntitiesRowLike<T extends EntityConstructor = EntityConstructor>(
|
|
806
|
+
options: Options<T> & { return: 'object' },
|
|
807
|
+
selectors: Selector[],
|
|
808
|
+
performQueryCallback: (data: {
|
|
809
|
+
options: Options<T>;
|
|
810
|
+
selectors: FormattedSelector[];
|
|
811
|
+
etype: string;
|
|
812
|
+
}) => {
|
|
813
|
+
result: any;
|
|
814
|
+
},
|
|
815
|
+
rowFetchCallback: () => any,
|
|
816
|
+
freeResultCallback: () => void,
|
|
817
|
+
getCountCallback: (row: any) => number,
|
|
818
|
+
getGUIDCallback: (row: any) => string,
|
|
819
|
+
getTagsAndDatesCallback: (row: any) => {
|
|
820
|
+
tags: string[];
|
|
821
|
+
cdate: number;
|
|
822
|
+
mdate: number;
|
|
823
|
+
},
|
|
824
|
+
getDataNameAndSValueCallback: (row: any) => {
|
|
825
|
+
name: string;
|
|
826
|
+
svalue: string;
|
|
827
|
+
},
|
|
828
|
+
): { result: any; process: () => EntityObjectType<T>[] | Error };
|
|
799
829
|
protected getEntitiesRowLike<T extends EntityConstructor = EntityConstructor>(
|
|
800
830
|
options: Options<T>,
|
|
801
831
|
selectors: Selector[],
|
|
@@ -848,7 +878,12 @@ export default abstract class NymphDriver {
|
|
|
848
878
|
},
|
|
849
879
|
): {
|
|
850
880
|
result: any;
|
|
851
|
-
process: () =>
|
|
881
|
+
process: () =>
|
|
882
|
+
| EntityInstanceType<T>[]
|
|
883
|
+
| EntityObjectType<T>[]
|
|
884
|
+
| string[]
|
|
885
|
+
| number
|
|
886
|
+
| Error;
|
|
852
887
|
} {
|
|
853
888
|
if (!this.isConnected()) {
|
|
854
889
|
throw new UnableToConnectError('not connected to DB');
|
|
@@ -866,12 +901,19 @@ export default abstract class NymphDriver {
|
|
|
866
901
|
}
|
|
867
902
|
}
|
|
868
903
|
|
|
869
|
-
let entities: EntityInstanceType<T>[] |
|
|
904
|
+
let entities: EntityInstanceType<T>[] | EntityObjectType<T>[] | string[] =
|
|
905
|
+
[];
|
|
870
906
|
let count = 0;
|
|
871
907
|
const EntityClass =
|
|
872
908
|
options.class ?? (this.nymph.getEntityClass('Entity') as T);
|
|
873
909
|
const etype = EntityClass.ETYPE;
|
|
874
910
|
|
|
911
|
+
if (options.source === 'client' && options.return === 'object') {
|
|
912
|
+
throw new InvalidParametersError(
|
|
913
|
+
'Object return type not allowed from client.',
|
|
914
|
+
);
|
|
915
|
+
}
|
|
916
|
+
|
|
875
917
|
// Check if the requested entity is cached.
|
|
876
918
|
if (
|
|
877
919
|
this.nymph.config.cache &&
|
|
@@ -888,33 +930,75 @@ export default abstract class NymphDriver {
|
|
|
888
930
|
(Object.keys(selectors[0]).length === 2 ||
|
|
889
931
|
(Object.keys(selectors[0]).length === 3 && 'tag' in selectors[0]))
|
|
890
932
|
) {
|
|
891
|
-
const
|
|
892
|
-
|
|
893
|
-
EntityClass.class,
|
|
894
|
-
!!options.skipAc,
|
|
895
|
-
);
|
|
933
|
+
const cacheEntity = this.pullCache(selectors[0]['guid']);
|
|
934
|
+
|
|
896
935
|
if (
|
|
897
|
-
|
|
898
|
-
|
|
936
|
+
cacheEntity != null &&
|
|
937
|
+
cacheEntity.guid != null &&
|
|
899
938
|
(!('tag' in selectors[0]) ||
|
|
900
|
-
|
|
901
|
-
|
|
939
|
+
!(
|
|
940
|
+
Array.isArray(selectors[0].tag)
|
|
902
941
|
? selectors[0].tag
|
|
903
|
-
: [selectors[0].tag]
|
|
904
|
-
))
|
|
942
|
+
: [selectors[0].tag]
|
|
943
|
+
).find((tag) => tag == null || !cacheEntity.tags.includes(tag)))
|
|
905
944
|
) {
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
945
|
+
// Return the value from the cache.
|
|
946
|
+
const { guid, cdate, mdate, tags, data, sdata } = cacheEntity;
|
|
947
|
+
|
|
948
|
+
if (options.return === 'count') {
|
|
949
|
+
return {
|
|
950
|
+
result: Promise.resolve(null),
|
|
951
|
+
process: () => 1,
|
|
952
|
+
};
|
|
953
|
+
} else if (options.return === 'guid') {
|
|
954
|
+
return {
|
|
955
|
+
result: Promise.resolve(null),
|
|
956
|
+
process: () => [guid],
|
|
957
|
+
};
|
|
958
|
+
} else if (options.return === 'object') {
|
|
959
|
+
return {
|
|
960
|
+
result: Promise.resolve(null),
|
|
961
|
+
process: () => [
|
|
962
|
+
{
|
|
963
|
+
guid,
|
|
964
|
+
cdate,
|
|
965
|
+
mdate,
|
|
966
|
+
tags,
|
|
967
|
+
...data,
|
|
968
|
+
...Object.fromEntries(
|
|
969
|
+
Object.entries(sdata).map(([name, value]) => [
|
|
970
|
+
name,
|
|
971
|
+
JSON.parse(value),
|
|
972
|
+
]),
|
|
973
|
+
),
|
|
974
|
+
} as EntityObjectType<T>,
|
|
975
|
+
],
|
|
976
|
+
};
|
|
977
|
+
} else {
|
|
978
|
+
const entity = this.nymph
|
|
979
|
+
.getEntityClass(EntityClass.class)
|
|
980
|
+
.factorySync() as EntityInstanceType<T>;
|
|
981
|
+
if (entity) {
|
|
982
|
+
entity.$nymph = this.nymph;
|
|
983
|
+
if (options.skipAc != null) {
|
|
984
|
+
entity.$useSkipAc(!!options.skipAc);
|
|
985
|
+
}
|
|
986
|
+
entity.guid = guid;
|
|
987
|
+
entity.cdate = cdate;
|
|
988
|
+
entity.mdate = mdate;
|
|
989
|
+
entity.tags = tags;
|
|
990
|
+
entity.$putData(data, sdata, 'server');
|
|
991
|
+
return {
|
|
992
|
+
result: Promise.resolve(null),
|
|
993
|
+
process: () => [entity],
|
|
994
|
+
};
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
return {
|
|
998
|
+
result: Promise.resolve(null),
|
|
999
|
+
process: () => [],
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
918
1002
|
}
|
|
919
1003
|
}
|
|
920
1004
|
}
|
|
@@ -971,26 +1055,43 @@ export default abstract class NymphDriver {
|
|
|
971
1055
|
// Make sure that $row is incremented :)
|
|
972
1056
|
row = rowFetchCallback();
|
|
973
1057
|
}
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
1058
|
+
|
|
1059
|
+
if (options.return === 'object') {
|
|
1060
|
+
(entities as EntityObjectType<T>[]).push({
|
|
1061
|
+
guid,
|
|
1062
|
+
cdate,
|
|
1063
|
+
mdate,
|
|
1064
|
+
tags,
|
|
1065
|
+
...data,
|
|
1066
|
+
...Object.fromEntries(
|
|
1067
|
+
Object.entries(sdata).map(([name, value]) => [
|
|
1068
|
+
name,
|
|
1069
|
+
JSON.parse(value),
|
|
1070
|
+
]),
|
|
1071
|
+
),
|
|
1072
|
+
} as EntityObjectType<T>);
|
|
1073
|
+
} else {
|
|
1074
|
+
const entity =
|
|
1075
|
+
EntityClass.factorySync() as EntityInstanceType<T>;
|
|
1076
|
+
entity.$nymph = this.nymph;
|
|
1077
|
+
if (options.skipAc != null) {
|
|
1078
|
+
entity.$useSkipAc(!!options.skipAc);
|
|
1079
|
+
}
|
|
1080
|
+
entity.guid = guid;
|
|
1081
|
+
entity.cdate = cdate;
|
|
1082
|
+
entity.mdate = mdate;
|
|
1083
|
+
entity.tags = tags;
|
|
1084
|
+
this.putDataCounter++;
|
|
1085
|
+
if (this.putDataCounter == 100) {
|
|
1086
|
+
throw new Error('Infinite loop detected in Entity loading.');
|
|
1087
|
+
}
|
|
1088
|
+
entity.$putData(data, sdata, 'server');
|
|
1089
|
+
this.putDataCounter--;
|
|
1090
|
+
entities.push(entity);
|
|
986
1091
|
}
|
|
987
|
-
entity.$putData(data, sdata, 'server');
|
|
988
|
-
this.putDataCounter--;
|
|
989
1092
|
if (this.nymph.config.cache) {
|
|
990
1093
|
this.pushCache(guid, cdate, mdate, tags, data, sdata);
|
|
991
1094
|
}
|
|
992
|
-
// @ts-ignore: ts doesn't know the return type here.
|
|
993
|
-
entities.push(entity);
|
|
994
1095
|
}
|
|
995
1096
|
}
|
|
996
1097
|
|
|
@@ -1128,36 +1229,30 @@ export default abstract class NymphDriver {
|
|
|
1128
1229
|
* Pull an entity from the cache.
|
|
1129
1230
|
*
|
|
1130
1231
|
* @param guid The entity's GUID.
|
|
1131
|
-
* @
|
|
1132
|
-
* @param useSkipAc Whether to tell the entity to use skip_ac.
|
|
1133
|
-
* @returns The entity or null if it's not cached.
|
|
1232
|
+
* @returns The entity's data or null if it's not cached.
|
|
1134
1233
|
*/
|
|
1135
|
-
protected pullCache
|
|
1136
|
-
guid: string
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1234
|
+
protected pullCache(guid: string): {
|
|
1235
|
+
guid: string;
|
|
1236
|
+
cdate: number;
|
|
1237
|
+
mdate: number;
|
|
1238
|
+
tags: string[];
|
|
1239
|
+
data: EntityData;
|
|
1240
|
+
sdata: SerializedEntityData;
|
|
1241
|
+
} | null {
|
|
1140
1242
|
// Increment the entity access count.
|
|
1141
1243
|
if (!(guid in this.entityCount)) {
|
|
1142
1244
|
this.entityCount[guid] = 0;
|
|
1143
1245
|
}
|
|
1144
1246
|
this.entityCount[guid]++;
|
|
1145
1247
|
if (guid in this.entityCache) {
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
entity.$putData(
|
|
1155
|
-
this.entityCache[guid]['data'],
|
|
1156
|
-
this.entityCache[guid]['sdata'],
|
|
1157
|
-
'server',
|
|
1158
|
-
);
|
|
1159
|
-
return entity;
|
|
1160
|
-
}
|
|
1248
|
+
return {
|
|
1249
|
+
guid,
|
|
1250
|
+
cdate: this.entityCache[guid]['cdate'],
|
|
1251
|
+
mdate: this.entityCache[guid]['mdate'],
|
|
1252
|
+
tags: this.entityCache[guid]['tags'],
|
|
1253
|
+
data: this.entityCache[guid]['data'],
|
|
1254
|
+
sdata: this.entityCache[guid]['sdata'],
|
|
1255
|
+
};
|
|
1161
1256
|
}
|
|
1162
1257
|
return null;
|
|
1163
1258
|
}
|
|
@@ -1194,11 +1289,11 @@ export default abstract class NymphDriver {
|
|
|
1194
1289
|
}
|
|
1195
1290
|
// Cache the entity.
|
|
1196
1291
|
this.entityCache[guid] = {
|
|
1197
|
-
cdate
|
|
1198
|
-
mdate
|
|
1199
|
-
tags
|
|
1200
|
-
data
|
|
1201
|
-
sdata
|
|
1292
|
+
cdate,
|
|
1293
|
+
mdate,
|
|
1294
|
+
tags,
|
|
1295
|
+
data,
|
|
1296
|
+
sdata,
|
|
1202
1297
|
};
|
|
1203
1298
|
while (
|
|
1204
1299
|
this.nymph.config.cacheLimit &&
|
|
@@ -1530,6 +1530,61 @@ export function EntitiesTest(
|
|
|
1530
1530
|
expect(resultGuid.indexOf(testEntity.guid ?? '')).toBeGreaterThan(-1);
|
|
1531
1531
|
});
|
|
1532
1532
|
|
|
1533
|
+
it('object return', async () => {
|
|
1534
|
+
await createTestEntities();
|
|
1535
|
+
|
|
1536
|
+
// Testing object return using logic operations...
|
|
1537
|
+
const resultObjects = await nymph.getEntities(
|
|
1538
|
+
{ class: TestModel, return: 'object' },
|
|
1539
|
+
{
|
|
1540
|
+
type: '&',
|
|
1541
|
+
'!ref': [
|
|
1542
|
+
['refArray', guid()],
|
|
1543
|
+
['refArray', guid()],
|
|
1544
|
+
],
|
|
1545
|
+
'!lte': ['number', 29.99],
|
|
1546
|
+
},
|
|
1547
|
+
{
|
|
1548
|
+
type: '|',
|
|
1549
|
+
'!lte': [
|
|
1550
|
+
['number', 29.99],
|
|
1551
|
+
['number', 30],
|
|
1552
|
+
],
|
|
1553
|
+
},
|
|
1554
|
+
{
|
|
1555
|
+
type: '!&',
|
|
1556
|
+
'!equal': ['string', 'test'],
|
|
1557
|
+
'!contain': [
|
|
1558
|
+
['array', 'full'],
|
|
1559
|
+
['array', 'of'],
|
|
1560
|
+
['array', 'values'],
|
|
1561
|
+
['array', 500],
|
|
1562
|
+
['array', { test: true }],
|
|
1563
|
+
['array', { nullbyte: '\\\x00\u0000 \x00' }],
|
|
1564
|
+
],
|
|
1565
|
+
},
|
|
1566
|
+
{
|
|
1567
|
+
type: '!|',
|
|
1568
|
+
'!equal': ['string', 'test'],
|
|
1569
|
+
contain: [
|
|
1570
|
+
['array', 'full'],
|
|
1571
|
+
['array', 'of'],
|
|
1572
|
+
['array', 'values'],
|
|
1573
|
+
['array', 500],
|
|
1574
|
+
],
|
|
1575
|
+
},
|
|
1576
|
+
);
|
|
1577
|
+
|
|
1578
|
+
const resultObject = resultObjects.find(
|
|
1579
|
+
(entity) => entity.guid === testEntity.guid,
|
|
1580
|
+
);
|
|
1581
|
+
|
|
1582
|
+
expect(resultObject).toBeInstanceOf(Object);
|
|
1583
|
+
expect(resultObject).not.toBeInstanceOf(TestModel);
|
|
1584
|
+
expect(Array.isArray(resultObject?.tags)).toBeTruthy();
|
|
1585
|
+
expect(resultObject?.string).toEqual('test');
|
|
1586
|
+
});
|
|
1587
|
+
|
|
1533
1588
|
it('deep selector', async () => {
|
|
1534
1589
|
await createTestEntities();
|
|
1535
1590
|
|
package/src/testMocks.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { guid } from '@nymphjs/guid';
|
|
2
2
|
|
|
3
3
|
import type Nymph from './Nymph.js';
|
|
4
|
-
import type { EntityInstanceType } from './Entity.js';
|
|
4
|
+
import type { EntityInstanceType, EntityObjectType } from './Entity.js';
|
|
5
5
|
import type {
|
|
6
6
|
EntityConstructor,
|
|
7
7
|
EntityInterface,
|
|
@@ -24,6 +24,10 @@ export class MockNymphDriver {
|
|
|
24
24
|
options: Options<T> & { return: 'guid' },
|
|
25
25
|
...selectors: Selector[]
|
|
26
26
|
): Promise<string | null>;
|
|
27
|
+
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
28
|
+
options: Options<T> & { return: 'object' },
|
|
29
|
+
...selectors: Selector[]
|
|
30
|
+
): Promise<EntityObjectType<T> | null>;
|
|
27
31
|
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
28
32
|
options: Options<T>,
|
|
29
33
|
...selectors: Selector[]
|
|
@@ -32,6 +36,10 @@ export class MockNymphDriver {
|
|
|
32
36
|
options: Options<T> & { return: 'guid' },
|
|
33
37
|
guid: string,
|
|
34
38
|
): Promise<string | null>;
|
|
39
|
+
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
40
|
+
options: Options<T> & { return: 'object' },
|
|
41
|
+
guid: string,
|
|
42
|
+
): Promise<EntityObjectType<T> | null>;
|
|
35
43
|
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
36
44
|
options: Options<T>,
|
|
37
45
|
guid: string,
|
|
@@ -39,7 +47,7 @@ export class MockNymphDriver {
|
|
|
39
47
|
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
40
48
|
options: Options<T> = {},
|
|
41
49
|
...selectors: Selector[] | string[]
|
|
42
|
-
): Promise<EntityInstanceType<T> | string | null> {
|
|
50
|
+
): Promise<EntityInstanceType<T> | EntityObjectType<T> | string | null> {
|
|
43
51
|
const guid =
|
|
44
52
|
typeof selectors[0] === 'string' ? selectors[0] : selectors[0].guid;
|
|
45
53
|
if (!options || !guid || typeof guid !== 'string' || !(guid in entities)) {
|
|
@@ -117,6 +125,10 @@ export class MockNymph {
|
|
|
117
125
|
options: Options<T> & { return: 'guid' },
|
|
118
126
|
...selectors: Selector[]
|
|
119
127
|
): Promise<string | null>;
|
|
128
|
+
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
129
|
+
options: Options<T> & { return: 'object' },
|
|
130
|
+
...selectors: Selector[]
|
|
131
|
+
): Promise<EntityObjectType<T> | null>;
|
|
120
132
|
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
121
133
|
options: Options<T>,
|
|
122
134
|
...selectors: Selector[]
|
|
@@ -125,6 +137,10 @@ export class MockNymph {
|
|
|
125
137
|
options: Options<T> & { return: 'guid' },
|
|
126
138
|
guid: string,
|
|
127
139
|
): Promise<string | null>;
|
|
140
|
+
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
141
|
+
options: Options<T> & { return: 'object' },
|
|
142
|
+
guid: string,
|
|
143
|
+
): Promise<EntityObjectType<T> | null>;
|
|
128
144
|
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
129
145
|
options: Options<T>,
|
|
130
146
|
guid: string,
|
|
@@ -132,7 +148,7 @@ export class MockNymph {
|
|
|
132
148
|
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
133
149
|
options: Options<T> = {},
|
|
134
150
|
...selectors: Selector[] | string[]
|
|
135
|
-
): Promise<EntityInstanceType<T> | string | null> {
|
|
151
|
+
): Promise<EntityInstanceType<T> | EntityObjectType<T> | string | null> {
|
|
136
152
|
// @ts-ignore: The selector type is correct here.
|
|
137
153
|
return await this.driver.getEntity(options, ...selectors);
|
|
138
154
|
}
|