@karmaniverous/entity-manager 1.0.0 → 2.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 CHANGED
@@ -221,7 +221,7 @@ This change can be accomplished with no breaking changes to existing implementat
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
223
  * [.getKeySpace(entityToken, keyToken, item, timestamp)](#module_entity-manager.EntityManager+getKeySpace) ⇒ <code>Array.&lt;string&gt;</code>
224
- * [.query(entityToken, keyToken, item, shardQuery, [pageKeys])](#module_entity-manager.EntityManager+query) ⇒ <code>Promise.&lt;ShardedQueryResult&gt;</code>
224
+ * [.query(entityToken, keyToken, item, shardQuery, [options])](#module_entity-manager.EntityManager+query) ⇒ <code>Promise.&lt;ShardedQueryResult&gt;</code>
225
225
  * [.removeKeys(entityToken, item)](#module_entity-manager.EntityManager+removeKeys) ⇒ <code>object</code>
226
226
  * _inner_
227
227
  * [~ShardQueryResult](#module_entity-manager..ShardQueryResult) : <code>object</code>
@@ -239,7 +239,7 @@ Manage DynamoDb entities.
239
239
  * [new exports.EntityManager(options)](#new_module_entity-manager.EntityManager_new)
240
240
  * [.addKeys(entityToken, item, [overwrite])](#module_entity-manager.EntityManager+addKeys) ⇒ <code>object</code>
241
241
  * [.getKeySpace(entityToken, keyToken, item, timestamp)](#module_entity-manager.EntityManager+getKeySpace) ⇒ <code>Array.&lt;string&gt;</code>
242
- * [.query(entityToken, keyToken, item, shardQuery, [pageKeys])](#module_entity-manager.EntityManager+query) ⇒ <code>Promise.&lt;ShardedQueryResult&gt;</code>
242
+ * [.query(entityToken, keyToken, item, shardQuery, [options])](#module_entity-manager.EntityManager+query) ⇒ <code>Promise.&lt;ShardedQueryResult&gt;</code>
243
243
  * [.removeKeys(entityToken, item)](#module_entity-manager.EntityManager+removeKeys) ⇒ <code>object</code>
244
244
 
245
245
  <a name="new_module_entity-manager.EntityManager_new"></a>
@@ -303,7 +303,7 @@ Return an array of sharded keys valid for a given entity token & timestamp.
303
303
 
304
304
  <a name="module_entity-manager.EntityManager+query"></a>
305
305
 
306
- #### entityManager.query(entityToken, keyToken, item, shardQuery, [pageKeys]) ⇒ <code>Promise.&lt;ShardedQueryResult&gt;</code>
306
+ #### entityManager.query(entityToken, keyToken, item, shardQuery, [options]) ⇒ <code>Promise.&lt;ShardedQueryResult&gt;</code>
307
307
  Query an entity across shards.
308
308
 
309
309
  **Kind**: instance method of [<code>EntityManager</code>](#module_entity-manager.EntityManager)
@@ -315,7 +315,9 @@ Query an entity across shards.
315
315
  | keyToken | <code>string</code> | Key token. |
316
316
  | item | <code>object</code> | Entity item sufficiently populated to generate property keyToken. |
317
317
  | shardQuery | <code>ShardQueryFunction</code> | Sharded query function. |
318
- | [pageKeys] | <code>object</code> | Map of shard page keys. |
318
+ | [options] | <code>object</code> | Options object. |
319
+ | [options.limit] | <code>number</code> | Request limit. |
320
+ | [options.pageKeys] | <code>object</code> | Map of shard page keys. |
319
321
 
320
322
  <a name="module_entity-manager.EntityManager+removeKeys"></a>
321
323
 
@@ -357,7 +359,9 @@ Shard query function
357
359
  | Param | Type | Description |
358
360
  | --- | --- | --- |
359
361
  | shardedKey | <code>string</code> | Sharded key. |
360
- | [pageKey] | <code>\*</code> | Page key. |
362
+ | [options] | <code>object</code> | Options object. |
363
+ | [options.limit] | <code>number</code> | Request limit. |
364
+ | [options.pageKey] | <code>\*</code> | Page key. |
361
365
 
362
366
  <a name="module_entity-manager..ShardedQueryResult"></a>
363
367
 
@@ -4,9 +4,14 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.EntityManager = void 0;
7
- var _isUndefined2 = _interopRequireDefault(require("lodash/isUndefined"));
8
7
  var _map2 = _interopRequireDefault(require("lodash/map"));
8
+ var _size2 = _interopRequireDefault(require("lodash/size"));
9
+ var _isEmpty2 = _interopRequireDefault(require("lodash/isEmpty"));
9
10
  var _fromPairs2 = _interopRequireDefault(require("lodash/fromPairs"));
11
+ var _isPlainObject2 = _interopRequireDefault(require("lodash/isPlainObject"));
12
+ var _isInteger2 = _interopRequireDefault(require("lodash/isInteger"));
13
+ var _isUndefined2 = _interopRequireDefault(require("lodash/isUndefined"));
14
+ var _isFunction2 = _interopRequireDefault(require("lodash/isFunction"));
10
15
  var _sortedUniq2 = _interopRequireDefault(require("lodash/sortedUniq"));
11
16
  var _forEach2 = _interopRequireDefault(require("lodash/forEach"));
12
17
  var _isNil2 = _interopRequireDefault(require("lodash/isNil"));
@@ -135,7 +140,9 @@ class EntityManager {
135
140
  *
136
141
  * @callback ShardQueryFunction
137
142
  * @param {string} shardedKey - Sharded key.
138
- * @param {*} [pageKey] - Page key.
143
+ * @param {object} [options] - Options object.
144
+ * @param {number} [options.limit] - Request limit.
145
+ * @param {*} [options.pageKey] - Page key.
139
146
  * @returns {Promise<ShardQueryResult>} Sharded query result.
140
147
  */
141
148
 
@@ -152,31 +159,50 @@ class EntityManager {
152
159
  * @param {string} keyToken - Key token.
153
160
  * @param {object} item - Entity item sufficiently populated to generate property keyToken.
154
161
  * @param {ShardQueryFunction} shardQuery - Sharded query function.
155
- * @param {object} [pageKeys] - Map of shard page keys.
162
+ * @param {object} [options] - Options object.
163
+ * @param {number} [options.limit] - Request limit.
164
+ * @param {object} [options.pageKeys] - Map of shard page keys.
156
165
  * @returns {Promise<ShardedQueryResult>} Sharded query result.
157
166
  */
158
- async query(entityToken, keyToken, item, shardQuery, pageKeys) {
167
+ async query(entityToken, keyToken, item, shardQuery) {
168
+ let {
169
+ limit,
170
+ pageKeys
171
+ } = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
172
+ // Validate params.
173
+ _classPrivateFieldGet(this, _entityManager).validateKeyToken(entityToken, keyToken);
174
+ _classPrivateFieldGet(this, _entityManager).validateItem(item);
175
+ if (!(0, _isFunction2.default)(shardQuery)) throw new Error('shardQuery must be a function');
176
+ if (!(0, _isUndefined2.default)(limit) && !(0, _isInteger2.default)(limit)) throw new Error('limit must be an integer');
177
+ if (!(0, _isUndefined2.default)(pageKeys) && !(0, _isPlainObject2.default)(pageKeys)) throw new Error('pageKeys must be an object');
178
+
159
179
  // Generate default pageKeys if not provided
160
180
  pageKeys ??= (0, _fromPairs2.default)(this.getKeySpace(entityToken, keyToken, item).map(shardedKey => [shardedKey, undefined]));
161
181
 
182
+ // Return empty result if no pageKeys.
183
+ if ((0, _isEmpty2.default)(pageKeys)) return {
184
+ items: [],
185
+ pageKeys: {}
186
+ };
187
+
188
+ // Calculate shard limit.
189
+ const shardLimit = (0, _isUndefined2.default)(limit) ? undefined : Math.ceil(limit / (0, _size2.default)(pageKeys));
190
+
162
191
  // Query every shard in pageKeys.
163
- const shardQueryResults = await Promise.all((0, _map2.default)(pageKeys, (pageKey, shardedKey) => new Promise(resolve => shardQuery(shardedKey, pageKey).then(_ref2 => {
192
+ const shardQueryResults = await Promise.all((0, _map2.default)(pageKeys, (pageKey, shardedKey) => new Promise(resolve => shardQuery(shardedKey, {
193
+ pageKey,
194
+ limit: shardLimit
195
+ }).then(_ref2 => {
164
196
  let {
165
197
  items,
166
198
  pageKey
167
199
  } = _ref2;
168
- console.log('shardQueryResult', {
169
- shardedKey,
170
- items,
171
- pageKey
172
- });
173
200
  return resolve({
174
201
  shardedKey,
175
202
  items,
176
203
  pageKey
177
204
  });
178
205
  }))));
179
- console.log('shardQueryResults', shardQueryResults);
180
206
 
181
207
  // Reduce shardQueryResults into a single result.
182
208
  const result = shardQueryResults.reduce((shardedQueryResult, _ref3) => {
@@ -379,6 +379,22 @@ class PrivateEntityManager {
379
379
  } else return true;
380
380
  }
381
381
 
382
+ /**
383
+ * Tests whether a key token is valid.
384
+ *
385
+ * @param {string} entityToken - Entity token.
386
+ * @param {string} keyToken - Key token.
387
+ * @returns {boolean} true if keyToken is valid.
388
+ */
389
+ validateKeyToken(entityToken, keyToken) {
390
+ this.validateEntityToken(entityToken);
391
+ if (!this.config.entities[entityToken].keys[keyToken]) {
392
+ const message = `Invalid entity ${entityToken} keyToken: ${keyToken}`;
393
+ this.logger.error(message);
394
+ throw new Error(message);
395
+ } else return true;
396
+ }
397
+
382
398
  /**
383
399
  * Tests whether an item is valid.
384
400
  *
@@ -130,7 +130,9 @@ export class EntityManager {
130
130
  *
131
131
  * @callback ShardQueryFunction
132
132
  * @param {string} shardedKey - Sharded key.
133
- * @param {*} [pageKey] - Page key.
133
+ * @param {object} [options] - Options object.
134
+ * @param {number} [options.limit] - Request limit.
135
+ * @param {*} [options.pageKey] - Page key.
134
136
  * @returns {Promise<ShardQueryResult>} Sharded query result.
135
137
  */
136
138
 
@@ -147,10 +149,28 @@ export class EntityManager {
147
149
  * @param {string} keyToken - Key token.
148
150
  * @param {object} item - Entity item sufficiently populated to generate property keyToken.
149
151
  * @param {ShardQueryFunction} shardQuery - Sharded query function.
150
- * @param {object} [pageKeys] - Map of shard page keys.
152
+ * @param {object} [options] - Options object.
153
+ * @param {number} [options.limit] - Request limit.
154
+ * @param {object} [options.pageKeys] - Map of shard page keys.
151
155
  * @returns {Promise<ShardedQueryResult>} Sharded query result.
152
156
  */
153
- async query(entityToken, keyToken, item, shardQuery, pageKeys) {
157
+ async query(
158
+ entityToken,
159
+ keyToken,
160
+ item,
161
+ shardQuery,
162
+ { limit, pageKeys } = {}
163
+ ) {
164
+ // Validate params.
165
+ this.#entityManager.validateKeyToken(entityToken, keyToken);
166
+ this.#entityManager.validateItem(item);
167
+ if (!_.isFunction(shardQuery))
168
+ throw new Error('shardQuery must be a function');
169
+ if (!_.isUndefined(limit) && !_.isInteger(limit))
170
+ throw new Error('limit must be an integer');
171
+ if (!_.isUndefined(pageKeys) && !_.isPlainObject(pageKeys))
172
+ throw new Error('pageKeys must be an object');
173
+
154
174
  // Generate default pageKeys if not provided
155
175
  pageKeys ??= _.fromPairs(
156
176
  this.getKeySpace(entityToken, keyToken, item).map((shardedKey) => [
@@ -159,22 +179,27 @@ export class EntityManager {
159
179
  ])
160
180
  );
161
181
 
182
+ // Return empty result if no pageKeys.
183
+ if (_.isEmpty(pageKeys)) return { items: [], pageKeys: {} };
184
+
185
+ // Calculate shard limit.
186
+ const shardLimit = _.isUndefined(limit)
187
+ ? undefined
188
+ : Math.ceil(limit / _.size(pageKeys));
189
+
162
190
  // Query every shard in pageKeys.
163
191
  const shardQueryResults = await Promise.all(
164
192
  _.map(
165
193
  pageKeys,
166
194
  (pageKey, shardedKey) =>
167
195
  new Promise((resolve) =>
168
- shardQuery(shardedKey, pageKey).then(({ items, pageKey }) => {
169
- console.log('shardQueryResult', { shardedKey, items, pageKey });
170
- return resolve({ shardedKey, items, pageKey });
171
- })
196
+ shardQuery(shardedKey, { pageKey, limit: shardLimit }).then(
197
+ ({ items, pageKey }) => resolve({ shardedKey, items, pageKey })
198
+ )
172
199
  )
173
200
  )
174
201
  );
175
202
 
176
- console.log('shardQueryResults', shardQueryResults);
177
-
178
203
  // Reduce shardQueryResults into a single result.
179
204
  const result = shardQueryResults.reduce(
180
205
  (shardedQueryResult, { shardedKey, items, pageKey }) => ({
@@ -348,6 +348,23 @@ export class PrivateEntityManager {
348
348
  } else return true;
349
349
  }
350
350
 
351
+ /**
352
+ * Tests whether a key token is valid.
353
+ *
354
+ * @param {string} entityToken - Entity token.
355
+ * @param {string} keyToken - Key token.
356
+ * @returns {boolean} true if keyToken is valid.
357
+ */
358
+ validateKeyToken(entityToken, keyToken) {
359
+ this.validateEntityToken(entityToken);
360
+
361
+ if (!this.config.entities[entityToken].keys[keyToken]) {
362
+ const message = `Invalid entity ${entityToken} keyToken: ${keyToken}`;
363
+ this.logger.error(message);
364
+ throw new Error(message);
365
+ } else return true;
366
+ }
367
+
351
368
  /**
352
369
  * Tests whether an item is valid.
353
370
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@karmaniverous/entity-manager",
3
- "version": "1.0.0",
3
+ "version": "2.0.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },