@karmaniverous/entity-manager 6.4.10 → 6.5.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.
@@ -23,6 +23,10 @@ const validateKeyExclusive = (key, label, ref, ctx) => {
23
23
  message: `${label} '${key}' is not exclusive`,
24
24
  });
25
25
  };
26
+ const componentArray = zod.z
27
+ .array(zod.z.string().min(1))
28
+ .nonempty()
29
+ .superRefine(validateArrayUnique);
26
30
  const configSchema = zod.z
27
31
  .object({
28
32
  entities: zod.z
@@ -46,10 +50,7 @@ const configSchema = zod.z
46
50
  .record(zod.z
47
51
  .object({
48
52
  atomic: zod.z.boolean().optional().default(false),
49
- elements: zod.z
50
- .array(zod.z.string().min(1))
51
- .nonempty()
52
- .superRefine(validateArrayUnique),
53
+ elements: componentArray,
53
54
  sharded: zod.z.boolean().optional().default(false),
54
55
  })
55
56
  .optional())
@@ -57,10 +58,10 @@ const configSchema = zod.z
57
58
  .default({}),
58
59
  elementTranscodes: zod.z.record(zod.z.string()).optional().default({}),
59
60
  indexes: zod.z
60
- .record(zod.z
61
- .array(zod.z.string().min(1))
62
- .nonempty()
63
- .superRefine(validateArrayUnique))
61
+ .record(zod.z.object({
62
+ components: componentArray,
63
+ projections: componentArray.optional(),
64
+ }))
64
65
  .optional()
65
66
  .default({}),
66
67
  shardBumps: zod.z
@@ -209,18 +210,42 @@ const configSchema = zod.z
209
210
  ],
210
211
  received: element,
211
212
  });
212
- // validate all ungenerated entity index components have a corresponding entity element type.
213
+ // validate indexes.
213
214
  const generatedProperties = Object.keys(entity.generated);
214
- for (const [indexKey, index] of Object.entries(entity.indexes))
215
- for (const component of index)
215
+ for (const [indexKey, index] of Object.entries(entity.indexes)) {
216
+ // validate all ungenerated entity index components have a corresponding entity element type
217
+ for (const component of index.components)
216
218
  if (![data.hashKey, data.rangeKey, ...generatedProperties].includes(component) &&
217
219
  !typedElements.includes(component))
218
220
  ctx.addIssue({
219
221
  code: zod.z.ZodIssueCode.invalid_enum_value,
220
222
  options: typedElements,
221
- path: ['entities', entityToken, 'indexes', indexKey],
223
+ path: [
224
+ 'entities',
225
+ entityToken,
226
+ 'indexes',
227
+ indexKey,
228
+ 'components',
229
+ ],
222
230
  received: component,
223
231
  });
232
+ // validate no index projections are index components, hashKey, or rangeKey
233
+ if (index.projections)
234
+ for (const projection of index.projections) {
235
+ if ([data.hashKey, data.rangeKey, ...index.components].includes(projection))
236
+ ctx.addIssue({
237
+ code: zod.z.ZodIssueCode.custom,
238
+ message: 'index projection is an index component, hash key, or range key',
239
+ path: [
240
+ 'entities',
241
+ entityToken,
242
+ 'indexes',
243
+ indexKey,
244
+ 'projections',
245
+ ],
246
+ });
247
+ }
248
+ }
224
249
  }
225
250
  });
226
251
 
@@ -51,7 +51,8 @@ function rehydratePageKeyMap(entityManager, dehydrated, entityToken, indexTokens
51
51
  ...rehydrateIndexItem.rehydrateIndexItem(entityManager, dehydratedIndexPageKeyMaps[i], entityToken, index, [entityManager.config.hashKey]),
52
52
  };
53
53
  item = updateItemRangeKey.updateItemRangeKey(entityManager, item, entityToken);
54
- return radash.zipToObject(entityManager.config.entities[entityToken].indexes[index], (component) => entityManager.config.entities[entityToken].generated[component]
54
+ return radash.zipToObject(entityManager.config.entities[entityToken].indexes[index]
55
+ .components, (component) => entityManager.config.entities[entityToken].generated[component]
55
56
  ? encodeGeneratedProperty.encodeGeneratedProperty(entityManager, item, entityToken, component)
56
57
  : item[component]);
57
58
  }));
@@ -21,7 +21,7 @@ function unwrapIndex(entityManager, entityToken, indexToken) {
21
21
  validateEntityIndexToken.validateEntityIndexToken(entityManager, entityToken, indexToken);
22
22
  const generated = entityManager.config.entities[entityToken].generated;
23
23
  const generatedKeys = Object.keys(radash.shake(generated));
24
- return entityManager.config.entities[entityToken].indexes[indexToken]
24
+ return entityManager.config.entities[entityToken].indexes[indexToken].components
25
25
  .map((component) => component === entityManager.config.hashKey
26
26
  ? entityManager.config.hashKey
27
27
  : component === entityManager.config.rangeKey
package/dist/index.d.ts CHANGED
@@ -80,6 +80,19 @@ interface ShardBump {
80
80
  */
81
81
  chars: number;
82
82
  }
83
+ /**
84
+ * Returns a Config entity index components type.
85
+ *
86
+ * @typeParam EntityToken - The {@link Entity | `Entity`} token.
87
+ * @typeParam M - The {@link EntityMap | `EntityMap`}.
88
+ * @typeParam HashKey - The property used across the configuration to store an {@link Entity | `Entity`}'s sharded hash key. Should be configured as the table hash key. Must not conflict with any {@link Entity | `Entity`} property.
89
+ * @typeParam RangeKey - The property used across the configuration to store an {@link Entity | `Entity`}'s range key. Should be configured as the table range key. Must not conflict with any {@link Entity | `Entity`} property.
90
+ * @typeParam T - The {@link TranscodeMap | `TranscodeMap`} identifying transcodable property types. Only {@link Entity | `Entity`} properties of these types can be components of an {@link ConfigEntity.indexes | index} or a {@link ConfigEntityGenerated | generated property}.
91
+
92
+ * @category Config
93
+ * @protected
94
+ */
95
+ type ConfigEntityIndexComponents<EntityToken extends keyof Exactify<M>, M extends EntityMap, HashKey extends string, RangeKey extends string, T extends TranscodeMap> = (TranscodableProperties<M[EntityToken], T> | PropertiesOfType<M[EntityToken], never> | HashKey | RangeKey)[];
83
96
  /**
84
97
  * Returns a Config entity type.
85
98
  *
@@ -175,7 +188,10 @@ type ConfigEntity<EntityToken extends keyof Exactify<M>, M extends EntityMap, Ha
175
188
  *
176
189
  * Related property types must be align with the {@link Config | `Config`} `T` type parameter. Note tha all {@link ConfigEntityGenerated | generated property} types are transcodable by definition.
177
190
  */
178
- indexes?: Record<string, (TranscodableProperties<M[EntityToken], T> | PropertiesOfType<M[EntityToken], never> | HashKey | RangeKey)[]>;
191
+ indexes?: Record<string, {
192
+ components: ConfigEntityIndexComponents<EntityToken, M, HashKey, RangeKey, T>;
193
+ projections?: (keyof M[EntityToken])[];
194
+ }>;
179
195
  /**
180
196
  * An array of {@link ShardBump | `ShardBump`} objects representing the {@link Entity | `Entity`}'s sharding strategy.
181
197
  *
@@ -377,7 +393,16 @@ declare const configSchema: z.ZodEffects<z.ZodObject<{
377
393
  sharded?: boolean | undefined;
378
394
  }>>>>>;
379
395
  elementTranscodes: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>>;
380
- indexes: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEffects<z.ZodArray<z.ZodString, "atleastone">, [string, ...string[]], [string, ...string[]]>>>>;
396
+ indexes: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
397
+ components: z.ZodEffects<z.ZodArray<z.ZodString, "atleastone">, [string, ...string[]], [string, ...string[]]>;
398
+ projections: z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodString, "atleastone">, [string, ...string[]], [string, ...string[]]>>;
399
+ }, "strip", z.ZodTypeAny, {
400
+ components: [string, ...string[]];
401
+ projections?: [string, ...string[]] | undefined;
402
+ }, {
403
+ components: [string, ...string[]];
404
+ projections?: [string, ...string[]] | undefined;
405
+ }>>>>;
381
406
  shardBumps: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{
382
407
  timestamp: z.ZodNumber;
383
408
  charBits: z.ZodNumber;
@@ -421,7 +446,10 @@ declare const configSchema: z.ZodEffects<z.ZodObject<{
421
446
  defaultLimit: number;
422
447
  defaultPageSize: number;
423
448
  elementTranscodes: Record<string, string>;
424
- indexes: Record<string, [string, ...string[]]>;
449
+ indexes: Record<string, {
450
+ components: [string, ...string[]];
451
+ projections?: [string, ...string[]] | undefined;
452
+ }>;
425
453
  shardBumps: {
426
454
  timestamp: number;
427
455
  charBits: number;
@@ -440,7 +468,10 @@ declare const configSchema: z.ZodEffects<z.ZodObject<{
440
468
  defaultLimit?: number | undefined;
441
469
  defaultPageSize?: number | undefined;
442
470
  elementTranscodes?: Record<string, string> | undefined;
443
- indexes?: Record<string, [string, ...string[]]> | undefined;
471
+ indexes?: Record<string, {
472
+ components: [string, ...string[]];
473
+ projections?: [string, ...string[]] | undefined;
474
+ }> | undefined;
444
475
  shardBumps?: {
445
476
  timestamp: number;
446
477
  charBits: number;
@@ -455,7 +486,10 @@ declare const configSchema: z.ZodEffects<z.ZodObject<{
455
486
  defaultLimit: number;
456
487
  defaultPageSize: number;
457
488
  elementTranscodes: Record<string, string>;
458
- indexes: Record<string, [string, ...string[]]>;
489
+ indexes: Record<string, {
490
+ components: [string, ...string[]];
491
+ projections?: [string, ...string[]] | undefined;
492
+ }>;
459
493
  shardBumps: {
460
494
  timestamp: number;
461
495
  charBits: number;
@@ -474,7 +508,10 @@ declare const configSchema: z.ZodEffects<z.ZodObject<{
474
508
  defaultLimit?: number | undefined;
475
509
  defaultPageSize?: number | undefined;
476
510
  elementTranscodes?: Record<string, string> | undefined;
477
- indexes?: Record<string, [string, ...string[]]> | undefined;
511
+ indexes?: Record<string, {
512
+ components: [string, ...string[]];
513
+ projections?: [string, ...string[]] | undefined;
514
+ }> | undefined;
478
515
  shardBumps?: {
479
516
  timestamp: number;
480
517
  charBits: number;
@@ -509,7 +546,10 @@ declare const configSchema: z.ZodEffects<z.ZodObject<{
509
546
  defaultLimit: number;
510
547
  defaultPageSize: number;
511
548
  elementTranscodes: Record<string, string>;
512
- indexes: Record<string, [string, ...string[]]>;
549
+ indexes: Record<string, {
550
+ components: [string, ...string[]];
551
+ projections?: [string, ...string[]] | undefined;
552
+ }>;
513
553
  shardBumps: {
514
554
  timestamp: number;
515
555
  charBits: number;
@@ -540,7 +580,10 @@ declare const configSchema: z.ZodEffects<z.ZodObject<{
540
580
  defaultLimit?: number | undefined;
541
581
  defaultPageSize?: number | undefined;
542
582
  elementTranscodes?: Record<string, string> | undefined;
543
- indexes?: Record<string, [string, ...string[]]> | undefined;
583
+ indexes?: Record<string, {
584
+ components: [string, ...string[]];
585
+ projections?: [string, ...string[]] | undefined;
586
+ }> | undefined;
544
587
  shardBumps?: {
545
588
  timestamp: number;
546
589
  charBits: number;
@@ -567,7 +610,10 @@ declare const configSchema: z.ZodEffects<z.ZodObject<{
567
610
  defaultLimit: number;
568
611
  defaultPageSize: number;
569
612
  elementTranscodes: Record<string, string>;
570
- indexes: Record<string, [string, ...string[]]>;
613
+ indexes: Record<string, {
614
+ components: [string, ...string[]];
615
+ projections?: [string, ...string[]] | undefined;
616
+ }>;
571
617
  shardBumps: {
572
618
  timestamp: number;
573
619
  charBits: number;
@@ -598,7 +644,10 @@ declare const configSchema: z.ZodEffects<z.ZodObject<{
598
644
  defaultLimit?: number | undefined;
599
645
  defaultPageSize?: number | undefined;
600
646
  elementTranscodes?: Record<string, string> | undefined;
601
- indexes?: Record<string, [string, ...string[]]> | undefined;
647
+ indexes?: Record<string, {
648
+ components: [string, ...string[]];
649
+ projections?: [string, ...string[]] | undefined;
650
+ }> | undefined;
602
651
  shardBumps?: {
603
652
  timestamp: number;
604
653
  charBits: number;
@@ -620,7 +669,7 @@ declare const configSchema: z.ZodEffects<z.ZodObject<{
620
669
  }> | undefined;
621
670
  }>;
622
671
  /**
623
- * Foo
672
+ * Simplified type taken on by a {@link Config | `Config`} object after parsing in the {@link EntityManager | `EntityManager`} constructor.
624
673
  *
625
674
  * @category Config
626
675
  */
@@ -828,4 +877,4 @@ declare class EntityManager<M extends EntityMap, HashKey extends string, RangeKe
828
877
  query<Item extends ItemMap<M, HashKey, RangeKey>[EntityToken], EntityToken extends keyof Exactify<M> & string>(options: QueryOptions<Item, EntityToken, M, HashKey, RangeKey>): Promise<QueryResult<Item, EntityToken, M, HashKey, RangeKey>>;
829
878
  }
830
879
 
831
- export { type Config, type ConfigEntities, type ConfigEntity, type ConfigEntityGenerated, type ConfigKeys, type ConfigTranscodes, EntityManager, type EntityMap, type ExclusiveKey, type ItemMap, type ParsedConfig, type QueryOptions, type QueryResult, type ShardBump, type ShardQueryFunction, type ShardQueryMap, type ShardQueryResult, type Unwrap, conditionalize };
880
+ export { type Config, type ConfigEntities, type ConfigEntity, type ConfigEntityGenerated, type ConfigEntityIndexComponents, type ConfigKeys, type ConfigTranscodes, EntityManager, type EntityMap, type ExclusiveKey, type ItemMap, type ParsedConfig, type QueryOptions, type QueryResult, type ShardBump, type ShardQueryFunction, type ShardQueryMap, type ShardQueryResult, type Unwrap, conditionalize };
@@ -21,6 +21,10 @@ const validateKeyExclusive = (key, label, ref, ctx) => {
21
21
  message: `${label} '${key}' is not exclusive`,
22
22
  });
23
23
  };
24
+ const componentArray = z
25
+ .array(z.string().min(1))
26
+ .nonempty()
27
+ .superRefine(validateArrayUnique);
24
28
  const configSchema = z
25
29
  .object({
26
30
  entities: z
@@ -44,10 +48,7 @@ const configSchema = z
44
48
  .record(z
45
49
  .object({
46
50
  atomic: z.boolean().optional().default(false),
47
- elements: z
48
- .array(z.string().min(1))
49
- .nonempty()
50
- .superRefine(validateArrayUnique),
51
+ elements: componentArray,
51
52
  sharded: z.boolean().optional().default(false),
52
53
  })
53
54
  .optional())
@@ -55,10 +56,10 @@ const configSchema = z
55
56
  .default({}),
56
57
  elementTranscodes: z.record(z.string()).optional().default({}),
57
58
  indexes: z
58
- .record(z
59
- .array(z.string().min(1))
60
- .nonempty()
61
- .superRefine(validateArrayUnique))
59
+ .record(z.object({
60
+ components: componentArray,
61
+ projections: componentArray.optional(),
62
+ }))
62
63
  .optional()
63
64
  .default({}),
64
65
  shardBumps: z
@@ -207,18 +208,42 @@ const configSchema = z
207
208
  ],
208
209
  received: element,
209
210
  });
210
- // validate all ungenerated entity index components have a corresponding entity element type.
211
+ // validate indexes.
211
212
  const generatedProperties = Object.keys(entity.generated);
212
- for (const [indexKey, index] of Object.entries(entity.indexes))
213
- for (const component of index)
213
+ for (const [indexKey, index] of Object.entries(entity.indexes)) {
214
+ // validate all ungenerated entity index components have a corresponding entity element type
215
+ for (const component of index.components)
214
216
  if (![data.hashKey, data.rangeKey, ...generatedProperties].includes(component) &&
215
217
  !typedElements.includes(component))
216
218
  ctx.addIssue({
217
219
  code: z.ZodIssueCode.invalid_enum_value,
218
220
  options: typedElements,
219
- path: ['entities', entityToken, 'indexes', indexKey],
221
+ path: [
222
+ 'entities',
223
+ entityToken,
224
+ 'indexes',
225
+ indexKey,
226
+ 'components',
227
+ ],
220
228
  received: component,
221
229
  });
230
+ // validate no index projections are index components, hashKey, or rangeKey
231
+ if (index.projections)
232
+ for (const projection of index.projections) {
233
+ if ([data.hashKey, data.rangeKey, ...index.components].includes(projection))
234
+ ctx.addIssue({
235
+ code: z.ZodIssueCode.custom,
236
+ message: 'index projection is an index component, hash key, or range key',
237
+ path: [
238
+ 'entities',
239
+ entityToken,
240
+ 'indexes',
241
+ indexKey,
242
+ 'projections',
243
+ ],
244
+ });
245
+ }
246
+ }
222
247
  }
223
248
  });
224
249
 
@@ -49,7 +49,8 @@ function rehydratePageKeyMap(entityManager, dehydrated, entityToken, indexTokens
49
49
  ...rehydrateIndexItem(entityManager, dehydratedIndexPageKeyMaps[i], entityToken, index, [entityManager.config.hashKey]),
50
50
  };
51
51
  item = updateItemRangeKey(entityManager, item, entityToken);
52
- return zipToObject(entityManager.config.entities[entityToken].indexes[index], (component) => entityManager.config.entities[entityToken].generated[component]
52
+ return zipToObject(entityManager.config.entities[entityToken].indexes[index]
53
+ .components, (component) => entityManager.config.entities[entityToken].generated[component]
53
54
  ? encodeGeneratedProperty(entityManager, item, entityToken, component)
54
55
  : item[component]);
55
56
  }));
@@ -19,7 +19,7 @@ function unwrapIndex(entityManager, entityToken, indexToken) {
19
19
  validateEntityIndexToken(entityManager, entityToken, indexToken);
20
20
  const generated = entityManager.config.entities[entityToken].generated;
21
21
  const generatedKeys = Object.keys(shake(generated));
22
- return entityManager.config.entities[entityToken].indexes[indexToken]
22
+ return entityManager.config.entities[entityToken].indexes[indexToken].components
23
23
  .map((component) => component === entityManager.config.hashKey
24
24
  ? entityManager.config.hashKey
25
25
  : component === entityManager.config.rangeKey
package/package.json CHANGED
@@ -132,5 +132,5 @@
132
132
  },
133
133
  "type": "module",
134
134
  "types": "dist/index.d.ts",
135
- "version": "6.4.10"
135
+ "version": "6.5.0"
136
136
  }