@nymphjs/nymph 1.0.0-alpha.32 → 1.0.0-alpha.36
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 +19 -0
- package/dist/Entity.test.js +1 -1
- package/dist/Entity.test.js.map +1 -1
- package/dist/Nymph.d.ts +6 -0
- package/dist/Nymph.js +3 -0
- package/dist/Nymph.js.map +1 -1
- package/dist/Nymph.types.d.ts +2 -2
- package/dist/driver/NymphDriver.d.ts +33 -6
- package/dist/driver/NymphDriver.js +34 -10
- package/dist/driver/NymphDriver.js.map +1 -1
- package/dist/driver/testArtifacts.js +27 -0
- package/dist/driver/testArtifacts.js.map +1 -1
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +48 -1
- package/dist/utils.js.map +1 -1
- package/package.json +2 -2
- package/src/Entity.test.ts +1 -1
- package/src/Nymph.ts +17 -6
- package/src/Nymph.types.ts +2 -2
- package/src/driver/NymphDriver.ts +88 -13
- package/src/driver/testArtifacts.ts +49 -0
- package/src/utils.ts +59 -0
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
EntityConstructor,
|
|
10
10
|
EntityData,
|
|
11
11
|
EntityInterface,
|
|
12
|
+
EntityReference,
|
|
12
13
|
SerializedEntityData,
|
|
13
14
|
} from '../Entity.types';
|
|
14
15
|
import { InvalidParametersError, UnableToConnectError } from '../errors';
|
|
@@ -69,6 +70,10 @@ export default abstract class NymphDriver {
|
|
|
69
70
|
protected abstract exportEntities(
|
|
70
71
|
writeLine: (line: string) => void
|
|
71
72
|
): Promise<void>;
|
|
73
|
+
abstract getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
74
|
+
options: Options<T> & { return: 'count' },
|
|
75
|
+
...selectors: Selector[]
|
|
76
|
+
): Promise<number>;
|
|
72
77
|
abstract getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
73
78
|
options: Options<T> & { return: 'guid' },
|
|
74
79
|
...selectors: Selector[]
|
|
@@ -80,7 +85,13 @@ export default abstract class NymphDriver {
|
|
|
80
85
|
abstract getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
81
86
|
options?: Options<T>,
|
|
82
87
|
...selectors: Selector[]
|
|
83
|
-
): Promise<ReturnType<T['factorySync']>[] | string[]>;
|
|
88
|
+
): Promise<ReturnType<T['factorySync']>[] | string[] | number>;
|
|
89
|
+
protected abstract getEntitiesSync<
|
|
90
|
+
T extends EntityConstructor = EntityConstructor
|
|
91
|
+
>(
|
|
92
|
+
options: Options<T> & { return: 'count' },
|
|
93
|
+
...selectors: Selector[]
|
|
94
|
+
): number;
|
|
84
95
|
protected abstract getEntitiesSync<
|
|
85
96
|
T extends EntityConstructor = EntityConstructor
|
|
86
97
|
>(
|
|
@@ -98,7 +109,7 @@ export default abstract class NymphDriver {
|
|
|
98
109
|
>(
|
|
99
110
|
options?: Options<T>,
|
|
100
111
|
...selectors: Selector[]
|
|
101
|
-
): ReturnType<T['factorySync']>[] | string[];
|
|
112
|
+
): ReturnType<T['factorySync']>[] | string[] | number;
|
|
102
113
|
abstract getUID(name: string): Promise<number | null>;
|
|
103
114
|
abstract import(filename: string): Promise<boolean>;
|
|
104
115
|
abstract newUID(name: string): Promise<number | null>;
|
|
@@ -516,16 +527,26 @@ export default abstract class NymphDriver {
|
|
|
516
527
|
*/
|
|
517
528
|
protected entityReferenceSearch(
|
|
518
529
|
value: any,
|
|
519
|
-
entity:
|
|
530
|
+
entity:
|
|
531
|
+
| EntityInterface
|
|
532
|
+
| EntityReference
|
|
533
|
+
| string
|
|
534
|
+
| (EntityInterface | EntityReference | string)[]
|
|
520
535
|
) {
|
|
521
536
|
// Get the GUID, if the passed $entity is an object.
|
|
522
537
|
const guids: string[] = [];
|
|
523
538
|
if (Array.isArray(entity)) {
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
539
|
+
if (entity[0] === 'nymph_entity_reference') {
|
|
540
|
+
guids.push(value[1]);
|
|
541
|
+
} else {
|
|
542
|
+
for (const curEntity of entity) {
|
|
543
|
+
if (typeof curEntity === 'string') {
|
|
544
|
+
guids.push(curEntity);
|
|
545
|
+
} else if (Array.isArray(curEntity)) {
|
|
546
|
+
guids.push(curEntity[1]);
|
|
547
|
+
} else if (typeof curEntity.guid === 'string') {
|
|
548
|
+
guids.push(curEntity.guid);
|
|
549
|
+
}
|
|
529
550
|
}
|
|
530
551
|
}
|
|
531
552
|
} else if (typeof entity === 'string') {
|
|
@@ -684,6 +705,10 @@ export default abstract class NymphDriver {
|
|
|
684
705
|
* @param selectors Unlimited optional selectors to search for, or a single GUID. If none are given, all entities are searched for the given options.
|
|
685
706
|
* @returns An entity, or null on failure or nothing found.
|
|
686
707
|
*/
|
|
708
|
+
public getEntitySync<T extends EntityConstructor = EntityConstructor>(
|
|
709
|
+
options: Options<T> & { return: 'count' },
|
|
710
|
+
...selectors: Selector[]
|
|
711
|
+
): number;
|
|
687
712
|
public getEntitySync<T extends EntityConstructor = EntityConstructor>(
|
|
688
713
|
options: Options<T> & { return: 'guid' },
|
|
689
714
|
...selectors: Selector[]
|
|
@@ -692,6 +717,10 @@ export default abstract class NymphDriver {
|
|
|
692
717
|
options: Options<T>,
|
|
693
718
|
...selectors: Selector[]
|
|
694
719
|
): ReturnType<T['factorySync']> | null;
|
|
720
|
+
public getEntitySync<T extends EntityConstructor = EntityConstructor>(
|
|
721
|
+
options: Options<T> & { return: 'count' },
|
|
722
|
+
guid: string
|
|
723
|
+
): number;
|
|
695
724
|
public getEntitySync<T extends EntityConstructor = EntityConstructor>(
|
|
696
725
|
options: Options<T> & { return: 'guid' },
|
|
697
726
|
guid: string
|
|
@@ -703,7 +732,7 @@ export default abstract class NymphDriver {
|
|
|
703
732
|
public getEntitySync<T extends EntityConstructor = EntityConstructor>(
|
|
704
733
|
options: Options<T> = {},
|
|
705
734
|
...selectors: Selector[] | string[]
|
|
706
|
-
): ReturnType<T['factorySync']> | string | null {
|
|
735
|
+
): ReturnType<T['factorySync']> | string | number | null {
|
|
707
736
|
// Set up options and selectors.
|
|
708
737
|
if (typeof selectors[0] === 'string') {
|
|
709
738
|
selectors = [{ type: '&', guid: selectors[0] }];
|
|
@@ -713,12 +742,39 @@ export default abstract class NymphDriver {
|
|
|
713
742
|
options,
|
|
714
743
|
...(selectors as Selector[])
|
|
715
744
|
);
|
|
745
|
+
if (options.return === 'count') {
|
|
746
|
+
return entities as unknown as number;
|
|
747
|
+
}
|
|
716
748
|
if (!entities || !entities.length) {
|
|
717
749
|
return null;
|
|
718
750
|
}
|
|
719
751
|
return entities[0];
|
|
720
752
|
}
|
|
721
753
|
|
|
754
|
+
protected getEntitesRowLike<T extends EntityConstructor = EntityConstructor>(
|
|
755
|
+
options: Options<T> & { return: 'count' },
|
|
756
|
+
selectors: Selector[],
|
|
757
|
+
performQueryCallback: (
|
|
758
|
+
options: Options<T>,
|
|
759
|
+
formattedSelectors: FormattedSelector[],
|
|
760
|
+
etype: string
|
|
761
|
+
) => {
|
|
762
|
+
result: any;
|
|
763
|
+
},
|
|
764
|
+
rowFetchCallback: () => any,
|
|
765
|
+
freeResultCallback: () => void,
|
|
766
|
+
getCountCallback: (row: any) => number,
|
|
767
|
+
getGUIDCallback: (row: any) => string,
|
|
768
|
+
getTagsAndDatesCallback: (row: any) => {
|
|
769
|
+
tags: string[];
|
|
770
|
+
cdate: number;
|
|
771
|
+
mdate: number;
|
|
772
|
+
},
|
|
773
|
+
getDataNameAndSValueCallback: (row: any) => {
|
|
774
|
+
name: string;
|
|
775
|
+
svalue: string;
|
|
776
|
+
}
|
|
777
|
+
): { result: any; process: () => number };
|
|
722
778
|
protected getEntitesRowLike<T extends EntityConstructor = EntityConstructor>(
|
|
723
779
|
options: Options<T> & { return: 'guid' },
|
|
724
780
|
selectors: Selector[],
|
|
@@ -731,6 +787,7 @@ export default abstract class NymphDriver {
|
|
|
731
787
|
},
|
|
732
788
|
rowFetchCallback: () => any,
|
|
733
789
|
freeResultCallback: () => void,
|
|
790
|
+
getCountCallback: (row: any) => number,
|
|
734
791
|
getGUIDCallback: (row: any) => string,
|
|
735
792
|
getTagsAndDatesCallback: (row: any) => {
|
|
736
793
|
tags: string[];
|
|
@@ -754,6 +811,7 @@ export default abstract class NymphDriver {
|
|
|
754
811
|
},
|
|
755
812
|
rowFetchCallback: () => any,
|
|
756
813
|
freeResultCallback: () => void,
|
|
814
|
+
getCountCallback: (row: any) => number,
|
|
757
815
|
getGUIDCallback: (row: any) => string,
|
|
758
816
|
getTagsAndDatesCallback: (row: any) => {
|
|
759
817
|
tags: string[];
|
|
@@ -777,6 +835,7 @@ export default abstract class NymphDriver {
|
|
|
777
835
|
},
|
|
778
836
|
rowFetchCallback: () => any,
|
|
779
837
|
freeResultCallback: () => void,
|
|
838
|
+
getCountCallback: (row: any) => number,
|
|
780
839
|
getGUIDCallback: (row: any) => string,
|
|
781
840
|
getTagsAndDatesCallback: (row: any) => {
|
|
782
841
|
tags: string[];
|
|
@@ -787,7 +846,10 @@ export default abstract class NymphDriver {
|
|
|
787
846
|
name: string;
|
|
788
847
|
svalue: string;
|
|
789
848
|
}
|
|
790
|
-
): {
|
|
849
|
+
): {
|
|
850
|
+
result: any;
|
|
851
|
+
process: () => ReturnType<T['factorySync']>[] | string[] | number;
|
|
852
|
+
} {
|
|
791
853
|
if (!this.isConnected()) {
|
|
792
854
|
throw new UnableToConnectError('not connected to DB');
|
|
793
855
|
}
|
|
@@ -805,6 +867,7 @@ export default abstract class NymphDriver {
|
|
|
805
867
|
}
|
|
806
868
|
|
|
807
869
|
let entities: ReturnType<T['factorySync']>[] | string[] = [];
|
|
870
|
+
let count = 0;
|
|
808
871
|
const EntityClass =
|
|
809
872
|
options.class ?? (this.nymph.getEntityClass('Entity') as T);
|
|
810
873
|
const etype = EntityClass.ETYPE;
|
|
@@ -842,7 +905,14 @@ export default abstract class NymphDriver {
|
|
|
842
905
|
const guid = entity.guid;
|
|
843
906
|
return {
|
|
844
907
|
result: Promise.resolve(null),
|
|
845
|
-
process: () =>
|
|
908
|
+
process: () =>
|
|
909
|
+
options.return === 'count'
|
|
910
|
+
? guid
|
|
911
|
+
? 1
|
|
912
|
+
: 0
|
|
913
|
+
: options.return === 'guid'
|
|
914
|
+
? [guid]
|
|
915
|
+
: [entity],
|
|
846
916
|
};
|
|
847
917
|
}
|
|
848
918
|
}
|
|
@@ -856,7 +926,12 @@ export default abstract class NymphDriver {
|
|
|
856
926
|
result,
|
|
857
927
|
process: () => {
|
|
858
928
|
let row = rowFetchCallback();
|
|
859
|
-
if (options.return === '
|
|
929
|
+
if (options.return === 'count') {
|
|
930
|
+
while (row != null) {
|
|
931
|
+
count += getCountCallback(row);
|
|
932
|
+
row = rowFetchCallback();
|
|
933
|
+
}
|
|
934
|
+
} else if (options.return === 'guid') {
|
|
860
935
|
while (row != null) {
|
|
861
936
|
(entities as string[]).push(getGUIDCallback(row));
|
|
862
937
|
row = rowFetchCallback();
|
|
@@ -912,7 +987,7 @@ export default abstract class NymphDriver {
|
|
|
912
987
|
|
|
913
988
|
freeResultCallback();
|
|
914
989
|
|
|
915
|
-
return entities;
|
|
990
|
+
return options.return === 'count' ? count : entities;
|
|
916
991
|
},
|
|
917
992
|
};
|
|
918
993
|
}
|
|
@@ -1319,6 +1319,55 @@ This one's zip code is 92064.`;
|
|
|
1319
1319
|
expect(testEntity.$inArray(resultEntity)).toEqual(true);
|
|
1320
1320
|
});
|
|
1321
1321
|
|
|
1322
|
+
it('count return', async () => {
|
|
1323
|
+
await createTestEntities();
|
|
1324
|
+
|
|
1325
|
+
const result = await nymph.getEntities({ class: TestModel });
|
|
1326
|
+
|
|
1327
|
+
// Testing count return...
|
|
1328
|
+
const resultCount = await nymph.getEntities({
|
|
1329
|
+
class: TestModel,
|
|
1330
|
+
return: 'count',
|
|
1331
|
+
});
|
|
1332
|
+
expect(resultCount).toBeGreaterThanOrEqual(1);
|
|
1333
|
+
expect(resultCount).toEqual(result.length);
|
|
1334
|
+
|
|
1335
|
+
const resultSelectors = await nymph.getEntities(
|
|
1336
|
+
{ class: TestModel },
|
|
1337
|
+
{ type: '&', ref: ['reference', refGuid] }
|
|
1338
|
+
);
|
|
1339
|
+
|
|
1340
|
+
// Testing count return with selectors...
|
|
1341
|
+
const resultSelectorsCount = await nymph.getEntities(
|
|
1342
|
+
{ class: TestModel, return: 'count' },
|
|
1343
|
+
{ type: '&', ref: ['reference', refGuid] }
|
|
1344
|
+
);
|
|
1345
|
+
expect(resultSelectorsCount).toBeGreaterThanOrEqual(1);
|
|
1346
|
+
expect(resultSelectorsCount).toEqual(resultSelectors.length);
|
|
1347
|
+
|
|
1348
|
+
// Testing count return with limit...
|
|
1349
|
+
const resultSelectorsLimit = await nymph.getEntities({
|
|
1350
|
+
class: TestModel,
|
|
1351
|
+
limit: 1,
|
|
1352
|
+
return: 'count',
|
|
1353
|
+
});
|
|
1354
|
+
expect(resultSelectorsLimit).toEqual(1);
|
|
1355
|
+
|
|
1356
|
+
// Testing count return with limit...
|
|
1357
|
+
const resultSelectorsSingle = await nymph.getEntity({
|
|
1358
|
+
class: TestModel,
|
|
1359
|
+
return: 'count',
|
|
1360
|
+
});
|
|
1361
|
+
expect(resultSelectorsSingle).toEqual(1);
|
|
1362
|
+
|
|
1363
|
+
// Testing empty count...
|
|
1364
|
+
const resultSelectorsEmpty = await nymph.getEntities(
|
|
1365
|
+
{ class: TestModel, return: 'count' },
|
|
1366
|
+
{ type: '&', ref: ['reference', newGUID()] }
|
|
1367
|
+
);
|
|
1368
|
+
expect(resultSelectorsEmpty).toEqual(0);
|
|
1369
|
+
});
|
|
1370
|
+
|
|
1322
1371
|
it('guid return', async () => {
|
|
1323
1372
|
await createTestEntities();
|
|
1324
1373
|
|
package/src/utils.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Entity from './Entity';
|
|
2
2
|
import { EntityReference } from './Entity.types';
|
|
3
3
|
import Nymph from './Nymph';
|
|
4
|
+
import { Options, Selector } from './Nymph.types';
|
|
4
5
|
|
|
5
6
|
export function xor(a: any, b: any): boolean {
|
|
6
7
|
return !!(a && !b) || (!a && b);
|
|
@@ -14,6 +15,64 @@ export function uniqueStrings(array: string[]) {
|
|
|
14
15
|
return Object.keys(obj);
|
|
15
16
|
}
|
|
16
17
|
|
|
18
|
+
export function classNamesToEntityConstructors(
|
|
19
|
+
nymph: Nymph,
|
|
20
|
+
selectors: Selector[]
|
|
21
|
+
): Selector[] {
|
|
22
|
+
const newSelectors: Selector[] = [];
|
|
23
|
+
|
|
24
|
+
for (const curSelector of selectors) {
|
|
25
|
+
const newSelector: Selector = { type: curSelector.type };
|
|
26
|
+
|
|
27
|
+
for (const k in curSelector) {
|
|
28
|
+
const key = k as keyof Selector;
|
|
29
|
+
const value = curSelector[key];
|
|
30
|
+
|
|
31
|
+
if (key === 'type') {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (value === undefined) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (key === 'qref' || key === '!qref') {
|
|
40
|
+
const tmpArr = (
|
|
41
|
+
Array.isArray(((value as Selector['qref']) ?? [])[0])
|
|
42
|
+
? value
|
|
43
|
+
: [value]
|
|
44
|
+
) as [string, [Options, ...Selector[]]][];
|
|
45
|
+
for (let i = 0; i < tmpArr.length; i++) {
|
|
46
|
+
const name = tmpArr[i][0];
|
|
47
|
+
const [qrefOptions, ...selectors] = tmpArr[i][1];
|
|
48
|
+
const QrefEntityClass =
|
|
49
|
+
typeof qrefOptions.class === 'string'
|
|
50
|
+
? nymph.getEntityClass(qrefOptions.class)
|
|
51
|
+
: qrefOptions.class ?? nymph.getEntityClass('Entity');
|
|
52
|
+
const options = { ...qrefOptions, class: QrefEntityClass };
|
|
53
|
+
if (!newSelector[key]) {
|
|
54
|
+
newSelector[key] = [];
|
|
55
|
+
}
|
|
56
|
+
(newSelector[key] as [string, [Options, ...Selector[]]][]).push([
|
|
57
|
+
name,
|
|
58
|
+
[options, ...classNamesToEntityConstructors(nymph, selectors)],
|
|
59
|
+
]);
|
|
60
|
+
}
|
|
61
|
+
} else if (key === 'selector' || key === '!selector') {
|
|
62
|
+
const tmpArr = (Array.isArray(value) ? value : [value]) as Selector[];
|
|
63
|
+
newSelector[key] = classNamesToEntityConstructors(nymph, tmpArr);
|
|
64
|
+
} else {
|
|
65
|
+
// @ts-ignore: ts doesn't know what value is here.
|
|
66
|
+
newSelector[key] = value;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
newSelectors.push(newSelector);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return newSelectors;
|
|
74
|
+
}
|
|
75
|
+
|
|
17
76
|
export function entitiesToReferences(item: any): any {
|
|
18
77
|
if (item instanceof Entity && typeof item.$toReference === 'function') {
|
|
19
78
|
// Convert entities to references.
|