@karmaniverous/entity-manager 4.4.3 → 5.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
@@ -373,7 +373,7 @@ Query an entity across shards.
373
373
  | options.shardQuery | <code>ShardQueryFunction</code> | Sharded query function. |
374
374
  | [options.limit] | <code>number</code> | Request limit. |
375
375
  | [options.pageKeys] | <code>object</code> | Map of shard page keys. |
376
- | [options.pages] | <code>number</code> \| <code>&#x27;all&#x27;</code> | Max number of pages to query. |
376
+ | [options.pageSize] | <code>number</code> | Request page size. |
377
377
 
378
378
  <a name="module_entity-manager.EntityManager+rehydrateIndex"></a>
379
379
 
@@ -435,8 +435,8 @@ Shard query function
435
435
  | Param | Type | Description |
436
436
  | --- | --- | --- |
437
437
  | shardedKey | <code>string</code> | Sharded key. |
438
- | [limit] | <code>number</code> | Request limit. |
439
438
  | [pageKey] | <code>\*</code> | Page key. |
439
+ | [limit] | <code>number</code> | Request limit. |
440
440
 
441
441
  <a name="module_entity-manager..ShardedQueryResult"></a>
442
442
 
@@ -6,11 +6,8 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.EntityManager = void 0;
7
7
  var _zipObject2 = _interopRequireDefault(require("lodash/zipObject"));
8
8
  var _map2 = _interopRequireDefault(require("lodash/map"));
9
- var _size2 = _interopRequireDefault(require("lodash/size"));
10
9
  var _isEmpty2 = _interopRequireDefault(require("lodash/isEmpty"));
11
10
  var _fromPairs2 = _interopRequireDefault(require("lodash/fromPairs"));
12
- var _parseInt2 = _interopRequireDefault(require("lodash/parseInt"));
13
- var _isString2 = _interopRequireDefault(require("lodash/isString"));
14
11
  var _isPlainObject2 = _interopRequireDefault(require("lodash/isPlainObject"));
15
12
  var _isInteger2 = _interopRequireDefault(require("lodash/isInteger"));
16
13
  var _isUndefined2 = _interopRequireDefault(require("lodash/isUndefined"));
@@ -213,8 +210,8 @@ class EntityManager {
213
210
  *
214
211
  * @callback ShardQueryFunction
215
212
  * @param {string} shardedKey - Sharded key.
216
- * @param {number} [limit] - Request limit.
217
213
  * @param {*} [pageKey] - Page key.
214
+ * @param {number} [limit] - Request limit.
218
215
  * @returns {Promise<ShardQueryResult>} Sharded query result.
219
216
  */
220
217
 
@@ -234,7 +231,7 @@ class EntityManager {
234
231
  * @param {ShardQueryFunction} options.shardQuery - Sharded query function.
235
232
  * @param {number} [options.limit] - Request limit.
236
233
  * @param {object} [options.pageKeys] - Map of shard page keys.
237
- * @param {number|'all'} [options.pages] - Max number of pages to query.
234
+ * @param {number} [options.pageSize] - Request page size.
238
235
  * @returns {Promise<ShardedQueryResult>} Sharded query result.
239
236
  */
240
237
  async query() {
@@ -245,7 +242,7 @@ class EntityManager {
245
242
  shardQuery,
246
243
  limit,
247
244
  pageKeys,
248
- pages = 1
245
+ pageSize
249
246
  } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
250
247
  // Validate params.
251
248
  this.#entityManager.validateKeyToken(entityToken, keyToken);
@@ -253,13 +250,13 @@ class EntityManager {
253
250
  if (!(0, _isFunction2.default)(shardQuery)) throw new Error('shardQuery must be a function');
254
251
  if (!(0, _isUndefined2.default)(limit) && !((0, _isInteger2.default)(limit) && limit >= 1)) throw new Error('limit must be a positive integer');
255
252
  if (!(0, _isUndefined2.default)(pageKeys) && !(0, _isPlainObject2.default)(pageKeys)) throw new Error('pageKeys must be an object');
256
- if (!(0, _isUndefined2.default)(pages) && !/^(?:\d+|all)$/i.test(pages.toString())) throw new Error("pages must be a positive integer or 'all'");
253
+ if (!(0, _isUndefined2.default)(pageSize) && !((0, _isInteger2.default)(pageSize) && pageSize >= 1)) throw new Error('pageSize must be a positive integer');
257
254
 
258
255
  // Apply default limit.
259
256
  limit ??= this.#entityManager.getEntityConfig(entityToken).defaultLimit;
260
257
 
261
- // Parse pages.
262
- if ((0, _isString2.default)(pages)) pages = pages.toLowerCase() === 'all' ? Infinity : (0, _parseInt2.default)(pages);
258
+ // Apply default pageSize.
259
+ pageSize ??= this.#entityManager.getEntityConfig(entityToken).defaultPageSize;
263
260
 
264
261
  // Generate default pageKeys if not provided
265
262
  pageKeys ??= (0, _fromPairs2.default)(this.getKeySpace(entityToken, keyToken, item).map(shardedKey => [shardedKey, undefined]));
@@ -270,7 +267,7 @@ class EntityManager {
270
267
  shardQuery,
271
268
  limit,
272
269
  pageKeys,
273
- pages
270
+ pageSize
274
271
  });
275
272
 
276
273
  // Return empty result if no pageKeys.
@@ -280,9 +277,6 @@ class EntityManager {
280
277
  pageKeys: {}
281
278
  };
282
279
 
283
- // Calculate shard limit.
284
- const shardLimit = (0, _isUndefined2.default)(limit) ? undefined : Math.ceil(limit / (0, _size2.default)(pageKeys));
285
-
286
280
  // Iterate search over pages.
287
281
  let page = 0;
288
282
  const result = {
@@ -291,8 +285,12 @@ class EntityManager {
291
285
  pageKeys
292
286
  };
293
287
  do {
288
+ // TODO: This loop will blow up as shards scale, since at a minimum it will return shardCount x pageSize
289
+ // items, which may be >> limit. Probably the way to fix this is to limit the number of shards queried per
290
+ // iteration in order to keep shardsQueried * pageSize > (limit - items.length) but only just.
291
+
294
292
  // Query every shard in pageKeys.
295
- const shardQueryResults = await Promise.all((0, _map2.default)(result.pageKeys, (pageKey, shardedKey) => new Promise(resolve => shardQuery(shardedKey, pageKey, shardLimit).then(_ref6 => {
293
+ const shardQueryResults = await Promise.all((0, _map2.default)(result.pageKeys, (pageKey, shardedKey) => new Promise(resolve => shardQuery(shardedKey, pageKey, pageSize).then(_ref6 => {
296
294
  let {
297
295
  count,
298
296
  items,
@@ -334,7 +332,7 @@ class EntityManager {
334
332
  result.items = [...result.items, ...pageResult.items];
335
333
  result.pageKeys = pageResult.pageKeys;
336
334
  page++;
337
- } while (page < pages && result.items.length < limit * pages && !(0, _isEmpty2.default)(result.pageKeys));
335
+ } while (result.items.length < limit && !(0, _isEmpty2.default)(result.pageKeys));
338
336
  return result;
339
337
  }
340
338
 
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.PrivateEntityManager = exports.DEFAULT_LIMIT = void 0;
6
+ exports.PrivateEntityManager = exports.DEFAULT_PAGE_SIZE = exports.DEFAULT_LIMIT = void 0;
7
7
  var _isInteger2 = _interopRequireDefault(require("lodash/isInteger"));
8
8
  var _isPlainObject2 = _interopRequireDefault(require("lodash/isPlainObject"));
9
9
  var _range2 = _interopRequireDefault(require("lodash/range"));
@@ -26,7 +26,8 @@ var _mapValues2 = _interopRequireDefault(require("lodash/mapValues"));
26
26
  var _jsonschema = require("jsonschema");
27
27
  var _stringHash = _interopRequireDefault(require("string-hash"));
28
28
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
29
- const DEFAULT_LIMIT = exports.DEFAULT_LIMIT = 25;
29
+ const DEFAULT_LIMIT = exports.DEFAULT_LIMIT = 10;
30
+ const DEFAULT_PAGE_SIZE = exports.DEFAULT_PAGE_SIZE = 10;
30
31
 
31
32
  /**
32
33
  * EntityManager config validation schema.
@@ -45,6 +46,9 @@ const configSchema = {
45
46
  defaultLimit: {
46
47
  type: 'integer'
47
48
  },
49
+ defaultPageSize: {
50
+ type: 'integer'
51
+ },
48
52
  indexes: {
49
53
  type: 'object',
50
54
  additionalProperties: {
@@ -175,6 +179,7 @@ class PrivateEntityManager {
175
179
  entities: (0, _mapValues2.default)(entities, _ref => {
176
180
  let {
177
181
  defaultLimit = DEFAULT_LIMIT,
182
+ defaultPageSize = DEFAULT_PAGE_SIZE,
178
183
  indexes = {},
179
184
  keys = {},
180
185
  sharding: {
@@ -187,6 +192,7 @@ class PrivateEntityManager {
187
192
  } = _ref;
188
193
  return {
189
194
  defaultLimit,
195
+ defaultPageSize,
190
196
  indexes,
191
197
  keys,
192
198
  sharding: {
@@ -196,8 +196,8 @@ export class EntityManager {
196
196
  *
197
197
  * @callback ShardQueryFunction
198
198
  * @param {string} shardedKey - Sharded key.
199
- * @param {number} [limit] - Request limit.
200
199
  * @param {*} [pageKey] - Page key.
200
+ * @param {number} [limit] - Request limit.
201
201
  * @returns {Promise<ShardQueryResult>} Sharded query result.
202
202
  */
203
203
 
@@ -217,7 +217,7 @@ export class EntityManager {
217
217
  * @param {ShardQueryFunction} options.shardQuery - Sharded query function.
218
218
  * @param {number} [options.limit] - Request limit.
219
219
  * @param {object} [options.pageKeys] - Map of shard page keys.
220
- * @param {number|'all'} [options.pages] - Max number of pages to query.
220
+ * @param {number} [options.pageSize] - Request page size.
221
221
  * @returns {Promise<ShardedQueryResult>} Sharded query result.
222
222
  */
223
223
  async query({
@@ -227,26 +227,30 @@ export class EntityManager {
227
227
  shardQuery,
228
228
  limit,
229
229
  pageKeys,
230
- pages = 1,
230
+ pageSize,
231
231
  } = {}) {
232
232
  // Validate params.
233
233
  this.#entityManager.validateKeyToken(entityToken, keyToken);
234
234
  this.#entityManager.validateItem(item);
235
+
235
236
  if (!_.isFunction(shardQuery))
236
237
  throw new Error('shardQuery must be a function');
238
+
237
239
  if (!_.isUndefined(limit) && !(_.isInteger(limit) && limit >= 1))
238
240
  throw new Error('limit must be a positive integer');
241
+
239
242
  if (!_.isUndefined(pageKeys) && !_.isPlainObject(pageKeys))
240
243
  throw new Error('pageKeys must be an object');
241
- if (!_.isUndefined(pages) && !/^(?:\d+|all)$/i.test(pages.toString()))
242
- throw new Error("pages must be a positive integer or 'all'");
244
+
245
+ if (!_.isUndefined(pageSize) && !(_.isInteger(pageSize) && pageSize >= 1))
246
+ throw new Error('pageSize must be a positive integer');
243
247
 
244
248
  // Apply default limit.
245
249
  limit ??= this.#entityManager.getEntityConfig(entityToken).defaultLimit;
246
250
 
247
- // Parse pages.
248
- if (_.isString(pages))
249
- pages = pages.toLowerCase() === 'all' ? Infinity : _.parseInt(pages);
251
+ // Apply default pageSize.
252
+ pageSize ??=
253
+ this.#entityManager.getEntityConfig(entityToken).defaultPageSize;
250
254
 
251
255
  // Generate default pageKeys if not provided
252
256
  pageKeys ??= _.fromPairs(
@@ -263,29 +267,28 @@ export class EntityManager {
263
267
  shardQuery,
264
268
  limit,
265
269
  pageKeys,
266
- pages,
270
+ pageSize,
267
271
  });
268
272
 
269
273
  // Return empty result if no pageKeys.
270
274
  if (_.isEmpty(pageKeys)) return { count: 0, items: [], pageKeys: {} };
271
275
 
272
- // Calculate shard limit.
273
- const shardLimit = _.isUndefined(limit)
274
- ? undefined
275
- : Math.ceil(limit / _.size(pageKeys));
276
-
277
276
  // Iterate search over pages.
278
277
  let page = 0;
279
278
  const result = { count: 0, items: [], pageKeys };
280
279
 
281
280
  do {
281
+ // TODO: This loop will blow up as shards scale, since at a minimum it will return shardCount x pageSize
282
+ // items, which may be >> limit. Probably the way to fix this is to limit the number of shards queried per
283
+ // iteration in order to keep shardsQueried * pageSize > (limit - items.length) but only just.
284
+
282
285
  // Query every shard in pageKeys.
283
286
  const shardQueryResults = await Promise.all(
284
287
  _.map(
285
288
  result.pageKeys,
286
289
  (pageKey, shardedKey) =>
287
290
  new Promise((resolve) =>
288
- shardQuery(shardedKey, pageKey, shardLimit).then(
291
+ shardQuery(shardedKey, pageKey, pageSize).then(
289
292
  ({ count, items, pageKey }) =>
290
293
  resolve({ count, items, pageKey, shardedKey })
291
294
  )
@@ -315,11 +318,7 @@ export class EntityManager {
315
318
  result.items = [...result.items, ...pageResult.items];
316
319
  result.pageKeys = pageResult.pageKeys;
317
320
  page++;
318
- } while (
319
- page < pages &&
320
- result.items.length < limit * pages &&
321
- !_.isEmpty(result.pageKeys)
322
- );
321
+ } while (result.items.length < limit && !_.isEmpty(result.pageKeys));
323
322
 
324
323
  return result;
325
324
  }
@@ -2,7 +2,8 @@ import { validate } from 'jsonschema';
2
2
  import _ from 'lodash';
3
3
  import stringHash from 'string-hash';
4
4
 
5
- export const DEFAULT_LIMIT = 25;
5
+ export const DEFAULT_LIMIT = 10;
6
+ export const DEFAULT_PAGE_SIZE = 10;
6
7
 
7
8
  /**
8
9
  * EntityManager config validation schema.
@@ -21,6 +22,9 @@ const configSchema = {
21
22
  defaultLimit: {
22
23
  type: 'integer',
23
24
  },
25
+ defaultPageSize: {
26
+ type: 'integer',
27
+ },
24
28
  indexes: {
25
29
  type: 'object',
26
30
  additionalProperties: {
@@ -141,6 +145,7 @@ export class PrivateEntityManager {
141
145
  entities,
142
146
  ({
143
147
  defaultLimit = DEFAULT_LIMIT,
148
+ defaultPageSize = DEFAULT_PAGE_SIZE,
144
149
  indexes = {},
145
150
  keys = {},
146
151
  sharding: {
@@ -152,6 +157,7 @@ export class PrivateEntityManager {
152
157
  } = {},
153
158
  }) => ({
154
159
  defaultLimit,
160
+ defaultPageSize,
155
161
  indexes,
156
162
  keys,
157
163
  sharding: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@karmaniverous/entity-manager",
3
- "version": "4.4.3",
3
+ "version": "5.0.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },