@karmaniverous/entity-manager 6.14.2 → 7.0.0
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 +171 -259
- package/dist/cjs/BaseEntityClient/BaseEntityClient.js +1 -1
- package/dist/cjs/BaseQueryBuilder/BaseQueryBuilder.js +3 -2
- package/dist/cjs/EntityManager/EntityManager.js +2 -2
- package/dist/cjs/EntityManager/createEntityManager.js +42 -0
- package/dist/cjs/EntityManager/decodeGeneratedProperty.js +4 -2
- package/dist/cjs/EntityManager/dehydratePageKeyMap.js +5 -4
- package/dist/cjs/EntityManager/getIndexComponents.js +6 -1
- package/dist/cjs/EntityManager/getPrimaryKey.js +51 -7
- package/dist/cjs/EntityManager/query.js +26 -11
- package/dist/cjs/EntityManager/rehydratePageKeyMap.js +6 -3
- package/dist/cjs/index.js +2 -0
- package/dist/index.d.ts +319 -132
- package/dist/mjs/BaseEntityClient/BaseEntityClient.js +1 -1
- package/dist/mjs/BaseQueryBuilder/BaseQueryBuilder.js +3 -2
- package/dist/mjs/EntityManager/EntityManager.js +2 -2
- package/dist/mjs/EntityManager/createEntityManager.js +40 -0
- package/dist/mjs/EntityManager/decodeGeneratedProperty.js +4 -2
- package/dist/mjs/EntityManager/dehydratePageKeyMap.js +5 -4
- package/dist/mjs/EntityManager/getIndexComponents.js +6 -1
- package/dist/mjs/EntityManager/getPrimaryKey.js +51 -7
- package/dist/mjs/EntityManager/query.js +26 -11
- package/dist/mjs/EntityManager/rehydratePageKeyMap.js +6 -3
- package/dist/mjs/index.js +1 -0
- package/package.json +132 -135
|
@@ -40,8 +40,8 @@ function dehydratePageKeyMap(entityManager, entityToken, pageKeyMap) {
|
|
|
40
40
|
}
|
|
41
41
|
// Extract, sort & validate indexs.
|
|
42
42
|
const indexes = Object.keys(pageKeyMap).sort();
|
|
43
|
-
indexes.map((
|
|
44
|
-
validateIndexToken.validateIndexToken(entityManager,
|
|
43
|
+
indexes.map((indexToken) => {
|
|
44
|
+
validateIndexToken.validateIndexToken(entityManager, indexToken);
|
|
45
45
|
});
|
|
46
46
|
// Extract & sort hash keys.
|
|
47
47
|
const hashKeys = Object.keys(pageKeyMap[indexes[0]]);
|
|
@@ -55,11 +55,12 @@ function dehydratePageKeyMap(entityManager, entityToken, pageKeyMap) {
|
|
|
55
55
|
continue;
|
|
56
56
|
}
|
|
57
57
|
// Compose item from page key
|
|
58
|
-
const
|
|
58
|
+
const pk = pageKeyMap[index][hashKey];
|
|
59
|
+
const item = Object.entries(pk).reduce((item, [property, value]) => {
|
|
59
60
|
if (property === entityManager.config.rangeKey ||
|
|
60
61
|
property in entityManager.config.generatedProperties.sharded ||
|
|
61
62
|
property in entityManager.config.generatedProperties.unsharded)
|
|
62
|
-
Object.assign(item, decodeGeneratedProperty.decodeGeneratedProperty(entityManager, value));
|
|
63
|
+
Object.assign(item, decodeGeneratedProperty.decodeGeneratedProperty(entityManager, entityToken, value));
|
|
63
64
|
else
|
|
64
65
|
Object.assign(item, { [property]: value });
|
|
65
66
|
return item;
|
|
@@ -17,7 +17,12 @@ function getIndexComponents(entityManager, indexToken) {
|
|
|
17
17
|
validateIndexToken.validateIndexToken(entityManager, indexToken);
|
|
18
18
|
const { hashKey, rangeKey, indexes } = entityManager.config;
|
|
19
19
|
const { hashKey: indexHashKey, rangeKey: indexRangeKey } = indexes[indexToken];
|
|
20
|
-
return radash.unique([
|
|
20
|
+
return radash.unique([
|
|
21
|
+
hashKey,
|
|
22
|
+
rangeKey,
|
|
23
|
+
indexHashKey,
|
|
24
|
+
indexRangeKey,
|
|
25
|
+
]);
|
|
21
26
|
}
|
|
22
27
|
|
|
23
28
|
exports.getIndexComponents = getIndexComponents;
|
|
@@ -1,25 +1,69 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var getHashKeySpace = require('./getHashKeySpace.js');
|
|
4
|
+
var updateItemHashKey = require('./updateItemHashKey.js');
|
|
5
|
+
var updateItemRangeKey = require('./updateItemRangeKey.js');
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
|
-
* Convert an {@link EntityItem | `EntityItem`} into
|
|
8
|
+
* Convert an {@link EntityItem | `EntityItem`} into one or more {@link EntityKey | `EntityKey`} values.
|
|
9
|
+
*
|
|
10
|
+
* Behavior:
|
|
11
|
+
* - Always returns an array of keys.
|
|
12
|
+
* - If `overwrite` is false and the item already has both hash and range keys, returns exactly that pair.
|
|
13
|
+
* - Otherwise, computes the range key. Then:
|
|
14
|
+
* - If the timestampProperty is present, computes exactly one hash key and returns a single key.
|
|
15
|
+
* - If the timestampProperty is missing, enumerates the hash-key space across all shard bumps
|
|
16
|
+
* (with uniqueProperty present → one suffix per bump) and returns one key per bump.
|
|
8
17
|
*
|
|
9
18
|
* @param entityManager - {@link EntityManager | `EntityManager`} instance.
|
|
10
19
|
* @param entityToken - {@link Config | `Config`} `entities` key.
|
|
11
20
|
* @param item - {@link EntityItem | `EntityItem`} object.
|
|
12
21
|
* @param overwrite - Overwrite existing properties (default `false`).
|
|
13
22
|
*
|
|
14
|
-
* @returns {@link EntityKey | `EntityKey`}
|
|
23
|
+
* @returns Array of {@link EntityKey | `EntityKey`} values derived from `item`.
|
|
15
24
|
*
|
|
16
25
|
* @throws `Error` if `entityToken` is invalid.
|
|
17
26
|
*/
|
|
18
27
|
function getPrimaryKey(entityManager, entityToken, item, overwrite = false) {
|
|
19
28
|
const { hashKey, rangeKey } = entityManager.config;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
29
|
+
// If both keys are present and we're not overwriting, return the exact pair.
|
|
30
|
+
if (!overwrite && item[hashKey] && item[rangeKey]) {
|
|
31
|
+
return [
|
|
32
|
+
{
|
|
33
|
+
[hashKey]: item[hashKey],
|
|
34
|
+
[rangeKey]: item[rangeKey],
|
|
35
|
+
},
|
|
36
|
+
];
|
|
37
|
+
}
|
|
38
|
+
// Compute/refresh the range key (throws if uniqueProperty missing).
|
|
39
|
+
const withRangeKey = updateItemRangeKey.updateItemRangeKey(entityManager, entityToken, item, true);
|
|
40
|
+
// If timestamp present, compute exactly one hash key and return single pair.
|
|
41
|
+
const tsProp = entityManager.config.entities[entityToken].timestampProperty;
|
|
42
|
+
if (withRangeKey[tsProp] !== undefined) {
|
|
43
|
+
const withHashKey = updateItemHashKey.updateItemHashKey(entityManager, entityToken, withRangeKey, true);
|
|
44
|
+
return [
|
|
45
|
+
{
|
|
46
|
+
[hashKey]: withHashKey[hashKey],
|
|
47
|
+
[rangeKey]: withHashKey[rangeKey],
|
|
48
|
+
},
|
|
49
|
+
];
|
|
50
|
+
}
|
|
51
|
+
// No timestamp: enumerate hash-key space across all shard bumps (0..Infinity).
|
|
52
|
+
const hashKeys = getHashKeySpace.getHashKeySpace(entityManager, entityToken, hashKey, withRangeKey, 0, Infinity);
|
|
53
|
+
// Map to keys and de-duplicate.
|
|
54
|
+
const rk = withRangeKey[rangeKey];
|
|
55
|
+
const seen = new Set();
|
|
56
|
+
const keys = hashKeys
|
|
57
|
+
.map((hk) => {
|
|
58
|
+
const key = { [hashKey]: hk, [rangeKey]: rk };
|
|
59
|
+
const sig = `${hk}|${rk}`;
|
|
60
|
+
if (seen.has(sig))
|
|
61
|
+
return undefined;
|
|
62
|
+
seen.add(sig);
|
|
63
|
+
return key;
|
|
64
|
+
})
|
|
65
|
+
.filter((k) => !!k);
|
|
66
|
+
return keys;
|
|
23
67
|
}
|
|
24
68
|
|
|
25
69
|
exports.getPrimaryKey = getPrimaryKey;
|
|
@@ -58,17 +58,20 @@ async function query(entityManager, options) {
|
|
|
58
58
|
// items, which may be >> limit. Probably the way to fix entityManager is to limit the number of shards queried per
|
|
59
59
|
// iteration in order to keep shardsQueried * pageSize > (limit - items.length) but only just.
|
|
60
60
|
// TODO: Test for invalid characters (path delimiters) in index keys & shard key values.
|
|
61
|
+
// Build typed tasks (indexToken, hashKey, pageKey).
|
|
62
|
+
const tasks = [];
|
|
63
|
+
for (const [indexToken, indexPageKeys] of Object.entries(rehydratedPageKeyMap)) {
|
|
64
|
+
for (const [hashKey, pk] of Object.entries(indexPageKeys)) {
|
|
65
|
+
tasks.push([indexToken, hashKey, pk]);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
61
68
|
// Query every shard on every index in pageKeyMap.
|
|
62
|
-
const shardQueryResults = await radash.parallel(throttle,
|
|
63
|
-
indexToken,
|
|
64
|
-
hashKey,
|
|
65
|
-
pageKey,
|
|
66
|
-
])), async ([indexToken, hashKey, pageKey]) => ({
|
|
69
|
+
const shardQueryResults = await radash.parallel(throttle, tasks, async ([indexToken, hashKey, pageKey]) => ({
|
|
67
70
|
indexToken,
|
|
68
71
|
queryResult: await shardQueryMap[indexToken](hashKey, pageKey, pageSize),
|
|
69
72
|
hashKey,
|
|
70
73
|
}));
|
|
71
|
-
// Reduce shardQueryResults &
|
|
74
|
+
// Reduce shardQueryResults & update working result.
|
|
72
75
|
workingResult = shardQueryResults.reduce(({ items, pageKeyMap }, { indexToken, queryResult, hashKey }) => {
|
|
73
76
|
Object.assign(rehydratedPageKeyMap[indexToken], {
|
|
74
77
|
[hashKey]: queryResult.pageKey,
|
|
@@ -78,12 +81,24 @@ async function query(entityManager, options) {
|
|
|
78
81
|
pageKeyMap,
|
|
79
82
|
};
|
|
80
83
|
}, workingResult);
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
84
|
+
// Repeat while pages remain & limit is not reached.
|
|
85
|
+
let pagesRemain = false;
|
|
86
|
+
for (const idx of Object.keys(workingResult.pageKeyMap)) {
|
|
87
|
+
const inner = workingResult.pageKeyMap[idx];
|
|
88
|
+
for (const h of Object.keys(inner)) {
|
|
89
|
+
if (inner[h] !== undefined) {
|
|
90
|
+
pagesRemain = true;
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (pagesRemain)
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
if (!pagesRemain)
|
|
98
|
+
break;
|
|
99
|
+
} while (workingResult.items.length < limit);
|
|
85
100
|
// Dedupe & sort working result.
|
|
86
|
-
workingResult.items = entityTools.sort(radash.unique(workingResult.items, (
|
|
101
|
+
workingResult.items = entityTools.sort(radash.unique(workingResult.items, (i) => i[entityManager.config.entities[entityToken]
|
|
87
102
|
.uniqueProperty].toString()), sortOrder);
|
|
88
103
|
const result = {
|
|
89
104
|
count: workingResult.items.length,
|
|
@@ -38,7 +38,7 @@ function rehydratePageKeyMap(entityManager, entityToken, indexTokens, item, dehy
|
|
|
38
38
|
// Validate indexTokens populated.
|
|
39
39
|
if (!indexTokens.length)
|
|
40
40
|
throw new Error('indexTokens empty');
|
|
41
|
-
// Validate indexTokens exist.
|
|
41
|
+
// Validate indexTokens exist and capture hashKeys.
|
|
42
42
|
const hashKeys = radash.unique(indexTokens.map((indexToken) => {
|
|
43
43
|
validateIndexToken.validateIndexToken(entityManager, indexToken);
|
|
44
44
|
return entityManager.config.indexes[indexToken].hashKey;
|
|
@@ -52,7 +52,10 @@ function rehydratePageKeyMap(entityManager, entityToken, indexTokens, item, dehy
|
|
|
52
52
|
});
|
|
53
53
|
// Shortcut empty dehydrated.
|
|
54
54
|
if (dehydrated && !dehydrated.length)
|
|
55
|
-
return [
|
|
55
|
+
return [
|
|
56
|
+
hashKeyToken,
|
|
57
|
+
{},
|
|
58
|
+
];
|
|
56
59
|
// Get hash key space.
|
|
57
60
|
const hashKeySpace = getHashKeySpace.getHashKeySpace(entityManager, entityToken, hashKeyToken, item, timestampFrom, timestampTo);
|
|
58
61
|
// Default dehydrated.
|
|
@@ -68,7 +71,7 @@ function rehydratePageKeyMap(entityManager, entityToken, indexTokens, item, dehy
|
|
|
68
71
|
if (!dehydratedIndexPageKeyMaps[i])
|
|
69
72
|
return;
|
|
70
73
|
let pageKeyItem = {
|
|
71
|
-
...decodeGeneratedProperty.decodeGeneratedProperty(entityManager, hashKey),
|
|
74
|
+
...decodeGeneratedProperty.decodeGeneratedProperty(entityManager, entityToken, hashKey),
|
|
72
75
|
...rehydrateIndexItem.rehydrateIndexItem(entityManager, entityToken, index, dehydratedIndexPageKeyMaps[i]),
|
|
73
76
|
};
|
|
74
77
|
pageKeyItem = updateItemRangeKey.updateItemRangeKey(entityManager, entityToken, pageKeyItem);
|
package/dist/cjs/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var BaseEntityClient = require('./BaseEntityClient/BaseEntityClient.js');
|
|
4
4
|
var BaseQueryBuilder = require('./BaseQueryBuilder/BaseQueryBuilder.js');
|
|
5
|
+
var createEntityManager = require('./EntityManager/createEntityManager.js');
|
|
5
6
|
var EntityManager = require('./EntityManager/EntityManager.js');
|
|
6
7
|
var ParsedConfig = require('./EntityManager/ParsedConfig.js');
|
|
7
8
|
|
|
@@ -9,5 +10,6 @@ var ParsedConfig = require('./EntityManager/ParsedConfig.js');
|
|
|
9
10
|
|
|
10
11
|
exports.BaseEntityClient = BaseEntityClient.BaseEntityClient;
|
|
11
12
|
exports.BaseQueryBuilder = BaseQueryBuilder.BaseQueryBuilder;
|
|
13
|
+
exports.createEntityManager = createEntityManager.createEntityManager;
|
|
12
14
|
exports.EntityManager = EntityManager.EntityManager;
|
|
13
15
|
exports.configSchema = ParsedConfig.configSchema;
|