@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.
- package/README.md +15 -439
- package/dist/cjs/_virtual/_commonjsHelpers.js +7 -0
- package/dist/cjs/_virtual/lz-string.js +5 -0
- package/dist/cjs/node_modules/@karmaniverous/entity-tools/dist/mjs/Nil.js +14 -0
- package/dist/cjs/node_modules/@karmaniverous/entity-tools/dist/mjs/defaultTranscodes.js +94 -0
- package/dist/cjs/node_modules/@karmaniverous/entity-tools/dist/mjs/sort.js +52 -0
- package/dist/cjs/node_modules/lz-string/libs/lz-string.js +517 -0
- package/dist/cjs/node_modules/radash/dist/esm/array.js +90 -0
- package/dist/cjs/node_modules/radash/dist/esm/async.js +62 -0
- package/dist/cjs/node_modules/radash/dist/esm/object.js +25 -0
- package/dist/cjs/node_modules/radash/dist/esm/typed.js +35 -0
- package/dist/cjs/node_modules/string-hash/index.js +23 -0
- package/dist/cjs/node_modules/tslib/tslib.es6.js +39 -0
- package/dist/cjs/node_modules/zod/lib/index.js +4342 -0
- package/dist/cjs/src/EntityManager.js +93 -0
- package/dist/cjs/src/ParsedConfig.js +227 -0
- package/dist/cjs/src/addKeys.js +47 -0
- package/dist/cjs/src/decodeEntityElement.js +37 -0
- package/dist/cjs/src/decodeGeneratedProperty.js +48 -0
- package/dist/cjs/src/dehydrateIndexItem.js +52 -0
- package/dist/cjs/src/dehydratePageKeyMap.js +75 -0
- package/dist/cjs/src/encodeEntityElement.js +36 -0
- package/dist/cjs/src/encodeGeneratedProperty.js +44 -0
- package/dist/cjs/src/getHashKeySpace.js +41 -0
- package/dist/cjs/src/getShardBump.js +24 -0
- package/dist/cjs/src/index.js +7 -0
- package/dist/cjs/src/query.js +104 -0
- package/dist/cjs/src/rehydrateIndexItem.js +48 -0
- package/dist/cjs/src/rehydratePageKeyMap.js +66 -0
- package/dist/cjs/src/removeKeys.js +33 -0
- package/dist/cjs/src/unwrapIndex.js +40 -0
- package/dist/cjs/src/updateItemHashKey.js +55 -0
- package/dist/cjs/src/updateItemRangeKey.js +45 -0
- package/dist/cjs/src/validateEntityGeneratedProperty.js +29 -0
- package/dist/cjs/src/validateEntityIndexToken.js +22 -0
- package/dist/cjs/src/validateEntityToken.js +17 -0
- package/dist/index.d.cts +826 -0
- package/dist/index.d.mts +826 -0
- package/dist/index.d.ts +826 -0
- package/dist/mjs/_virtual/_commonjsHelpers.js +5 -0
- package/dist/mjs/_virtual/lz-string.js +3 -0
- package/dist/mjs/node_modules/@karmaniverous/entity-tools/dist/mjs/Nil.js +12 -0
- package/dist/mjs/node_modules/@karmaniverous/entity-tools/dist/mjs/defaultTranscodes.js +92 -0
- package/dist/mjs/node_modules/@karmaniverous/entity-tools/dist/mjs/sort.js +50 -0
- package/dist/mjs/node_modules/lz-string/libs/lz-string.js +515 -0
- package/dist/mjs/node_modules/radash/dist/esm/array.js +80 -0
- package/dist/mjs/node_modules/radash/dist/esm/async.js +58 -0
- package/dist/mjs/node_modules/radash/dist/esm/object.js +22 -0
- package/dist/mjs/node_modules/radash/dist/esm/typed.js +28 -0
- package/dist/mjs/node_modules/string-hash/index.js +21 -0
- package/dist/mjs/node_modules/tslib/tslib.es6.js +36 -0
- package/dist/mjs/node_modules/zod/lib/index.js +4233 -0
- package/dist/mjs/src/EntityManager.js +91 -0
- package/dist/mjs/src/ParsedConfig.js +225 -0
- package/dist/mjs/src/addKeys.js +45 -0
- package/dist/mjs/src/decodeEntityElement.js +35 -0
- package/dist/mjs/src/decodeGeneratedProperty.js +46 -0
- package/dist/mjs/src/dehydrateIndexItem.js +50 -0
- package/dist/mjs/src/dehydratePageKeyMap.js +73 -0
- package/dist/mjs/src/encodeEntityElement.js +34 -0
- package/dist/mjs/src/encodeGeneratedProperty.js +42 -0
- package/dist/mjs/src/getHashKeySpace.js +39 -0
- package/dist/mjs/src/getShardBump.js +22 -0
- package/dist/mjs/src/index.js +1 -0
- package/dist/mjs/src/query.js +102 -0
- package/dist/mjs/src/rehydrateIndexItem.js +46 -0
- package/dist/mjs/src/rehydratePageKeyMap.js +64 -0
- package/dist/mjs/src/removeKeys.js +31 -0
- package/dist/mjs/src/unwrapIndex.js +38 -0
- package/dist/mjs/src/updateItemHashKey.js +53 -0
- package/dist/mjs/src/updateItemRangeKey.js +43 -0
- package/dist/mjs/src/validateEntityGeneratedProperty.js +27 -0
- package/dist/mjs/src/validateEntityIndexToken.js +20 -0
- package/dist/mjs/src/validateEntityToken.js +15 -0
- package/package.json +108 -59
- package/.env +0 -1
- package/dist/default/lib/EntityManager/EntityManager.js +0 -423
- package/dist/default/lib/EntityManager/PrivateEntityManager.js +0 -421
- package/dist/default/lib/index.js +0 -12
- package/dist/package.json +0 -3
- package/lib/EntityManager/EntityManager.js +0 -396
- package/lib/EntityManager/PrivateEntityManager.js +0 -436
- package/lib/index.js +0 -1
package/package.json
CHANGED
|
@@ -1,87 +1,136 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
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
|
-
"
|
|
7
|
+
"@karmaniverous/entity-tools": "^0.2.3",
|
|
8
|
+
"@karmaniverous/string-utilities": "^0.2.1",
|
|
24
9
|
"jsonschema": "^1.4.1",
|
|
25
|
-
"
|
|
26
|
-
"
|
|
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
|
-
"@
|
|
30
|
-
"@
|
|
31
|
-
"@
|
|
32
|
-
"@
|
|
33
|
-
"@
|
|
34
|
-
"@
|
|
35
|
-
"@
|
|
36
|
-
"@
|
|
37
|
-
"@
|
|
38
|
-
"
|
|
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
|
-
"
|
|
41
|
-
"eslint": "
|
|
42
|
-
"eslint-
|
|
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-
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
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":
|
|
53
|
-
|
|
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
|
-
"
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
"
|
|
79
|
-
"
|
|
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
|
-
"
|
|
84
|
-
"
|
|
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;
|