@karmaniverous/entity-manager 6.13.3 → 6.14.1

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.
Files changed (59) hide show
  1. package/README.md +330 -16
  2. package/dist/cjs/{EntityManager.js → EntityManager/EntityManager.js} +18 -44
  3. package/dist/cjs/{ParsedConfig.js → EntityManager/ParsedConfig.js} +46 -55
  4. package/dist/cjs/{addKeys.js → EntityManager/addKeys.js} +1 -0
  5. package/dist/cjs/{decodeElement.js → EntityManager/decodeElement.js} +2 -1
  6. package/dist/cjs/{dehydratePageKeyMap.js → EntityManager/dehydratePageKeyMap.js} +3 -1
  7. package/dist/cjs/{encodeElement.js → EntityManager/encodeElement.js} +2 -2
  8. package/dist/cjs/{encodeGeneratedProperty.js → EntityManager/encodeGeneratedProperty.js} +1 -1
  9. package/dist/cjs/EntityManager/getPrimaryKey.js +25 -0
  10. package/dist/cjs/{rehydratePageKeyMap.js → EntityManager/rehydratePageKeyMap.js} +3 -1
  11. package/dist/cjs/{removeKeys.js → EntityManager/removeKeys.js} +10 -8
  12. package/dist/cjs/{updateItemHashKey.js → EntityManager/updateItemHashKey.js} +4 -1
  13. package/dist/cjs/index.js +5 -3
  14. package/dist/index.d.ts +109 -252
  15. package/dist/mjs/{EntityManager.js → EntityManager/EntityManager.js} +18 -44
  16. package/dist/mjs/{ParsedConfig.js → EntityManager/ParsedConfig.js} +46 -55
  17. package/dist/mjs/{addKeys.js → EntityManager/addKeys.js} +1 -0
  18. package/dist/mjs/{decodeElement.js → EntityManager/decodeElement.js} +2 -1
  19. package/dist/mjs/{dehydratePageKeyMap.js → EntityManager/dehydratePageKeyMap.js} +3 -1
  20. package/dist/mjs/{encodeElement.js → EntityManager/encodeElement.js} +2 -2
  21. package/dist/mjs/{encodeGeneratedProperty.js → EntityManager/encodeGeneratedProperty.js} +1 -1
  22. package/dist/mjs/EntityManager/getPrimaryKey.js +23 -0
  23. package/dist/mjs/{rehydratePageKeyMap.js → EntityManager/rehydratePageKeyMap.js} +3 -1
  24. package/dist/mjs/{removeKeys.js → EntityManager/removeKeys.js} +10 -8
  25. package/dist/mjs/{updateItemHashKey.js → EntityManager/updateItemHashKey.js} +4 -1
  26. package/dist/mjs/index.js +4 -3
  27. package/package.json +44 -45
  28. /package/dist/cjs/{BaseEntityClient.js → BaseEntityClient/BaseEntityClient.js} +0 -0
  29. /package/dist/cjs/{BaseQueryBuilder.js → BaseQueryBuilder/BaseQueryBuilder.js} +0 -0
  30. /package/dist/cjs/{decodeGeneratedProperty.js → EntityManager/decodeGeneratedProperty.js} +0 -0
  31. /package/dist/cjs/{dehydrateIndexItem.js → EntityManager/dehydrateIndexItem.js} +0 -0
  32. /package/dist/cjs/{findIndexToken.js → EntityManager/findIndexToken.js} +0 -0
  33. /package/dist/cjs/{getHashKeySpace.js → EntityManager/getHashKeySpace.js} +0 -0
  34. /package/dist/cjs/{getIndexComponents.js → EntityManager/getIndexComponents.js} +0 -0
  35. /package/dist/cjs/{getShardBump.js → EntityManager/getShardBump.js} +0 -0
  36. /package/dist/cjs/{query.js → EntityManager/query.js} +0 -0
  37. /package/dist/cjs/{rehydrateIndexItem.js → EntityManager/rehydrateIndexItem.js} +0 -0
  38. /package/dist/cjs/{unwrapIndex.js → EntityManager/unwrapIndex.js} +0 -0
  39. /package/dist/cjs/{updateItemRangeKey.js → EntityManager/updateItemRangeKey.js} +0 -0
  40. /package/dist/cjs/{validateEntityToken.js → EntityManager/validateEntityToken.js} +0 -0
  41. /package/dist/cjs/{validateGeneratedProperty.js → EntityManager/validateGeneratedProperty.js} +0 -0
  42. /package/dist/cjs/{validateIndexToken.js → EntityManager/validateIndexToken.js} +0 -0
  43. /package/dist/cjs/{validateTranscodedProperty.js → EntityManager/validateTranscodedProperty.js} +0 -0
  44. /package/dist/mjs/{BaseEntityClient.js → BaseEntityClient/BaseEntityClient.js} +0 -0
  45. /package/dist/mjs/{BaseQueryBuilder.js → BaseQueryBuilder/BaseQueryBuilder.js} +0 -0
  46. /package/dist/mjs/{decodeGeneratedProperty.js → EntityManager/decodeGeneratedProperty.js} +0 -0
  47. /package/dist/mjs/{dehydrateIndexItem.js → EntityManager/dehydrateIndexItem.js} +0 -0
  48. /package/dist/mjs/{findIndexToken.js → EntityManager/findIndexToken.js} +0 -0
  49. /package/dist/mjs/{getHashKeySpace.js → EntityManager/getHashKeySpace.js} +0 -0
  50. /package/dist/mjs/{getIndexComponents.js → EntityManager/getIndexComponents.js} +0 -0
  51. /package/dist/mjs/{getShardBump.js → EntityManager/getShardBump.js} +0 -0
  52. /package/dist/mjs/{query.js → EntityManager/query.js} +0 -0
  53. /package/dist/mjs/{rehydrateIndexItem.js → EntityManager/rehydrateIndexItem.js} +0 -0
  54. /package/dist/mjs/{unwrapIndex.js → EntityManager/unwrapIndex.js} +0 -0
  55. /package/dist/mjs/{updateItemRangeKey.js → EntityManager/updateItemRangeKey.js} +0 -0
  56. /package/dist/mjs/{validateEntityToken.js → EntityManager/validateEntityToken.js} +0 -0
  57. /package/dist/mjs/{validateGeneratedProperty.js → EntityManager/validateGeneratedProperty.js} +0 -0
  58. /package/dist/mjs/{validateIndexToken.js → EntityManager/validateIndexToken.js} +0 -0
  59. /package/dist/mjs/{validateTranscodedProperty.js → EntityManager/validateTranscodedProperty.js} +0 -0
package/README.md CHANGED
@@ -1,34 +1,348 @@
1
- <!-- TYPEDOC_EXCLUDE -->
1
+ # entity-manager
2
2
 
3
- > [API Documentation](https://docs.karmanivero.us/entity-manager/) [CHANGELOG](https://github.com/karmaniverous/entity-manager/tree/main/CHANGELOG.md)
3
+ [![npm version](https://img.shields.io/npm/v/@karmaniverous/entity-manager.svg)](https://www.npmjs.com/package/@karmaniverous/entity-manager) ![Node Current](https://img.shields.io/node/v/@karmaniverous/entity-manager) <!-- TYPEDOC_EXCLUDE --> [![docs](https://img.shields.io/badge/docs-website-blue)](https://docs.karmanivero.us/entity-manager) [![changelog](https://img.shields.io/badge/changelog-latest-blue.svg)](https://github.com/karmaniverous/entity-manager/tree/main/CHANGELOG.md)<!-- /TYPEDOC_EXCLUDE --> [![license](https://img.shields.io/badge/license-BSD--3--Clause-blue.svg)](https://github.com/karmaniverous/entity-manager/tree/main/LICENSE.md)
4
4
 
5
- <!-- /TYPEDOC_EXCLUDE -->
5
+ EntityManager implements rational indexing & cross-shard querying at scale in your NoSQL database so you can focus on your application logic.
6
6
 
7
- # entity-manager
7
+ If you have any questions, please [start a discussion](https://github.com/karmaniverous/entity-manager/discussions). Otherwise stay tuned!
8
8
 
9
- **EntityManager implements rational indexing & cross-shard querying at scale in your NoSQL database so you can focus on your application logic.**
9
+ ## What is this?
10
10
 
11
- > The Typescript refactor is still in flux, but stabilizing! Still fleshing out the [demo](https://github.com/karmaniverous/entity-manager-demo) & [documentation](https://karmanivero.us/projects/entity-manager/intro/).
11
+ Entity Manager is a TypeScript-first library that applies a provider‑agnostic, highly opinionated single‑table design to your NoSQL data. It lets you:
12
12
 
13
- If you have any questions, please [start a discussion](https://github.com/karmaniverous/entity-manager/discussions). Otherwise stay tuned!
13
+ - Define a global hash key and range key, plus additional generated properties used by your indexes.
14
+ - Encode/decode indexable elements via transcodes so strings sort like their original types.
15
+ - Configure a time‑based sharding strategy (shard bumps) that grows as you scale.
16
+ - Query across many shards and indexes in parallel through injected “shard query” functions — results are combined, de‑duplicated, sorted, and returned with a compact, dehydrated page key for the next request.
17
+
18
+ It is designed to work with stores like DynamoDB but keeps the orchestration provider‑neutral.
19
+
20
+ Key links:
21
+
22
+ - API: https://docs.karmanivero.us/entity-manager
23
+ - Requirements: see .stan/system/stan.requirements.md (authoritative for v6.14.0)
24
+ - Example test configuration: see test/config.ts
25
+
26
+ ## Features
27
+
28
+ - Global model for generated properties, indexes, and property transcodes
29
+ - generatedProperties.sharded and generatedProperties.unsharded
30
+ - Global indexes: indexToken → { hashKey, rangeKey, projections? }
31
+ - Global propertyTranscodes: property → transcodeName
32
+ - Deterministic sharding
33
+ - Time‑windowed shard bumps: { timestamp, charBits, chars }
34
+ - Full shard space assignment per bump (uses radix\*\*chars placeholders)
35
+ - Cross‑bump query enumeration over all applicable shards
36
+ - Page key dehydration/rehydration
37
+ - Compact string arrays and lz‑string compression for transport
38
+ - Rehydrate back to pageKey objects for each index+shard
39
+ - Provider‑agnostic parallel query orchestration
40
+ - Inject shard query functions for each index
41
+ - Parallel fan‑out with configurable throttle
42
+ - Combine, dedupe by unique property, and sort results
43
+ - Strong typing + runtime validation
44
+ - Zod‑validated config parsing
45
+ - Robust TypeScript surface for config, items, keys, queries
46
+
47
+ ## Install
48
+
49
+ ```bash
50
+ npm install @karmaniverous/entity-manager
51
+ # optional: testing support used in the repo
52
+ npm install --save-dev @karmaniverous/mock-db
53
+ ```
54
+
55
+ TypeScript is strongly recommended. The library will validate configuration at runtime for JavaScript users, but you lose compile‑time guarantees.
56
+
57
+ ## Usage overview
58
+
59
+ The pattern has three parts:
60
+
61
+ 1. Define your entity types and a config map
62
+
63
+ - Each entity type lists all properties that exist on your records.
64
+ - Entity‑level behaviors live in the config’s entities block (timestamp property, unique property, shard bumps).
65
+ - Generated properties, indexes, and transcodes are defined globally.
66
+
67
+ 2. Create an EntityManager instance
68
+
69
+ - Pass your config (validated with Zod).
70
+ - Optionally inject a logger with debug/error methods (defaults to console).
71
+
72
+ 3. Use EntityManager helpers
73
+
74
+ - addKeys / getPrimaryKey / removeKeys
75
+ - encodeGeneratedProperty / decodeGeneratedProperty
76
+ - getIndexComponents / unwrapIndex / dehydrateIndexItem / rehydrateIndexItem
77
+ - dehydratePageKeyMap / rehydratePageKeyMap
78
+ - query(options) to orchestrate cross‑shard multi‑index queries
79
+
80
+ ## Quick start (TypeScript)
81
+
82
+ Below is a minimal end‑to‑end example showing shape and intent. It mirrors the current implementation’s global config model.
83
+
84
+ ```ts
85
+ import {
86
+ defaultTranscodes,
87
+ type ConfigMap,
88
+ } from '@karmaniverous/entity-manager';
89
+ import { EntityManager } from '@karmaniverous/entity-manager';
90
+
91
+ // 1) Entity definitions (Typescript types)
92
+ interface User {
93
+ userId: string; // unique property
94
+ created: number; // timestamp property
95
+ updated: number;
96
+ firstNameCanonical: string;
97
+ lastNameCanonical: string;
98
+ // Generated properties exist on stored items but are configured globally:
99
+ // e.g., firstNameRK (unsharded), lastNameRK (unsharded), userPK (sharded)
100
+ }
101
+
102
+ type MyConfigMap = ConfigMap<{
103
+ EntityMap: { user: User };
104
+ HashKey: 'hashKey'; // defaults are 'hashKey' / 'rangeKey' if omitted
105
+ RangeKey: 'rangeKey';
106
+ ShardedKeys: 'userPK'; // token(s) for sharded generated properties
107
+ UnshardedKeys: 'firstNameRK' | 'lastNameRK';
108
+ TranscodedProperties:
109
+ | 'userId'
110
+ | 'created'
111
+ | 'updated'
112
+ | 'firstNameCanonical'
113
+ | 'lastNameCanonical';
114
+ }>;
115
+
116
+ // 2) Build a config with the global model
117
+ const now = Date.now();
118
+ const manager = new EntityManager<MyConfigMap>({
119
+ // Per-entity: unique + timestamp + shard schedule (+ optional defaults)
120
+ entities: {
121
+ user: {
122
+ uniqueProperty: 'userId',
123
+ timestampProperty: 'created',
124
+ shardBumps: [
125
+ // records with timestamp < now → effectively unsharded
126
+ { timestamp: now, charBits: 1, chars: 0 },
127
+ // records with timestamp ≥ now → 1 char at radix 4 (2^2) gives 4 shards
128
+ { timestamp: now, charBits: 2, chars: 1 },
129
+ ],
130
+ // optional defaults (used by query if omitted in options)
131
+ defaultLimit: 10,
132
+ defaultPageSize: 10,
133
+ },
134
+ },
135
+
136
+ // Global generated properties (tokens → element lists)
137
+ generatedProperties: {
138
+ sharded: {
139
+ userPK: ['userId'], // atomic (all required)
140
+ },
141
+ unsharded: {
142
+ firstNameRK: ['firstNameCanonical', 'lastNameCanonical', 'created'],
143
+ lastNameRK: ['lastNameCanonical', 'firstNameCanonical', 'created'],
144
+ },
145
+ },
146
+
147
+ // Global key tokens
148
+ hashKey: 'hashKey',
149
+ rangeKey: 'rangeKey',
150
+
151
+ // Global indexes (hashKey, rangeKey must match allowed token sets)
152
+ indexes: {
153
+ created: { hashKey: 'hashKey', rangeKey: 'created' },
154
+ updated: { hashKey: 'hashKey', rangeKey: 'updated' },
155
+ firstName: { hashKey: 'hashKey', rangeKey: 'firstNameRK' },
156
+ lastName: { hashKey: 'hashKey', rangeKey: 'lastNameRK' },
157
+ userCreated: { hashKey: 'userPK', rangeKey: 'created' }, // sharded alt hash
158
+ },
159
+
160
+ // Transcode mapping for scalar/unsharded elements and properties
161
+ propertyTranscodes: {
162
+ userId: 'string',
163
+ created: 'timestamp',
164
+ updated: 'timestamp',
165
+ firstNameCanonical: 'string',
166
+ lastNameCanonical: 'string',
167
+ },
168
+
169
+ // Transcodes (can override/extend defaultTranscodes)
170
+ transcodes: defaultTranscodes,
171
+
172
+ // Delimiters and query throttle (defaults shown)
173
+ generatedKeyDelimiter: '|',
174
+ generatedValueDelimiter: '#',
175
+ shardKeyDelimiter: '!',
176
+ throttle: 10,
177
+ });
178
+ ```
179
+
180
+ ### Generate keys on items
181
+
182
+ ```ts
183
+ // A partial item (no keys yet)
184
+ const user = {
185
+ userId: 'u123',
186
+ created: Date.now(),
187
+ updated: Date.now(),
188
+ firstNameCanonical: 'lee',
189
+ lastNameCanonical: 'zhang',
190
+ };
191
+
192
+ // Add hashKey, rangeKey, and generated properties
193
+ const record = manager.addKeys('user', user); // returns EntityRecord<...>
194
+
195
+ // Get just the primary key
196
+ const keyOnly = manager.getPrimaryKey('user', user); // { hashKey, rangeKey }
197
+
198
+ // Remove generated keys from a stored record
199
+ const pruned = manager.removeKeys('user', record);
200
+ ```
201
+
202
+ ### Encode/decode generated property strings
203
+
204
+ ```ts
205
+ // Encode an unsharded generated property (always returns a string)
206
+ const fn = manager.encodeGeneratedProperty('firstNameRK', record);
207
+ // e.g. "firstNameCanonical#lee|lastNameCanonical#zhang|created#000001711234567"
208
+
209
+ // Decode back into an object fragment
210
+ import { decodeGeneratedProperty } from '@karmaniverous/entity-manager';
211
+ const decoded = decodeGeneratedProperty(manager, fn); // { firstNameCanonical: 'lee', ... }
212
+ ```
213
+
214
+ ### Query across shards and indexes
215
+
216
+ Entity Manager relies on injected shard query functions to perform provider‑specific queries on each shard/index page. The library orchestrates:
217
+
218
+ - page‑key rehydration → parallel shard queries → de‑duplication and sorting → page‑key dehydration.
219
+
220
+ ```ts
221
+ import type {
222
+ QueryOptions,
223
+ ShardQueryFunction,
224
+ } from '@karmaniverous/entity-manager';
225
+
226
+ // Example shard query using a made-up client (see @karmaniverous/mock-db in repo tests)
227
+ const firstNameQuery: ShardQueryFunction<MyConfigMap> = async (
228
+ hashKey,
229
+ pageKey,
230
+ pageSize,
231
+ ) => {
232
+ // Return { count, items, pageKey? } for this shard+index page
233
+ // pageKey is a partial item object with necessary index components
234
+ // ... perform provider-specific work here ...
235
+ return { count: 0, items: [], pageKey };
236
+ };
237
+
238
+ // Invoke query with shardQueryMap
239
+ const result = await manager.query({
240
+ entityToken: 'user',
241
+ item: {}, // often used to supply elements for alternate hash keys
242
+ shardQueryMap: { firstName: firstNameQuery },
243
+ limit: 50,
244
+ pageSize: 10,
245
+ // optional: pageKeyMap: previousResult.pageKeyMap,
246
+ // optional: timestampFrom / timestampTo for shard-space windowing
247
+ });
248
+ ```
249
+
250
+ Notes:
251
+
252
+ - The result includes a compressed pageKeyMap string for the next call.
253
+ - Entity Manager enumerates the hash key space for the time window, rehydrates the prior page keys (if any), and fans out queries across all shard+index pairs in `shardQueryMap` (up to `throttle`).
254
+ - Items are deduplicated by the entity’s unique property and sorted by `sortOrder` (if provided).
255
+
256
+ ## Configuration reference (current model, v6.14.0)
257
+
258
+ - entities: Record<entityToken, { timestampProperty, uniqueProperty, shardBumps?, defaultLimit?, defaultPageSize? }>
259
+ - generatedProperties:
260
+ - sharded: Record<ShardedKey, TranscodedProperties[]>
261
+ - unsharded: Record<UnshardedKey, TranscodedProperties[]>
262
+ - indexes: Record<indexToken, {
263
+ - hashKey: HashKey | ShardedKey
264
+ - rangeKey: RangeKey | UnshardedKey | TranscodedProperties
265
+ - projections?: string[]
266
+ }>
267
+ - propertyTranscodes: Record<TranscodedProperties, keyof TranscodeMap>
268
+ - transcodes: Record<transcodeName, { encode, decode }> (defaults to defaultTranscodes)
269
+ - hashKey: HashKey (e.g., 'hashKey')
270
+ - rangeKey: RangeKey (e.g., 'rangeKey')
271
+ - generatedKeyDelimiter: string (default '|', must match /\W+/)
272
+ - generatedValueDelimiter: string (default '#', must match /\W+/)
273
+ - shardKeyDelimiter: string (default '!', must match /\W+/)
274
+ - throttle: number (default 10)
275
+
276
+ Validation highlights:
277
+
278
+ - Delimiters must not contain each other.
279
+ - Keys and tokens must be mutually exclusive as required.
280
+ - Generated property element lists are non‑empty and have no duplicates.
281
+ - propertyTranscodes values must exist in transcodes.
282
+ - Index hashKey/rangeKey must use valid token sets.
283
+ - shardBumps are sorted, include a zero‑timestamp bump if missing, and chars must increase monotonically with timestamp.
284
+
285
+ Sharding:
286
+
287
+ - For assignment: a record always uses all placeholders for its applicable bump; suffix space is (2**charBits) ** chars.
288
+ - For queries: hash key space spans all bumps overlapping [timestampFrom, timestampTo].
289
+
290
+ ## ESM / CJS
291
+
292
+ ```ts
293
+ // ESM
294
+ import {
295
+ EntityManager,
296
+ defaultTranscodes,
297
+ } from '@karmaniverous/entity-manager';
298
+
299
+ // CJS
300
+ const {
301
+ EntityManager,
302
+ defaultTranscodes,
303
+ } = require('@karmaniverous/entity-manager');
304
+ ```
305
+
306
+ ## Logging
307
+
308
+ All helpers log debug context and error detail via the injected logger (defaults to `console`). In tests, you may supply a quiet logger:
309
+
310
+ ```ts
311
+ const logger = { debug: () => undefined, error: console.error };
312
+ const manager = new EntityManager(config, logger);
313
+ ```
314
+
315
+ ## Delimiter safety
316
+
317
+ Generated key/value delimiters and the shard key delimiter are used when composing strings:
14
318
 
15
- ## Why?
319
+ - generatedKeyDelimiter: '|' (between pairs)
320
+ - generatedValueDelimiter: '#' (between key and value)
321
+ - shardKeyDelimiter: '!' (between entity token and shard suffix)
16
322
 
17
- Traditional relational database systems like MySQL or SQL Server implement indexing & scaling strategies at a platform level based on schemas defined at design time.
323
+ Your scalar property values used in generated properties should not include these delimiters. If they must, set custom delimiters (must match /\W+/ and not contain each other).
18
324
 
19
- NoSQL platforms like DynamoDB offer far better performance at scale, but structured index & shard keys must be defined as data elements and exploited by application logic in data retrieval & cross-shard queries. **They shift the burden of complexity from the database platform to the developer!**
325
+ ## Types you’ll use most
20
326
 
21
- EntityManager encapsulates a provider-agnostic, highly opinionated approach to the [single-table design pattern](https://aws.amazon.com/blogs/compute/creating-a-single-table-design-with-amazon-dynamodb/).
327
+ - ConfigMap<M>
328
+ - EntityItem<C>, EntityRecord<C>, EntityKey<C>, EntityToken<C>
329
+ - QueryOptions<C>, QueryResult<C>
330
+ - PageKey<C>, PageKeyMap<C>
331
+ - ShardQueryFunction<C>, ShardQueryMap<C>, ShardBump
22
332
 
23
- With EntityManager, you can:
333
+ See the full API: https://docs.karmanivero.us/entity-manager
24
334
 
25
- - Define related data entities & structured keys wth a simple, declarative configuration format.
335
+ ## Scripts (repo)
26
336
 
27
- - Specify a partition sharding strategy that maximizes query performance while permitting planned, staged scaling over time.
337
+ - build: rollup outputs ESM/CJS + .d.ts
338
+ - test: vitest with coverage
339
+ - lint: ESLint (type‑aware) + Prettier integration
340
+ - docs: TypeDoc (links to external type docs for shared utility packages)
341
+ - typecheck: tsc + tsd (type‑level tests)
28
342
 
29
- - Add or remove structured index keys from entity data objects with a single method call.
343
+ ## License
30
344
 
31
- - Perform paged, cross-shard, multi-index queries with a single method call.
345
+ BSD‑3‑Clause (see package.json).
32
346
 
33
347
  ---
34
348
 
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  var tslib = require('tslib');
4
- var radash = require('radash');
5
4
  var addKeys = require('./addKeys.js');
6
5
  var encodeGeneratedProperty = require('./encodeGeneratedProperty.js');
7
6
  var findIndexToken = require('./findIndexToken.js');
7
+ var getPrimaryKey = require('./getPrimaryKey.js');
8
8
  var ParsedConfig = require('./ParsedConfig.js');
9
9
  var query = require('./query.js');
10
10
  var removeKeys = require('./removeKeys.js');
@@ -52,59 +52,33 @@ class EntityManager {
52
52
  /**
53
53
  * Encode a generated property value. Returns a string or undefined if atomicity requirement of sharded properties not met.
54
54
  *
55
- * @param property - {@link Config.generatedProperties | Generated property} key.
55
+ * @param property - {@link Config | Config} `generatedProperties` key.
56
56
  * @param item - {@link EntityItem | `EntityItem`} object.
57
57
  *
58
58
  * @returns Encoded generated property value.
59
59
  *
60
- * @throws `Error` if `property` is not a {@link Config.generatedProperties | generated property}.
60
+ * @throws `Error` if `property` is not a {@link Config | Config} `generatedProperties` key.
61
61
  */
62
62
  encodeGeneratedProperty(property, item) {
63
63
  return encodeGeneratedProperty.encodeGeneratedProperty(this, property, item);
64
64
  }
65
- /**
66
- * Update generated properties, hash key, and range key on an {@link EntityItem | `EntityItem`} object.
67
- *
68
- * @param entityToken - {@link Config | `Config`} `entities` key.
69
- * @param item - {@link EntityItem | `EntityItem`} object.
70
- * @param overwrite - Overwrite existing properties (default `false`).
71
- *
72
- * @returns {@link EntityRecord | `EntityRecord`} object with updated properties.
73
- *
74
- * @throws `Error` if `entityToken` is invalid.
75
- */
76
- addKeys(entityToken, item, overwrite = false) {
77
- return addKeys.addKeys(this, entityToken, item, overwrite);
65
+ addKeys(entityToken, i, overwrite = false) {
66
+ if (Array.isArray(i)) {
67
+ return i.map((item) => addKeys.addKeys(this, entityToken, item, overwrite));
68
+ }
69
+ return addKeys.addKeys(this, entityToken, i, overwrite);
78
70
  }
79
- /**
80
- * Convert an {@link EntityItem | `EntityItem`} into an {@link EntityKey | `EntityKey`}.
81
- *
82
- * @param entityToken - {@link Config | `Config`} `entities` key.
83
- * @param item - {@link EntityItem | `EntityItem`} object.
84
- * @param overwrite - Overwrite existing properties (default `false`).
85
- *
86
- * @returns {@link EntityKey | `EntityKey`} extracted from shallow clone of `item` with updated properties.
87
- *
88
- * @throws `Error` if `entityToken` is invalid.
89
- */
90
- getPrimaryKey(entityToken, item, overwrite = false) {
91
- const { hashKey, rangeKey } = this.config;
92
- return radash.pick(!overwrite && item[hashKey] && item[rangeKey]
93
- ? item
94
- : addKeys.addKeys(this, entityToken, item, overwrite), [this.config.hashKey, this.config.rangeKey]);
71
+ getPrimaryKey(entityToken, i, overwrite = false) {
72
+ if (Array.isArray(i)) {
73
+ return i.map((item) => getPrimaryKey.getPrimaryKey(this, entityToken, item, overwrite));
74
+ }
75
+ return getPrimaryKey.getPrimaryKey(this, entityToken, i, overwrite);
95
76
  }
96
- /**
97
- * Strips generated properties, hash key, and range key from an {@link EntityRecord | `EntityRecord`} object.
98
- *
99
- * @param entityToken - {@link Config | `Config`} `entities` key.
100
- * @param item - {@link EntityRecord | `EntityRecord`} object.
101
- *
102
- * @returns {@link EntityItem | `EntityItem`} with generated properties, hash key & range key removed.
103
- *
104
- * @throws `Error` if `entityToken` is invalid.
105
- */
106
- removeKeys(entityToken, item) {
107
- return removeKeys.removeKeys(this, entityToken, item);
77
+ removeKeys(entityToken, i) {
78
+ if (Array.isArray(i)) {
79
+ return i.map((item) => removeKeys.removeKeys(this, entityToken, item));
80
+ }
81
+ return removeKeys.removeKeys(this, entityToken, i);
108
82
  }
109
83
  /**
110
84
  * Find an index token in a {@link Config | `Config`} object based on the index `hashKey` and `rangeKey`.