electrodb 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts CHANGED
@@ -2716,23 +2716,23 @@ type GoBatchGetTerminal<
2716
2716
  > = <Options extends GoBatchGetTerminalOptions<keyof ResponseItem>>(
2717
2717
  options?: Options,
2718
2718
  ) => Options extends GoBatchGetTerminalOptions<infer Attr>
2719
- ? "preserveBatchOrder" extends keyof Options
2720
- ? Options["preserveBatchOrder"] extends true
2721
- ? Promise<{
2722
- data: Array<
2723
- Resolve<
2724
- | {
2725
- [Name in keyof ResponseItem as Name extends Attr
2726
- ? Name
2727
- : never]: ResponseItem[Name];
2728
- }
2729
- | null
2730
- >
2731
- >;
2732
- unprocessed: Array<
2733
- Resolve<AllTableIndexCompositeAttributes<A, F, C, S>>
2734
- >;
2735
- }>
2719
+ ? "preserveBatchOrder" extends keyof Options
2720
+ ? Options["preserveBatchOrder"] extends true
2721
+ ? Promise<{
2722
+ data: Array<
2723
+ Resolve<
2724
+ | {
2725
+ [Name in keyof ResponseItem as Name extends Attr
2726
+ ? Name
2727
+ : never]: ResponseItem[Name];
2728
+ }
2729
+ | null
2730
+ >
2731
+ >;
2732
+ unprocessed: Array<
2733
+ Resolve<AllTableIndexCompositeAttributes<A, F, C, S>>
2734
+ >;
2735
+ }>
2736
2736
  : Promise<{
2737
2737
  data: Array<
2738
2738
  Resolve<{
@@ -2758,23 +2758,23 @@ type GoBatchGetTerminal<
2758
2758
  >;
2759
2759
  }>
2760
2760
  : "preserveBatchOrder" extends keyof Options
2761
- ? Options["preserveBatchOrder"] extends true
2762
- ? {
2763
- data: Array<Resolve<ResponseItem | null>>;
2764
- unprocessed: Array<
2765
- Resolve<AllTableIndexCompositeAttributes<A, F, C, S>>
2766
- >;
2767
- }
2768
- : {
2761
+ ? Options["preserveBatchOrder"] extends true
2762
+ ? Promise<{
2763
+ data: Array<Resolve<ResponseItem | null>>;
2764
+ unprocessed: Array<
2765
+ Resolve<AllTableIndexCompositeAttributes<A, F, C, S>>
2766
+ >;
2767
+ }>
2768
+ : Promise<{
2769
+ data: Array<Resolve<ResponseItem>>;
2770
+ unprocessed: Array<
2771
+ Resolve<AllTableIndexCompositeAttributes<A, F, C, S>>
2772
+ >;
2773
+ }>
2774
+ : Promise<{
2769
2775
  data: Array<Resolve<ResponseItem>>;
2770
- unprocessed: Array<
2771
- Resolve<AllTableIndexCompositeAttributes<A, F, C, S>>
2772
- >;
2773
- }
2774
- : {
2775
- data: Array<Resolve<ResponseItem>>;
2776
- unprocessed: Array<Resolve<AllTableIndexCompositeAttributes<A, F, C, S>>>;
2777
- };
2776
+ unprocessed: Array<Resolve<AllTableIndexCompositeAttributes<A, F, C, S>>>;
2777
+ }>;
2778
2778
 
2779
2779
  type GoGetTerminal<
2780
2780
  A extends string,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "electrodb",
3
- "version": "3.1.0",
3
+ "version": "3.2.0",
4
4
  "description": "A library to more easily create and interact with multiple entities and heretical relationships in dynamodb",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/src/entity.js CHANGED
@@ -4276,6 +4276,7 @@ class Entity {
4276
4276
  facets: parsedPKAttributes.attributes,
4277
4277
  isCustom: parsedPKAttributes.isCustom,
4278
4278
  facetLabels: parsedPKAttributes.labels,
4279
+ template: index.pk.template,
4279
4280
  };
4280
4281
  let sk = {};
4281
4282
  let parsedSKAttributes = {};
@@ -4294,6 +4295,7 @@ class Entity {
4294
4295
  facets: parsedSKAttributes.attributes,
4295
4296
  isCustom: parsedSKAttributes.isCustom,
4296
4297
  facetLabels: parsedSKAttributes.labels,
4298
+ template: index.sk.template,
4297
4299
  };
4298
4300
  facets.fields.push(sk.field);
4299
4301
  }
@@ -4409,10 +4411,12 @@ class Entity {
4409
4411
  const definition = Object.values(facets.byField[pk.field]).find(
4410
4412
  (definition) => definition.index !== indexName,
4411
4413
  );
4414
+
4412
4415
  const definitionsMatch = validations.stringArrayMatch(
4413
4416
  pk.facets,
4414
4417
  definition.facets,
4415
4418
  );
4419
+
4416
4420
  if (!definitionsMatch) {
4417
4421
  throw new e.ElectroError(
4418
4422
  e.ErrorCodes.InconsistentIndexDefinition,
@@ -4427,6 +4431,20 @@ class Entity {
4427
4431
  )}'. Key fields must have the same composite attribute definitions across all indexes they are involved with`,
4428
4432
  );
4429
4433
  }
4434
+
4435
+ const keyTemplatesMatch = pk.template === definition.template
4436
+
4437
+ if (!keyTemplatesMatch) {
4438
+ throw new e.ElectroError(
4439
+ e.ErrorCodes.IncompatibleKeyCompositeAttributeTemplate,
4440
+ `Partition Key (pk) on Access Pattern '${u.formatIndexNameForDisplay(
4441
+ accessPattern,
4442
+ )}' is defined with the template ${pk.template || '(undefined)'}, but the accessPattern '${u.formatIndexNameForDisplay(
4443
+ definition.index,
4444
+ )}' defines this field with the key labels ${definition.template || '(undefined)'}'. Key fields must have the same template definitions across all indexes they are involved with`,
4445
+ );
4446
+ }
4447
+
4430
4448
  seenIndexFields[pk.field].push({ accessPattern, type: "pk" });
4431
4449
  } else {
4432
4450
  seenIndexFields[pk.field] = [];
@@ -4447,7 +4465,8 @@ class Entity {
4447
4465
  const isAlsoDefinedAsPK = seenIndexFields[sk.field].find(
4448
4466
  (field) => field.type === "pk",
4449
4467
  );
4450
- if (isAlsoDefinedAsPK) {
4468
+
4469
+ if (isAlsoDefinedAsPK && !sk.isCustom) {
4451
4470
  throw new e.ElectroError(
4452
4471
  e.ErrorCodes.InconsistentIndexDefinition,
4453
4472
  `The Sort Key (sk) on Access Pattern '${u.formatIndexNameForDisplay(
@@ -4456,16 +4475,19 @@ class Entity {
4456
4475
  pk.field
4457
4476
  }' which is already referenced by the Access Pattern(s) '${u.formatIndexNameForDisplay(
4458
4477
  isAlsoDefinedAsPK.accessPattern,
4459
- )}' as a Partition Key. Fields mapped to Partition Keys cannot be also mapped to Sort Keys.`,
4478
+ )}' as a Partition Key. Fields mapped to Partition Keys cannot be also mapped to Sort Keys unless their format is defined with a 'template'.`,
4460
4479
  );
4461
4480
  }
4481
+
4462
4482
  const definition = Object.values(facets.byField[sk.field]).find(
4463
4483
  (definition) => definition.index !== indexName,
4464
4484
  );
4485
+
4465
4486
  const definitionsMatch = validations.stringArrayMatch(
4466
4487
  sk.facets,
4467
4488
  definition.facets,
4468
- );
4489
+ )
4490
+
4469
4491
  if (!definitionsMatch) {
4470
4492
  throw new e.ElectroError(
4471
4493
  e.ErrorCodes.DuplicateIndexFields,
@@ -4480,6 +4502,20 @@ class Entity {
4480
4502
  )}'. Key fields must have the same composite attribute definitions across all indexes they are involved with`,
4481
4503
  );
4482
4504
  }
4505
+
4506
+ const keyTemplatesMatch = sk.template === definition.template
4507
+
4508
+ if (!keyTemplatesMatch) {
4509
+ throw new e.ElectroError(
4510
+ e.ErrorCodes.IncompatibleKeyCompositeAttributeTemplate,
4511
+ `Sort Key (sk) on Access Pattern '${u.formatIndexNameForDisplay(
4512
+ accessPattern,
4513
+ )}' is defined with the template ${sk.template || '(undefined)'}, but the accessPattern '${u.formatIndexNameForDisplay(
4514
+ definition.index,
4515
+ )}' defines this field with the key labels ${definition.template || '(undefined)'}'. Key fields must have the same template definitions across all indexes they are involved with`,
4516
+ );
4517
+ }
4518
+
4483
4519
  seenIndexFields[sk.field].push({ accessPattern, type: "sk" });
4484
4520
  } else {
4485
4521
  seenIndexFields[sk.field] = [];
package/src/operations.js CHANGED
@@ -19,6 +19,7 @@ class ExpressionState {
19
19
  this.expression = "";
20
20
  this.prefix = prefix || "";
21
21
  this.refs = {};
22
+ this.formattedNameToOriginalNameMap = new Map();
22
23
  }
23
24
 
24
25
  incrementName(name) {
@@ -30,14 +31,28 @@ class ExpressionState {
30
31
 
31
32
  formatName(name = "") {
32
33
  const nameWasNotANumber = isNaN(name);
33
- name = `${name}`.replaceAll(/[^\w]/g, "");
34
- if (name.length === 0) {
35
- name = "p";
36
- } else if (nameWasNotANumber !== isNaN(name)) {
34
+ const originalName = `${name}`;
35
+ let formattedName = originalName.replaceAll(/[^\w]/g, "");
36
+
37
+ if (formattedName.length === 0) {
38
+ formattedName = "p";
39
+ } else if (nameWasNotANumber !== isNaN(formattedName)) {
37
40
  // name became number due to replace
38
- name = `p${name}`;
41
+ formattedName = `p${formattedName}`;
39
42
  }
40
- return name;
43
+
44
+ const originalFormattedName = formattedName;
45
+ let nameSuffix = 1;
46
+
47
+ while (
48
+ this.formattedNameToOriginalNameMap.has(formattedName) &&
49
+ this.formattedNameToOriginalNameMap.get(formattedName) !== originalName
50
+ ) {
51
+ formattedName = `${originalFormattedName}_${++nameSuffix}`;
52
+ }
53
+
54
+ this.formattedNameToOriginalNameMap.set(formattedName, originalName);
55
+ return formattedName;
41
56
  }
42
57
 
43
58
  // todo: make the structure: name, value, paths