@karmaniverous/entity-manager 2.0.0 → 2.1.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
CHANGED
|
@@ -220,6 +220,9 @@ This change can be accomplished with no breaking changes to existing implementat
|
|
|
220
220
|
* [.EntityManager](#module_entity-manager.EntityManager)
|
|
221
221
|
* [new exports.EntityManager(options)](#new_module_entity-manager.EntityManager_new)
|
|
222
222
|
* [.addKeys(entityToken, item, [overwrite])](#module_entity-manager.EntityManager+addKeys) ⇒ <code>object</code>
|
|
223
|
+
* [.calcShardKey(entityToken, item)](#module_entity-manager.EntityManager+calcShardKey) ⇒ <code>string</code>
|
|
224
|
+
* [.dehydrateIndex(entityToken, indexToken, item, [delimiter])](#module_entity-manager.EntityManager+dehydrateIndex) ⇒ <code>string</code>
|
|
225
|
+
* [.rehydrateIndex(entityToken, indexToken, value, [delimiter])](#module_entity-manager.EntityManager+rehydrateIndex) ⇒ <code>object</code>
|
|
223
226
|
* [.getKeySpace(entityToken, keyToken, item, timestamp)](#module_entity-manager.EntityManager+getKeySpace) ⇒ <code>Array.<string></code>
|
|
224
227
|
* [.query(entityToken, keyToken, item, shardQuery, [options])](#module_entity-manager.EntityManager+query) ⇒ <code>Promise.<ShardedQueryResult></code>
|
|
225
228
|
* [.removeKeys(entityToken, item)](#module_entity-manager.EntityManager+removeKeys) ⇒ <code>object</code>
|
|
@@ -238,6 +241,9 @@ Manage DynamoDb entities.
|
|
|
238
241
|
* [.EntityManager](#module_entity-manager.EntityManager)
|
|
239
242
|
* [new exports.EntityManager(options)](#new_module_entity-manager.EntityManager_new)
|
|
240
243
|
* [.addKeys(entityToken, item, [overwrite])](#module_entity-manager.EntityManager+addKeys) ⇒ <code>object</code>
|
|
244
|
+
* [.calcShardKey(entityToken, item)](#module_entity-manager.EntityManager+calcShardKey) ⇒ <code>string</code>
|
|
245
|
+
* [.dehydrateIndex(entityToken, indexToken, item, [delimiter])](#module_entity-manager.EntityManager+dehydrateIndex) ⇒ <code>string</code>
|
|
246
|
+
* [.rehydrateIndex(entityToken, indexToken, value, [delimiter])](#module_entity-manager.EntityManager+rehydrateIndex) ⇒ <code>object</code>
|
|
241
247
|
* [.getKeySpace(entityToken, keyToken, item, timestamp)](#module_entity-manager.EntityManager+getKeySpace) ⇒ <code>Array.<string></code>
|
|
242
248
|
* [.query(entityToken, keyToken, item, shardQuery, [options])](#module_entity-manager.EntityManager+query) ⇒ <code>Promise.<ShardedQueryResult></code>
|
|
243
249
|
* [.removeKeys(entityToken, item)](#module_entity-manager.EntityManager+removeKeys) ⇒ <code>object</code>
|
|
@@ -279,6 +285,60 @@ Add sharded keys to an entity item. Does not mutate original item.
|
|
|
279
285
|
| item | <code>object</code> | | Entity item. |
|
|
280
286
|
| [overwrite] | <code>boolean</code> | <code>false</code> | Overwrite existing properties. |
|
|
281
287
|
|
|
288
|
+
<a name="module_entity-manager.EntityManager+calcShardKey"></a>
|
|
289
|
+
|
|
290
|
+
#### entityManager.calcShardKey(entityToken, item) ⇒ <code>string</code>
|
|
291
|
+
Calculated the shard key for an entity item.
|
|
292
|
+
|
|
293
|
+
**Kind**: instance method of [<code>EntityManager</code>](#module_entity-manager.EntityManager)
|
|
294
|
+
**Returns**: <code>string</code> - Shard key.
|
|
295
|
+
|
|
296
|
+
| Param | Type | Description |
|
|
297
|
+
| --- | --- | --- |
|
|
298
|
+
| entityToken | <code>string</code> | Entity token. |
|
|
299
|
+
| item | <code>object</code> | Entity item. |
|
|
300
|
+
|
|
301
|
+
<a name="module_entity-manager.EntityManager+dehydrateIndex"></a>
|
|
302
|
+
|
|
303
|
+
#### entityManager.dehydrateIndex(entityToken, indexToken, item, [delimiter]) ⇒ <code>string</code>
|
|
304
|
+
Convert a item into a delimited string containing the properties of a named index.
|
|
305
|
+
|
|
306
|
+
**Kind**: instance method of [<code>EntityManager</code>](#module_entity-manager.EntityManager)
|
|
307
|
+
**Returns**: <code>string</code> - Dehydrated index.
|
|
308
|
+
**Throws**:
|
|
309
|
+
|
|
310
|
+
- <code>Error</code> If entityToken is invalid.
|
|
311
|
+
- <code>Error</code> If indexToken is invalid.
|
|
312
|
+
- <code>Error</code> If item is invalid.
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
| Param | Type | Default | Description |
|
|
316
|
+
| --- | --- | --- | --- |
|
|
317
|
+
| entityToken | <code>string</code> | | Entity token. |
|
|
318
|
+
| indexToken | <code>string</code> | | Index token. |
|
|
319
|
+
| item | <code>object</code> | | Entity item. |
|
|
320
|
+
| [delimiter] | <code>string</code> | <code>"~"</code> | Delimiter. |
|
|
321
|
+
|
|
322
|
+
<a name="module_entity-manager.EntityManager+rehydrateIndex"></a>
|
|
323
|
+
|
|
324
|
+
#### entityManager.rehydrateIndex(entityToken, indexToken, value, [delimiter]) ⇒ <code>object</code>
|
|
325
|
+
Convert a delimited string into a named index key.
|
|
326
|
+
|
|
327
|
+
**Kind**: instance method of [<code>EntityManager</code>](#module_entity-manager.EntityManager)
|
|
328
|
+
**Returns**: <code>object</code> - Rehydrated index key.
|
|
329
|
+
**Throws**:
|
|
330
|
+
|
|
331
|
+
- <code>Error</code> If entityToken is invalid.
|
|
332
|
+
- <code>Error</code> If indexToken is invalid.
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
| Param | Type | Default | Description |
|
|
336
|
+
| --- | --- | --- | --- |
|
|
337
|
+
| entityToken | <code>string</code> | | Entity token. |
|
|
338
|
+
| indexToken | <code>string</code> | | Index token. |
|
|
339
|
+
| value | <code>string</code> | | Dehydrated index value. |
|
|
340
|
+
| [delimiter] | <code>string</code> | <code>"~"</code> | Delimiter. |
|
|
341
|
+
|
|
282
342
|
<a name="module_entity-manager.EntityManager+getKeySpace"></a>
|
|
283
343
|
|
|
284
344
|
#### entityManager.getKeySpace(entityToken, keyToken, item, timestamp) ⇒ <code>Array.<string></code>
|
|
@@ -13,9 +13,16 @@ var _isInteger2 = _interopRequireDefault(require("lodash/isInteger"));
|
|
|
13
13
|
var _isUndefined2 = _interopRequireDefault(require("lodash/isUndefined"));
|
|
14
14
|
var _isFunction2 = _interopRequireDefault(require("lodash/isFunction"));
|
|
15
15
|
var _sortedUniq2 = _interopRequireDefault(require("lodash/sortedUniq"));
|
|
16
|
+
var _zipObject2 = _interopRequireDefault(require("lodash/zipObject"));
|
|
17
|
+
var _flatten2 = _interopRequireDefault(require("lodash/flatten"));
|
|
18
|
+
var _uniq2 = _interopRequireDefault(require("lodash/uniq"));
|
|
19
|
+
var _sortBy2 = _interopRequireDefault(require("lodash/sortBy"));
|
|
20
|
+
var _pick2 = _interopRequireDefault(require("lodash/pick"));
|
|
21
|
+
var _values2 = _interopRequireDefault(require("lodash/values"));
|
|
16
22
|
var _forEach2 = _interopRequireDefault(require("lodash/forEach"));
|
|
17
23
|
var _isNil2 = _interopRequireDefault(require("lodash/isNil"));
|
|
18
24
|
var _cloneDeep2 = _interopRequireDefault(require("lodash/cloneDeep"));
|
|
25
|
+
var _inspectParametersDeclaration = require("inspect-parameters-declaration");
|
|
19
26
|
var _PrivateEntityManager = require("./PrivateEntityManager.js");
|
|
20
27
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
21
28
|
function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); }
|
|
@@ -26,6 +33,7 @@ function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _
|
|
|
26
33
|
function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); }
|
|
27
34
|
function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } }
|
|
28
35
|
var _entityManager = /*#__PURE__*/new WeakMap();
|
|
36
|
+
var _getIndexProperties = /*#__PURE__*/new WeakMap();
|
|
29
37
|
/**
|
|
30
38
|
* Manage DynamoDb entities.
|
|
31
39
|
*
|
|
@@ -51,6 +59,10 @@ class EntityManager {
|
|
|
51
59
|
writable: true,
|
|
52
60
|
value: void 0
|
|
53
61
|
});
|
|
62
|
+
_classPrivateFieldInitSpec(this, _getIndexProperties, {
|
|
63
|
+
writable: true,
|
|
64
|
+
value: (entityToken, indexComponents) => (0, _sortBy2.default)((0, _uniq2.default)((0, _flatten2.default)(indexComponents.map(keyToken => (0, _inspectParametersDeclaration.getParametersNames)(_classPrivateFieldGet(this, _entityManager).getKeyGenerator(entityToken, keyToken))))))
|
|
65
|
+
});
|
|
54
66
|
_classPrivateFieldSet(this, _entityManager, new _PrivateEntityManager.PrivateEntityManager({
|
|
55
67
|
config,
|
|
56
68
|
logger
|
|
@@ -82,15 +94,12 @@ class EntityManager {
|
|
|
82
94
|
shardKeyToken
|
|
83
95
|
} = _classPrivateFieldGet(this, _entityManager);
|
|
84
96
|
const {
|
|
85
|
-
keys
|
|
86
|
-
sharding
|
|
97
|
+
keys
|
|
87
98
|
} = _classPrivateFieldGet(this, _entityManager).getEntityConfig(entityToken);
|
|
88
99
|
|
|
89
100
|
// Add shardKey.
|
|
90
101
|
if (overwrite || (0, _isNil2.default)(newItem[shardKeyToken])) {
|
|
91
|
-
|
|
92
|
-
const timestamp = sharding.timestamp(newItem);
|
|
93
|
-
newItem[shardKeyToken] = _classPrivateFieldGet(this, _entityManager).getShardKey(entityToken, entityKey, timestamp);
|
|
102
|
+
newItem[shardKeyToken] = this.calcShardKey(entityToken, newItem);
|
|
94
103
|
}
|
|
95
104
|
|
|
96
105
|
// Add keys.
|
|
@@ -104,6 +113,71 @@ class EntityManager {
|
|
|
104
113
|
return newItem;
|
|
105
114
|
}
|
|
106
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Calculated the shard key for an entity item.
|
|
118
|
+
*
|
|
119
|
+
* @param {string} entityToken - Entity token.
|
|
120
|
+
* @param {object} item - Entity item.
|
|
121
|
+
* @returns {string} Shard key.
|
|
122
|
+
*/
|
|
123
|
+
calcShardKey(entityToken, item) {
|
|
124
|
+
const {
|
|
125
|
+
sharding
|
|
126
|
+
} = _classPrivateFieldGet(this, _entityManager).getEntityConfig(entityToken);
|
|
127
|
+
const entityKey = sharding.entityKey(item);
|
|
128
|
+
const timestamp = sharding.timestamp(item);
|
|
129
|
+
return _classPrivateFieldGet(this, _entityManager).getShardKey(entityToken, entityKey, timestamp);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Convert a item into a delimited string containing the properties of a named index.
|
|
134
|
+
*
|
|
135
|
+
* @param {string} entityToken - Entity token.
|
|
136
|
+
* @param {string} indexToken - Index token.
|
|
137
|
+
* @param {object} item - Entity item.
|
|
138
|
+
* @param {string} [delimiter] - Delimiter.
|
|
139
|
+
* @returns {string} Dehydrated index.
|
|
140
|
+
* @throws {Error} If entityToken is invalid.
|
|
141
|
+
* @throws {Error} If indexToken is invalid.
|
|
142
|
+
* @throws {Error} If item is invalid.
|
|
143
|
+
*/
|
|
144
|
+
dehydrateIndex(entityToken, indexToken, item) {
|
|
145
|
+
let delimiter = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : '~';
|
|
146
|
+
// Validate item.
|
|
147
|
+
_classPrivateFieldGet(this, _entityManager).validateItem(item);
|
|
148
|
+
const indexComponents = _classPrivateFieldGet(this, _entityManager).getIndexComponents(entityToken, indexToken);
|
|
149
|
+
const indexProperties = _classPrivateFieldGet(this, _getIndexProperties).call(this, entityToken, indexComponents);
|
|
150
|
+
const {
|
|
151
|
+
shardKeyToken
|
|
152
|
+
} = _classPrivateFieldGet(this, _entityManager);
|
|
153
|
+
return (0, _values2.default)((0, _pick2.default)({
|
|
154
|
+
...item,
|
|
155
|
+
[shardKeyToken]: this.calcShardKey(entityToken, item)
|
|
156
|
+
}, indexProperties)).join(delimiter);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Convert a delimited string into a named index key.
|
|
160
|
+
*
|
|
161
|
+
* @param {string} entityToken - Entity token.
|
|
162
|
+
* @param {string} indexToken - Index token.
|
|
163
|
+
* @param {string} value - Dehydrated index value.
|
|
164
|
+
* @param {string} [delimiter] - Delimiter.
|
|
165
|
+
* @returns {object} Rehydrated index key.
|
|
166
|
+
* @throws {Error} If entityToken is invalid.
|
|
167
|
+
* @throws {Error} If indexToken is invalid.
|
|
168
|
+
*/
|
|
169
|
+
rehydrateIndex(entityToken, indexToken) {
|
|
170
|
+
let value = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
|
|
171
|
+
let delimiter = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : '~';
|
|
172
|
+
const indexComponents = _classPrivateFieldGet(this, _entityManager).getIndexComponents(entityToken, indexToken);
|
|
173
|
+
const indexProperties = _classPrivateFieldGet(this, _getIndexProperties).call(this, entityToken, indexComponents);
|
|
174
|
+
const item = (0, _zipObject2.default)(indexProperties, value.split(delimiter));
|
|
175
|
+
return indexComponents.reduce((index, component) => ({
|
|
176
|
+
...index,
|
|
177
|
+
[component]: _classPrivateFieldGet(this, _entityManager).getKeyGenerator(entityToken, component)(item)
|
|
178
|
+
}), {});
|
|
179
|
+
}
|
|
180
|
+
|
|
107
181
|
/**
|
|
108
182
|
* Return an array of sharded keys valid for a given entity token & timestamp.
|
|
109
183
|
*
|
|
@@ -14,6 +14,8 @@ var _has2 = _interopRequireDefault(require("lodash/has"));
|
|
|
14
14
|
var _map2 = _interopRequireDefault(require("lodash/map"));
|
|
15
15
|
var _isFunction2 = _interopRequireDefault(require("lodash/isFunction"));
|
|
16
16
|
var _isNil2 = _interopRequireDefault(require("lodash/isNil"));
|
|
17
|
+
var _keys2 = _interopRequireDefault(require("lodash/keys"));
|
|
18
|
+
var _difference2 = _interopRequireDefault(require("lodash/difference"));
|
|
17
19
|
var _some2 = _interopRequireDefault(require("lodash/some"));
|
|
18
20
|
var _toPairs2 = _interopRequireDefault(require("lodash/toPairs"));
|
|
19
21
|
var _sortBy2 = _interopRequireDefault(require("lodash/sortBy"));
|
|
@@ -43,6 +45,16 @@ const configSchema = {
|
|
|
43
45
|
'^\\w+$': {
|
|
44
46
|
type: 'object',
|
|
45
47
|
properties: {
|
|
48
|
+
indexes: {
|
|
49
|
+
type: 'object',
|
|
50
|
+
additionalProperties: {
|
|
51
|
+
type: 'array',
|
|
52
|
+
items: {
|
|
53
|
+
type: 'string'
|
|
54
|
+
},
|
|
55
|
+
minItems: 1
|
|
56
|
+
}
|
|
57
|
+
},
|
|
46
58
|
keys: {
|
|
47
59
|
type: 'object'
|
|
48
60
|
},
|
|
@@ -160,6 +172,7 @@ class PrivateEntityManager {
|
|
|
160
172
|
const conformedConfig = {
|
|
161
173
|
entities: (0, _mapValues2.default)(entities, _ref => {
|
|
162
174
|
let {
|
|
175
|
+
indexes = {},
|
|
163
176
|
keys = {},
|
|
164
177
|
sharding: {
|
|
165
178
|
bumps = {},
|
|
@@ -170,6 +183,7 @@ class PrivateEntityManager {
|
|
|
170
183
|
} = {}
|
|
171
184
|
} = _ref;
|
|
172
185
|
return {
|
|
186
|
+
indexes,
|
|
173
187
|
keys,
|
|
174
188
|
sharding: {
|
|
175
189
|
bumps: (0, _fromPairs2.default)((0, _sortBy2.default)((0, _toPairs2.default)(bumps), 0)),
|
|
@@ -186,6 +200,7 @@ class PrivateEntityManager {
|
|
|
186
200
|
// Validate entity properties.
|
|
187
201
|
(0, _some2.default)(conformedConfig.entities, (_ref2, entityToken) => {
|
|
188
202
|
let {
|
|
203
|
+
indexes,
|
|
189
204
|
keys,
|
|
190
205
|
sharding: {
|
|
191
206
|
bumps,
|
|
@@ -195,6 +210,16 @@ class PrivateEntityManager {
|
|
|
195
210
|
timestamp
|
|
196
211
|
}
|
|
197
212
|
} = _ref2;
|
|
213
|
+
// Validate entity index components are entity keys.
|
|
214
|
+
(0, _some2.default)(indexes, (index, indexToken) => {
|
|
215
|
+
const invalidIndexComponents = (0, _difference2.default)(index, (0, _keys2.default)(keys));
|
|
216
|
+
if (invalidIndexComponents.length) {
|
|
217
|
+
const message = `${entityToken} index '${indexToken}' components '${invalidIndexComponents}' are not entity keys.`;
|
|
218
|
+
this.logger.error(message);
|
|
219
|
+
throw new Error(message);
|
|
220
|
+
} else return false;
|
|
221
|
+
});
|
|
222
|
+
|
|
198
223
|
// Validate entity keys are functions or undefined.
|
|
199
224
|
(0, _some2.default)(keys, (value, key) => {
|
|
200
225
|
if (!(0, _isNil2.default)(value) && !(0, _isFunction2.default)(value)) {
|
|
@@ -284,6 +309,17 @@ class PrivateEntityManager {
|
|
|
284
309
|
this.validateEntityToken(entityToken);
|
|
285
310
|
return this.config.entities[entityToken];
|
|
286
311
|
}
|
|
312
|
+
getIndexComponents(entityToken, indexToken) {
|
|
313
|
+
const {
|
|
314
|
+
indexes
|
|
315
|
+
} = this.getEntityConfig(entityToken);
|
|
316
|
+
if (!(0, _has2.default)(indexes, indexToken)) {
|
|
317
|
+
const message = `Index '${indexToken}' does not exist for entity '${entityToken}'.`;
|
|
318
|
+
this.logger.error(message);
|
|
319
|
+
throw new Error(message);
|
|
320
|
+
}
|
|
321
|
+
return indexes[indexToken];
|
|
322
|
+
}
|
|
287
323
|
getKeyGenerator(entityToken, keyToken) {
|
|
288
324
|
const {
|
|
289
325
|
keys
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* @module entity-manager
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { getParametersNames } from 'inspect-parameters-declaration';
|
|
5
6
|
import _ from 'lodash';
|
|
6
7
|
|
|
7
8
|
import { PrivateEntityManager } from './PrivateEntityManager.js';
|
|
@@ -54,17 +55,11 @@ export class EntityManager {
|
|
|
54
55
|
|
|
55
56
|
// Get entity config.
|
|
56
57
|
const { shardKeyToken } = this.#entityManager;
|
|
57
|
-
const { keys
|
|
58
|
+
const { keys } = this.#entityManager.getEntityConfig(entityToken);
|
|
58
59
|
|
|
59
60
|
// Add shardKey.
|
|
60
61
|
if (overwrite || _.isNil(newItem[shardKeyToken])) {
|
|
61
|
-
|
|
62
|
-
const timestamp = sharding.timestamp(newItem);
|
|
63
|
-
newItem[shardKeyToken] = this.#entityManager.getShardKey(
|
|
64
|
-
entityToken,
|
|
65
|
-
entityKey,
|
|
66
|
-
timestamp
|
|
67
|
-
);
|
|
62
|
+
newItem[shardKeyToken] = this.calcShardKey(entityToken, newItem);
|
|
68
63
|
}
|
|
69
64
|
|
|
70
65
|
// Add keys.
|
|
@@ -79,6 +74,108 @@ export class EntityManager {
|
|
|
79
74
|
return newItem;
|
|
80
75
|
}
|
|
81
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Calculated the shard key for an entity item.
|
|
79
|
+
*
|
|
80
|
+
* @param {string} entityToken - Entity token.
|
|
81
|
+
* @param {object} item - Entity item.
|
|
82
|
+
* @returns {string} Shard key.
|
|
83
|
+
*/
|
|
84
|
+
calcShardKey(entityToken, item) {
|
|
85
|
+
const { sharding } = this.#entityManager.getEntityConfig(entityToken);
|
|
86
|
+
const entityKey = sharding.entityKey(item);
|
|
87
|
+
const timestamp = sharding.timestamp(item);
|
|
88
|
+
|
|
89
|
+
return this.#entityManager.getShardKey(entityToken, entityKey, timestamp);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Convert a item into a delimited string containing the properties of a named index.
|
|
94
|
+
*
|
|
95
|
+
* @param {string} entityToken - Entity token.
|
|
96
|
+
* @param {string} indexToken - Index token.
|
|
97
|
+
* @param {object} item - Entity item.
|
|
98
|
+
* @param {string} [delimiter] - Delimiter.
|
|
99
|
+
* @returns {string} Dehydrated index.
|
|
100
|
+
* @throws {Error} If entityToken is invalid.
|
|
101
|
+
* @throws {Error} If indexToken is invalid.
|
|
102
|
+
* @throws {Error} If item is invalid.
|
|
103
|
+
*/
|
|
104
|
+
dehydrateIndex(entityToken, indexToken, item, delimiter = '~') {
|
|
105
|
+
// Validate item.
|
|
106
|
+
this.#entityManager.validateItem(item);
|
|
107
|
+
|
|
108
|
+
const indexComponents = this.#entityManager.getIndexComponents(
|
|
109
|
+
entityToken,
|
|
110
|
+
indexToken
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
const indexProperties = this.#getIndexProperties(
|
|
114
|
+
entityToken,
|
|
115
|
+
indexComponents
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const { shardKeyToken } = this.#entityManager;
|
|
119
|
+
return _.values(
|
|
120
|
+
_.pick(
|
|
121
|
+
{
|
|
122
|
+
...item,
|
|
123
|
+
[shardKeyToken]: this.calcShardKey(entityToken, item),
|
|
124
|
+
},
|
|
125
|
+
indexProperties
|
|
126
|
+
)
|
|
127
|
+
).join(delimiter);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
#getIndexProperties = (entityToken, indexComponents) =>
|
|
131
|
+
_.sortBy(
|
|
132
|
+
_.uniq(
|
|
133
|
+
_.flatten(
|
|
134
|
+
indexComponents.map((keyToken) =>
|
|
135
|
+
getParametersNames(
|
|
136
|
+
this.#entityManager.getKeyGenerator(entityToken, keyToken)
|
|
137
|
+
)
|
|
138
|
+
)
|
|
139
|
+
)
|
|
140
|
+
)
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Convert a delimited string into a named index key.
|
|
145
|
+
*
|
|
146
|
+
* @param {string} entityToken - Entity token.
|
|
147
|
+
* @param {string} indexToken - Index token.
|
|
148
|
+
* @param {string} value - Dehydrated index value.
|
|
149
|
+
* @param {string} [delimiter] - Delimiter.
|
|
150
|
+
* @returns {object} Rehydrated index key.
|
|
151
|
+
* @throws {Error} If entityToken is invalid.
|
|
152
|
+
* @throws {Error} If indexToken is invalid.
|
|
153
|
+
*/
|
|
154
|
+
rehydrateIndex(entityToken, indexToken, value = '', delimiter = '~') {
|
|
155
|
+
const indexComponents = this.#entityManager.getIndexComponents(
|
|
156
|
+
entityToken,
|
|
157
|
+
indexToken
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
const indexProperties = this.#getIndexProperties(
|
|
161
|
+
entityToken,
|
|
162
|
+
indexComponents
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
const item = _.zipObject(indexProperties, value.split(delimiter));
|
|
166
|
+
|
|
167
|
+
return indexComponents.reduce(
|
|
168
|
+
(index, component) => ({
|
|
169
|
+
...index,
|
|
170
|
+
[component]: this.#entityManager.getKeyGenerator(
|
|
171
|
+
entityToken,
|
|
172
|
+
component
|
|
173
|
+
)(item),
|
|
174
|
+
}),
|
|
175
|
+
{}
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
82
179
|
/**
|
|
83
180
|
* Return an array of sharded keys valid for a given entity token & timestamp.
|
|
84
181
|
*
|
|
@@ -16,6 +16,16 @@ const configSchema = {
|
|
|
16
16
|
'^\\w+$': {
|
|
17
17
|
type: 'object',
|
|
18
18
|
properties: {
|
|
19
|
+
indexes: {
|
|
20
|
+
type: 'object',
|
|
21
|
+
additionalProperties: {
|
|
22
|
+
type: 'array',
|
|
23
|
+
items: {
|
|
24
|
+
type: 'string',
|
|
25
|
+
},
|
|
26
|
+
minItems: 1,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
19
29
|
keys: {
|
|
20
30
|
type: 'object',
|
|
21
31
|
},
|
|
@@ -117,6 +127,7 @@ export class PrivateEntityManager {
|
|
|
117
127
|
entities: _.mapValues(
|
|
118
128
|
entities,
|
|
119
129
|
({
|
|
130
|
+
indexes = {},
|
|
120
131
|
keys = {},
|
|
121
132
|
sharding: {
|
|
122
133
|
bumps = {},
|
|
@@ -126,6 +137,7 @@ export class PrivateEntityManager {
|
|
|
126
137
|
timestamp,
|
|
127
138
|
} = {},
|
|
128
139
|
}) => ({
|
|
140
|
+
indexes,
|
|
129
141
|
keys,
|
|
130
142
|
sharding: {
|
|
131
143
|
bumps: _.fromPairs(_.sortBy(_.toPairs(bumps), 0)),
|
|
@@ -144,11 +156,22 @@ export class PrivateEntityManager {
|
|
|
144
156
|
conformedConfig.entities,
|
|
145
157
|
(
|
|
146
158
|
{
|
|
159
|
+
indexes,
|
|
147
160
|
keys,
|
|
148
161
|
sharding: { bumps, entityKey, nibbleBits, nibbles, timestamp },
|
|
149
162
|
},
|
|
150
163
|
entityToken
|
|
151
164
|
) => {
|
|
165
|
+
// Validate entity index components are entity keys.
|
|
166
|
+
_.some(indexes, (index, indexToken) => {
|
|
167
|
+
const invalidIndexComponents = _.difference(index, _.keys(keys));
|
|
168
|
+
if (invalidIndexComponents.length) {
|
|
169
|
+
const message = `${entityToken} index '${indexToken}' components '${invalidIndexComponents}' are not entity keys.`;
|
|
170
|
+
this.logger.error(message);
|
|
171
|
+
throw new Error(message);
|
|
172
|
+
} else return false;
|
|
173
|
+
});
|
|
174
|
+
|
|
152
175
|
// Validate entity keys are functions or undefined.
|
|
153
176
|
_.some(keys, (value, key) => {
|
|
154
177
|
if (!_.isNil(value) && !_.isFunction(value)) {
|
|
@@ -240,6 +263,18 @@ export class PrivateEntityManager {
|
|
|
240
263
|
return this.config.entities[entityToken];
|
|
241
264
|
}
|
|
242
265
|
|
|
266
|
+
getIndexComponents(entityToken, indexToken) {
|
|
267
|
+
const { indexes } = this.getEntityConfig(entityToken);
|
|
268
|
+
|
|
269
|
+
if (!_.has(indexes, indexToken)) {
|
|
270
|
+
const message = `Index '${indexToken}' does not exist for entity '${entityToken}'.`;
|
|
271
|
+
this.logger.error(message);
|
|
272
|
+
throw new Error(message);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return indexes[indexToken];
|
|
276
|
+
}
|
|
277
|
+
|
|
243
278
|
getKeyGenerator(entityToken, keyToken) {
|
|
244
279
|
const { keys } = this.getEntityConfig(entityToken);
|
|
245
280
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@karmaniverous/entity-manager",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
],
|
|
21
21
|
"license": "BSD-3-Clause",
|
|
22
22
|
"dependencies": {
|
|
23
|
+
"inspect-parameters-declaration": "^0.1.0",
|
|
23
24
|
"jsonschema": "^1.4.1",
|
|
24
25
|
"lodash": "^4.17.21",
|
|
25
26
|
"string-hash": "^1.1.3"
|