@karmaniverous/entity-manager 6.7.5 → 6.8.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.
Files changed (54) hide show
  1. package/dist/cjs/BaseEntityClient.js +1 -1
  2. package/dist/cjs/BaseQueryBuilder.js +1 -1
  3. package/dist/cjs/EntityManager.js +8 -8
  4. package/dist/cjs/ParsedConfig.js +143 -113
  5. package/dist/cjs/addKeys.js +6 -6
  6. package/dist/{mjs/decodeEntityElement.js → cjs/decodeElement.js} +10 -12
  7. package/dist/cjs/decodeGeneratedProperty.js +6 -10
  8. package/dist/cjs/dehydrateIndexItem.js +12 -11
  9. package/dist/cjs/dehydratePageKeyMap.js +10 -7
  10. package/dist/{mjs/encodeEntityElement.js → cjs/encodeElement.js} +8 -10
  11. package/dist/cjs/encodeGeneratedProperty.js +13 -14
  12. package/dist/cjs/getHashKeySpace.js +6 -6
  13. package/dist/cjs/getIndexComponents.js +6 -8
  14. package/dist/cjs/getShardBump.js +1 -1
  15. package/dist/cjs/query.js +1 -1
  16. package/dist/cjs/rehydrateIndexItem.js +12 -10
  17. package/dist/cjs/rehydratePageKeyMap.js +18 -11
  18. package/dist/cjs/removeKeys.js +3 -2
  19. package/dist/cjs/unwrapIndex.js +25 -11
  20. package/dist/cjs/updateItemHashKey.js +5 -3
  21. package/dist/cjs/updateItemRangeKey.js +6 -4
  22. package/dist/cjs/validateGeneratedProperty.js +23 -0
  23. package/dist/cjs/validateIndexToken.js +16 -0
  24. package/dist/cjs/validateTranscodedProperty.js +16 -0
  25. package/dist/index.d.ts +176 -529
  26. package/dist/mjs/BaseEntityClient.js +1 -1
  27. package/dist/mjs/BaseQueryBuilder.js +1 -1
  28. package/dist/mjs/EntityManager.js +8 -8
  29. package/dist/mjs/ParsedConfig.js +143 -113
  30. package/dist/mjs/addKeys.js +6 -6
  31. package/dist/{cjs/decodeEntityElement.js → mjs/decodeElement.js} +8 -14
  32. package/dist/mjs/decodeGeneratedProperty.js +6 -10
  33. package/dist/mjs/dehydrateIndexItem.js +12 -11
  34. package/dist/mjs/dehydratePageKeyMap.js +10 -7
  35. package/dist/{cjs/encodeEntityElement.js → mjs/encodeElement.js} +7 -13
  36. package/dist/mjs/encodeGeneratedProperty.js +13 -14
  37. package/dist/mjs/getHashKeySpace.js +6 -6
  38. package/dist/mjs/getIndexComponents.js +6 -8
  39. package/dist/mjs/getShardBump.js +1 -1
  40. package/dist/mjs/query.js +1 -1
  41. package/dist/mjs/rehydrateIndexItem.js +12 -10
  42. package/dist/mjs/rehydratePageKeyMap.js +18 -11
  43. package/dist/mjs/removeKeys.js +3 -2
  44. package/dist/mjs/unwrapIndex.js +26 -12
  45. package/dist/mjs/updateItemHashKey.js +5 -3
  46. package/dist/mjs/updateItemRangeKey.js +6 -4
  47. package/dist/mjs/validateGeneratedProperty.js +21 -0
  48. package/dist/mjs/validateIndexToken.js +14 -0
  49. package/dist/mjs/validateTranscodedProperty.js +14 -0
  50. package/package.json +5 -5
  51. package/dist/cjs/validateEntityGeneratedProperty.js +0 -29
  52. package/dist/cjs/validateEntityIndexToken.js +0 -22
  53. package/dist/mjs/validateEntityGeneratedProperty.js +0 -27
  54. package/dist/mjs/validateEntityIndexToken.js +0 -20
@@ -9,7 +9,7 @@ class BaseEntityClient {
9
9
  /**
10
10
  * DynamoDB EntityClient constructor.
11
11
  *
12
- * @param options - {@link EntityClientOptions | `EntityClientOptions`} object.
12
+ * @param options - {@link BaseEntityClientOptions | `BaseEntityClientOptions`} object.
13
13
  */
14
14
  constructor(options) {
15
15
  const { batchProcessOptions = {}, logger = console } = options;
@@ -5,7 +5,7 @@ var radash = require('radash');
5
5
  /**
6
6
  * Abstract base class supporting a fluent API for building a {@link ShardQueryMap | `ShardQueryMap`} using a database client.
7
7
  *
8
- * @category ShardQueryMapBuilder
8
+ * @category QueryBuilder
9
9
  */
10
10
  class BaseQueryBuilder {
11
11
  /** BaseQueryBuilder constructor. */
@@ -42,10 +42,10 @@ class EntityManager {
42
42
  tslib.__classPrivateFieldSet(this, _EntityManager_config, ParsedConfig.configSchema.parse(value), "f");
43
43
  }
44
44
  /**
45
- * Update generated properties, hash key, and range key on an {@link ItemMap | `ItemMap`} object.
45
+ * Update generated properties, hash key, and range key on an {@link EntityItem | `EntityItem`} object.
46
46
  *
47
- * @param entityToken - {@link ConfigKeys.entities | `this.config.entities`} key.
48
- * @param item - {@link ItemMap | `ItemMap`} object.
47
+ * @param entityToken - {@link Config | `Config`} `entities` key.
48
+ * @param item - {@link EntityItem | `EntityItem`} object.
49
49
  * @param overwrite - Overwrite existing properties (default `false`).
50
50
  *
51
51
  * @returns Shallow clone of `item` with updated properties.
@@ -56,10 +56,10 @@ class EntityManager {
56
56
  return addKeys.addKeys(this, entityToken, item, overwrite);
57
57
  }
58
58
  /**
59
- * Strips generated properties, hash key, and range key from an {@link ItemMap | `ItemMap`} object.
59
+ * Strips generated properties, hash key, and range key from an {@link EntityItem | `EntityItem`} object.
60
60
  *
61
- * @param entityToken - {@link ConfigKeys.entities | `this.config.entities`} key.
62
- * @param item - {@link ItemMap | `ItemMap`} object.
61
+ * @param entityToken - {@link Config | `Config`} `entities` key.
62
+ * @param item - {@link EntityItem | `EntityItem`} object.
63
63
  *
64
64
  * @returns Shallow clone of `item` without generated properties, hash key or range key.
65
65
  *
@@ -74,7 +74,7 @@ class EntityManager {
74
74
  * @remarks
75
75
  * The provided `shardQueryMap` performs the actual query of individual data pages on individual index/shard combinations.
76
76
  *
77
- * Individual shard query results will be combined, deduped by {@link ConfigEntity.uniqueProperty} property value, and sorted by {@link QueryOptions.sortOrder | `sortOrder`}.
77
+ * Individual shard query results will be combined, deduped by {@link Config | `Config`} `uniqueProperty` value, and sorted by {@link QueryOptions.sortOrder | `sortOrder`}.
78
78
  *
79
79
  * In queries on sharded data, expect the leading and trailing edges of returned data pages to interleave somewhat with preceding & following pages.
80
80
  *
@@ -84,7 +84,7 @@ class EntityManager {
84
84
  *
85
85
  * @returns {@link QueryResult} object.
86
86
  *
87
- * @throws Error if {@link QueryOptions.shardQueryMapBuilder | `shardQueryMapBuilder`} `pageKeyMap` keys do not match its `shardQueryMap` keys.
87
+ * @throws Error if `options` {@link QueryOptions.pageKeyMap | `pageKeyMap`} `pageKeyMap` keys do not match {@link QueryOptions.shardQueryMap | `shardQueryMap`} keys.
88
88
  */
89
89
  async query(options) {
90
90
  return await query.query(this, options);
@@ -11,16 +11,18 @@ const validateArrayUnique = (arr, ctx, identity = (item) => item, path = []) =>
11
11
  if (count > 1)
12
12
  ctx.addIssue({
13
13
  code: zod.z.ZodIssueCode.custom,
14
- message: `duplicate array element '${element}'`,
14
+ message: `duplicate array element`,
15
+ params: { element },
15
16
  path,
16
17
  });
17
18
  }
18
19
  };
19
- const validateKeyExclusive = (key, label, ref, ctx) => {
20
- if (ref.includes(key))
20
+ const validateKeysExclusive = (keys, label, ref, ctx) => {
21
+ const intersection = keys.filter((key) => ref.includes(key));
22
+ if (intersection.length)
21
23
  ctx.addIssue({
22
24
  code: zod.z.ZodIssueCode.custom,
23
- message: `${label} '${key}' is not exclusive`,
25
+ message: `${label} key collision: ${intersection.toString()}`,
24
26
  });
25
27
  };
26
28
  const componentArray = zod.z
@@ -46,25 +48,6 @@ const configSchema = zod.z
46
48
  .safe()
47
49
  .optional()
48
50
  .default(10),
49
- generated: zod.z
50
- .record(zod.z
51
- .object({
52
- atomic: zod.z.boolean().optional().default(false),
53
- elements: componentArray,
54
- sharded: zod.z.boolean().optional().default(false),
55
- })
56
- .optional())
57
- .optional()
58
- .default({}),
59
- elementTranscodes: zod.z.record(zod.z.string()).optional().default({}),
60
- indexes: zod.z
61
- .record(zod.z.object({
62
- hashKey: zod.z.string().min(1),
63
- rangeKey: zod.z.string().min(1),
64
- projections: componentArray.optional(),
65
- }))
66
- .optional()
67
- .default({}),
68
51
  shardBumps: zod.z
69
52
  .array(zod.z
70
53
  .object({
@@ -105,21 +88,30 @@ const configSchema = zod.z
105
88
  timestampProperty: zod.z.string().min(1),
106
89
  uniqueProperty: zod.z.string().min(1),
107
90
  })
108
- .strict()
109
- .superRefine((data, ctx) => {
110
- const generatedKeys = Object.keys(data.generated);
111
- // validate timestampProperty is not a generated key.
112
- validateKeyExclusive(data.timestampProperty, 'timestampProperty', generatedKeys, ctx);
113
- // validate uniqueProperty is not a generated key.
114
- validateKeyExclusive(data.uniqueProperty, 'uniqueProperty', generatedKeys, ctx);
91
+ .strict())
92
+ .optional()
93
+ .default({}),
94
+ generatedProperties: zod.z
95
+ .object({
96
+ sharded: zod.z.record(componentArray).optional().default({}),
97
+ unsharded: zod.z.record(componentArray).optional().default({}),
98
+ })
99
+ .optional()
100
+ .default({ sharded: {}, unsharded: {} }),
101
+ hashKey: zod.z.string(),
102
+ indexes: zod.z
103
+ .record(zod.z.object({
104
+ hashKey: zod.z.string().min(1),
105
+ rangeKey: zod.z.string().min(1),
106
+ projections: componentArray.optional(),
115
107
  }))
116
108
  .optional()
117
109
  .default({}),
118
110
  generatedKeyDelimiter: zod.z.string().regex(/\W+/).optional().default('|'),
119
111
  generatedValueDelimiter: zod.z.string().regex(/\W+/).optional().default('#'),
112
+ propertyTranscodes: zod.z.record(zod.z.string()).optional().default({}),
113
+ rangeKey: zod.z.string(),
120
114
  shardKeyDelimiter: zod.z.string().regex(/\W+/).optional().default('!'),
121
- hashKey: zod.z.string().optional().default('hashKey'),
122
- rangeKey: zod.z.string().optional().default('rangeKey'),
123
115
  throttle: zod.z.number().int().positive().safe().optional().default(10),
124
116
  transcodes: zod.z
125
117
  .record(zod.z
@@ -138,12 +130,20 @@ const configSchema = zod.z
138
130
  ctx.addIssue({
139
131
  code: zod.z.ZodIssueCode.custom,
140
132
  message: 'generatedKeyDelimiter contains generatedValueDelimiter',
133
+ params: {
134
+ generatedKeyDelimiter: data.generatedKeyDelimiter,
135
+ generatedValueDelimiter: data.generatedValueDelimiter,
136
+ },
141
137
  path: ['generatedKeyDelimiter'],
142
138
  });
143
139
  if (data.generatedKeyDelimiter.includes(data.shardKeyDelimiter))
144
140
  ctx.addIssue({
145
141
  code: zod.z.ZodIssueCode.custom,
146
142
  message: 'generatedKeyDelimiter contains shardKeyDelimiter',
143
+ params: {
144
+ generatedKeyDelimiter: data.generatedKeyDelimiter,
145
+ shardKeyDelimiter: data.shardKeyDelimiter,
146
+ },
147
147
  path: ['generatedKeyDelimiter'],
148
148
  });
149
149
  // validate no generated value delimiter collision
@@ -151,12 +151,20 @@ const configSchema = zod.z
151
151
  ctx.addIssue({
152
152
  code: zod.z.ZodIssueCode.custom,
153
153
  message: 'generatedValueDelimiter contains generatedKeyDelimiter',
154
+ params: {
155
+ generatedValueDelimiter: data.generatedValueDelimiter,
156
+ generatedKeyDelimiter: data.generatedKeyDelimiter,
157
+ },
154
158
  path: ['generatedValueDelimiter'],
155
159
  });
156
160
  if (data.generatedValueDelimiter.includes(data.shardKeyDelimiter))
157
161
  ctx.addIssue({
158
162
  code: zod.z.ZodIssueCode.custom,
159
163
  message: 'generatedValueDelimiter contains shardKeyDelimiter',
164
+ params: {
165
+ generatedValueDelimiter: data.generatedValueDelimiter,
166
+ shardKeyDelimiter: data.shardKeyDelimiter,
167
+ },
160
168
  path: ['generatedValueDelimiter'],
161
169
  });
162
170
  // validate no shard key delimiter collision
@@ -164,103 +172,125 @@ const configSchema = zod.z
164
172
  ctx.addIssue({
165
173
  code: zod.z.ZodIssueCode.custom,
166
174
  message: 'shardKeyDelimiter contains generatedKeyDelimiter',
175
+ params: {
176
+ generatedKeyDelimiter: data.generatedKeyDelimiter,
177
+ shardKeyDelimiter: data.shardKeyDelimiter,
178
+ },
167
179
  path: ['shardKeyDelimiter'],
168
180
  });
169
181
  if (data.shardKeyDelimiter.includes(data.generatedValueDelimiter))
170
182
  ctx.addIssue({
171
183
  code: zod.z.ZodIssueCode.custom,
172
184
  message: 'shardKeyDelimiter contains generatedValueDelimiter',
185
+ params: {
186
+ generatedValueDelimiter: data.generatedValueDelimiter,
187
+ shardKeyDelimiter: data.shardKeyDelimiter,
188
+ },
173
189
  path: ['shardKeyDelimiter'],
174
190
  });
175
- const reservedKeys = Object.values(data.entities).reduce((reserved, { generated, timestampProperty, uniqueProperty }) => new Set([
176
- ...reserved,
177
- ...Object.keys(generated),
178
- timestampProperty,
179
- uniqueProperty,
180
- ]), new Set());
181
- // validate hashKey is not a reserved key.
182
- validateKeyExclusive(data.hashKey, 'hashKey', [...reservedKeys, data.rangeKey], ctx);
183
- // validate rangeKey is not a reserved key.
184
- validateKeyExclusive(data.rangeKey, 'rangeKey', [...reservedKeys, data.hashKey], ctx);
185
- // validate entities
191
+ // get reserved keys
192
+ const shardedKeys = Object.keys(data.generatedProperties.sharded);
193
+ const unshardedKeys = Object.keys(data.generatedProperties.unsharded);
194
+ const transcodedProperties = Object.keys(data.propertyTranscodes);
195
+ // validate hashKey exclusive.
196
+ validateKeysExclusive([data.hashKey], 'hashKey', [
197
+ data.rangeKey,
198
+ ...shardedKeys,
199
+ ...unshardedKeys,
200
+ ...transcodedProperties,
201
+ ], ctx);
202
+ // validate rangeKey exclusive.
203
+ validateKeysExclusive([data.rangeKey], 'rangeKey', [...shardedKeys, ...unshardedKeys, ...transcodedProperties], ctx);
204
+ // validate shardedKeys exclusive.
205
+ validateKeysExclusive(shardedKeys, 'shardedKeys', [...unshardedKeys, ...transcodedProperties], ctx);
206
+ // validate unshardedKeys exclusive.
207
+ validateKeysExclusive(unshardedKeys, 'unshardedKeys', transcodedProperties, ctx);
208
+ // validate all propertyTranscode values are transcode keys.
186
209
  const transcodes = Object.keys(data.transcodes);
187
- for (const [entityToken, entity] of Object.entries(data.entities)) {
188
- // validate all entity generated element type values are transcode keys.
189
- for (const [element, generatedElementType] of Object.entries(entity.elementTranscodes))
190
- if (!transcodes.includes(generatedElementType))
210
+ for (const [property, transcode] of Object.entries(data.propertyTranscodes))
211
+ if (!transcodes.includes(transcode))
212
+ ctx.addIssue({
213
+ code: zod.z.ZodIssueCode.invalid_enum_value,
214
+ options: transcodes,
215
+ path: ['propertyTranscodes', property],
216
+ received: transcode,
217
+ });
218
+ // Validate all sharded property elements are transcoded properties.
219
+ for (const [property, elements] of Object.entries(data.generatedProperties.sharded))
220
+ for (const element of elements)
221
+ if (!transcodedProperties.includes(element))
191
222
  ctx.addIssue({
192
223
  code: zod.z.ZodIssueCode.invalid_enum_value,
193
- options: transcodes,
194
- path: ['entities', entityToken, 'elementTranscodes', element],
195
- received: generatedElementType,
196
- });
197
- // validate all entity generated property elements have a corresponding entity element type.
198
- const typedElements = Object.keys(entity.elementTranscodes);
199
- for (const [generatedKey, generated] of Object.entries(entity.generated))
200
- for (const element of generated?.elements ?? [])
201
- if (!typedElements.includes(element))
202
- ctx.addIssue({
203
- code: zod.z.ZodIssueCode.invalid_enum_value,
204
- options: typedElements,
205
- path: [
206
- 'entities',
207
- entityToken,
208
- 'generated',
209
- generatedKey,
210
- 'elements',
211
- ],
212
- received: element,
213
- });
214
- // validate indexes.
215
- const generatedProperties = Object.keys(entity.generated);
216
- for (const [indexKey, { hashKey, rangeKey, projections },] of Object.entries(entity.indexes)) {
217
- // validate index hash key is sharded
218
- if (hashKey !== data.hashKey && !entity.generated[hashKey]?.sharded)
219
- ctx.addIssue({
220
- code: zod.z.ZodIssueCode.custom,
221
- message: 'index hash key is not sharded',
222
- path: ['entities', entityToken, 'indexes', indexKey, 'hashKey'],
224
+ options: transcodedProperties,
225
+ received: element,
226
+ path: ['generatedProperties', 'sharded', property],
223
227
  });
224
- // validate index range key is unsharded
225
- if (rangeKey !== data.rangeKey && entity.generated[rangeKey]?.sharded)
228
+ // Validate all unsharded property elements are transcoded properties.
229
+ for (const [property, elements] of Object.entries(data.generatedProperties.unsharded))
230
+ for (const element of elements)
231
+ if (!transcodedProperties.includes(element))
226
232
  ctx.addIssue({
227
- code: zod.z.ZodIssueCode.custom,
228
- message: 'index range key is sharded',
229
- path: ['entities', entityToken, 'indexes', indexKey, 'rangeKey'],
233
+ code: zod.z.ZodIssueCode.invalid_enum_value,
234
+ options: transcodedProperties,
235
+ received: element,
236
+ path: ['generatedProperties', 'unsharded', property],
230
237
  });
231
- // validate all ungenerated entity index components have a corresponding entity element type
232
- for (const component of [hashKey, rangeKey])
233
- if (![data.hashKey, data.rangeKey, ...generatedProperties].includes(component) &&
234
- !typedElements.includes(component))
238
+ // Validate indexes.
239
+ for (const [indexKey, { hashKey, rangeKey, projections }] of Object.entries(data.indexes)) {
240
+ // Validate hash key is sharded.
241
+ if (![data.hashKey, ...shardedKeys].includes(hashKey)) {
242
+ ctx.addIssue({
243
+ code: zod.z.ZodIssueCode.invalid_enum_value,
244
+ options: [data.hashKey, ...shardedKeys],
245
+ path: ['indexes', indexKey, 'hashKey'],
246
+ received: hashKey,
247
+ });
248
+ }
249
+ // Validate range key is unsharded or transcodable.
250
+ if (![data.rangeKey, ...unshardedKeys, ...transcodedProperties].includes(rangeKey)) {
251
+ ctx.addIssue({
252
+ code: zod.z.ZodIssueCode.invalid_enum_value,
253
+ options: [data.rangeKey, ...unshardedKeys],
254
+ path: ['indexes', indexKey, 'rangeKey'],
255
+ received: rangeKey,
256
+ });
257
+ }
258
+ // Validate no index projections are keys.
259
+ if (projections)
260
+ for (const projection of projections)
261
+ if ([
262
+ data.hashKey,
263
+ data.rangeKey,
264
+ hashKey,
265
+ rangeKey,
266
+ ...shardedKeys,
267
+ ...unshardedKeys,
268
+ ].includes(projection))
235
269
  ctx.addIssue({
236
- code: zod.z.ZodIssueCode.invalid_enum_value,
237
- options: typedElements,
238
- path: [
239
- 'entities',
240
- entityToken,
241
- 'indexes',
242
- indexKey,
243
- 'components',
244
- ],
245
- received: component,
270
+ code: zod.z.ZodIssueCode.custom,
271
+ message: 'index projection is a key',
272
+ params: { projection },
273
+ path: ['indexes', indexKey, 'projections'],
246
274
  });
247
- // validate no index projections are index components, hashKey, or rangeKey
248
- if (projections)
249
- for (const projection of projections) {
250
- if ([data.hashKey, data.rangeKey, hashKey, rangeKey].includes(projection))
251
- ctx.addIssue({
252
- code: zod.z.ZodIssueCode.custom,
253
- message: 'index projection is an index component, hash key, or range key',
254
- path: [
255
- 'entities',
256
- entityToken,
257
- 'indexes',
258
- indexKey,
259
- 'projections',
260
- ],
261
- });
262
- }
263
- }
275
+ }
276
+ // validate entities
277
+ for (const [entityToken, { timestampProperty, uniqueProperty },] of Object.entries(data.entities)) {
278
+ // validate timestampProperty is a transcoded property.
279
+ if (!transcodedProperties.includes(timestampProperty))
280
+ ctx.addIssue({
281
+ code: zod.z.ZodIssueCode.invalid_enum_value,
282
+ options: transcodedProperties,
283
+ path: ['entities', entityToken, 'timestampProperty'],
284
+ received: timestampProperty,
285
+ });
286
+ // validate uniqueProperty is a transcoded property.
287
+ if (!transcodedProperties.includes(uniqueProperty))
288
+ ctx.addIssue({
289
+ code: zod.z.ZodIssueCode.invalid_enum_value,
290
+ options: transcodedProperties,
291
+ path: ['entities', entityToken, 'uniqueProperty'],
292
+ received: uniqueProperty,
293
+ });
264
294
  }
265
295
  });
266
296
 
@@ -7,11 +7,11 @@ var updateItemRangeKey = require('./updateItemRangeKey.js');
7
7
  var validateEntityToken = require('./validateEntityToken.js');
8
8
 
9
9
  /**
10
- * Update generated properties, hash key, and range key on an {@link ItemMap | `ItemMap`} object.
10
+ * Update generated properties, hash key, and range key on an {@link EntityItem | `EntityItem`} object.
11
11
  *
12
12
  * @param entityManager - {@link EntityManager | `EntityManager`} instance.
13
- * @param entityToken - {@link ConfigKeys.entities | `this.config.entities`} key.
14
- * @param item - {@link ItemMap | `ItemMap`} object.
13
+ * @param entityToken - {@link ConfigEntity.uniqueProperty | `this.config.entities`} key.
14
+ * @param item - {@link EntityItem | `EntityItem`} object.
15
15
  * @param overwrite - Overwrite existing properties (default `false`).
16
16
  *
17
17
  * @returns Shallow clone of `item` with updated properties.
@@ -27,10 +27,10 @@ function addKeys(entityManager, entityToken, item, overwrite = false) {
27
27
  // Update range key.
28
28
  newItem = updateItemRangeKey.updateItemRangeKey(entityManager, entityToken, newItem, overwrite);
29
29
  // Update generated properties.
30
- for (const property in entityManager.config.entities[entityToken]
31
- .generated) {
30
+ const { sharded, unsharded } = entityManager.config.generatedProperties;
31
+ for (const property in { ...sharded, ...unsharded }) {
32
32
  if (overwrite || entityTools.isNil(item[property])) {
33
- const encoded = encodeGeneratedProperty.encodeGeneratedProperty(entityManager, entityToken, property, newItem);
33
+ const encoded = encodeGeneratedProperty.encodeGeneratedProperty(entityManager, property, newItem);
34
34
  if (encoded)
35
35
  Object.assign(newItem, { [property]: encoded });
36
36
  else
@@ -1,14 +1,15 @@
1
- import { validateEntityToken } from './validateEntityToken.js';
1
+ 'use strict';
2
+
3
+ var validateTranscodedProperty = require('./validateTranscodedProperty.js');
2
4
 
3
5
  /**
4
- * Decode an {@link Entity | `Entity`} generated property element or ungenerated index component using the associated {@link Transcodes | Transcodes} `encode` function.
6
+ * Decode an {@link EntityItem | `EntityItem`} generated property element or ungenerated index component using the associated {@link Transcodes | Transcodes} `encode` function.
5
7
  *
6
8
  * Returns all `undefined` values.
7
9
  *
8
10
  * If `element` is the {@link Config.hashKey | `hashKey`} or {@link Config.rangeKey | `rangeKey`}, returns the value as-is.
9
11
  *
10
12
  * @param entityManager - {@link EntityManager | `EntityManager`} instance.
11
- * @param entityToken - {@link ConfigKeys.entities | `entityManager.config.entities`} key.
12
13
  * @param element - The {@link Entity | `Entity`} generated property element or ungenerated index component to encode.
13
14
  * @param value - Encoded entity element.
14
15
  *
@@ -16,17 +17,15 @@ import { validateEntityToken } from './validateEntityToken.js';
16
17
  *
17
18
  * @throws `Error` if `entityToken` is invalid.
18
19
  */
19
- function decodeEntityElement(entityManager, entityToken, element, value) {
20
+ function decodeElement(entityManager, element, value) {
20
21
  try {
21
- validateEntityToken(entityManager, entityToken);
22
- const { entities, hashKey, rangeKey, transcodes } = entityManager.config;
22
+ // Validate params.
23
+ validateTranscodedProperty.validateTranscodedProperty(entityManager, element);
23
24
  if (!value)
24
25
  return;
25
- if ([hashKey, rangeKey].includes(element))
26
- return value;
27
- const decoded = transcodes[entities[entityToken].elementTranscodes[element]].decode(value);
26
+ const { propertyTranscodes, transcodes } = entityManager.config;
27
+ const decoded = transcodes[propertyTranscodes[element]].decode(value);
28
28
  entityManager.logger.debug('decoded entity element', {
29
- entityToken,
30
29
  element,
31
30
  value,
32
31
  decoded,
@@ -36,7 +35,6 @@ function decodeEntityElement(entityManager, entityToken, element, value) {
36
35
  catch (error) {
37
36
  if (error instanceof Error)
38
37
  entityManager.logger.error(error.message, {
39
- entityToken,
40
38
  element,
41
39
  value,
42
40
  });
@@ -44,4 +42,4 @@ function decodeEntityElement(entityManager, entityToken, element, value) {
44
42
  }
45
43
  }
46
44
 
47
- export { decodeEntityElement };
45
+ exports.decodeElement = decodeElement;
@@ -1,25 +1,22 @@
1
1
  'use strict';
2
2
 
3
3
  var radash = require('radash');
4
- var decodeEntityElement = require('./decodeEntityElement.js');
5
- var validateEntityToken = require('./validateEntityToken.js');
4
+ var decodeElement = require('./decodeElement.js');
6
5
 
7
6
  /**
8
- * Decode a generated property value. Returns a partial ItemMap.
7
+ * Decode a generated property value. Returns an {@link EntityItem | `EntityItem`}.
9
8
  *
10
9
  * @param entityManager - {@link EntityManager | `EntityManager`} instance.
11
10
  * @param entityToken - `entityManager.config.entities` key.
12
11
  * @param encoded - Encoded generated property value.
13
12
  *
14
- * @returns Partial {@link ItemMap | `ItemMap`} object with updated properties decoded from `encoded`.
13
+ * @returns {@link EntityItem | `EntityItem`} object with updated properties decoded from `encoded`.
15
14
  *
16
15
  * @throws `Error` if `entityToken` is invalid.
17
16
  */
18
- function decodeGeneratedProperty(entityManager, entityToken, encoded) {
17
+ function decodeGeneratedProperty(entityManager, encoded) {
19
18
  try {
20
19
  const { generatedKeyDelimiter, generatedValueDelimiter, hashKey, shardKeyDelimiter, } = entityManager.config;
21
- // Validate params.
22
- validateEntityToken.validateEntityToken(entityManager, entityToken);
23
20
  // Handle degenerate case.
24
21
  if (!encoded)
25
22
  return {};
@@ -37,9 +34,8 @@ function decodeGeneratedProperty(entityManager, entityToken, encoded) {
37
34
  return pair;
38
35
  });
39
36
  // Assign decoded properties.
40
- Object.assign(decoded, radash.objectify(values, ([key]) => key, ([key, value]) => decodeEntityElement.decodeEntityElement(entityManager, entityToken, key, value)));
37
+ Object.assign(decoded, radash.objectify(values, ([key]) => key, ([key, value]) => decodeElement.decodeElement(entityManager, key, value)));
41
38
  entityManager.logger.debug('decoded generated property', {
42
- entityToken,
43
39
  encoded,
44
40
  decoded,
45
41
  });
@@ -47,7 +43,7 @@ function decodeGeneratedProperty(entityManager, entityToken, encoded) {
47
43
  }
48
44
  catch (error) {
49
45
  if (error instanceof Error)
50
- entityManager.logger.error(error.message, { entityToken, encoded });
46
+ entityManager.logger.error(error.message, { encoded });
51
47
  throw error;
52
48
  }
53
49
  }
@@ -1,11 +1,12 @@
1
1
  'use strict';
2
2
 
3
- var encodeEntityElement = require('./encodeEntityElement.js');
3
+ var encodeElement = require('./encodeElement.js');
4
4
  var unwrapIndex = require('./unwrapIndex.js');
5
- var validateEntityIndexToken = require('./validateEntityIndexToken.js');
5
+ var validateEntityToken = require('./validateEntityToken.js');
6
+ var validateIndexToken = require('./validateIndexToken.js');
6
7
 
7
8
  /**
8
- * Condense a partial {@link ItemMap | `ItemMap`} object into a delimited string representing the deduped, sorted, ungenerated component elements of an {@link ConfigEntity.indexes | Entity index}.
9
+ * Condense an {@link EntityItem | `EntityItem`} into a delimited string representing the deduped, sorted, ungenerated component elements of an {@link Config.indexes | index}, leaving out those of the index hash key.
9
10
  *
10
11
  * @remarks
11
12
  * Reverses {@link EntityManager.rehydrateIndexItem | `rehydrateIndexItem`}.
@@ -18,31 +19,31 @@ var validateEntityIndexToken = require('./validateEntityIndexToken.js');
18
19
  * `item` must be populated with all required index component elements!
19
20
  *
20
21
  * @param entityManager - {@link EntityManager | `EntityManager`} instance.
21
- * @param entityToken - {@link ConfigKeys.entities | `entityManager.config.entities`} key.
22
- * @param indexToken - {@link ConfigEntity.indexes | `entityManager.config.entities.<entityToken>.indexes`} key.
23
- * @param item - Partial {@link ItemMap | `ItemMap`} object.
22
+ * @param entityToken - {@link Config.entities | `entityManager.config.entities`} key.
23
+ * @param indexToken - {@link ConfigEntity.indexes | `entityManager.config.indexes`} key.
24
+ * @param item - {@link EntityItem | `EntityItem`} object.
24
25
  *
25
26
  * @returns Dehydrated index value.
26
27
  *
27
- * @throws `Error` if `entityToken` is invalid.
28
28
  * @throws `Error` if `indexToken` is invalid.
29
29
  */
30
30
  function dehydrateIndexItem(entityManager, entityToken, indexToken, item) {
31
31
  try {
32
- const { generatedKeyDelimiter } = entityManager.config;
33
32
  // Validate params.
34
- validateEntityIndexToken.validateEntityIndexToken(entityManager, entityToken, indexToken);
33
+ validateEntityToken.validateEntityToken(entityManager, entityToken);
34
+ validateIndexToken.validateIndexToken(entityManager, indexToken);
35
35
  // Handle degenerate case.
36
36
  if (!item)
37
37
  return '';
38
38
  // Unwrap index elements.
39
- const { hashKey } = entityManager.config.entities[entityToken].indexes[indexToken];
39
+ const { hashKey } = entityManager.config.indexes[indexToken];
40
40
  const elements = unwrapIndex.unwrapIndex(entityManager, entityToken, indexToken, [
41
41
  hashKey,
42
42
  ]);
43
43
  // Join index element values.
44
+ const { generatedKeyDelimiter } = entityManager.config;
44
45
  const dehydrated = elements
45
- .map((element) => encodeEntityElement.encodeEntityElement(entityManager, entityToken, element, item))
46
+ .map((element) => encodeElement.encodeElement(entityManager, element, item))
46
47
  .join(generatedKeyDelimiter);
47
48
  entityManager.logger.debug('dehydrated index', {
48
49
  item,
@@ -2,8 +2,8 @@
2
2
 
3
3
  var decodeGeneratedProperty = require('./decodeGeneratedProperty.js');
4
4
  var dehydrateIndexItem = require('./dehydrateIndexItem.js');
5
- var validateEntityIndexToken = require('./validateEntityIndexToken.js');
6
5
  var validateEntityToken = require('./validateEntityToken.js');
6
+ var validateIndexToken = require('./validateIndexToken.js');
7
7
 
8
8
  /**
9
9
  * Dehydrate a {@link PageKeyMap | `PageKeyMap`} object into an array of dehydrated page keys.
@@ -11,7 +11,7 @@ var validateEntityToken = require('./validateEntityToken.js');
11
11
  * Reverses {@link EntityManager.rehydratePageKeyMap | `rehydratePageKeyMap`}.
12
12
  *
13
13
  * @param entityManager - {@link EntityManager | `EntityManager`} instance.
14
- * @param entityToken - {@link ConfigKeys.entities | `entityManager.config.entities`} key.
14
+ * @param entityToken - {@link Config.entities | `entityManager.config.entities`} key.
15
15
  * @param pageKeyMap - {@link PageKeyMap | `PageKeyMap`} object to dehydrate.
16
16
  *
17
17
  * @returns Array of dehydrated page keys.
@@ -40,7 +40,7 @@ function dehydratePageKeyMap(entityManager, entityToken, pageKeyMap) {
40
40
  }
41
41
  // Extract, sort & validate indexs.
42
42
  const indexes = Object.keys(pageKeyMap).sort();
43
- indexes.map((index) => validateEntityIndexToken.validateEntityIndexToken(entityManager, entityToken, index));
43
+ indexes.map((index) => validateIndexToken.validateIndexToken(entityManager, index));
44
44
  // Extract & sort hash keys.
45
45
  const hashKeys = Object.keys(pageKeyMap[indexes[0]]);
46
46
  // Dehydrate page keys.
@@ -54,13 +54,16 @@ function dehydratePageKeyMap(entityManager, entityToken, pageKeyMap) {
54
54
  }
55
55
  // Compose item from page key
56
56
  const item = Object.entries(pageKeyMap[index][hashKey]).reduce((item, [property, value]) => {
57
- if (property in entityManager.config.entities[entityToken].generated ||
58
- property === entityManager.config.rangeKey)
59
- Object.assign(item, decodeGeneratedProperty.decodeGeneratedProperty(entityManager, entityToken, value));
57
+ if (property === entityManager.config.rangeKey ||
58
+ property in entityManager.config.generatedProperties.sharded ||
59
+ property in entityManager.config.generatedProperties.unsharded)
60
+ Object.assign(item, decodeGeneratedProperty.decodeGeneratedProperty(entityManager, value));
60
61
  else
61
62
  Object.assign(item, { [property]: value });
62
63
  return item;
63
- }, {});
64
+ },
65
+ // eslint-disable-next-line @typescript-eslint/prefer-reduce-type-parameter
66
+ {});
64
67
  // Dehydrate index from item.
65
68
  dehydrated.push(dehydrateIndexItem.dehydrateIndexItem(entityManager, entityToken, index, item));
66
69
  }