electrodb 2.12.3 → 2.13.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 (3) hide show
  1. package/index.d.ts +58 -54
  2. package/package.json +8 -5
  3. package/src/entity.js +41 -4
package/index.d.ts CHANGED
@@ -2529,6 +2529,7 @@ export interface QueryOptions {
2529
2529
  params?: object;
2530
2530
  table?: string;
2531
2531
  limit?: number;
2532
+ count?: number;
2532
2533
  originalErr?: boolean;
2533
2534
  ignoreOwnership?: boolean;
2534
2535
  pages?: number | "all";
@@ -2655,6 +2656,7 @@ interface GoQueryTerminalOptions<Attributes> {
2655
2656
  includeKeys?: boolean;
2656
2657
  table?: string;
2657
2658
  limit?: number;
2659
+ count?: number;
2658
2660
  params?: object;
2659
2661
  originalErr?: boolean;
2660
2662
  ignoreOwnership?: boolean;
@@ -3965,65 +3967,67 @@ export type ItemAttribute<A extends Attribute> =
3965
3967
  : never;
3966
3968
 
3967
3969
  export type ReturnedAttribute<A extends Attribute> =
3968
- A["type"] extends OpaquePrimitiveTypeName<infer T>
3969
- ? T
3970
- : A["type"] extends CustomAttributeTypeName<infer T>
3971
- ? T
3972
- : A["type"] extends infer R
3973
- ? R extends "static"
3974
- ? never
3975
- : R extends "string"
3976
- ? string
3977
- : R extends "number"
3978
- ? number
3979
- : R extends "boolean"
3980
- ? boolean
3981
- : R extends ReadonlyArray<infer E>
3982
- ? E
3983
- : R extends "map"
3984
- ? "properties" extends keyof A
3985
- ? {
3986
- [P in keyof A["properties"] as A["properties"][P] extends RequiredAttribute
3987
- ? P
3988
- : never]: A["properties"][P] extends infer M
3989
- ? M extends Attribute
3990
- ? ReturnedAttribute<M>
3991
- : never
3992
- : never;
3993
- } & {
3994
- [P in keyof A["properties"] as A["properties"][P] extends
3995
- | HiddenAttribute
3996
- | RequiredAttribute
3997
- ? never
3998
- : P]?: A["properties"][P] extends infer M
3999
- ? M extends Attribute
4000
- ? ReturnedAttribute<M> | undefined
4001
- : never
4002
- : never;
4003
- }
4004
- : never
4005
- : R extends "list"
4006
- ? "items" extends keyof A
4007
- ? A["items"] extends infer I
4008
- ? I extends Attribute
4009
- ? ReturnedAttribute<I>[]
3970
+ A["type"] extends infer T
3971
+ ? T extends OpaquePrimitiveTypeName<infer OP>
3972
+ ? OP
3973
+ : T extends CustomAttributeTypeName<infer CA>
3974
+ ? CA
3975
+ : T extends infer R
3976
+ ? R extends "static"
3977
+ ? never
3978
+ : R extends "string"
3979
+ ? string
3980
+ : R extends "number"
3981
+ ? number
3982
+ : R extends "boolean"
3983
+ ? boolean
3984
+ : R extends ReadonlyArray<infer E>
3985
+ ? E
3986
+ : R extends "map"
3987
+ ? "properties" extends keyof A
3988
+ ? {
3989
+ [P in keyof A["properties"] as A["properties"][P] extends RequiredAttribute
3990
+ ? P
3991
+ : never]: A["properties"][P] extends infer M
3992
+ ? M extends Attribute
3993
+ ? ReturnedAttribute<M>
3994
+ : never
3995
+ : never;
3996
+ } & {
3997
+ [P in keyof A["properties"] as A["properties"][P] extends
3998
+ | HiddenAttribute
3999
+ | RequiredAttribute
4000
+ ? never
4001
+ : P]?: A["properties"][P] extends infer M
4002
+ ? M extends Attribute
4003
+ ? ReturnedAttribute<M> | undefined
4004
+ : never
4005
+ : never;
4006
+ }
4007
+ : never
4008
+ : R extends "list"
4009
+ ? "items" extends keyof A
4010
+ ? A["items"] extends infer I
4011
+ ? I extends Attribute
4012
+ ? ReturnedAttribute<I>[]
4013
+ : never
4010
4014
  : never
4011
4015
  : never
4012
- : never
4013
- : R extends "set"
4014
- ? "items" extends keyof A
4015
- ? A["items"] extends infer I
4016
- ? I extends "string"
4017
- ? string[]
4018
- : I extends "number"
4019
- ? number[]
4020
- : I extends ReadonlyArray<infer ENUM>
4021
- ? ENUM[]
4016
+ : R extends "set"
4017
+ ? "items" extends keyof A
4018
+ ? A["items"] extends infer I
4019
+ ? I extends "string"
4020
+ ? string[]
4021
+ : I extends "number"
4022
+ ? number[]
4023
+ : I extends ReadonlyArray<infer ENUM>
4024
+ ? ENUM[]
4025
+ : never
4022
4026
  : never
4023
4027
  : never
4028
+ : R extends "any"
4029
+ ? any
4024
4030
  : never
4025
- : R extends "any"
4026
- ? any
4027
4031
  : never
4028
4032
  : never;
4029
4033
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "electrodb",
3
- "version": "2.12.3",
3
+ "version": "2.13.1",
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": {
@@ -10,14 +10,15 @@
10
10
  "test:ci": "npm install && npm test",
11
11
  "test:run": "npm run test:types && npm run test:init && npm run test:unit",
12
12
  "test:init": "node ./test/init.js",
13
+ "test:init:hard": "node ./test/init.js --recreate",
13
14
  "test:unit": "mocha -r ts-node/register ./test/**.spec.*",
14
15
  "test:types": "tsd",
15
16
  "test:format": "prettier -c src/**/*.js examples/**/*",
16
- "coverage": "npm run test:init && nyc npm run test:unit && nyc report --reporter=text-lcov | coveralls",
17
- "coverage:local:coveralls": "npm run test:init && nyc npm run test:unit && nyc report --reporter=text-lcov | coveralls",
18
- "coverage:local:html": "npm run test:init && nyc npm run test:unit && nyc report --reporter=html",
17
+ "coverage": "npm run test:init:hard && nyc npm run test:unit && nyc report --reporter=text-lcov | coveralls",
18
+ "coverage:local:coveralls": "npm run test:init:hard && nyc npm run test:unit && nyc report --reporter=text-lcov | coveralls",
19
+ "coverage:local:html": "npm run test:init:hard && nyc npm run test:unit && nyc report --reporter=html",
19
20
  "ddb:start": "docker compose up -d dynamodb",
20
- "ddb:load": "docker compose exec electro npm run test:init",
21
+ "ddb:load": "docker compose exec electro npm run test:init:hard",
21
22
  "ddb:stop": "docker compose stop",
22
23
  "examples:load:library": "npm run ddb:start && npm run local:init && ts-node ./examples/library/load.ts",
23
24
  "examples:query:library": "npm run ddb:start && npm run local:init && ts-node ./examples/library/query.ts",
@@ -28,7 +29,9 @@
28
29
  "examples:provisiontable": "npm run ddb:start && npm run local:init && ts-node ./examples/provisionTable",
29
30
  "examples:locks": "npm run ddb:start && npm run local:init && ts-node ./examples/locks",
30
31
  "local:init": "LOCAL_DYNAMO_ENDPOINT='http://localhost:8000' npm run test:init",
32
+ "local:init:hard": "LOCAL_DYNAMO_ENDPOINT='http://localhost:8000' npm run test:init:hard",
31
33
  "local:start": "npm run ddb:start && npm run local:init",
34
+ "local:fresh": "npm run ddb:start && npm run local:init:hard",
32
35
  "local:stop": "npm run ddb:stop",
33
36
  "local:exec": "LOCAL_DYNAMO_ENDPOINT='http://localhost:8000' ts-node ./test/debug.ts",
34
37
  "local:debug": "npm run local:start && npm run local:exec",
package/src/entity.js CHANGED
@@ -625,6 +625,21 @@ class Entity {
625
625
  });
626
626
  }
627
627
 
628
+ _safeMinimum(...values) {
629
+ let eligibleNumbers = [];
630
+ for (let value of values) {
631
+ if (typeof value === 'number') {
632
+ eligibleNumbers.push(value);
633
+ }
634
+ }
635
+
636
+ if (eligibleNumbers.length) {
637
+ return Math.min(...eligibleNumbers);
638
+ }
639
+
640
+ return undefined;
641
+ }
642
+
628
643
  async executeBulkGet(parameters, config) {
629
644
  if (!Array.isArray(parameters)) {
630
645
  parameters = [parameters];
@@ -703,10 +718,11 @@ class Entity {
703
718
  }
704
719
 
705
720
  async executeQuery(method, parameters, config = {}) {
721
+ const indexName = parameters.IndexName;
706
722
  let results = config._isCollectionQuery ? {} : [];
707
723
  let ExclusiveStartKey = this._formatExclusiveStartKey({
724
+ indexName,
708
725
  config,
709
- indexName: parameters.IndexName,
710
726
  });
711
727
  if (ExclusiveStartKey === null) {
712
728
  ExclusiveStartKey = undefined;
@@ -724,7 +740,9 @@ class Entity {
724
740
  { ExclusiveStartKey, ...parameters, Limit: limit },
725
741
  config,
726
742
  );
743
+
727
744
  ExclusiveStartKey = response.LastEvaluatedKey;
745
+
728
746
  response = this.formatResponse(response, parameters.IndexName, {
729
747
  ...config,
730
748
  includeKeys: shouldHydrate || config.includeKeys,
@@ -755,10 +773,15 @@ class Entity {
755
773
  results[entity] = [...results[entity], ...items];
756
774
  }
757
775
  } else if (Array.isArray(response.data)) {
758
- if (max) {
776
+ let prevCount = count
777
+ if (!!max || !!config.count) {
759
778
  count += response.data.length;
760
779
  }
761
780
  let items = response.data;
781
+ const moreItemsThanRequired = !!config.count && count > config.count;
782
+ if (moreItemsThanRequired) {
783
+ items = items.slice(0, config.count - prevCount);
784
+ }
762
785
  if (shouldHydrate) {
763
786
  const hydrated = await this.hydrate(
764
787
  parameters.IndexName,
@@ -771,14 +794,20 @@ class Entity {
771
794
  );
772
795
  }
773
796
  results = [...results, ...items];
797
+ if (moreItemsThanRequired || count === config.count) {
798
+ const lastItem = results[results.length - 1];
799
+ ExclusiveStartKey = this._fromCompositeToKeysByIndex({ indexName, provided: lastItem });
800
+ break;
801
+ }
774
802
  } else {
775
803
  return response;
776
804
  }
777
805
  iterations++;
778
806
  } while (
779
807
  ExclusiveStartKey &&
780
- (pages === AllPages || iterations < pages) &&
781
- (max === undefined || count < max)
808
+ (pages === AllPages || (config.count !== undefined || iterations < pages)) &&
809
+ (max === undefined || count < max) &&
810
+ (config.count === undefined || count < config.count)
782
811
  );
783
812
 
784
813
  const cursor = this._formatReturnPager(config, ExclusiveStartKey);
@@ -1654,6 +1683,7 @@ class Entity {
1654
1683
  _isPagination: false,
1655
1684
  _isCollectionQuery: false,
1656
1685
  pages: 1,
1686
+ count: undefined,
1657
1687
  listeners: [],
1658
1688
  preserveBatchOrder: false,
1659
1689
  attributes: [],
@@ -1777,6 +1807,13 @@ class Entity {
1777
1807
  }
1778
1808
  }
1779
1809
 
1810
+ if (option.count !== undefined) {
1811
+ if (typeof option.count !== "number" || option.count < 1) {
1812
+ throw new e.ElectroError(e.ErrorCodes.InvalidOptions, `Query option 'count' must be of type 'number' and greater than zero.`);
1813
+ }
1814
+ config.count = option.count;
1815
+ }
1816
+
1780
1817
  if (option.limit !== undefined) {
1781
1818
  config.limit = option.limit;
1782
1819
  config.params.Limit = option.limit;