@karmaniverous/entity-manager 6.4.2 → 6.4.4
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/README.md +1 -1
- package/dist/cjs/EntityManager.js +3 -1
- package/dist/cjs/addKeys.js +12 -0
- package/dist/cjs/decodeEntityElement.js +12 -0
- package/dist/cjs/decodeGeneratedProperty.js +7 -0
- package/dist/cjs/dehydrateIndexItem.js +13 -0
- package/dist/cjs/dehydratePageKeyMap.js +14 -0
- package/dist/cjs/encodeEntityElement.js +8 -0
- package/dist/cjs/encodeGeneratedProperty.js +12 -0
- package/dist/cjs/getHashKeySpace.js +12 -0
- package/dist/cjs/index.js +0 -2
- package/dist/cjs/query.js +26 -0
- package/dist/cjs/rehydrateIndexItem.js +14 -0
- package/dist/cjs/rehydratePageKeyMap.js +12 -0
- package/dist/cjs/removeKeys.js +7 -0
- package/dist/cjs/unwrapIndex.js +2 -0
- package/dist/cjs/updateItemHashKey.js +17 -0
- package/dist/cjs/updateItemRangeKey.js +17 -0
- package/dist/index.d.ts +19 -80
- package/dist/mjs/EntityManager.js +3 -1
- package/dist/mjs/addKeys.js +12 -0
- package/dist/mjs/decodeEntityElement.js +12 -0
- package/dist/mjs/decodeGeneratedProperty.js +7 -0
- package/dist/mjs/dehydrateIndexItem.js +13 -0
- package/dist/mjs/dehydratePageKeyMap.js +14 -0
- package/dist/mjs/encodeEntityElement.js +8 -0
- package/dist/mjs/encodeGeneratedProperty.js +12 -0
- package/dist/mjs/getHashKeySpace.js +12 -0
- package/dist/mjs/index.js +0 -1
- package/dist/mjs/query.js +26 -0
- package/dist/mjs/rehydrateIndexItem.js +14 -0
- package/dist/mjs/rehydratePageKeyMap.js +12 -0
- package/dist/mjs/removeKeys.js +7 -0
- package/dist/mjs/unwrapIndex.js +2 -0
- package/dist/mjs/updateItemHashKey.js +17 -0
- package/dist/mjs/updateItemRangeKey.js +17 -0
- package/package.json +14 -14
- package/dist/cjs/EntityManagerClient.js +0 -90
- package/dist/mjs/EntityManagerClient.js +0 -88
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
**EntityManager implements rational indexing & cross-shard querying at scale in your NoSQL database so you can focus on your application logic.**
|
|
10
10
|
|
|
11
|
-
I've just released a full Typescript refactor. Everything works
|
|
11
|
+
I've just released a full Typescript refactor. Everything works beautifully, but I'm still fleshing out [the documentation](https://karmanivero.us/projects/entity-manager/intro/).
|
|
12
12
|
|
|
13
13
|
If you have any questions, please [start a discussion](https://github.com/karmaniverous/entity-manager/discussions). Otherwise stay tuned!
|
|
14
14
|
|
|
@@ -18,10 +18,12 @@ class EntityManager {
|
|
|
18
18
|
* Create an EntityManager instance.
|
|
19
19
|
*
|
|
20
20
|
* @param config - EntityManager {@link Config | `Config`} object.
|
|
21
|
+
* @param logger - Logger object (defaults to `console`, must support `debug` & `error` methods).
|
|
21
22
|
*/
|
|
22
|
-
constructor(config) {
|
|
23
|
+
constructor(config, logger = console) {
|
|
23
24
|
_EntityManager_config.set(this, void 0);
|
|
24
25
|
tslib.__classPrivateFieldSet(this, _EntityManager_config, ParsedConfig.configSchema.parse(config), "f");
|
|
26
|
+
this.logger = logger;
|
|
25
27
|
}
|
|
26
28
|
/**
|
|
27
29
|
* Get the current EntityManager {@link Config | `Config`} object.
|
package/dist/cjs/addKeys.js
CHANGED
|
@@ -37,9 +37,21 @@ function addKeys(entityManager, item, entityToken, overwrite = false) {
|
|
|
37
37
|
delete newItem[property];
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
+
entityManager.logger.debug('updated entity item generated properties', {
|
|
41
|
+
item,
|
|
42
|
+
entityToken,
|
|
43
|
+
overwrite,
|
|
44
|
+
newItem,
|
|
45
|
+
});
|
|
40
46
|
return newItem;
|
|
41
47
|
}
|
|
42
48
|
catch (error) {
|
|
49
|
+
if (error instanceof Error)
|
|
50
|
+
entityManager.logger.error(error.message, {
|
|
51
|
+
item,
|
|
52
|
+
entityToken,
|
|
53
|
+
overwrite,
|
|
54
|
+
});
|
|
43
55
|
throw error;
|
|
44
56
|
}
|
|
45
57
|
}
|
|
@@ -27,9 +27,21 @@ function decodeEntityElement(entityManager, value, entityToken, element) {
|
|
|
27
27
|
if ([hashKey, rangeKey].includes(element))
|
|
28
28
|
return value;
|
|
29
29
|
const decoded = transcodes[entities[entityToken].elementTranscodes[element]].decode(value);
|
|
30
|
+
entityManager.logger.debug('decoded entity element', {
|
|
31
|
+
value,
|
|
32
|
+
entityToken,
|
|
33
|
+
element,
|
|
34
|
+
decoded,
|
|
35
|
+
});
|
|
30
36
|
return decoded;
|
|
31
37
|
}
|
|
32
38
|
catch (error) {
|
|
39
|
+
if (error instanceof Error)
|
|
40
|
+
entityManager.logger.error(error.message, {
|
|
41
|
+
value,
|
|
42
|
+
entityToken,
|
|
43
|
+
element,
|
|
44
|
+
});
|
|
33
45
|
throw error;
|
|
34
46
|
}
|
|
35
47
|
}
|
|
@@ -38,9 +38,16 @@ function decodeGeneratedProperty(entityManager, encoded, entityToken) {
|
|
|
38
38
|
});
|
|
39
39
|
// Assign decoded properties.
|
|
40
40
|
Object.assign(decoded, radash.objectify(values, ([key]) => key, ([key, value]) => decodeEntityElement.decodeEntityElement(entityManager, value, entityToken, key)));
|
|
41
|
+
entityManager.logger.debug('decoded generated property', {
|
|
42
|
+
encoded,
|
|
43
|
+
entityToken,
|
|
44
|
+
decoded,
|
|
45
|
+
});
|
|
41
46
|
return decoded;
|
|
42
47
|
}
|
|
43
48
|
catch (error) {
|
|
49
|
+
if (error instanceof Error)
|
|
50
|
+
entityManager.logger.error(error.message, { encoded, entityToken });
|
|
44
51
|
throw error;
|
|
45
52
|
}
|
|
46
53
|
}
|
|
@@ -42,9 +42,22 @@ function dehydrateIndexItem(entityManager, item, entityToken, indexToken, omit =
|
|
|
42
42
|
const dehydrated = elements
|
|
43
43
|
.map((element) => encodeEntityElement.encodeEntityElement(entityManager, item, entityToken, element))
|
|
44
44
|
.join(generatedKeyDelimiter);
|
|
45
|
+
entityManager.logger.debug('dehydrated index', {
|
|
46
|
+
item,
|
|
47
|
+
entityToken,
|
|
48
|
+
indexToken,
|
|
49
|
+
elements,
|
|
50
|
+
dehydrated,
|
|
51
|
+
});
|
|
45
52
|
return dehydrated;
|
|
46
53
|
}
|
|
47
54
|
catch (error) {
|
|
55
|
+
if (error instanceof Error)
|
|
56
|
+
entityManager.logger.error(error.message, {
|
|
57
|
+
item,
|
|
58
|
+
entityToken,
|
|
59
|
+
indexToken,
|
|
60
|
+
});
|
|
48
61
|
throw error;
|
|
49
62
|
}
|
|
50
63
|
}
|
|
@@ -31,6 +31,11 @@ function dehydratePageKeyMap(entityManager, pageKeyMap, entityToken) {
|
|
|
31
31
|
// Shortcut empty pageKeyMap.
|
|
32
32
|
if (!Object.keys(pageKeyMap).length) {
|
|
33
33
|
const dehydrated = [];
|
|
34
|
+
entityManager.logger.debug('dehydrated empty page key map', {
|
|
35
|
+
pageKeyMap,
|
|
36
|
+
entityToken,
|
|
37
|
+
dehydrated,
|
|
38
|
+
});
|
|
34
39
|
return dehydrated;
|
|
35
40
|
}
|
|
36
41
|
// Extract, sort & validate indexs.
|
|
@@ -65,9 +70,18 @@ function dehydratePageKeyMap(entityManager, pageKeyMap, entityToken) {
|
|
|
65
70
|
// Replace with empty array if all pageKeys are empty strings.
|
|
66
71
|
if (dehydrated.every((pageKey) => pageKey === ''))
|
|
67
72
|
dehydrated = [];
|
|
73
|
+
entityManager.logger.debug('dehydrated page key map', {
|
|
74
|
+
pageKeyMap,
|
|
75
|
+
entityToken,
|
|
76
|
+
indexes,
|
|
77
|
+
hashKeys,
|
|
78
|
+
dehydrated,
|
|
79
|
+
});
|
|
68
80
|
return dehydrated;
|
|
69
81
|
}
|
|
70
82
|
catch (error) {
|
|
83
|
+
if (error instanceof Error)
|
|
84
|
+
entityManager.logger.error(error.message, { entityToken, pageKeyMap });
|
|
71
85
|
throw error;
|
|
72
86
|
}
|
|
73
87
|
}
|
|
@@ -26,9 +26,17 @@ function encodeEntityElement(entityManager, item, entityToken, element) {
|
|
|
26
26
|
if (value === undefined || [hashKey, rangeKey].includes(element))
|
|
27
27
|
return value;
|
|
28
28
|
const encoded = transcodes[entities[entityToken].elementTranscodes[element]].encode(item[element]) || undefined;
|
|
29
|
+
entityManager.logger.debug('encoded entity element', {
|
|
30
|
+
item,
|
|
31
|
+
entityToken,
|
|
32
|
+
element,
|
|
33
|
+
encoded,
|
|
34
|
+
});
|
|
29
35
|
return encoded;
|
|
30
36
|
}
|
|
31
37
|
catch (error) {
|
|
38
|
+
if (error instanceof Error)
|
|
39
|
+
entityManager.logger.error(error.message, { item, entityToken, element });
|
|
32
40
|
throw error;
|
|
33
41
|
}
|
|
34
42
|
}
|
|
@@ -34,9 +34,21 @@ function encodeGeneratedProperty(entityManager, item, entityToken, property) {
|
|
|
34
34
|
...(sharded ? [item[entityManager.config.hashKey]] : []),
|
|
35
35
|
...elementMap.map(([element, value]) => [element, (value ?? '').toString()].join(entityManager.config.generatedValueDelimiter)),
|
|
36
36
|
].join(entityManager.config.generatedKeyDelimiter);
|
|
37
|
+
entityManager.logger.debug('encoded generated property', {
|
|
38
|
+
item,
|
|
39
|
+
entityToken,
|
|
40
|
+
property,
|
|
41
|
+
encoded,
|
|
42
|
+
});
|
|
37
43
|
return encoded;
|
|
38
44
|
}
|
|
39
45
|
catch (error) {
|
|
46
|
+
if (error instanceof Error)
|
|
47
|
+
entityManager.logger.error(error.message, {
|
|
48
|
+
item,
|
|
49
|
+
entityToken,
|
|
50
|
+
property,
|
|
51
|
+
});
|
|
40
52
|
throw error;
|
|
41
53
|
}
|
|
42
54
|
}
|
|
@@ -31,9 +31,21 @@ function getHashKeySpace(entityManager, entityToken, timestampFrom = 0, timestam
|
|
|
31
31
|
: '';
|
|
32
32
|
})
|
|
33
33
|
.map((shardKey) => `${entityToken}${entityManager.config.shardKeyDelimiter}${shardKey}`);
|
|
34
|
+
entityManager.logger.debug('generated hash key space', {
|
|
35
|
+
entityToken,
|
|
36
|
+
timestampFrom,
|
|
37
|
+
timestampTo,
|
|
38
|
+
hashKeySpace,
|
|
39
|
+
});
|
|
34
40
|
return hashKeySpace;
|
|
35
41
|
}
|
|
36
42
|
catch (error) {
|
|
43
|
+
if (error instanceof Error)
|
|
44
|
+
entityManager.logger.error(error.message, {
|
|
45
|
+
entityToken,
|
|
46
|
+
timestampFrom,
|
|
47
|
+
timestampTo,
|
|
48
|
+
});
|
|
37
49
|
throw error;
|
|
38
50
|
}
|
|
39
51
|
}
|
package/dist/cjs/index.js
CHANGED
|
@@ -2,12 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
var conditionalize = require('./conditionalize.js');
|
|
4
4
|
var EntityManager = require('./EntityManager.js');
|
|
5
|
-
var EntityManagerClient = require('./EntityManagerClient.js');
|
|
6
5
|
var ShardQueryMapBuilder = require('./ShardQueryMapBuilder.js');
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
|
|
10
9
|
exports.conditionalize = conditionalize.conditionalize;
|
|
11
10
|
exports.EntityManager = EntityManager.EntityManager;
|
|
12
|
-
exports.EntityManagerClient = EntityManagerClient.EntityManagerClient;
|
|
13
11
|
exports.ShardQueryMapBuilder = ShardQueryMapBuilder.ShardQueryMapBuilder;
|
package/dist/cjs/query.js
CHANGED
|
@@ -92,9 +92,35 @@ async function query(entityManager, { entityToken, hashKey, limit, pageKeyMap, p
|
|
|
92
92
|
items: workingResult.items,
|
|
93
93
|
pageKeyMap: compressToEncodedURIComponent(JSON.stringify(dehydratePageKeyMap.dehydratePageKeyMap(entityManager, workingResult.pageKeyMap, entityToken))),
|
|
94
94
|
};
|
|
95
|
+
entityManager.logger.debug('queried entityToken across shards', {
|
|
96
|
+
entityToken,
|
|
97
|
+
hashKey,
|
|
98
|
+
limit,
|
|
99
|
+
pageKeyMap,
|
|
100
|
+
pageSize,
|
|
101
|
+
shardQueryMap,
|
|
102
|
+
timestampFrom,
|
|
103
|
+
timestampTo,
|
|
104
|
+
throttle,
|
|
105
|
+
rehydratedPageKeyMap,
|
|
106
|
+
workingResult,
|
|
107
|
+
result,
|
|
108
|
+
});
|
|
95
109
|
return result;
|
|
96
110
|
}
|
|
97
111
|
catch (error) {
|
|
112
|
+
if (error instanceof Error)
|
|
113
|
+
entityManager.logger.error(error.message, {
|
|
114
|
+
entityToken,
|
|
115
|
+
hashKey,
|
|
116
|
+
limit,
|
|
117
|
+
pageKeyMap,
|
|
118
|
+
pageSize,
|
|
119
|
+
shardQueryMap,
|
|
120
|
+
timestampFrom,
|
|
121
|
+
timestampTo,
|
|
122
|
+
throttle,
|
|
123
|
+
});
|
|
98
124
|
throw error;
|
|
99
125
|
}
|
|
100
126
|
}
|
|
@@ -37,9 +37,23 @@ function rehydrateIndexItem(entityManager, dehydrated, entityToken, indexToken,
|
|
|
37
37
|
throw new Error('index rehydration key-value mismatch');
|
|
38
38
|
// Assign values to elements.
|
|
39
39
|
const rehydrated = radash.shake(radash.zipToObject(elements, values.map((value, i) => decodeEntityElement.decodeEntityElement(entityManager, value, entityToken, elements[i]))));
|
|
40
|
+
entityManager.logger.debug('rehydrated index', {
|
|
41
|
+
dehydrated,
|
|
42
|
+
entityToken,
|
|
43
|
+
indexToken,
|
|
44
|
+
elements,
|
|
45
|
+
values,
|
|
46
|
+
rehydrated,
|
|
47
|
+
});
|
|
40
48
|
return rehydrated;
|
|
41
49
|
}
|
|
42
50
|
catch (error) {
|
|
51
|
+
if (error instanceof Error)
|
|
52
|
+
entityManager.logger.error(error.message, {
|
|
53
|
+
dehydrated,
|
|
54
|
+
entityToken,
|
|
55
|
+
indexToken,
|
|
56
|
+
});
|
|
43
57
|
throw error;
|
|
44
58
|
}
|
|
45
59
|
}
|
|
@@ -55,9 +55,21 @@ function rehydratePageKeyMap(entityManager, dehydrated, entityToken, indexTokens
|
|
|
55
55
|
? encodeGeneratedProperty.encodeGeneratedProperty(entityManager, item, entityToken, component)
|
|
56
56
|
: item[component]);
|
|
57
57
|
}));
|
|
58
|
+
entityManager.logger.debug('rehydrated page key map', {
|
|
59
|
+
dehydrated,
|
|
60
|
+
entityToken,
|
|
61
|
+
indexTokens,
|
|
62
|
+
rehydrated,
|
|
63
|
+
});
|
|
58
64
|
return rehydrated;
|
|
59
65
|
}
|
|
60
66
|
catch (error) {
|
|
67
|
+
if (error instanceof Error)
|
|
68
|
+
entityManager.logger.error(error.message, {
|
|
69
|
+
dehydrated,
|
|
70
|
+
entityToken,
|
|
71
|
+
indexTokens,
|
|
72
|
+
});
|
|
61
73
|
throw error;
|
|
62
74
|
}
|
|
63
75
|
}
|
package/dist/cjs/removeKeys.js
CHANGED
|
@@ -24,9 +24,16 @@ function removeKeys(entityManager, item, entityToken) {
|
|
|
24
24
|
// Delete generated properties.
|
|
25
25
|
for (const property in entityManager.config.entities[entityToken].generated)
|
|
26
26
|
delete newItem[property];
|
|
27
|
+
entityManager.logger.debug('stripped entity item generated properties', {
|
|
28
|
+
item,
|
|
29
|
+
entityToken,
|
|
30
|
+
newItem,
|
|
31
|
+
});
|
|
27
32
|
return newItem;
|
|
28
33
|
}
|
|
29
34
|
catch (error) {
|
|
35
|
+
if (error instanceof Error)
|
|
36
|
+
entityManager.logger.error(error.message, { item, entityToken });
|
|
30
37
|
throw error;
|
|
31
38
|
}
|
|
32
39
|
}
|
package/dist/cjs/unwrapIndex.js
CHANGED
|
@@ -23,6 +23,11 @@ function updateItemHashKey(entityManager, item, entityToken, overwrite = false)
|
|
|
23
23
|
validateEntityToken.validateEntityToken(entityManager, entityToken);
|
|
24
24
|
// Return current item if hashKey exists and overwrite is false.
|
|
25
25
|
if (item[entityManager.config.hashKey] && !overwrite) {
|
|
26
|
+
entityManager.logger.debug('did not overwrite existing entity item hash key', {
|
|
27
|
+
item,
|
|
28
|
+
entityToken,
|
|
29
|
+
overwrite,
|
|
30
|
+
});
|
|
26
31
|
return { ...item };
|
|
27
32
|
}
|
|
28
33
|
// Get item timestamp property & validate.
|
|
@@ -45,9 +50,21 @@ function updateItemHashKey(entityManager, item, entityToken, overwrite = false)
|
|
|
45
50
|
.padStart(chars, '0');
|
|
46
51
|
}
|
|
47
52
|
const newItem = Object.assign({ ...item }, { [entityManager.config.hashKey]: hashKey });
|
|
53
|
+
entityManager.logger.debug('updated entity item hash key', {
|
|
54
|
+
entityToken,
|
|
55
|
+
overwrite,
|
|
56
|
+
item,
|
|
57
|
+
newItem,
|
|
58
|
+
});
|
|
48
59
|
return newItem;
|
|
49
60
|
}
|
|
50
61
|
catch (error) {
|
|
62
|
+
if (error instanceof Error)
|
|
63
|
+
entityManager.logger.error(error.message, {
|
|
64
|
+
item,
|
|
65
|
+
entityToken,
|
|
66
|
+
overwrite,
|
|
67
|
+
});
|
|
51
68
|
throw error;
|
|
52
69
|
}
|
|
53
70
|
}
|
|
@@ -22,6 +22,11 @@ function updateItemRangeKey(entityManager, item, entityToken, overwrite = false)
|
|
|
22
22
|
validateEntityToken.validateEntityToken(entityManager, entityToken);
|
|
23
23
|
// Return current item if rangeKey exists and overwrite is false.
|
|
24
24
|
if (item[entityManager.config.rangeKey] && !overwrite) {
|
|
25
|
+
entityManager.logger.debug('did not overwrite existing entity item range key', {
|
|
26
|
+
item,
|
|
27
|
+
entityToken,
|
|
28
|
+
overwrite,
|
|
29
|
+
});
|
|
25
30
|
return { ...item };
|
|
26
31
|
}
|
|
27
32
|
// Get item unique property & validate.
|
|
@@ -35,9 +40,21 @@ function updateItemRangeKey(entityManager, item, entityToken, overwrite = false)
|
|
|
35
40
|
uniqueProperty,
|
|
36
41
|
].join(entityManager.config.generatedValueDelimiter),
|
|
37
42
|
});
|
|
43
|
+
entityManager.logger.debug('updated entity item range key', {
|
|
44
|
+
entityToken,
|
|
45
|
+
overwrite,
|
|
46
|
+
item,
|
|
47
|
+
newItem,
|
|
48
|
+
});
|
|
38
49
|
return newItem;
|
|
39
50
|
}
|
|
40
51
|
catch (error) {
|
|
52
|
+
if (error instanceof Error)
|
|
53
|
+
entityManager.logger.error(error.message, {
|
|
54
|
+
item,
|
|
55
|
+
entityToken,
|
|
56
|
+
overwrite,
|
|
57
|
+
});
|
|
41
58
|
throw error;
|
|
42
59
|
}
|
|
43
60
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Entity, Exactify, TranscodeMap, PropertiesOfType, TranscodableProperties, Transcodes, DefaultTranscodeMap,
|
|
1
|
+
import { Entity, Exactify, TranscodeMap, PropertiesOfType, TranscodableProperties, Transcodes, DefaultTranscodeMap, SortOrder } from '@karmaniverous/entity-tools';
|
|
2
2
|
export { DefaultTranscodeMap, Entity, Exactify, PartialTranscodable, PropertiesNotOfType, PropertiesOfType, SortOrder, TranscodableProperties, TranscodeMap, Transcodes, defaultTranscodes } from '@karmaniverous/entity-tools';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
|
|
@@ -632,23 +632,17 @@ type ParsedConfig = z.infer<typeof configSchema>;
|
|
|
632
632
|
/**
|
|
633
633
|
* A result returned by a {@link ShardQueryFunction | `ShardQueryFunction`} querying an individual shard.
|
|
634
634
|
*
|
|
635
|
-
* @typeParam Item - The {@link
|
|
636
|
-
* @typeParam T - The {@link TranscodeMap | `TranscodeMap`} identifying property types that can be indexed.
|
|
635
|
+
* @typeParam Item - The {@link Item | `Item`} type being queried.
|
|
637
636
|
|
|
638
637
|
* @category Query
|
|
639
638
|
*/
|
|
640
|
-
interface ShardQueryResult<Item extends
|
|
639
|
+
interface ShardQueryResult<Item extends Entity> {
|
|
641
640
|
/** The number of records returned. */
|
|
642
641
|
count: number;
|
|
643
642
|
/** The returned records. */
|
|
644
643
|
items: Item[];
|
|
645
644
|
/** The page key for the next query on this shard. */
|
|
646
|
-
pageKey?:
|
|
647
|
-
}
|
|
648
|
-
interface ClientShardQueryResult {
|
|
649
|
-
count: number;
|
|
650
|
-
items: Entity[];
|
|
651
|
-
pageKey?: Entity;
|
|
645
|
+
pageKey?: Partial<Item>;
|
|
652
646
|
}
|
|
653
647
|
|
|
654
648
|
/**
|
|
@@ -658,27 +652,24 @@ interface ClientShardQueryResult {
|
|
|
658
652
|
* provided by the {@link EntityManager.query | `EntityManager.query`} method, which assembles many returned
|
|
659
653
|
* pages queried across multiple shards into a single query result.
|
|
660
654
|
*
|
|
661
|
-
* @typeParam Item - The {@link
|
|
662
|
-
* @typeParam T - The {@link TranscodeMap | `TranscodeMap`} identifying property types that can be indexed. Defaults to {@link DefaultTranscodeMap | `DefaultTranscodeMap`}.
|
|
655
|
+
* @typeParam Item - The {@link Item | `Item`} type being queried.
|
|
663
656
|
|
|
664
|
-
* @param hashKey - The
|
|
657
|
+
* @param hashKey - The hash key value of the shard being queried.
|
|
665
658
|
* @param pageKey - The page key returned by the previous query on this shard.
|
|
666
659
|
* @param pageSize - The maximum number of items to return from this query.
|
|
667
660
|
*
|
|
668
661
|
* @category Query
|
|
669
662
|
*/
|
|
670
|
-
type ShardQueryFunction<Item extends
|
|
671
|
-
type ClientShardQueryFunction = (hashKey: string, pageKey?: Entity, pageSize?: number) => Promise<ClientShardQueryResult>;
|
|
663
|
+
type ShardQueryFunction<Item extends Entity> = (hashKey: string, pageKey?: Partial<Item>, pageSize?: number) => Promise<ShardQueryResult<Item>>;
|
|
672
664
|
|
|
673
|
-
type ShardQueryMap<Item extends
|
|
674
|
-
type ClientShardQueryMap = Record<string, ClientShardQueryFunction>;
|
|
665
|
+
type ShardQueryMap<Item extends Entity> = Record<string, ShardQueryFunction<Item>>;
|
|
675
666
|
|
|
676
667
|
/**
|
|
677
668
|
* Options passed to the {@link EntityManager.query | `EntityManager.query`} method.
|
|
678
669
|
*
|
|
679
670
|
* @category Query
|
|
680
671
|
*/
|
|
681
|
-
interface QueryOptions<Item extends ItemMap<M, HashKey, RangeKey>[EntityToken], EntityToken extends keyof Exactify<M> & string, M extends EntityMap, HashKey extends string, RangeKey extends string
|
|
672
|
+
interface QueryOptions<Item extends ItemMap<M, HashKey, RangeKey>[EntityToken], EntityToken extends keyof Exactify<M> & string, M extends EntityMap, HashKey extends string, RangeKey extends string> {
|
|
682
673
|
/** Identifies the entity to be queried. Key of {@link Config | `EntityManager.config.entities`}. */
|
|
683
674
|
entityToken: EntityToken;
|
|
684
675
|
/**
|
|
@@ -717,7 +708,7 @@ interface QueryOptions<Item extends ItemMap<M, HashKey, RangeKey>[EntityToken],
|
|
|
717
708
|
* page key, e.g. to match the same string against `firstName` and `lastName`
|
|
718
709
|
* properties without performing a table scan for either.
|
|
719
710
|
*/
|
|
720
|
-
shardQueryMap: ShardQueryMap<Item
|
|
711
|
+
shardQueryMap: ShardQueryMap<Item>;
|
|
721
712
|
/**
|
|
722
713
|
* A {@link SortOrder | `SortOrder`} object specifying the sort order of the result set. Defaults to `[]`.
|
|
723
714
|
*/
|
|
@@ -776,12 +767,14 @@ interface QueryResult<Item extends ItemMap<M, HashKey, RangeKey>[EntityToken], E
|
|
|
776
767
|
*/
|
|
777
768
|
declare class EntityManager<M extends EntityMap, HashKey extends string, RangeKey extends string, T extends TranscodeMap> {
|
|
778
769
|
#private;
|
|
770
|
+
logger: Pick<Console, 'debug' | 'error'>;
|
|
779
771
|
/**
|
|
780
772
|
* Create an EntityManager instance.
|
|
781
773
|
*
|
|
782
774
|
* @param config - EntityManager {@link Config | `Config`} object.
|
|
775
|
+
* @param logger - Logger object (defaults to `console`, must support `debug` & `error` methods).
|
|
783
776
|
*/
|
|
784
|
-
constructor(config: Config<M, HashKey, RangeKey, T>);
|
|
777
|
+
constructor(config: Config<M, HashKey, RangeKey, T>, logger?: Pick<Console, 'debug' | 'error'>);
|
|
785
778
|
/**
|
|
786
779
|
* Get the current EntityManager {@link Config | `Config`} object.
|
|
787
780
|
*
|
|
@@ -835,21 +828,7 @@ declare class EntityManager<M extends EntityMap, HashKey extends string, RangeKe
|
|
|
835
828
|
*
|
|
836
829
|
* @throws Error if {@link QueryOptions.pageKeyMap | `pageKeyMap`} keys do not match {@link QueryOptions.shardQueryMap | `shardQueryMap`} keys.
|
|
837
830
|
*/
|
|
838
|
-
query<Item extends ItemMap<M, HashKey, RangeKey>[EntityToken], EntityToken extends keyof Exactify<M> & string>(options: QueryOptions<Item, EntityToken, M, HashKey, RangeKey
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
/**
|
|
842
|
-
* Options for EntityManager client methods that support batch operations.
|
|
843
|
-
*/
|
|
844
|
-
interface EntityManagerClientBatchOptions {
|
|
845
|
-
/** Batch size. */
|
|
846
|
-
batchSize?: number;
|
|
847
|
-
/** Delay increment in ms for retry operations. Doubles on each retry. */
|
|
848
|
-
delayIncrement?: number;
|
|
849
|
-
/** Max retries for retry operations. */
|
|
850
|
-
maxRetries?: number;
|
|
851
|
-
/** Throttle for parallel operations. */
|
|
852
|
-
throttle?: number;
|
|
831
|
+
query<Item extends ItemMap<M, HashKey, RangeKey>[EntityToken], EntityToken extends keyof Exactify<M> & string>(options: QueryOptions<Item, EntityToken, M, HashKey, RangeKey>): Promise<QueryResult<Item, EntityToken, M, HashKey, RangeKey>>;
|
|
853
832
|
}
|
|
854
833
|
|
|
855
834
|
/**
|
|
@@ -879,58 +858,18 @@ interface LoggerOptions {
|
|
|
879
858
|
logInternals?: boolean;
|
|
880
859
|
}
|
|
881
860
|
|
|
882
|
-
/**
|
|
883
|
-
* EntityManagerClient base class options.
|
|
884
|
-
*
|
|
885
|
-
* @category Client
|
|
886
|
-
*/
|
|
887
|
-
type EntityManagerClientOptions = EntityManagerClientBatchOptions & LoggerOptions;
|
|
888
|
-
/**
|
|
889
|
-
* EntityManagerClient base class.
|
|
890
|
-
*
|
|
891
|
-
* @typeParam Options - Options type extended from {@link EntityManagerClientOptions | `EntityManagerClientOptions`}.
|
|
892
|
-
*
|
|
893
|
-
* @category Client
|
|
894
|
-
*/
|
|
895
|
-
declare abstract class EntityManagerClient<Options extends EntityManagerClientOptions> {
|
|
896
|
-
#private;
|
|
897
|
-
/**
|
|
898
|
-
* EntityManagerClient base constructor.
|
|
899
|
-
* @param options - Options object extended from {@link EntityManagerClientOptions | `EntityManagerClientOptions`}.
|
|
900
|
-
*/
|
|
901
|
-
constructor({ batchSize, delayIncrement, maxRetries, throttle, logger, logInternals, ...childOptions }: Options);
|
|
902
|
-
/**
|
|
903
|
-
* Returns the options used to create the EntityManagerClient instance.
|
|
904
|
-
*/
|
|
905
|
-
get options(): Required<Options>;
|
|
906
|
-
/**
|
|
907
|
-
* Executes a batch operation.
|
|
908
|
-
*
|
|
909
|
-
* @param items - Items to batch execute.
|
|
910
|
-
* @param executeBatch - Function to execute the batch.
|
|
911
|
-
* @param getUnprocessedItems - Function to get unprocessed items from the output.
|
|
912
|
-
* @param options - Batch options.
|
|
913
|
-
*
|
|
914
|
-
* @typeParam Item - Input item type.
|
|
915
|
-
* @typeParam Output - Output type.
|
|
916
|
-
*
|
|
917
|
-
* @returns Output array.
|
|
918
|
-
*/
|
|
919
|
-
protected batchExecute<Item, Output>(items: Item[], executeBatch: (items: Item[]) => Promise<Output>, getUnprocessedItems?: (output: Output) => Item[] | undefined, { batchSize, delayIncrement, maxRetries, throttle, }?: EntityManagerClientBatchOptions): Promise<Output[]>;
|
|
920
|
-
}
|
|
921
|
-
|
|
922
861
|
/**
|
|
923
862
|
* {@link ShardQueryMapBuilder | `ShardQueryMapBuilder`} options.
|
|
924
863
|
*
|
|
925
864
|
* @category Query
|
|
926
865
|
*/
|
|
927
|
-
interface ShardQueryMapBuilderOptions {
|
|
866
|
+
interface ShardQueryMapBuilderOptions<Item extends Entity> {
|
|
928
867
|
/** `entityManager.config.entities` key. */
|
|
929
868
|
entityToken: string;
|
|
930
869
|
/** Either the designated entity hash key or a generated property with `sharded === true`. */
|
|
931
870
|
hashKeyToken: string;
|
|
932
871
|
/** A partial `Item` sufficiently populated to generate the query hash key & index values. */
|
|
933
|
-
item:
|
|
872
|
+
item: Item;
|
|
934
873
|
/** Dehydrated page key from the previous query data page. */
|
|
935
874
|
pageKey?: string;
|
|
936
875
|
}
|
|
@@ -940,10 +879,10 @@ interface ShardQueryMapBuilderOptions {
|
|
|
940
879
|
*
|
|
941
880
|
* @category Query
|
|
942
881
|
*/
|
|
943
|
-
declare abstract class ShardQueryMapBuilder<Options extends ShardQueryMapBuilderOptions
|
|
882
|
+
declare abstract class ShardQueryMapBuilder<Item extends Entity, Options extends ShardQueryMapBuilderOptions<Item>> {
|
|
944
883
|
readonly options: Options;
|
|
945
884
|
constructor(options: Options);
|
|
946
|
-
abstract getShardQueryMap():
|
|
885
|
+
abstract getShardQueryMap(): ShardQueryMap<Item>;
|
|
947
886
|
}
|
|
948
887
|
|
|
949
888
|
/**
|
|
@@ -956,4 +895,4 @@ type WithRequiredAndNonNullable<T, K extends keyof T> = T & {
|
|
|
956
895
|
[P in K]-?: NonNullable<T[P]>;
|
|
957
896
|
};
|
|
958
897
|
|
|
959
|
-
export { type Config, type ConfigEntities, type ConfigEntity, type ConfigEntityGenerated, type ConfigKeys, type ConfigTranscodes, EntityManager,
|
|
898
|
+
export { type Config, type ConfigEntities, type ConfigEntity, type ConfigEntityGenerated, type ConfigKeys, type ConfigTranscodes, EntityManager, type EntityMap, type ExclusiveKey, type ItemMap, type Logger, type LoggerEndpoint, type LoggerOptions, type ParsedConfig, type QueryOptions, type QueryResult, type ShardBump, type ShardQueryFunction, type ShardQueryMap, ShardQueryMapBuilder, type ShardQueryMapBuilderOptions, type ShardQueryResult, type Unwrap, type WithRequiredAndNonNullable, conditionalize };
|
|
@@ -16,10 +16,12 @@ class EntityManager {
|
|
|
16
16
|
* Create an EntityManager instance.
|
|
17
17
|
*
|
|
18
18
|
* @param config - EntityManager {@link Config | `Config`} object.
|
|
19
|
+
* @param logger - Logger object (defaults to `console`, must support `debug` & `error` methods).
|
|
19
20
|
*/
|
|
20
|
-
constructor(config) {
|
|
21
|
+
constructor(config, logger = console) {
|
|
21
22
|
_EntityManager_config.set(this, void 0);
|
|
22
23
|
__classPrivateFieldSet(this, _EntityManager_config, configSchema.parse(config), "f");
|
|
24
|
+
this.logger = logger;
|
|
23
25
|
}
|
|
24
26
|
/**
|
|
25
27
|
* Get the current EntityManager {@link Config | `Config`} object.
|
package/dist/mjs/addKeys.js
CHANGED
|
@@ -35,9 +35,21 @@ function addKeys(entityManager, item, entityToken, overwrite = false) {
|
|
|
35
35
|
delete newItem[property];
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
+
entityManager.logger.debug('updated entity item generated properties', {
|
|
39
|
+
item,
|
|
40
|
+
entityToken,
|
|
41
|
+
overwrite,
|
|
42
|
+
newItem,
|
|
43
|
+
});
|
|
38
44
|
return newItem;
|
|
39
45
|
}
|
|
40
46
|
catch (error) {
|
|
47
|
+
if (error instanceof Error)
|
|
48
|
+
entityManager.logger.error(error.message, {
|
|
49
|
+
item,
|
|
50
|
+
entityToken,
|
|
51
|
+
overwrite,
|
|
52
|
+
});
|
|
41
53
|
throw error;
|
|
42
54
|
}
|
|
43
55
|
}
|
|
@@ -25,9 +25,21 @@ function decodeEntityElement(entityManager, value, entityToken, element) {
|
|
|
25
25
|
if ([hashKey, rangeKey].includes(element))
|
|
26
26
|
return value;
|
|
27
27
|
const decoded = transcodes[entities[entityToken].elementTranscodes[element]].decode(value);
|
|
28
|
+
entityManager.logger.debug('decoded entity element', {
|
|
29
|
+
value,
|
|
30
|
+
entityToken,
|
|
31
|
+
element,
|
|
32
|
+
decoded,
|
|
33
|
+
});
|
|
28
34
|
return decoded;
|
|
29
35
|
}
|
|
30
36
|
catch (error) {
|
|
37
|
+
if (error instanceof Error)
|
|
38
|
+
entityManager.logger.error(error.message, {
|
|
39
|
+
value,
|
|
40
|
+
entityToken,
|
|
41
|
+
element,
|
|
42
|
+
});
|
|
31
43
|
throw error;
|
|
32
44
|
}
|
|
33
45
|
}
|
|
@@ -36,9 +36,16 @@ function decodeGeneratedProperty(entityManager, encoded, entityToken) {
|
|
|
36
36
|
});
|
|
37
37
|
// Assign decoded properties.
|
|
38
38
|
Object.assign(decoded, objectify(values, ([key]) => key, ([key, value]) => decodeEntityElement(entityManager, value, entityToken, key)));
|
|
39
|
+
entityManager.logger.debug('decoded generated property', {
|
|
40
|
+
encoded,
|
|
41
|
+
entityToken,
|
|
42
|
+
decoded,
|
|
43
|
+
});
|
|
39
44
|
return decoded;
|
|
40
45
|
}
|
|
41
46
|
catch (error) {
|
|
47
|
+
if (error instanceof Error)
|
|
48
|
+
entityManager.logger.error(error.message, { encoded, entityToken });
|
|
42
49
|
throw error;
|
|
43
50
|
}
|
|
44
51
|
}
|
|
@@ -40,9 +40,22 @@ function dehydrateIndexItem(entityManager, item, entityToken, indexToken, omit =
|
|
|
40
40
|
const dehydrated = elements
|
|
41
41
|
.map((element) => encodeEntityElement(entityManager, item, entityToken, element))
|
|
42
42
|
.join(generatedKeyDelimiter);
|
|
43
|
+
entityManager.logger.debug('dehydrated index', {
|
|
44
|
+
item,
|
|
45
|
+
entityToken,
|
|
46
|
+
indexToken,
|
|
47
|
+
elements,
|
|
48
|
+
dehydrated,
|
|
49
|
+
});
|
|
43
50
|
return dehydrated;
|
|
44
51
|
}
|
|
45
52
|
catch (error) {
|
|
53
|
+
if (error instanceof Error)
|
|
54
|
+
entityManager.logger.error(error.message, {
|
|
55
|
+
item,
|
|
56
|
+
entityToken,
|
|
57
|
+
indexToken,
|
|
58
|
+
});
|
|
46
59
|
throw error;
|
|
47
60
|
}
|
|
48
61
|
}
|
|
@@ -29,6 +29,11 @@ function dehydratePageKeyMap(entityManager, pageKeyMap, entityToken) {
|
|
|
29
29
|
// Shortcut empty pageKeyMap.
|
|
30
30
|
if (!Object.keys(pageKeyMap).length) {
|
|
31
31
|
const dehydrated = [];
|
|
32
|
+
entityManager.logger.debug('dehydrated empty page key map', {
|
|
33
|
+
pageKeyMap,
|
|
34
|
+
entityToken,
|
|
35
|
+
dehydrated,
|
|
36
|
+
});
|
|
32
37
|
return dehydrated;
|
|
33
38
|
}
|
|
34
39
|
// Extract, sort & validate indexs.
|
|
@@ -63,9 +68,18 @@ function dehydratePageKeyMap(entityManager, pageKeyMap, entityToken) {
|
|
|
63
68
|
// Replace with empty array if all pageKeys are empty strings.
|
|
64
69
|
if (dehydrated.every((pageKey) => pageKey === ''))
|
|
65
70
|
dehydrated = [];
|
|
71
|
+
entityManager.logger.debug('dehydrated page key map', {
|
|
72
|
+
pageKeyMap,
|
|
73
|
+
entityToken,
|
|
74
|
+
indexes,
|
|
75
|
+
hashKeys,
|
|
76
|
+
dehydrated,
|
|
77
|
+
});
|
|
66
78
|
return dehydrated;
|
|
67
79
|
}
|
|
68
80
|
catch (error) {
|
|
81
|
+
if (error instanceof Error)
|
|
82
|
+
entityManager.logger.error(error.message, { entityToken, pageKeyMap });
|
|
69
83
|
throw error;
|
|
70
84
|
}
|
|
71
85
|
}
|
|
@@ -24,9 +24,17 @@ function encodeEntityElement(entityManager, item, entityToken, element) {
|
|
|
24
24
|
if (value === undefined || [hashKey, rangeKey].includes(element))
|
|
25
25
|
return value;
|
|
26
26
|
const encoded = transcodes[entities[entityToken].elementTranscodes[element]].encode(item[element]) || undefined;
|
|
27
|
+
entityManager.logger.debug('encoded entity element', {
|
|
28
|
+
item,
|
|
29
|
+
entityToken,
|
|
30
|
+
element,
|
|
31
|
+
encoded,
|
|
32
|
+
});
|
|
27
33
|
return encoded;
|
|
28
34
|
}
|
|
29
35
|
catch (error) {
|
|
36
|
+
if (error instanceof Error)
|
|
37
|
+
entityManager.logger.error(error.message, { item, entityToken, element });
|
|
30
38
|
throw error;
|
|
31
39
|
}
|
|
32
40
|
}
|
|
@@ -32,9 +32,21 @@ function encodeGeneratedProperty(entityManager, item, entityToken, property) {
|
|
|
32
32
|
...(sharded ? [item[entityManager.config.hashKey]] : []),
|
|
33
33
|
...elementMap.map(([element, value]) => [element, (value ?? '').toString()].join(entityManager.config.generatedValueDelimiter)),
|
|
34
34
|
].join(entityManager.config.generatedKeyDelimiter);
|
|
35
|
+
entityManager.logger.debug('encoded generated property', {
|
|
36
|
+
item,
|
|
37
|
+
entityToken,
|
|
38
|
+
property,
|
|
39
|
+
encoded,
|
|
40
|
+
});
|
|
35
41
|
return encoded;
|
|
36
42
|
}
|
|
37
43
|
catch (error) {
|
|
44
|
+
if (error instanceof Error)
|
|
45
|
+
entityManager.logger.error(error.message, {
|
|
46
|
+
item,
|
|
47
|
+
entityToken,
|
|
48
|
+
property,
|
|
49
|
+
});
|
|
38
50
|
throw error;
|
|
39
51
|
}
|
|
40
52
|
}
|
|
@@ -29,9 +29,21 @@ function getHashKeySpace(entityManager, entityToken, timestampFrom = 0, timestam
|
|
|
29
29
|
: '';
|
|
30
30
|
})
|
|
31
31
|
.map((shardKey) => `${entityToken}${entityManager.config.shardKeyDelimiter}${shardKey}`);
|
|
32
|
+
entityManager.logger.debug('generated hash key space', {
|
|
33
|
+
entityToken,
|
|
34
|
+
timestampFrom,
|
|
35
|
+
timestampTo,
|
|
36
|
+
hashKeySpace,
|
|
37
|
+
});
|
|
32
38
|
return hashKeySpace;
|
|
33
39
|
}
|
|
34
40
|
catch (error) {
|
|
41
|
+
if (error instanceof Error)
|
|
42
|
+
entityManager.logger.error(error.message, {
|
|
43
|
+
entityToken,
|
|
44
|
+
timestampFrom,
|
|
45
|
+
timestampTo,
|
|
46
|
+
});
|
|
35
47
|
throw error;
|
|
36
48
|
}
|
|
37
49
|
}
|
package/dist/mjs/index.js
CHANGED
package/dist/mjs/query.js
CHANGED
|
@@ -90,9 +90,35 @@ async function query(entityManager, { entityToken, hashKey, limit, pageKeyMap, p
|
|
|
90
90
|
items: workingResult.items,
|
|
91
91
|
pageKeyMap: compressToEncodedURIComponent(JSON.stringify(dehydratePageKeyMap(entityManager, workingResult.pageKeyMap, entityToken))),
|
|
92
92
|
};
|
|
93
|
+
entityManager.logger.debug('queried entityToken across shards', {
|
|
94
|
+
entityToken,
|
|
95
|
+
hashKey,
|
|
96
|
+
limit,
|
|
97
|
+
pageKeyMap,
|
|
98
|
+
pageSize,
|
|
99
|
+
shardQueryMap,
|
|
100
|
+
timestampFrom,
|
|
101
|
+
timestampTo,
|
|
102
|
+
throttle,
|
|
103
|
+
rehydratedPageKeyMap,
|
|
104
|
+
workingResult,
|
|
105
|
+
result,
|
|
106
|
+
});
|
|
93
107
|
return result;
|
|
94
108
|
}
|
|
95
109
|
catch (error) {
|
|
110
|
+
if (error instanceof Error)
|
|
111
|
+
entityManager.logger.error(error.message, {
|
|
112
|
+
entityToken,
|
|
113
|
+
hashKey,
|
|
114
|
+
limit,
|
|
115
|
+
pageKeyMap,
|
|
116
|
+
pageSize,
|
|
117
|
+
shardQueryMap,
|
|
118
|
+
timestampFrom,
|
|
119
|
+
timestampTo,
|
|
120
|
+
throttle,
|
|
121
|
+
});
|
|
96
122
|
throw error;
|
|
97
123
|
}
|
|
98
124
|
}
|
|
@@ -35,9 +35,23 @@ function rehydrateIndexItem(entityManager, dehydrated, entityToken, indexToken,
|
|
|
35
35
|
throw new Error('index rehydration key-value mismatch');
|
|
36
36
|
// Assign values to elements.
|
|
37
37
|
const rehydrated = shake(zipToObject(elements, values.map((value, i) => decodeEntityElement(entityManager, value, entityToken, elements[i]))));
|
|
38
|
+
entityManager.logger.debug('rehydrated index', {
|
|
39
|
+
dehydrated,
|
|
40
|
+
entityToken,
|
|
41
|
+
indexToken,
|
|
42
|
+
elements,
|
|
43
|
+
values,
|
|
44
|
+
rehydrated,
|
|
45
|
+
});
|
|
38
46
|
return rehydrated;
|
|
39
47
|
}
|
|
40
48
|
catch (error) {
|
|
49
|
+
if (error instanceof Error)
|
|
50
|
+
entityManager.logger.error(error.message, {
|
|
51
|
+
dehydrated,
|
|
52
|
+
entityToken,
|
|
53
|
+
indexToken,
|
|
54
|
+
});
|
|
41
55
|
throw error;
|
|
42
56
|
}
|
|
43
57
|
}
|
|
@@ -53,9 +53,21 @@ function rehydratePageKeyMap(entityManager, dehydrated, entityToken, indexTokens
|
|
|
53
53
|
? encodeGeneratedProperty(entityManager, item, entityToken, component)
|
|
54
54
|
: item[component]);
|
|
55
55
|
}));
|
|
56
|
+
entityManager.logger.debug('rehydrated page key map', {
|
|
57
|
+
dehydrated,
|
|
58
|
+
entityToken,
|
|
59
|
+
indexTokens,
|
|
60
|
+
rehydrated,
|
|
61
|
+
});
|
|
56
62
|
return rehydrated;
|
|
57
63
|
}
|
|
58
64
|
catch (error) {
|
|
65
|
+
if (error instanceof Error)
|
|
66
|
+
entityManager.logger.error(error.message, {
|
|
67
|
+
dehydrated,
|
|
68
|
+
entityToken,
|
|
69
|
+
indexTokens,
|
|
70
|
+
});
|
|
59
71
|
throw error;
|
|
60
72
|
}
|
|
61
73
|
}
|
package/dist/mjs/removeKeys.js
CHANGED
|
@@ -22,9 +22,16 @@ function removeKeys(entityManager, item, entityToken) {
|
|
|
22
22
|
// Delete generated properties.
|
|
23
23
|
for (const property in entityManager.config.entities[entityToken].generated)
|
|
24
24
|
delete newItem[property];
|
|
25
|
+
entityManager.logger.debug('stripped entity item generated properties', {
|
|
26
|
+
item,
|
|
27
|
+
entityToken,
|
|
28
|
+
newItem,
|
|
29
|
+
});
|
|
25
30
|
return newItem;
|
|
26
31
|
}
|
|
27
32
|
catch (error) {
|
|
33
|
+
if (error instanceof Error)
|
|
34
|
+
entityManager.logger.error(error.message, { item, entityToken });
|
|
28
35
|
throw error;
|
|
29
36
|
}
|
|
30
37
|
}
|
package/dist/mjs/unwrapIndex.js
CHANGED
|
@@ -21,6 +21,11 @@ function updateItemHashKey(entityManager, item, entityToken, overwrite = false)
|
|
|
21
21
|
validateEntityToken(entityManager, entityToken);
|
|
22
22
|
// Return current item if hashKey exists and overwrite is false.
|
|
23
23
|
if (item[entityManager.config.hashKey] && !overwrite) {
|
|
24
|
+
entityManager.logger.debug('did not overwrite existing entity item hash key', {
|
|
25
|
+
item,
|
|
26
|
+
entityToken,
|
|
27
|
+
overwrite,
|
|
28
|
+
});
|
|
24
29
|
return { ...item };
|
|
25
30
|
}
|
|
26
31
|
// Get item timestamp property & validate.
|
|
@@ -43,9 +48,21 @@ function updateItemHashKey(entityManager, item, entityToken, overwrite = false)
|
|
|
43
48
|
.padStart(chars, '0');
|
|
44
49
|
}
|
|
45
50
|
const newItem = Object.assign({ ...item }, { [entityManager.config.hashKey]: hashKey });
|
|
51
|
+
entityManager.logger.debug('updated entity item hash key', {
|
|
52
|
+
entityToken,
|
|
53
|
+
overwrite,
|
|
54
|
+
item,
|
|
55
|
+
newItem,
|
|
56
|
+
});
|
|
46
57
|
return newItem;
|
|
47
58
|
}
|
|
48
59
|
catch (error) {
|
|
60
|
+
if (error instanceof Error)
|
|
61
|
+
entityManager.logger.error(error.message, {
|
|
62
|
+
item,
|
|
63
|
+
entityToken,
|
|
64
|
+
overwrite,
|
|
65
|
+
});
|
|
49
66
|
throw error;
|
|
50
67
|
}
|
|
51
68
|
}
|
|
@@ -20,6 +20,11 @@ function updateItemRangeKey(entityManager, item, entityToken, overwrite = false)
|
|
|
20
20
|
validateEntityToken(entityManager, entityToken);
|
|
21
21
|
// Return current item if rangeKey exists and overwrite is false.
|
|
22
22
|
if (item[entityManager.config.rangeKey] && !overwrite) {
|
|
23
|
+
entityManager.logger.debug('did not overwrite existing entity item range key', {
|
|
24
|
+
item,
|
|
25
|
+
entityToken,
|
|
26
|
+
overwrite,
|
|
27
|
+
});
|
|
23
28
|
return { ...item };
|
|
24
29
|
}
|
|
25
30
|
// Get item unique property & validate.
|
|
@@ -33,9 +38,21 @@ function updateItemRangeKey(entityManager, item, entityToken, overwrite = false)
|
|
|
33
38
|
uniqueProperty,
|
|
34
39
|
].join(entityManager.config.generatedValueDelimiter),
|
|
35
40
|
});
|
|
41
|
+
entityManager.logger.debug('updated entity item range key', {
|
|
42
|
+
entityToken,
|
|
43
|
+
overwrite,
|
|
44
|
+
item,
|
|
45
|
+
newItem,
|
|
46
|
+
});
|
|
36
47
|
return newItem;
|
|
37
48
|
}
|
|
38
49
|
catch (error) {
|
|
50
|
+
if (error instanceof Error)
|
|
51
|
+
entityManager.logger.error(error.message, {
|
|
52
|
+
item,
|
|
53
|
+
entityToken,
|
|
54
|
+
overwrite,
|
|
55
|
+
});
|
|
39
56
|
throw error;
|
|
40
57
|
}
|
|
41
58
|
}
|
package/package.json
CHANGED
|
@@ -14,50 +14,50 @@
|
|
|
14
14
|
},
|
|
15
15
|
"description": "Rational indexing & cross-shard querying at scale in your NoSQL database so you can focus on your application logic.",
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"@dotenvx/dotenvx": "^1.
|
|
18
|
-
"@eslint/js": "^9.
|
|
17
|
+
"@dotenvx/dotenvx": "^1.20.0",
|
|
18
|
+
"@eslint/js": "^9.13.0",
|
|
19
19
|
"@faker-js/faker": "^9.0.3",
|
|
20
20
|
"@karmaniverous/mock-db": "^0.3.3",
|
|
21
21
|
"@rollup/plugin-alias": "^5.1.1",
|
|
22
|
-
"@rollup/plugin-commonjs": "^28.0.
|
|
22
|
+
"@rollup/plugin-commonjs": "^28.0.1",
|
|
23
23
|
"@rollup/plugin-json": "^6.1.0",
|
|
24
24
|
"@rollup/plugin-node-resolve": "^15.3.0",
|
|
25
25
|
"@rollup/plugin-strip": "^3.0.4",
|
|
26
|
-
"@rollup/plugin-typescript": "^12.1.
|
|
26
|
+
"@rollup/plugin-typescript": "^12.1.1",
|
|
27
27
|
"@types/chai": "^5.0.0",
|
|
28
28
|
"@types/eslint__js": "^8.42.3",
|
|
29
29
|
"@types/eslint-config-prettier": "^6.11.3",
|
|
30
30
|
"@types/eslint-plugin-mocha": "^10.4.0",
|
|
31
31
|
"@types/mocha": "^10.0.9",
|
|
32
|
-
"@types/node": "^22.7.
|
|
32
|
+
"@types/node": "^22.7.8",
|
|
33
33
|
"@types/string-hash": "^1.1.3",
|
|
34
34
|
"auto-changelog": "^2.5.0",
|
|
35
35
|
"chai": "^5.1.1",
|
|
36
36
|
"cross-env": "^7.0.3",
|
|
37
|
-
"eslint": "^9.
|
|
37
|
+
"eslint": "^9.13.0",
|
|
38
38
|
"eslint-config-prettier": "^9.1.0",
|
|
39
39
|
"eslint-plugin-mocha": "^10.5.0",
|
|
40
40
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
41
41
|
"eslint-plugin-tsdoc": "^0.3.0",
|
|
42
42
|
"jsdom-global": "^3.0.2",
|
|
43
|
-
"knip": "^5.33.
|
|
44
|
-
"lefthook": "^1.7.
|
|
43
|
+
"knip": "^5.33.3",
|
|
44
|
+
"lefthook": "^1.7.22",
|
|
45
45
|
"mocha": "^10.7.3",
|
|
46
46
|
"nyc": "^17.1.0",
|
|
47
47
|
"prettier": "^3.3.3",
|
|
48
|
-
"release-it": "^17.
|
|
48
|
+
"release-it": "^17.10.0",
|
|
49
49
|
"rimraf": "^6.0.1",
|
|
50
50
|
"rollup": "^4.24.0",
|
|
51
51
|
"rollup-plugin-dts": "^6.1.1",
|
|
52
52
|
"source-map-support": "^0.5.21",
|
|
53
53
|
"ts-node": "^10.9.2",
|
|
54
|
-
"tslib": "^2.
|
|
55
|
-
"typedoc": "^0.26.
|
|
56
|
-
"typedoc-plugin-mdn-links": "^3.3.
|
|
54
|
+
"tslib": "^2.8.0",
|
|
55
|
+
"typedoc": "^0.26.10",
|
|
56
|
+
"typedoc-plugin-mdn-links": "^3.3.4",
|
|
57
57
|
"typedoc-plugin-replace-text": "^4.0.0",
|
|
58
58
|
"typedoc-plugin-zod": "^1.2.1",
|
|
59
59
|
"typescript": "^5.6.3",
|
|
60
|
-
"typescript-eslint": "^8.
|
|
60
|
+
"typescript-eslint": "^8.11.0"
|
|
61
61
|
},
|
|
62
62
|
"exports": {
|
|
63
63
|
".": {
|
|
@@ -132,5 +132,5 @@
|
|
|
132
132
|
},
|
|
133
133
|
"type": "module",
|
|
134
134
|
"types": "dist/index.d.ts",
|
|
135
|
-
"version": "6.4.
|
|
135
|
+
"version": "6.4.4"
|
|
136
136
|
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var tslib = require('tslib');
|
|
4
|
-
var radash = require('radash');
|
|
5
|
-
var promises = require('timers/promises');
|
|
6
|
-
var conditionalize = require('./conditionalize.js');
|
|
7
|
-
|
|
8
|
-
var _EntityManagerClient_options;
|
|
9
|
-
/**
|
|
10
|
-
* EntityManagerClient base class.
|
|
11
|
-
*
|
|
12
|
-
* @typeParam Options - Options type extended from {@link EntityManagerClientOptions | `EntityManagerClientOptions`}.
|
|
13
|
-
*
|
|
14
|
-
* @category Client
|
|
15
|
-
*/
|
|
16
|
-
class EntityManagerClient {
|
|
17
|
-
/**
|
|
18
|
-
* EntityManagerClient base constructor.
|
|
19
|
-
* @param options - Options object extended from {@link EntityManagerClientOptions | `EntityManagerClientOptions`}.
|
|
20
|
-
*/
|
|
21
|
-
constructor({ batchSize = 25, delayIncrement = 100, maxRetries = 5, throttle = 10, logger = console, logInternals = false, ...childOptions }) {
|
|
22
|
-
_EntityManagerClient_options.set(this, void 0);
|
|
23
|
-
if (!radash.isFunction(logger.debug))
|
|
24
|
-
throw new Error('logger must support debug method');
|
|
25
|
-
if (!radash.isFunction(logger.error))
|
|
26
|
-
throw new Error('logger must support error method');
|
|
27
|
-
tslib.__classPrivateFieldSet(this, _EntityManagerClient_options, {
|
|
28
|
-
batchSize,
|
|
29
|
-
delayIncrement,
|
|
30
|
-
maxRetries,
|
|
31
|
-
throttle,
|
|
32
|
-
logInternals,
|
|
33
|
-
logger: {
|
|
34
|
-
...logger,
|
|
35
|
-
debug: conditionalize.conditionalize(logger.debug, logInternals),
|
|
36
|
-
},
|
|
37
|
-
...childOptions,
|
|
38
|
-
}, "f");
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Returns the options used to create the EntityManagerClient instance.
|
|
42
|
-
*/
|
|
43
|
-
get options() {
|
|
44
|
-
return tslib.__classPrivateFieldGet(this, _EntityManagerClient_options, "f");
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Executes a batch operation.
|
|
48
|
-
*
|
|
49
|
-
* @param items - Items to batch execute.
|
|
50
|
-
* @param executeBatch - Function to execute the batch.
|
|
51
|
-
* @param getUnprocessedItems - Function to get unprocessed items from the output.
|
|
52
|
-
* @param options - Batch options.
|
|
53
|
-
*
|
|
54
|
-
* @typeParam Item - Input item type.
|
|
55
|
-
* @typeParam Output - Output type.
|
|
56
|
-
*
|
|
57
|
-
* @returns Output array.
|
|
58
|
-
*/
|
|
59
|
-
async batchExecute(items, executeBatch, getUnprocessedItems, { batchSize = this.options.batchSize, delayIncrement = this.options.delayIncrement, maxRetries = this.options.maxRetries, throttle = this.options.throttle, } = {}) {
|
|
60
|
-
const batches = radash.cluster(items, batchSize);
|
|
61
|
-
const outputs = [];
|
|
62
|
-
await radash.parallel(throttle, batches, async (batch) => {
|
|
63
|
-
let delay = 0;
|
|
64
|
-
let retry = 0;
|
|
65
|
-
while (batch.length) {
|
|
66
|
-
if (delay)
|
|
67
|
-
await promises.setTimeout(delay);
|
|
68
|
-
const output = await executeBatch(batch);
|
|
69
|
-
this.options.logger.debug('executed batch', {
|
|
70
|
-
batch,
|
|
71
|
-
delay,
|
|
72
|
-
retry,
|
|
73
|
-
output,
|
|
74
|
-
});
|
|
75
|
-
outputs.push(output);
|
|
76
|
-
batch = getUnprocessedItems?.(output) ?? [];
|
|
77
|
-
if (batch.length) {
|
|
78
|
-
if (retry === maxRetries)
|
|
79
|
-
throw new Error('max retries exceeded');
|
|
80
|
-
delay = delay ? delay * 2 : delayIncrement;
|
|
81
|
-
retry++;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
return outputs;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
_EntityManagerClient_options = new WeakMap();
|
|
89
|
-
|
|
90
|
-
exports.EntityManagerClient = EntityManagerClient;
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { __classPrivateFieldSet, __classPrivateFieldGet } from 'tslib';
|
|
2
|
-
import { isFunction, cluster, parallel } from 'radash';
|
|
3
|
-
import { setTimeout } from 'timers/promises';
|
|
4
|
-
import { conditionalize } from './conditionalize.js';
|
|
5
|
-
|
|
6
|
-
var _EntityManagerClient_options;
|
|
7
|
-
/**
|
|
8
|
-
* EntityManagerClient base class.
|
|
9
|
-
*
|
|
10
|
-
* @typeParam Options - Options type extended from {@link EntityManagerClientOptions | `EntityManagerClientOptions`}.
|
|
11
|
-
*
|
|
12
|
-
* @category Client
|
|
13
|
-
*/
|
|
14
|
-
class EntityManagerClient {
|
|
15
|
-
/**
|
|
16
|
-
* EntityManagerClient base constructor.
|
|
17
|
-
* @param options - Options object extended from {@link EntityManagerClientOptions | `EntityManagerClientOptions`}.
|
|
18
|
-
*/
|
|
19
|
-
constructor({ batchSize = 25, delayIncrement = 100, maxRetries = 5, throttle = 10, logger = console, logInternals = false, ...childOptions }) {
|
|
20
|
-
_EntityManagerClient_options.set(this, void 0);
|
|
21
|
-
if (!isFunction(logger.debug))
|
|
22
|
-
throw new Error('logger must support debug method');
|
|
23
|
-
if (!isFunction(logger.error))
|
|
24
|
-
throw new Error('logger must support error method');
|
|
25
|
-
__classPrivateFieldSet(this, _EntityManagerClient_options, {
|
|
26
|
-
batchSize,
|
|
27
|
-
delayIncrement,
|
|
28
|
-
maxRetries,
|
|
29
|
-
throttle,
|
|
30
|
-
logInternals,
|
|
31
|
-
logger: {
|
|
32
|
-
...logger,
|
|
33
|
-
debug: conditionalize(logger.debug, logInternals),
|
|
34
|
-
},
|
|
35
|
-
...childOptions,
|
|
36
|
-
}, "f");
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Returns the options used to create the EntityManagerClient instance.
|
|
40
|
-
*/
|
|
41
|
-
get options() {
|
|
42
|
-
return __classPrivateFieldGet(this, _EntityManagerClient_options, "f");
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Executes a batch operation.
|
|
46
|
-
*
|
|
47
|
-
* @param items - Items to batch execute.
|
|
48
|
-
* @param executeBatch - Function to execute the batch.
|
|
49
|
-
* @param getUnprocessedItems - Function to get unprocessed items from the output.
|
|
50
|
-
* @param options - Batch options.
|
|
51
|
-
*
|
|
52
|
-
* @typeParam Item - Input item type.
|
|
53
|
-
* @typeParam Output - Output type.
|
|
54
|
-
*
|
|
55
|
-
* @returns Output array.
|
|
56
|
-
*/
|
|
57
|
-
async batchExecute(items, executeBatch, getUnprocessedItems, { batchSize = this.options.batchSize, delayIncrement = this.options.delayIncrement, maxRetries = this.options.maxRetries, throttle = this.options.throttle, } = {}) {
|
|
58
|
-
const batches = cluster(items, batchSize);
|
|
59
|
-
const outputs = [];
|
|
60
|
-
await parallel(throttle, batches, async (batch) => {
|
|
61
|
-
let delay = 0;
|
|
62
|
-
let retry = 0;
|
|
63
|
-
while (batch.length) {
|
|
64
|
-
if (delay)
|
|
65
|
-
await setTimeout(delay);
|
|
66
|
-
const output = await executeBatch(batch);
|
|
67
|
-
this.options.logger.debug('executed batch', {
|
|
68
|
-
batch,
|
|
69
|
-
delay,
|
|
70
|
-
retry,
|
|
71
|
-
output,
|
|
72
|
-
});
|
|
73
|
-
outputs.push(output);
|
|
74
|
-
batch = getUnprocessedItems?.(output) ?? [];
|
|
75
|
-
if (batch.length) {
|
|
76
|
-
if (retry === maxRetries)
|
|
77
|
-
throw new Error('max retries exceeded');
|
|
78
|
-
delay = delay ? delay * 2 : delayIncrement;
|
|
79
|
-
retry++;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
return outputs;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
_EntityManagerClient_options = new WeakMap();
|
|
87
|
-
|
|
88
|
-
export { EntityManagerClient };
|