@karmaniverous/entity-manager 6.14.0 → 6.14.2

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.
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var radash = require('radash');
4
+ var stringHash = require('string-hash');
4
5
  var encodeGeneratedProperty = require('./encodeGeneratedProperty.js');
5
6
  var validateGeneratedProperty = require('./validateGeneratedProperty.js');
6
7
 
@@ -24,6 +25,9 @@ function getHashKeySpace(entityManager, entityToken, hashKeyToken, item, timesta
24
25
  if (hashKeyToken !== entityManager.config.hashKey)
25
26
  validateGeneratedProperty.validateGeneratedProperty(entityManager, hashKeyToken, true);
26
27
  const { shardBumps } = entityManager.config.entities[entityToken];
28
+ // Detect presence of the entity's unique property on the item.
29
+ const uniqueProp = entityManager.config.entities[entityToken].uniqueProperty;
30
+ const uniqueValue = item[uniqueProp];
27
31
  const hashKeySpace = shardBumps
28
32
  // Filter shard bumps by timestamp range.
29
33
  .filter((bump, i) => (i === shardBumps.length - 1 ||
@@ -32,9 +36,18 @@ function getHashKeySpace(entityManager, entityToken, hashKeyToken, item, timesta
32
36
  // Generate shard key space.
33
37
  .flatMap(({ charBits, chars }) => {
34
38
  const radix = 2 ** charBits;
35
- return chars
36
- ? [...radash.range(0, radix ** chars - 1)].map((char) => char.toString(radix).padStart(chars, '0'))
37
- : '';
39
+ // If the item's unique property is present, deterministically
40
+ // compute exactly one shard suffix for this bump. Otherwise,
41
+ // enumerate the full shard space for the bump.
42
+ if (chars) {
43
+ if (uniqueValue) {
44
+ const space = radix ** chars;
45
+ const mod = stringHash(uniqueValue) % space;
46
+ return mod.toString(radix).padStart(chars, '0');
47
+ }
48
+ return [...radash.range(0, radix ** chars - 1)].map((char) => char.toString(radix).padStart(chars, '0'));
49
+ }
50
+ return '';
38
51
  })
39
52
  // Map shard keys to hash keys.
40
53
  .map((shardKey) => {
@@ -47,7 +47,9 @@ function rehydratePageKeyMap(entityManager, entityToken, indexTokens, item, dehy
47
47
  if (hashKeys.length > 1)
48
48
  throw new Error('inconsistent hashKeys');
49
49
  const [hashKeyToken] = hashKeys;
50
- indexTokens.map((index) => validateIndexToken.validateIndexToken(entityManager, index));
50
+ indexTokens.map((index) => {
51
+ validateIndexToken.validateIndexToken(entityManager, index);
52
+ });
51
53
  // Shortcut empty dehydrated.
52
54
  if (dehydrated && !dehydrated.length)
53
55
  return [hashKeyToken, {}];
@@ -17,14 +17,16 @@ function removeKeys(entityManager, entityToken, item) {
17
17
  try {
18
18
  // Validate params.
19
19
  validateEntityToken.validateEntityToken(entityManager, entityToken);
20
- // Delete hash & range keys.
21
- const newItem = { ...item };
22
- delete newItem[entityManager.config.hashKey];
23
- delete newItem[entityManager.config.rangeKey];
24
- // Delete generated properties.
25
- const { sharded, unsharded } = entityManager.config.generatedProperties;
26
- for (const property in { ...sharded, ...unsharded })
27
- delete newItem[property];
20
+ // Build a set of keys to strip (hash, range, and all generated properties).
21
+ const { hashKey, rangeKey, generatedProperties: { sharded, unsharded }, } = entityManager.config;
22
+ const keysToStrip = new Set([
23
+ hashKey,
24
+ rangeKey,
25
+ ...Object.keys(sharded),
26
+ ...Object.keys(unsharded),
27
+ ]);
28
+ // Create a shallow copy of item omitting the keys above (no delete operator).
29
+ const newItem = Object.fromEntries(Object.entries(item).filter(([key]) => !keysToStrip.has(key)));
28
30
  entityManager.logger.debug('stripped entity item generated properties', {
29
31
  entityToken,
30
32
  item,
@@ -42,12 +42,15 @@ function updateItemHashKey(entityManager, entityToken, item, overwrite = false)
42
42
  if (chars) {
43
43
  // Radix is the numerical base of the shardKey.
44
44
  const radix = 2 ** charBits;
45
+ // Compute the full shard space for this bump. Use radix ** chars to ensure
46
+ // all placeholders are utilized (e.g., chars=2, charBits=2 => 16 combos).
47
+ const space = radix ** chars;
45
48
  // Get item unique property & validate.
46
49
  const uniqueId = item[entityManager.config.entities[entityToken]
47
50
  .uniqueProperty];
48
51
  if (entityTools.isNil(uniqueId))
49
52
  throw new Error(`missing item unique property`);
50
- hashKey += (stringHash(uniqueId.toString()) % (chars * radix))
53
+ hashKey += (stringHash(uniqueId) % space)
51
54
  .toString(radix)
52
55
  .padStart(chars, '0');
53
56
  }
package/dist/index.d.ts CHANGED
@@ -157,31 +157,15 @@ type EntityRecord<C extends BaseConfigMap> = EntityItem<C> & EntityKey<C>;
157
157
  */
158
158
  type EntityToken<C extends BaseConfigMap> = keyof Exactify<C['EntityMap']> & string;
159
159
 
160
- declare const configSchema: z.ZodEffects<z.ZodObject<{
160
+ declare const configSchema: z.ZodObject<{
161
161
  entities: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
162
162
  defaultLimit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
163
163
  defaultPageSize: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
164
- shardBumps: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{
164
+ shardBumps: z.ZodPipe<z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{
165
165
  timestamp: z.ZodNumber;
166
166
  charBits: z.ZodNumber;
167
167
  chars: z.ZodNumber;
168
- }, "strict", z.ZodTypeAny, {
169
- timestamp: number;
170
- charBits: number;
171
- chars: number;
172
- }, {
173
- timestamp: number;
174
- charBits: number;
175
- chars: number;
176
- }>, "many">>>, {
177
- timestamp: number;
178
- charBits: number;
179
- chars: number;
180
- }[], {
181
- timestamp: number;
182
- charBits: number;
183
- chars: number;
184
- }[] | undefined>, {
168
+ }, z.core.$strict>>>>, z.ZodTransform<{
185
169
  timestamp: number;
186
170
  charBits: number;
187
171
  chars: number;
@@ -189,62 +173,20 @@ declare const configSchema: z.ZodEffects<z.ZodObject<{
189
173
  timestamp: number;
190
174
  charBits: number;
191
175
  chars: number;
192
- }[] | undefined>, {
193
- timestamp: number;
194
- charBits: number;
195
- chars: number;
196
- }[], {
197
- timestamp: number;
198
- charBits: number;
199
- chars: number;
200
- }[] | undefined>;
176
+ }[]>>;
201
177
  timestampProperty: z.ZodString;
202
178
  uniqueProperty: z.ZodString;
203
- }, "strict", z.ZodTypeAny, {
204
- defaultLimit: number;
205
- defaultPageSize: number;
206
- shardBumps: {
207
- timestamp: number;
208
- charBits: number;
209
- chars: number;
210
- }[];
211
- timestampProperty: string;
212
- uniqueProperty: string;
213
- }, {
214
- timestampProperty: string;
215
- uniqueProperty: string;
216
- defaultLimit?: number | undefined;
217
- defaultPageSize?: number | undefined;
218
- shardBumps?: {
219
- timestamp: number;
220
- charBits: number;
221
- chars: number;
222
- }[] | undefined;
223
- }>>>>;
179
+ }, z.core.$strict>>>>;
224
180
  generatedProperties: z.ZodDefault<z.ZodOptional<z.ZodObject<{
225
- sharded: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEffects<z.ZodArray<z.ZodString, "atleastone">, [string, ...string[]], [string, ...string[]]>>>>;
226
- unsharded: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEffects<z.ZodArray<z.ZodString, "atleastone">, [string, ...string[]], [string, ...string[]]>>>>;
227
- }, "strip", z.ZodTypeAny, {
228
- sharded: Record<string, [string, ...string[]]>;
229
- unsharded: Record<string, [string, ...string[]]>;
230
- }, {
231
- sharded?: Record<string, [string, ...string[]]> | undefined;
232
- unsharded?: Record<string, [string, ...string[]]> | undefined;
233
- }>>>;
181
+ sharded: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>>;
182
+ unsharded: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>>;
183
+ }, z.core.$strip>>>;
234
184
  hashKey: z.ZodString;
235
185
  indexes: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
236
186
  hashKey: z.ZodString;
237
187
  rangeKey: z.ZodString;
238
- projections: z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodString, "many">, string[], string[]>>;
239
- }, "strip", z.ZodTypeAny, {
240
- hashKey: string;
241
- rangeKey: string;
242
- projections?: string[] | undefined;
243
- }, {
244
- hashKey: string;
245
- rangeKey: string;
246
- projections?: string[] | undefined;
247
- }>>>>;
188
+ projections: z.ZodOptional<z.ZodArray<z.ZodString>>;
189
+ }, z.core.$strip>>>>;
248
190
  generatedKeyDelimiter: z.ZodDefault<z.ZodOptional<z.ZodString>>;
249
191
  generatedValueDelimiter: z.ZodDefault<z.ZodOptional<z.ZodString>>;
250
192
  propertyTranscodes: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>>;
@@ -252,144 +194,10 @@ declare const configSchema: z.ZodEffects<z.ZodObject<{
252
194
  shardKeyDelimiter: z.ZodDefault<z.ZodOptional<z.ZodString>>;
253
195
  throttle: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
254
196
  transcodes: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
255
- encode: z.ZodFunction<z.ZodTuple<[z.ZodAny], z.ZodUnknown>, z.ZodString>;
256
- decode: z.ZodFunction<z.ZodTuple<[z.ZodString], z.ZodUnknown>, z.ZodAny>;
257
- }, "strict", z.ZodTypeAny, {
258
- encode: (args_0: any, ...args: unknown[]) => string;
259
- decode: (args_0: string, ...args: unknown[]) => any;
260
- }, {
261
- encode: (args_0: any, ...args: unknown[]) => string;
262
- decode: (args_0: string, ...args: unknown[]) => any;
263
- }>>>>;
264
- }, "strict", z.ZodTypeAny, {
265
- hashKey: string;
266
- rangeKey: string;
267
- entities: Record<string, {
268
- defaultLimit: number;
269
- defaultPageSize: number;
270
- shardBumps: {
271
- timestamp: number;
272
- charBits: number;
273
- chars: number;
274
- }[];
275
- timestampProperty: string;
276
- uniqueProperty: string;
277
- }>;
278
- generatedProperties: {
279
- sharded: Record<string, [string, ...string[]]>;
280
- unsharded: Record<string, [string, ...string[]]>;
281
- };
282
- propertyTranscodes: Record<string, string>;
283
- transcodes: Record<string, {
284
- encode: (args_0: any, ...args: unknown[]) => string;
285
- decode: (args_0: string, ...args: unknown[]) => any;
286
- }>;
287
- indexes: Record<string, {
288
- hashKey: string;
289
- rangeKey: string;
290
- projections?: string[] | undefined;
291
- }>;
292
- generatedKeyDelimiter: string;
293
- generatedValueDelimiter: string;
294
- shardKeyDelimiter: string;
295
- throttle: number;
296
- }, {
297
- hashKey: string;
298
- rangeKey: string;
299
- entities?: Record<string, {
300
- timestampProperty: string;
301
- uniqueProperty: string;
302
- defaultLimit?: number | undefined;
303
- defaultPageSize?: number | undefined;
304
- shardBumps?: {
305
- timestamp: number;
306
- charBits: number;
307
- chars: number;
308
- }[] | undefined;
309
- }> | undefined;
310
- generatedProperties?: {
311
- sharded?: Record<string, [string, ...string[]]> | undefined;
312
- unsharded?: Record<string, [string, ...string[]]> | undefined;
313
- } | undefined;
314
- propertyTranscodes?: Record<string, string> | undefined;
315
- transcodes?: Record<string, {
316
- encode: (args_0: any, ...args: unknown[]) => string;
317
- decode: (args_0: string, ...args: unknown[]) => any;
318
- }> | undefined;
319
- indexes?: Record<string, {
320
- hashKey: string;
321
- rangeKey: string;
322
- projections?: string[] | undefined;
323
- }> | undefined;
324
- generatedKeyDelimiter?: string | undefined;
325
- generatedValueDelimiter?: string | undefined;
326
- shardKeyDelimiter?: string | undefined;
327
- throttle?: number | undefined;
328
- }>, {
329
- hashKey: string;
330
- rangeKey: string;
331
- entities: Record<string, {
332
- defaultLimit: number;
333
- defaultPageSize: number;
334
- shardBumps: {
335
- timestamp: number;
336
- charBits: number;
337
- chars: number;
338
- }[];
339
- timestampProperty: string;
340
- uniqueProperty: string;
341
- }>;
342
- generatedProperties: {
343
- sharded: Record<string, [string, ...string[]]>;
344
- unsharded: Record<string, [string, ...string[]]>;
345
- };
346
- propertyTranscodes: Record<string, string>;
347
- transcodes: Record<string, {
348
- encode: (args_0: any, ...args: unknown[]) => string;
349
- decode: (args_0: string, ...args: unknown[]) => any;
350
- }>;
351
- indexes: Record<string, {
352
- hashKey: string;
353
- rangeKey: string;
354
- projections?: string[] | undefined;
355
- }>;
356
- generatedKeyDelimiter: string;
357
- generatedValueDelimiter: string;
358
- shardKeyDelimiter: string;
359
- throttle: number;
360
- }, {
361
- hashKey: string;
362
- rangeKey: string;
363
- entities?: Record<string, {
364
- timestampProperty: string;
365
- uniqueProperty: string;
366
- defaultLimit?: number | undefined;
367
- defaultPageSize?: number | undefined;
368
- shardBumps?: {
369
- timestamp: number;
370
- charBits: number;
371
- chars: number;
372
- }[] | undefined;
373
- }> | undefined;
374
- generatedProperties?: {
375
- sharded?: Record<string, [string, ...string[]]> | undefined;
376
- unsharded?: Record<string, [string, ...string[]]> | undefined;
377
- } | undefined;
378
- propertyTranscodes?: Record<string, string> | undefined;
379
- transcodes?: Record<string, {
380
- encode: (args_0: any, ...args: unknown[]) => string;
381
- decode: (args_0: string, ...args: unknown[]) => any;
382
- }> | undefined;
383
- indexes?: Record<string, {
384
- hashKey: string;
385
- rangeKey: string;
386
- projections?: string[] | undefined;
387
- }> | undefined;
388
- generatedKeyDelimiter?: string | undefined;
389
- generatedValueDelimiter?: string | undefined;
390
- shardKeyDelimiter?: string | undefined;
391
- throttle?: number | undefined;
392
- }>;
197
+ encode: z.ZodCustom<unknown, unknown>;
198
+ decode: z.ZodCustom<unknown, unknown>;
199
+ }, z.core.$strict>>>>;
200
+ }, z.core.$strict>;
393
201
  /**
394
202
  * Simplified type taken on by a {@link Config | `Config`} object after parsing in the {@link EntityManager | `EntityManager`} constructor.
395
203
  *
@@ -612,7 +420,7 @@ declare class EntityManager<C extends BaseConfigMap> {
612
420
  * Update generated properties, hash key, and range key on an array of {@link EntityItem | `EntityItem`} objects.
613
421
  *
614
422
  * @param entityToken - {@link Config | `Config`} `entities` key.
615
- * @param items - Array of {@link EntityItem | `EntityItem`} objects.
423
+ * @param item - Array of {@link EntityItem | `EntityItem`} objects.
616
424
  * @param overwrite - Overwrite existing properties (default `false`).
617
425
  *
618
426
  * @returns An array of {@link EntityRecord | `EntityRecord`} objects with updated properties.
@@ -817,4 +625,5 @@ declare abstract class BaseQueryBuilder<C extends BaseConfigMap, EntityClient ex
817
625
  query(options: QueryBuilderQueryOptions<C>): Promise<QueryResult<C>>;
818
626
  }
819
627
 
820
- export { type BaseConfigMap, BaseEntityClient, type BaseEntityClientOptions, BaseQueryBuilder, type BaseQueryBuilderOptions, type Config, type ConfigMap, type EntityItem, type EntityKey, EntityManager, type EntityRecord, type EntityToken, type PageKey, type ParsedConfig, type QueryBuilderQueryOptions, type QueryOptions, type QueryResult, type ShardBump, type ShardQueryFunction, type ShardQueryMap, type ShardQueryResult, type ValidateConfigMap, configSchema };
628
+ export { BaseEntityClient, BaseQueryBuilder, EntityManager, configSchema };
629
+ export type { BaseConfigMap, BaseEntityClientOptions, BaseQueryBuilderOptions, Config, ConfigMap, EntityItem, EntityKey, EntityRecord, EntityToken, PageKey, ParsedConfig, QueryBuilderQueryOptions, QueryOptions, QueryResult, ShardBump, ShardQueryFunction, ShardQueryMap, ShardQueryResult, ValidateConfigMap };
@@ -8,7 +8,7 @@ const validateArrayUnique = (arr, ctx, identity = (item) => item, path = []) =>
8
8
  for (const [element, count] of Object.entries(counts)) {
9
9
  if (count > 1)
10
10
  ctx.addIssue({
11
- code: z.ZodIssueCode.custom,
11
+ code: 'custom',
12
12
  message: `duplicate array element`,
13
13
  params: { element },
14
14
  path,
@@ -19,7 +19,7 @@ const validateKeysExclusive = (keys, label, ref, ctx) => {
19
19
  const intersection = keys.filter((key) => ref.includes(key));
20
20
  if (intersection.length)
21
21
  ctx.addIssue({
22
- code: z.ZodIssueCode.custom,
22
+ code: 'custom',
23
23
  message: `${label} key collision: ${intersection.toString()}`,
24
24
  });
25
25
  };
@@ -30,26 +30,14 @@ const componentArray = z
30
30
  const configSchema = z
31
31
  .object({
32
32
  entities: z
33
- .record(z
33
+ .record(z.string(), z
34
34
  .object({
35
- defaultLimit: z
36
- .number()
37
- .int()
38
- .positive()
39
- .safe()
40
- .optional()
41
- .default(10),
42
- defaultPageSize: z
43
- .number()
44
- .int()
45
- .positive()
46
- .safe()
47
- .optional()
48
- .default(10),
35
+ defaultLimit: z.number().int().positive().optional().default(10),
36
+ defaultPageSize: z.number().int().positive().optional().default(10),
49
37
  shardBumps: z
50
38
  .array(z
51
39
  .object({
52
- timestamp: z.number().nonnegative().safe(),
40
+ timestamp: z.number().int().nonnegative(),
53
41
  charBits: z.number().int().min(1).max(5),
54
42
  chars: z.number().int().min(0).max(40),
55
43
  })
@@ -77,7 +65,7 @@ const configSchema = z
77
65
  for (let i = 1; i < val.length; i++)
78
66
  if (val[i].chars <= val[i - 1].chars)
79
67
  ctx.addIssue({
80
- code: z.ZodIssueCode.custom,
68
+ code: 'custom',
81
69
  message: `shardBump chars do not monotonically increase at timestamp ${val[i].timestamp.toString()}`,
82
70
  path: [i],
83
71
  });
@@ -91,14 +79,14 @@ const configSchema = z
91
79
  .default({}),
92
80
  generatedProperties: z
93
81
  .object({
94
- sharded: z.record(componentArray).optional().default({}),
95
- unsharded: z.record(componentArray).optional().default({}),
82
+ sharded: z.record(z.string(), componentArray).optional().default({}),
83
+ unsharded: z.record(z.string(), componentArray).optional().default({}),
96
84
  })
97
85
  .optional()
98
86
  .default({ sharded: {}, unsharded: {} }),
99
87
  hashKey: z.string(),
100
88
  indexes: z
101
- .record(z.object({
89
+ .record(z.string(), z.object({
102
90
  hashKey: z.string().min(1),
103
91
  rangeKey: z.string().min(1),
104
92
  projections: z
@@ -110,15 +98,18 @@ const configSchema = z
110
98
  .default({}),
111
99
  generatedKeyDelimiter: z.string().regex(/\W+/).optional().default('|'),
112
100
  generatedValueDelimiter: z.string().regex(/\W+/).optional().default('#'),
113
- propertyTranscodes: z.record(z.string()).optional().default({}),
101
+ propertyTranscodes: z.record(z.string(), z.string()).optional().default({}),
114
102
  rangeKey: z.string(),
115
103
  shardKeyDelimiter: z.string().regex(/\W+/).optional().default('!'),
116
- throttle: z.number().int().positive().safe().optional().default(10),
104
+ throttle: z.number().int().positive().optional().default(10),
117
105
  transcodes: z
118
- .record(z
106
+ .record(z.string(), z
119
107
  .object({
120
- encode: z.function().args(z.any()).returns(z.string()),
121
- decode: z.function().args(z.string()).returns(z.any()),
108
+ // Accept function shapes without relying on z.function()
109
+ // to avoid TS inference conflicts across Zod versions and
110
+ // to remain compatible with narrower parameter types.
111
+ encode: z.custom((fn) => typeof fn === 'function'),
112
+ decode: z.custom((fn) => typeof fn === 'function'),
122
113
  })
123
114
  .strict())
124
115
  .optional()
@@ -129,7 +120,7 @@ const configSchema = z
129
120
  // validate no generated key delimiter collision
130
121
  if (data.generatedKeyDelimiter.includes(data.generatedValueDelimiter))
131
122
  ctx.addIssue({
132
- code: z.ZodIssueCode.custom,
123
+ code: 'custom',
133
124
  message: 'generatedKeyDelimiter contains generatedValueDelimiter',
134
125
  params: {
135
126
  generatedKeyDelimiter: data.generatedKeyDelimiter,
@@ -139,7 +130,7 @@ const configSchema = z
139
130
  });
140
131
  if (data.generatedKeyDelimiter.includes(data.shardKeyDelimiter))
141
132
  ctx.addIssue({
142
- code: z.ZodIssueCode.custom,
133
+ code: 'custom',
143
134
  message: 'generatedKeyDelimiter contains shardKeyDelimiter',
144
135
  params: {
145
136
  generatedKeyDelimiter: data.generatedKeyDelimiter,
@@ -150,7 +141,7 @@ const configSchema = z
150
141
  // validate no generated value delimiter collision
151
142
  if (data.generatedValueDelimiter.includes(data.generatedKeyDelimiter))
152
143
  ctx.addIssue({
153
- code: z.ZodIssueCode.custom,
144
+ code: 'custom',
154
145
  message: 'generatedValueDelimiter contains generatedKeyDelimiter',
155
146
  params: {
156
147
  generatedValueDelimiter: data.generatedValueDelimiter,
@@ -160,7 +151,7 @@ const configSchema = z
160
151
  });
161
152
  if (data.generatedValueDelimiter.includes(data.shardKeyDelimiter))
162
153
  ctx.addIssue({
163
- code: z.ZodIssueCode.custom,
154
+ code: 'custom',
164
155
  message: 'generatedValueDelimiter contains shardKeyDelimiter',
165
156
  params: {
166
157
  generatedValueDelimiter: data.generatedValueDelimiter,
@@ -171,7 +162,7 @@ const configSchema = z
171
162
  // validate no shard key delimiter collision
172
163
  if (data.shardKeyDelimiter.includes(data.generatedKeyDelimiter))
173
164
  ctx.addIssue({
174
- code: z.ZodIssueCode.custom,
165
+ code: 'custom',
175
166
  message: 'shardKeyDelimiter contains generatedKeyDelimiter',
176
167
  params: {
177
168
  generatedKeyDelimiter: data.generatedKeyDelimiter,
@@ -181,7 +172,7 @@ const configSchema = z
181
172
  });
182
173
  if (data.shardKeyDelimiter.includes(data.generatedValueDelimiter))
183
174
  ctx.addIssue({
184
- code: z.ZodIssueCode.custom,
175
+ code: 'custom',
185
176
  message: 'shardKeyDelimiter contains generatedValueDelimiter',
186
177
  params: {
187
178
  generatedValueDelimiter: data.generatedValueDelimiter,
@@ -211,19 +202,17 @@ const configSchema = z
211
202
  for (const [property, transcode] of Object.entries(data.propertyTranscodes))
212
203
  if (!transcodes.includes(transcode))
213
204
  ctx.addIssue({
214
- code: z.ZodIssueCode.invalid_enum_value,
215
- options: transcodes,
205
+ code: 'custom',
206
+ message: `propertyTranscodes['${property}'] references unknown transcode '${transcode}'`,
216
207
  path: ['propertyTranscodes', property],
217
- received: transcode,
218
208
  });
219
209
  // Validate all sharded property elements are transcoded properties.
220
210
  for (const [property, elements] of Object.entries(data.generatedProperties.sharded))
221
211
  for (const element of elements)
222
212
  if (!transcodedProperties.includes(element))
223
213
  ctx.addIssue({
224
- code: z.ZodIssueCode.invalid_enum_value,
225
- options: transcodedProperties,
226
- received: element,
214
+ code: 'custom',
215
+ message: `generatedProperties.sharded['${property}'] contains non-transcoded element '${element}'`,
227
216
  path: ['generatedProperties', 'sharded', property],
228
217
  });
229
218
  // Validate all unsharded property elements are transcoded properties.
@@ -231,9 +220,8 @@ const configSchema = z
231
220
  for (const element of elements)
232
221
  if (!transcodedProperties.includes(element))
233
222
  ctx.addIssue({
234
- code: z.ZodIssueCode.invalid_enum_value,
235
- options: transcodedProperties,
236
- received: element,
223
+ code: 'custom',
224
+ message: `generatedProperties.unsharded['${property}'] contains non-transcoded element '${element}'`,
237
225
  path: ['generatedProperties', 'unsharded', property],
238
226
  });
239
227
  // Validate indexes.
@@ -242,19 +230,24 @@ const configSchema = z
242
230
  // Validate hash key is sharded.
243
231
  if (![data.hashKey, ...shardedKeys].includes(hashKey)) {
244
232
  ctx.addIssue({
245
- code: z.ZodIssueCode.invalid_enum_value,
246
- options: [data.hashKey, ...shardedKeys],
233
+ code: 'custom',
234
+ message: `index '${indexKey}' hashKey '${hashKey}' must be one of [${[
235
+ data.hashKey,
236
+ ...shardedKeys,
237
+ ].join(', ')}]`,
247
238
  path: ['indexes', indexKey, 'hashKey'],
248
- received: hashKey,
249
239
  });
250
240
  }
251
241
  // Validate range key is unsharded or transcodable.
252
242
  if (![data.rangeKey, ...unshardedKeys, ...transcodedProperties].includes(rangeKey)) {
253
243
  ctx.addIssue({
254
- code: z.ZodIssueCode.invalid_enum_value,
255
- options: [data.rangeKey, ...unshardedKeys],
244
+ code: 'custom',
245
+ message: `index '${indexKey}' rangeKey '${rangeKey}' must be one of [${[
246
+ data.rangeKey,
247
+ ...unshardedKeys,
248
+ ...transcodedProperties,
249
+ ].join(', ')}]`,
256
250
  path: ['indexes', indexKey, 'rangeKey'],
257
- received: rangeKey,
258
251
  });
259
252
  }
260
253
  // Validate no index projections are keys.
@@ -269,7 +262,7 @@ const configSchema = z
269
262
  ...unshardedKeys,
270
263
  ].includes(projection))
271
264
  ctx.addIssue({
272
- code: z.ZodIssueCode.custom,
265
+ code: 'custom',
273
266
  message: 'index projection is a key',
274
267
  params: { projection },
275
268
  path: ['indexes', indexKey, 'projections'],
@@ -280,18 +273,16 @@ const configSchema = z
280
273
  // validate timestampProperty is a transcoded property.
281
274
  if (!transcodedProperties.includes(timestampProperty))
282
275
  ctx.addIssue({
283
- code: z.ZodIssueCode.invalid_enum_value,
284
- options: transcodedProperties,
276
+ code: 'custom',
277
+ message: `entities['${entityToken}'].timestampProperty '${timestampProperty}' must be one of [${transcodedProperties.join(', ')}]`,
285
278
  path: ['entities', entityToken, 'timestampProperty'],
286
- received: timestampProperty,
287
279
  });
288
280
  // validate uniqueProperty is a transcoded property.
289
281
  if (!transcodedProperties.includes(uniqueProperty))
290
282
  ctx.addIssue({
291
- code: z.ZodIssueCode.invalid_enum_value,
292
- options: transcodedProperties,
283
+ code: 'custom',
284
+ message: `entities['${entityToken}'].uniqueProperty '${uniqueProperty}' must be one of [${transcodedProperties.join(', ')}]`,
293
285
  path: ['entities', entityToken, 'uniqueProperty'],
294
- received: uniqueProperty,
295
286
  });
296
287
  }
297
288
  });
@@ -32,6 +32,7 @@ function addKeys(entityManager, entityToken, item, overwrite = false) {
32
32
  if (encoded)
33
33
  Object.assign(newItem, { [property]: encoded });
34
34
  else
35
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
35
36
  delete newItem[property];
36
37
  }
37
38
  }
@@ -22,7 +22,8 @@ function decodeElement(entityManager, element, value) {
22
22
  if (!value)
23
23
  return;
24
24
  const { propertyTranscodes, transcodes } = entityManager.config;
25
- const decoded = transcodes[propertyTranscodes[element]].decode(value);
25
+ const decodeFn = transcodes[propertyTranscodes[element]].decode;
26
+ const decoded = decodeFn(value);
26
27
  entityManager.logger.debug('decoded entity element', {
27
28
  element,
28
29
  value,
@@ -38,7 +38,9 @@ function dehydratePageKeyMap(entityManager, entityToken, pageKeyMap) {
38
38
  }
39
39
  // Extract, sort & validate indexs.
40
40
  const indexes = Object.keys(pageKeyMap).sort();
41
- indexes.map((index) => validateIndexToken(entityManager, index));
41
+ indexes.map((index) => {
42
+ validateIndexToken(entityManager, index);
43
+ });
42
44
  // Extract & sort hash keys.
43
45
  const hashKeys = Object.keys(pageKeyMap[indexes[0]]);
44
46
  // Dehydrate page keys.
@@ -19,8 +19,8 @@ function encodeElement(entityManager, element, item) {
19
19
  const value = item[element];
20
20
  if (value === undefined || [hashKey, rangeKey].includes(element))
21
21
  return value;
22
- const encoded = transcodes[propertyTranscodes[element]].encode(item[element]) ||
23
- undefined;
22
+ const encodeFn = transcodes[propertyTranscodes[element]].encode;
23
+ const encoded = encodeFn(item[element]) || undefined;
24
24
  entityManager.logger.debug('encoded entity element', {
25
25
  element,
26
26
  item,