@karmaniverous/entity-manager 5.0.8 → 6.0.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 (83) hide show
  1. package/README.md +15 -439
  2. package/dist/cjs/_virtual/_commonjsHelpers.js +7 -0
  3. package/dist/cjs/_virtual/lz-string.js +5 -0
  4. package/dist/cjs/node_modules/@karmaniverous/entity-tools/dist/mjs/Nil.js +14 -0
  5. package/dist/cjs/node_modules/@karmaniverous/entity-tools/dist/mjs/defaultTranscodes.js +94 -0
  6. package/dist/cjs/node_modules/@karmaniverous/entity-tools/dist/mjs/sort.js +52 -0
  7. package/dist/cjs/node_modules/lz-string/libs/lz-string.js +517 -0
  8. package/dist/cjs/node_modules/radash/dist/esm/array.js +90 -0
  9. package/dist/cjs/node_modules/radash/dist/esm/async.js +62 -0
  10. package/dist/cjs/node_modules/radash/dist/esm/object.js +25 -0
  11. package/dist/cjs/node_modules/radash/dist/esm/typed.js +35 -0
  12. package/dist/cjs/node_modules/string-hash/index.js +23 -0
  13. package/dist/cjs/node_modules/tslib/tslib.es6.js +39 -0
  14. package/dist/cjs/node_modules/zod/lib/index.js +4342 -0
  15. package/dist/cjs/src/EntityManager.js +93 -0
  16. package/dist/cjs/src/ParsedConfig.js +227 -0
  17. package/dist/cjs/src/addKeys.js +47 -0
  18. package/dist/cjs/src/decodeEntityElement.js +37 -0
  19. package/dist/cjs/src/decodeGeneratedProperty.js +48 -0
  20. package/dist/cjs/src/dehydrateIndexItem.js +52 -0
  21. package/dist/cjs/src/dehydratePageKeyMap.js +75 -0
  22. package/dist/cjs/src/encodeEntityElement.js +36 -0
  23. package/dist/cjs/src/encodeGeneratedProperty.js +44 -0
  24. package/dist/cjs/src/getHashKeySpace.js +41 -0
  25. package/dist/cjs/src/getShardBump.js +24 -0
  26. package/dist/cjs/src/index.js +7 -0
  27. package/dist/cjs/src/query.js +104 -0
  28. package/dist/cjs/src/rehydrateIndexItem.js +48 -0
  29. package/dist/cjs/src/rehydratePageKeyMap.js +66 -0
  30. package/dist/cjs/src/removeKeys.js +33 -0
  31. package/dist/cjs/src/unwrapIndex.js +40 -0
  32. package/dist/cjs/src/updateItemHashKey.js +55 -0
  33. package/dist/cjs/src/updateItemRangeKey.js +45 -0
  34. package/dist/cjs/src/validateEntityGeneratedProperty.js +29 -0
  35. package/dist/cjs/src/validateEntityIndexToken.js +22 -0
  36. package/dist/cjs/src/validateEntityToken.js +17 -0
  37. package/dist/index.d.cts +826 -0
  38. package/dist/index.d.mts +826 -0
  39. package/dist/index.d.ts +826 -0
  40. package/dist/mjs/_virtual/_commonjsHelpers.js +5 -0
  41. package/dist/mjs/_virtual/lz-string.js +3 -0
  42. package/dist/mjs/node_modules/@karmaniverous/entity-tools/dist/mjs/Nil.js +12 -0
  43. package/dist/mjs/node_modules/@karmaniverous/entity-tools/dist/mjs/defaultTranscodes.js +92 -0
  44. package/dist/mjs/node_modules/@karmaniverous/entity-tools/dist/mjs/sort.js +50 -0
  45. package/dist/mjs/node_modules/lz-string/libs/lz-string.js +515 -0
  46. package/dist/mjs/node_modules/radash/dist/esm/array.js +80 -0
  47. package/dist/mjs/node_modules/radash/dist/esm/async.js +58 -0
  48. package/dist/mjs/node_modules/radash/dist/esm/object.js +22 -0
  49. package/dist/mjs/node_modules/radash/dist/esm/typed.js +28 -0
  50. package/dist/mjs/node_modules/string-hash/index.js +21 -0
  51. package/dist/mjs/node_modules/tslib/tslib.es6.js +36 -0
  52. package/dist/mjs/node_modules/zod/lib/index.js +4233 -0
  53. package/dist/mjs/src/EntityManager.js +91 -0
  54. package/dist/mjs/src/ParsedConfig.js +225 -0
  55. package/dist/mjs/src/addKeys.js +45 -0
  56. package/dist/mjs/src/decodeEntityElement.js +35 -0
  57. package/dist/mjs/src/decodeGeneratedProperty.js +46 -0
  58. package/dist/mjs/src/dehydrateIndexItem.js +50 -0
  59. package/dist/mjs/src/dehydratePageKeyMap.js +73 -0
  60. package/dist/mjs/src/encodeEntityElement.js +34 -0
  61. package/dist/mjs/src/encodeGeneratedProperty.js +42 -0
  62. package/dist/mjs/src/getHashKeySpace.js +39 -0
  63. package/dist/mjs/src/getShardBump.js +22 -0
  64. package/dist/mjs/src/index.js +1 -0
  65. package/dist/mjs/src/query.js +102 -0
  66. package/dist/mjs/src/rehydrateIndexItem.js +46 -0
  67. package/dist/mjs/src/rehydratePageKeyMap.js +64 -0
  68. package/dist/mjs/src/removeKeys.js +31 -0
  69. package/dist/mjs/src/unwrapIndex.js +38 -0
  70. package/dist/mjs/src/updateItemHashKey.js +53 -0
  71. package/dist/mjs/src/updateItemRangeKey.js +43 -0
  72. package/dist/mjs/src/validateEntityGeneratedProperty.js +27 -0
  73. package/dist/mjs/src/validateEntityIndexToken.js +20 -0
  74. package/dist/mjs/src/validateEntityToken.js +15 -0
  75. package/package.json +108 -59
  76. package/.env +0 -1
  77. package/dist/default/lib/EntityManager/EntityManager.js +0 -423
  78. package/dist/default/lib/EntityManager/PrivateEntityManager.js +0 -421
  79. package/dist/default/lib/index.js +0 -12
  80. package/dist/package.json +0 -3
  81. package/lib/EntityManager/EntityManager.js +0 -396
  82. package/lib/EntityManager/PrivateEntityManager.js +0 -436
  83. package/lib/index.js +0 -1
package/package.json CHANGED
@@ -1,87 +1,136 @@
1
1
  {
2
- "name": "@karmaniverous/entity-manager",
3
- "version": "5.0.8",
4
- "publishConfig": {
5
- "access": "public"
6
- },
7
- "repository": {
8
- "type": "git",
9
- "url": "https://github.com/karmaniverous/entity-manager"
10
- },
11
- "author": "Jason G. Williscroft",
2
+ "author": "Jason Williscroft",
12
3
  "bugs": {
13
4
  "url": "https://github.com/karmaniverous/entity-manager/issues"
14
5
  },
15
- "description": "Configurably decorate entity objects with sharded index keys.",
16
- "homepage": "https://github.com/karmaniverous/entity-manager#readme",
17
- "keywords": [
18
- "dynamo-db",
19
- "sharding"
20
- ],
21
- "license": "BSD-3-Clause",
22
6
  "dependencies": {
23
- "inspect-parameters-declaration": "^0.1.0",
7
+ "@karmaniverous/entity-tools": "^0.2.3",
8
+ "@karmaniverous/string-utilities": "^0.2.1",
24
9
  "jsonschema": "^1.4.1",
25
- "lodash": "^4.17.21",
26
- "string-hash": "^1.1.3"
10
+ "lz-string": "^1.5.0",
11
+ "radash": "^12.1.0",
12
+ "string-hash": "^1.1.3",
13
+ "zod": "^3.23.8"
27
14
  },
15
+ "description": "Configurably decorate entity objects with sharded index keys.",
28
16
  "devDependencies": {
29
- "@babel/cli": "^7.24.8",
30
- "@babel/core": "^7.25.2",
31
- "@babel/eslint-parser": "^7.25.1",
32
- "@babel/plugin-syntax-import-assertions": "^7.24.7",
33
- "@babel/preset-env": "^7.25.2",
34
- "@babel/register": "^7.24.6",
35
- "@karmaniverous/edge-logger": "^1.3.12",
36
- "@karmaniverous/tagged-templates": "^0.1.2",
37
- "@types/node": "^20.14.13",
38
- "babel-plugin-lodash": "^3.3.4",
17
+ "@dotenvx/dotenvx": "^1.14.1",
18
+ "@eslint/js": "^9.10.0",
19
+ "@faker-js/faker": "^9.0.1",
20
+ "@karmaniverous/mock-db": "^0.3.1",
21
+ "@rollup/plugin-alias": "^5.1.0",
22
+ "@rollup/plugin-commonjs": "^26.0.1",
23
+ "@rollup/plugin-json": "^6.1.0",
24
+ "@rollup/plugin-node-resolve": "^15.2.3",
25
+ "@rollup/plugin-strip": "^3.0.4",
26
+ "@rollup/plugin-typescript": "^11.1.6",
27
+ "@types/chai": "^4.3.19",
28
+ "@types/eslint__js": "^8.42.3",
29
+ "@types/eslint-config-prettier": "^6.11.3",
30
+ "@types/eslint-plugin-mocha": "^10.4.0",
31
+ "@types/mocha": "^10.0.8",
32
+ "@types/node": "^22.5.5",
33
+ "@types/string-hash": "^1.1.3",
34
+ "auto-changelog": "^2.5.0",
39
35
  "chai": "^5.1.1",
40
- "concat-md": "^0.5.1",
41
- "eslint": "=8",
42
- "eslint-plugin-jsdoc": "^48.9.3",
36
+ "cross-env": "^7.0.3",
37
+ "eslint": "^9.10.0",
38
+ "eslint-config-prettier": "^9.1.0",
43
39
  "eslint-plugin-mocha": "^10.5.0",
44
- "eslint-plugin-promise": "^6.6.0",
45
- "jsdoc-to-markdown": "^8.0.3",
46
- "knip": "^5.27.0",
47
- "mocha": "^10.7.0",
48
- "release-it": "^17.6.0"
40
+ "eslint-plugin-simple-import-sort": "^12.1.1",
41
+ "eslint-plugin-tsdoc": "^0.3.0",
42
+ "jsdom-global": "^3.0.2",
43
+ "knip": "^5.30.2",
44
+ "lefthook": "^1.7.15",
45
+ "mocha": "^10.7.3",
46
+ "nyc": "^17.0.0",
47
+ "prettier": "^3.3.3",
48
+ "release-it": "^17.6.0",
49
+ "rimraf": "^6.0.1",
50
+ "rollup": "^4.21.3",
51
+ "rollup-plugin-dts": "^6.1.1",
52
+ "source-map-support": "^0.5.21",
53
+ "ts-node": "^10.9.2",
54
+ "tslib": "^2.7.0",
55
+ "typedoc": "^0.26.7",
56
+ "typedoc-plugin-mdn-links": "^3.2.12",
57
+ "typedoc-plugin-replace-text": "^4.0.0",
58
+ "typedoc-plugin-zod": "^1.2.1",
59
+ "typescript": "^5.6.2",
60
+ "typescript-eslint": "^8.6.0"
49
61
  },
50
62
  "exports": {
51
63
  ".": {
52
- "import": "./lib/index.js",
53
- "require": "./dist/default/lib/index.js"
64
+ "import": {
65
+ "types": "./dist/index.d.mts",
66
+ "default": "./dist/mjs/index.js"
67
+ },
68
+ "require": {
69
+ "types": "./dist/index.d.cts",
70
+ "default": "./dist/cjs/index.js"
71
+ }
54
72
  }
55
73
  },
56
- "main": "./lib/index.js",
57
- "mocha": {
58
- "exclude": [
59
- "./dist/**",
60
- "./node_modules/**",
61
- "./**/*.json"
62
- ],
63
- "require": [
64
- "@babel/register"
65
- ],
66
- "spec": "./**/*.test.!(*.*)",
67
- "timeout": 60000
74
+ "files": [
75
+ "dist"
76
+ ],
77
+ "homepage": "https://github.com/karmaniverous/entity-manager#readme",
78
+ "keywords": [
79
+ "dynamo-db",
80
+ "sharding"
81
+ ],
82
+ "license": "BSD-3-Clause",
83
+ "main": "dist/cjs/index.js",
84
+ "module": "dist/mjs/index.js",
85
+ "name": "@karmaniverous/entity-manager",
86
+ "publishConfig": {
87
+ "access": "public"
68
88
  },
69
89
  "release-it": {
90
+ "git": {
91
+ "changelog": "npx auto-changelog --stdout --commit-limit false --unreleased --template https://raw.githubusercontent.com/release-it/release-it/main/templates/changelog-compact.hbs",
92
+ "commitMessage": "chore: release v${version}",
93
+ "requireBranch": "main"
94
+ },
70
95
  "github": {
71
96
  "release": true
72
97
  },
98
+ "hooks": {
99
+ "after:init": [
100
+ "npm run lint",
101
+ "npm run test",
102
+ "npm run build"
103
+ ],
104
+ "before:npm:release": [
105
+ "npx auto-changelog -p",
106
+ "npm run docs",
107
+ "git add -A"
108
+ ],
109
+ "after:release": [
110
+ "git switch -c release/${version}",
111
+ "git push -u origin release/${version}",
112
+ "git switch ${branchName}"
113
+ ]
114
+ },
73
115
  "npm": {
74
116
  "publish": true
75
117
  }
76
118
  },
119
+ "repository": {
120
+ "type": "git",
121
+ "url": "git+https://github.com/karmaniverous/entity-manager.git"
122
+ },
77
123
  "scripts": {
78
- "lint": "eslint lib/**",
79
- "test": "mocha",
80
- "build": "babel lib -d dist/default/lib --delete-dir-on-start --config-file ./dist/default/.babelrc",
81
- "doc": "jsdoc2md -c doc/jsdoc.config.json -f lib/**/*.* -t doc/api-template.hbs > doc/2-api.jsdoc2.md && concat-md doc --hide-anchor-links > README.md",
124
+ "build": "rimraf dist && rollup --config rollup.config.ts --configPlugin @rollup/plugin-typescript",
125
+ "docs": "typedoc",
82
126
  "knip": "knip",
83
- "prerelease": "npm run lint && npm run test && npm run build && npm run doc",
84
- "release": "release-it"
127
+ "lint": "eslint src/** && prettier -c src",
128
+ "lint:fix": "eslint --fix src/** && prettier --write src",
129
+ "release": "dotenvx run -f .env.local -- release-it",
130
+ "release:pre": "dotenvx run -f .env.local -- release-it --no-git.requireBranch --github.prerelease --preRelease",
131
+ "test": "dotenvx run --quiet --log-level=LOG_LEVEL=debug -- nyc mocha"
85
132
  },
86
- "type": "module"
133
+ "type": "module",
134
+ "types": "dist/index.d.ts",
135
+ "version": "6.0.0"
87
136
  }
package/.env DELETED
@@ -1 +0,0 @@
1
- # Load with getdotenv: https://github.com/karmaniverous/get-dotenv
@@ -1,423 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.EntityManager = void 0;
7
- var _zipObject2 = _interopRequireDefault(require("lodash/zipObject"));
8
- var _map2 = _interopRequireDefault(require("lodash/map"));
9
- var _isEmpty2 = _interopRequireDefault(require("lodash/isEmpty"));
10
- var _fromPairs2 = _interopRequireDefault(require("lodash/fromPairs"));
11
- var _isPlainObject2 = _interopRequireDefault(require("lodash/isPlainObject"));
12
- var _isInteger2 = _interopRequireDefault(require("lodash/isInteger"));
13
- var _isUndefined2 = _interopRequireDefault(require("lodash/isUndefined"));
14
- var _sortedUniq2 = _interopRequireDefault(require("lodash/sortedUniq"));
15
- var _has2 = _interopRequireDefault(require("lodash/has"));
16
- var _entries2 = _interopRequireDefault(require("lodash/entries"));
17
- var _sortBy2 = _interopRequireDefault(require("lodash/sortBy"));
18
- var _sortedUniqBy2 = _interopRequireDefault(require("lodash/sortedUniqBy"));
19
- var _isFunction2 = _interopRequireDefault(require("lodash/isFunction"));
20
- var _isArray2 = _interopRequireDefault(require("lodash/isArray"));
21
- var _forEach2 = _interopRequireDefault(require("lodash/forEach"));
22
- var _isNil2 = _interopRequireDefault(require("lodash/isNil"));
23
- var _cloneDeep2 = _interopRequireDefault(require("lodash/cloneDeep"));
24
- var _inspectParametersDeclaration = require("inspect-parameters-declaration");
25
- var _PrivateEntityManager = require("./PrivateEntityManager.js");
26
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
27
- /**
28
- * @module entity-manager
29
- */
30
-
31
- /**
32
- * Manage DynamoDb entities.
33
- *
34
- * @class
35
- */
36
- class EntityManager {
37
- #entityManager;
38
-
39
- /**
40
- * Create an EntityManager instance.
41
- *
42
- * @param {object} options - Options object.
43
- * @param {object} [options.config] - EntityManager configuration object (see {@link https://github.com/karmaniverous/entity-manager#configuration README} for a breakdown).
44
- * @param {object} [options.logger] - Logger instance (defaults to console, must support error & debug methods).
45
- * @returns {EntityManager} EntityManager instance.
46
- * @throws {Error} If config is invalid.
47
- * @throws {Error} If logger is invalid.
48
- */
49
- constructor(_ref) {
50
- let {
51
- config,
52
- logger
53
- } = _ref;
54
- this.#entityManager = new _PrivateEntityManager.PrivateEntityManager({
55
- config,
56
- logger
57
- });
58
- }
59
-
60
- /**
61
- * Add sharded keys to an entity item. Does not mutate original item.
62
- *
63
- * @param {string} entityToken - Entity token.
64
- * @param {object} item - Entity item.
65
- * @param {boolean} [overwrite] - Overwrite existing properties.
66
- * @returns {object} Decorated entity item.
67
- * @throws {Error} If entityToken is invalid.
68
- * @throws {Error} If item is invalid.
69
- */
70
- addKeys(entityToken, item) {
71
- let overwrite = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
72
- this.#entityManager.logger.debug(`adding sharded index keys to ${entityToken}${overwrite ? ' with overwrite' : ''}...`, {
73
- item
74
- });
75
-
76
- // Validate item.
77
- this.#entityManager.validateItem(item);
78
-
79
- // Clone item.
80
- const newItem = (0, _cloneDeep2.default)(item);
81
-
82
- // Get entity config.
83
- const {
84
- shardKeyToken
85
- } = this.#entityManager;
86
- const {
87
- keys
88
- } = this.#entityManager.getEntityConfig(entityToken);
89
-
90
- // Add shardKey.
91
- if (overwrite || (0, _isNil2.default)(newItem[shardKeyToken])) {
92
- newItem[shardKeyToken] = this.calcShardKey(entityToken, newItem);
93
- }
94
-
95
- // Add keys.
96
- (0, _forEach2.default)(keys, (_ref2, key) => {
97
- let {
98
- encode
99
- } = _ref2;
100
- if (overwrite || (0, _isNil2.default)(newItem[key])) newItem[key] = encode(newItem);
101
- });
102
- this.#entityManager.logger.debug('done', {
103
- newItem
104
- });
105
-
106
- // Remove undefined shardKey.
107
- if ((0, _isNil2.default)(newItem[shardKeyToken])) delete newItem[shardKeyToken];
108
- return newItem;
109
- }
110
-
111
- /**
112
- * Calculated the shard key for an entity item.
113
- *
114
- * @param {string} entityToken - Entity token.
115
- * @param {object} item - Entity item.
116
- * @returns {string} Shard key.
117
- */
118
- calcShardKey(entityToken, item) {
119
- const {
120
- sharding
121
- } = this.#entityManager.getEntityConfig(entityToken);
122
- const entityKey = sharding.entityKey(item);
123
- const timestamp = sharding.timestamp(item);
124
- return this.#entityManager.getShardKey(entityToken, entityKey, timestamp);
125
- }
126
-
127
- /**
128
- * Condense an index object into a delimited string.
129
- *
130
- * @param {string} entityToken - Entity token.
131
- * @param {string|string[]} indexToken - Index token or array of key tokens.
132
- * @param {object} index - Index object.
133
- * @param {string} [delimiter] - Delimiter.
134
- * @returns {string} Dehydrated index.
135
- * @throws {Error} If entityToken is invalid.
136
- * @throws {Error} If indexToken is invalid.
137
- * @throws {Error} If item is invalid.
138
- */
139
- dehydrateIndex(entityToken, indexToken, index) {
140
- let delimiter = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : '~';
141
- // Validate item.
142
- this.#entityManager.validateItem(index);
143
- const indexComponents = (0, _isArray2.default)(indexToken) ? indexToken : this.#entityManager.getIndexComponents(entityToken, indexToken);
144
- const indexProperties = indexComponents.reduce((properties, component) => {
145
- const {
146
- decode
147
- } = this.getKey(entityToken, component);
148
- if (!(0, _isFunction2.default)(decode)) throw new Error(`no decode function defined on ${entityToken} entity key '${component}'`);
149
- return {
150
- ...properties,
151
- ...(decode(index[component] ?? '') ?? {})
152
- };
153
- }, {});
154
- return (0, _sortedUniqBy2.default)((0, _sortBy2.default)((0, _entries2.default)(indexProperties), _ref3 => {
155
- let [key] = _ref3;
156
- return key;
157
- }), _ref4 => {
158
- let [key] = _ref4;
159
- return key;
160
- }).map(_ref5 => {
161
- let [, value] = _ref5;
162
- return value;
163
- }).join(delimiter);
164
- }
165
-
166
- /**
167
- * Return the config for a given entity key token.
168
- *
169
- * @param {string} entityToken - Entity token.
170
- * @param {string} keyToken - Key token.
171
- * @returns {object} Entity key config.
172
- */
173
- getKey(entityToken, keyToken) {
174
- const {
175
- keys
176
- } = this.#entityManager.getEntityConfig(entityToken);
177
- if (!(0, _has2.default)(keys, keyToken)) throw new Error(`Key '${keyToken}' does not exist for entity '${entityToken}'.`);
178
- return keys[keyToken];
179
- }
180
-
181
- /**
182
- * Return an array of sharded keys valid for a given entity token & timestamp.
183
- *
184
- * @param {string} entityToken - Entity token.
185
- * @param {string} keyToken - Key token.
186
- * @param {object} item - Entity item sufficiently populated to generate property keyToken.
187
- * @param {number} timestamp - Timestamp.
188
- * @returns {string[]} Array of keys.
189
- * @throws {Error} If entityToken is invalid.
190
- * @throws {Error} If item is invalid.
191
- * @throws {Error} If keyToken is invalid.
192
- * @throws {Error} If timestamp is invalid.
193
- */
194
- getKeySpace(entityToken, keyToken, item) {
195
- let timestamp = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : Date.now();
196
- this.#entityManager.logger.debug(`getting shard key space for ${entityToken} on key '${keyToken}' at timestamp ${timestamp}...`, {
197
- item
198
- });
199
- const shardKeySpace = this.#entityManager.getShardKeySpace(entityToken, timestamp);
200
- const result = (0, _sortedUniq2.default)(shardKeySpace.map(shardKey => this.getKey(entityToken, keyToken).encode({
201
- ...item,
202
- [this.#entityManager.shardKeyToken]: shardKey
203
- })));
204
- this.#entityManager.logger.debug('done', {
205
- result
206
- });
207
- return result;
208
- }
209
-
210
- /**
211
- * @typedef {object} ShardQueryResult
212
- * @property {any[]} items - Query result array.
213
- * @property {*} pageKey - Shard page key.
214
- */
215
-
216
- /**
217
- * Shard query function
218
- *
219
- * @callback ShardQueryFunction
220
- * @param {string} shardedKey - Sharded key.
221
- * @param {*} [pageKey] - Page key.
222
- * @param {number} [limit] - Request limit.
223
- * @returns {Promise<ShardQueryResult>} Sharded query result.
224
- */
225
-
226
- /**
227
- * @typedef {object} ShardedQueryResult
228
- * @property {any[]} items - Query result array.
229
- * @property {object} pageKeys - Shard page keys.
230
- */
231
-
232
- /**
233
- * Query an entity across shards.
234
- *
235
- * @param {object} options - Query options.
236
- * @param {string} options.entityToken - Entity token.
237
- * @param {string} [options.keyToken] - Key token.
238
- * @param {object} [options.item] - Entity item sufficiently populated to generate property keyToken.
239
- * @param {ShardQueryFunction} options.shardQuery - Sharded query function.
240
- * @param {number} [options.limit] - Request limit.
241
- * @param {object} [options.pageKeys] - Map of shard page keys.
242
- * @param {number} [options.pageSize] - Request page size.
243
- * @returns {Promise<ShardedQueryResult>} Sharded query result.
244
- */
245
- async query() {
246
- let {
247
- entityToken,
248
- keyToken = 'entityPK',
249
- item = {},
250
- shardQuery,
251
- limit,
252
- pageKeys,
253
- pageSize
254
- } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
255
- // Validate params.
256
- this.#entityManager.validateKeyToken(entityToken, keyToken);
257
- this.#entityManager.validateItem(item);
258
- if (!(0, _isFunction2.default)(shardQuery)) throw new Error('shardQuery must be a function');
259
- if (!(0, _isUndefined2.default)(limit) && !(limit === Infinity || (0, _isInteger2.default)(limit) && limit >= 1)) throw new Error('limit must be a positive integer or Infinity.');
260
- if (!(0, _isUndefined2.default)(pageKeys) && !(0, _isPlainObject2.default)(pageKeys)) throw new Error('pageKeys must be an object');
261
- if (!(0, _isUndefined2.default)(pageSize) && !((0, _isInteger2.default)(pageSize) && pageSize >= 1)) throw new Error('pageSize must be a positive integer');
262
-
263
- // Apply default limit.
264
- limit ??= this.#entityManager.getEntityConfig(entityToken).defaultLimit;
265
-
266
- // Apply default pageSize.
267
- pageSize ??= this.#entityManager.getEntityConfig(entityToken).defaultPageSize;
268
-
269
- // Generate default pageKeys if not provided
270
- pageKeys ??= (0, _fromPairs2.default)(this.getKeySpace(entityToken, keyToken, item).map(shardedKey => [shardedKey, undefined]));
271
- this.#entityManager.logger.debug('EntityManager.query parsed params', {
272
- entityToken,
273
- keyToken,
274
- item,
275
- shardQuery,
276
- limit,
277
- pageKeys,
278
- pageSize
279
- });
280
-
281
- // Return empty result if no pageKeys.
282
- if ((0, _isEmpty2.default)(pageKeys)) return {
283
- count: 0,
284
- items: [],
285
- pageKeys: {}
286
- };
287
-
288
- // Iterate search over pages.
289
- let page = 0;
290
- const result = {
291
- count: 0,
292
- items: [],
293
- pageKeys
294
- };
295
- do {
296
- // TODO: This loop will blow up as shards scale, since at a minimum it will return shardCount x pageSize
297
- // items, which may be >> limit. Probably the way to fix this is to limit the number of shards queried per
298
- // iteration in order to keep shardsQueried * pageSize > (limit - items.length) but only just.
299
-
300
- // Query every shard in pageKeys.
301
- const shardQueryResults = await Promise.all((0, _map2.default)(result.pageKeys, (pageKey, shardedKey) => new Promise(resolve => shardQuery(shardedKey, pageKey, pageSize).then(_ref6 => {
302
- let {
303
- count,
304
- items,
305
- pageKey
306
- } = _ref6;
307
- return resolve({
308
- count,
309
- items,
310
- pageKey,
311
- shardedKey
312
- });
313
- }))));
314
-
315
- // Reduce shardQueryResults into a single result.
316
- const pageResult = shardQueryResults.reduce((shardedQueryResult, _ref7) => {
317
- let {
318
- count,
319
- items,
320
- pageKey,
321
- shardedKey
322
- } = _ref7;
323
- return {
324
- count: shardedQueryResult.count + count,
325
- items: [...shardedQueryResult.items, ...items],
326
- pageKeys: {
327
- ...shardedQueryResult.pageKeys,
328
- ...((0, _isUndefined2.default)(pageKey) ? {} : {
329
- [shardedKey]: pageKey
330
- })
331
- }
332
- };
333
- }, {
334
- count: 0,
335
- items: [],
336
- pageKeys: {}
337
- });
338
- this.#entityManager.logger.debug(`EntityManager.query page ${page} result`, {
339
- pageResult
340
- });
341
- result.count += pageResult.count;
342
- result.items = [...result.items, ...pageResult.items];
343
- result.pageKeys = pageResult.pageKeys;
344
- page++;
345
- } while (result.items.length < limit && !(0, _isEmpty2.default)(result.pageKeys));
346
- return result;
347
- }
348
-
349
- /**
350
- * Convert a delimited string into a named index key.
351
- *
352
- * @param {string} entityToken - Entity token.
353
- * @param {string|string[]} indexToken - Index token or array of key tokens.
354
- * @param {string} value - Dehydrated index value.
355
- * @param {string} [delimiter] - Delimiter.
356
- * @returns {object} Rehydrated index key.
357
- * @throws {Error} If entityToken is invalid.
358
- * @throws {Error} If indexToken is invalid.
359
- */
360
- rehydrateIndex(entityToken, indexToken) {
361
- let value = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
362
- let delimiter = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : '~';
363
- const indexComponents = (0, _isArray2.default)(indexToken) ? indexToken : this.#entityManager.getIndexComponents(entityToken, indexToken);
364
- const indexKeys = (0, _sortBy2.default)(indexComponents.reduce((keys, component) => {
365
- const {
366
- encode
367
- } = this.getKey(entityToken, component);
368
- return [...new Set([...keys, ...(0, _inspectParametersDeclaration.getParametersNames)(encode)]).values()];
369
- }, []));
370
- const indexProperties = (0, _zipObject2.default)(indexKeys, value.split(delimiter));
371
- return indexComponents.reduce((index, component) => {
372
- const {
373
- encode
374
- } = this.getKey(entityToken, component);
375
- return {
376
- ...index,
377
- [component]: encode(indexProperties)
378
- };
379
- }, {});
380
- }
381
-
382
- /**
383
- * Remove sharded keys from an entity item. Does not mutate original item.
384
- *
385
- * @param {string} entityToken - Entity token.
386
- * @param {object} item - Entity item.
387
- * @returns {object} Stripped entity item.
388
- * @throws {Error} If entityToken is invalid.
389
- * @throws {Error} If item is invalid.
390
- */
391
- removeKeys(entityToken, item) {
392
- this.#entityManager.logger.debug(`removing sharded index keys from ${entityToken}...`, {
393
- item
394
- });
395
-
396
- // Validate item.
397
- this.#entityManager.validateItem(item);
398
-
399
- // Clone item.
400
- const newItem = (0, _cloneDeep2.default)(item);
401
-
402
- // Get entity config.
403
- const {
404
- shardKeyToken
405
- } = this.#entityManager;
406
- const {
407
- keys
408
- } = this.#entityManager.getEntityConfig(entityToken);
409
-
410
- // Remove shardKey.
411
- delete newItem[shardKeyToken];
412
-
413
- // Remove keys.
414
- (0, _forEach2.default)(keys, (value, key) => {
415
- if (!value.retain) delete newItem[key];
416
- });
417
- this.#entityManager.logger.debug('done', {
418
- newItem
419
- });
420
- return newItem;
421
- }
422
- }
423
- exports.EntityManager = EntityManager;