@karmaniverous/entity-manager 7.3.4 → 8.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 +7 -1
- package/dist/cjs/EntityManager/EntityManager.js +7 -4
- package/dist/cjs/EntityManager/encodeGeneratedProperty.js +5 -2
- package/dist/cjs/EntityManager/getHashKeySpace.js +1 -1
- package/dist/cjs/EntityManager/getPrimaryKey.js +13 -6
- package/dist/cjs/EntityManager/removeKeys.js +11 -4
- package/dist/cjs/EntityManager/updateItemHashKey.js +9 -7
- package/dist/cjs/EntityManager/updateItemRangeKey.js +9 -8
- package/dist/index.d.ts +86 -58
- package/dist/mjs/EntityManager/EntityManager.js +7 -4
- package/dist/mjs/EntityManager/encodeGeneratedProperty.js +5 -2
- package/dist/mjs/EntityManager/getHashKeySpace.js +1 -1
- package/dist/mjs/EntityManager/getPrimaryKey.js +13 -6
- package/dist/mjs/EntityManager/removeKeys.js +11 -4
- package/dist/mjs/EntityManager/updateItemHashKey.js +9 -7
- package/dist/mjs/EntityManager/updateItemRangeKey.js +9 -8
- package/package.json +14 -14
package/README.md
CHANGED
|
@@ -363,7 +363,11 @@ const manager = createEntityManager(config, logger);
|
|
|
363
363
|
- `createEntityManager(config, logger?)`
|
|
364
364
|
- `ConfigInput` (values‑first), `CapturedConfigMapFrom`, `EntitiesFromSchema`
|
|
365
365
|
- Token aware
|
|
366
|
-
- `EntityToken<CC
|
|
366
|
+
- `EntityToken<CC>`
|
|
367
|
+
- `EntityItem<CC, ET>` — strict domain (full), includes optional key/token properties
|
|
368
|
+
- `EntityItemPartial<CC, ET, K>` — projected/seed domain; required keys when K provided, permissive partial when K omitted
|
|
369
|
+
- `EntityRecord<CC, ET>` — DB record (required keys) + partial domain fields
|
|
370
|
+
- `EntityRecordPartial<CC, ET, K>` — projected DB record
|
|
367
371
|
- Index aware (values‑first config literal, “CF” channel)
|
|
368
372
|
- `PageKeyByIndex<CC, ET, IT, CF>`
|
|
369
373
|
- `ShardQueryFunction<CC, ET, IT, CF>`, `ShardQueryMap<CC, ET, ITS, CF>`
|
|
@@ -373,6 +377,8 @@ const manager = createEntityManager(config, logger);
|
|
|
373
377
|
- `KeysFrom<K>`
|
|
374
378
|
- `Projected<T, K>`
|
|
375
379
|
- `ProjectedItemByToken<CC, ET, K>`
|
|
380
|
+
- Advanced (storage shapes; exported for reference and TypeDoc)
|
|
381
|
+
- `StorageItem<CC>`, `StorageRecord<CC>`
|
|
376
382
|
|
|
377
383
|
See the full API: https://docs.karmanivero.us/entity-manager
|
|
378
384
|
|
|
@@ -64,7 +64,7 @@ class EntityManager {
|
|
|
64
64
|
* Encode a generated property value. Returns a string or undefined if atomicity requirement of sharded properties not met.
|
|
65
65
|
*
|
|
66
66
|
* @param property - {@link Config | Config} `generatedProperties` key.
|
|
67
|
-
* @param item - {@link
|
|
67
|
+
* @param item - {@link StorageItem | `StorageItem`} object.
|
|
68
68
|
*
|
|
69
69
|
* @returns Encoded generated property value.
|
|
70
70
|
*
|
|
@@ -87,9 +87,11 @@ class EntityManager {
|
|
|
87
87
|
}
|
|
88
88
|
removeKeys(entityToken, i) {
|
|
89
89
|
if (Array.isArray(i)) {
|
|
90
|
-
|
|
90
|
+
const out = i.map((item) => removeKeys.removeKeys(this, entityToken, item));
|
|
91
|
+
return out;
|
|
91
92
|
}
|
|
92
|
-
|
|
93
|
+
const out = removeKeys.removeKeys(this, entityToken, i);
|
|
94
|
+
return out;
|
|
93
95
|
}
|
|
94
96
|
findIndexToken(hashKeyToken, rangeKeyToken, suppressError) {
|
|
95
97
|
// Dispatch with a literal to satisfy overload selection.
|
|
@@ -120,7 +122,8 @@ class EntityManager {
|
|
|
120
122
|
* @protected
|
|
121
123
|
*/
|
|
122
124
|
async query(options) {
|
|
123
|
-
|
|
125
|
+
const result = await query.query(this, options);
|
|
126
|
+
return result;
|
|
124
127
|
}
|
|
125
128
|
}
|
|
126
129
|
_EntityManager_config = new WeakMap();
|
|
@@ -8,7 +8,7 @@ var validateGeneratedProperty = require('./validateGeneratedProperty.js');
|
|
|
8
8
|
*
|
|
9
9
|
* @param entityManager - {@link EntityManager | `EntityManager`} instance.
|
|
10
10
|
* @param property - {@link Config.generatedProperties | Generated property} key.
|
|
11
|
-
* @param item - {@link
|
|
11
|
+
* @param item - {@link StorageItem | `StorageItem`} object.
|
|
12
12
|
*
|
|
13
13
|
* @returns Encoded generated property value.
|
|
14
14
|
*
|
|
@@ -21,7 +21,10 @@ function encodeGeneratedProperty(entityManager, property, item) {
|
|
|
21
21
|
const sharded = property in entityManager.config.generatedProperties.sharded;
|
|
22
22
|
const elements = entityManager.config.generatedProperties[sharded ? 'sharded' : 'unsharded'][property];
|
|
23
23
|
// Map elements to [element, value] pairs.
|
|
24
|
-
const elementMap = elements.map((element) => [
|
|
24
|
+
const elementMap = elements.map((element) => [
|
|
25
|
+
element,
|
|
26
|
+
item[element],
|
|
27
|
+
]);
|
|
25
28
|
// Return undefined if sharded & atomicity requirement fails.
|
|
26
29
|
if (sharded && elementMap.some(([, value]) => entityTools.isNil(value)))
|
|
27
30
|
return;
|
|
@@ -52,7 +52,7 @@ function getHashKeySpace(entityManager, entityToken, hashKeyToken, item, timesta
|
|
|
52
52
|
// Map shard keys to hash keys.
|
|
53
53
|
.map((shardKey) => {
|
|
54
54
|
// Calculate record hash key.
|
|
55
|
-
let hashKey = `${entityToken}${entityManager.config.shardKeyDelimiter}${shardKey}`;
|
|
55
|
+
let hashKey = `${String(entityToken)}${entityManager.config.shardKeyDelimiter}${shardKey}`;
|
|
56
56
|
// If hash key space basis is a different property, encode it.
|
|
57
57
|
if (hashKeyToken !== entityManager.config.hashKey)
|
|
58
58
|
hashKey = encodeGeneratedProperty.encodeGeneratedProperty(entityManager, hashKeyToken, {
|
|
@@ -27,11 +27,14 @@ var updateItemRangeKey = require('./updateItemRangeKey.js');
|
|
|
27
27
|
function getPrimaryKey(entityManager, entityToken, item, overwrite = false) {
|
|
28
28
|
const { hashKey, rangeKey } = entityManager.config;
|
|
29
29
|
// If both keys are present and we're not overwriting, return the exact pair.
|
|
30
|
-
|
|
30
|
+
const rec = item;
|
|
31
|
+
const hk = hashKey;
|
|
32
|
+
const rk = rangeKey;
|
|
33
|
+
if (!overwrite && rec[hk] && rec[rk]) {
|
|
31
34
|
return [
|
|
32
35
|
{
|
|
33
|
-
[hashKey]:
|
|
34
|
-
[rangeKey]:
|
|
36
|
+
[hashKey]: rec[hk],
|
|
37
|
+
[rangeKey]: rec[rk],
|
|
35
38
|
},
|
|
36
39
|
];
|
|
37
40
|
}
|
|
@@ -40,6 +43,7 @@ function getPrimaryKey(entityManager, entityToken, item, overwrite = false) {
|
|
|
40
43
|
// If timestamp present, compute exactly one hash key and return single pair.
|
|
41
44
|
const tsProp = entityManager.config.entities[entityToken].timestampProperty;
|
|
42
45
|
if (withRangeKey[tsProp] !== undefined) {
|
|
46
|
+
// Note: use StorageItem here
|
|
43
47
|
const withHashKey = updateItemHashKey.updateItemHashKey(entityManager, entityToken, withRangeKey, true);
|
|
44
48
|
return [
|
|
45
49
|
{
|
|
@@ -51,12 +55,15 @@ function getPrimaryKey(entityManager, entityToken, item, overwrite = false) {
|
|
|
51
55
|
// No timestamp: enumerate hash-key space across all shard bumps (0..Infinity).
|
|
52
56
|
const hashKeys = getHashKeySpace.getHashKeySpace(entityManager, entityToken, hashKey, withRangeKey, 0, Infinity);
|
|
53
57
|
// Map to keys and de-duplicate.
|
|
54
|
-
const
|
|
58
|
+
const rangeKeyValue = withRangeKey[rangeKey];
|
|
55
59
|
const seen = new Set();
|
|
56
60
|
const keys = hashKeys
|
|
57
61
|
.map((hk) => {
|
|
58
|
-
const key = {
|
|
59
|
-
|
|
62
|
+
const key = {
|
|
63
|
+
[hashKey]: hk,
|
|
64
|
+
[rangeKey]: rangeKeyValue,
|
|
65
|
+
};
|
|
66
|
+
const sig = `${hk}|${rangeKeyValue}`;
|
|
60
67
|
if (seen.has(sig))
|
|
61
68
|
return undefined;
|
|
62
69
|
seen.add(sig);
|
|
@@ -25,14 +25,21 @@ function removeKeys(entityManager, entityToken, item) {
|
|
|
25
25
|
...Object.keys(sharded),
|
|
26
26
|
...Object.keys(unsharded),
|
|
27
27
|
]);
|
|
28
|
-
// Create a shallow copy of item omitting the keys above (no delete operator)
|
|
29
|
-
|
|
28
|
+
// Create a shallow copy of item omitting the keys above (no delete operator),
|
|
29
|
+
// avoiding any-typed assignments.
|
|
30
|
+
const source = item;
|
|
31
|
+
const newItemObj = {};
|
|
32
|
+
for (const [key, value] of Object.entries(source)) {
|
|
33
|
+
if (!keysToStrip.has(key)) {
|
|
34
|
+
newItemObj[key] = value;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
30
37
|
entityManager.logger.debug('stripped entity item generated properties', {
|
|
31
38
|
entityToken,
|
|
32
39
|
item,
|
|
33
|
-
newItem,
|
|
40
|
+
newItem: newItemObj,
|
|
34
41
|
});
|
|
35
|
-
return
|
|
42
|
+
return newItemObj;
|
|
36
43
|
}
|
|
37
44
|
catch (error) {
|
|
38
45
|
if (error instanceof Error)
|
|
@@ -6,11 +6,11 @@ var getShardBump = require('./getShardBump.js');
|
|
|
6
6
|
var validateEntityToken = require('./validateEntityToken.js');
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* Update the hash key on an
|
|
9
|
+
* Update the hash key on an {@link EntityItemPartial | `EntityItemPartial`} object.
|
|
10
10
|
*
|
|
11
11
|
* @param entityManager - {@link EntityManager | `EntityManager`} instance.
|
|
12
12
|
* @param entityToken - {@link Config.entities | `this.config.entities`} key.
|
|
13
|
-
* @param item - {@link
|
|
13
|
+
* @param item - {@link StorageItem | `StorageItem`} object.
|
|
14
14
|
* @param overwrite - Overwrite existing {@link ConfigKeys.hashKey | `this.config.hashKey`} property value (default `false`).
|
|
15
15
|
*
|
|
16
16
|
* @returns Shallow clone of `item` with updated hash key.
|
|
@@ -32,13 +32,14 @@ function updateItemHashKey(entityManager, entityToken, item, overwrite = false)
|
|
|
32
32
|
return { ...item };
|
|
33
33
|
}
|
|
34
34
|
// Get item timestamp property & validate.
|
|
35
|
-
const
|
|
36
|
-
.timestampProperty
|
|
35
|
+
const tsProp = entityManager.config.entities[entityToken]
|
|
36
|
+
.timestampProperty;
|
|
37
|
+
const timestamp = item[tsProp];
|
|
37
38
|
if (entityTools.isNil(timestamp))
|
|
38
39
|
throw new Error(`missing item timestamp property`);
|
|
39
40
|
// Find first entity sharding bump before timestamp.
|
|
40
41
|
const { charBits, chars } = getShardBump.getShardBump(entityManager, entityToken, timestamp);
|
|
41
|
-
let hashKey = `${entityToken}${entityManager.config.shardKeyDelimiter}`;
|
|
42
|
+
let hashKey = `${String(entityToken)}${entityManager.config.shardKeyDelimiter}`;
|
|
42
43
|
if (chars) {
|
|
43
44
|
// Radix is the numerical base of the shardKey.
|
|
44
45
|
const radix = 2 ** charBits;
|
|
@@ -46,8 +47,9 @@ function updateItemHashKey(entityManager, entityToken, item, overwrite = false)
|
|
|
46
47
|
// all placeholders are utilized (e.g., chars=2, charBits=2 => 16 combos).
|
|
47
48
|
const space = radix ** chars;
|
|
48
49
|
// Get item unique property & validate.
|
|
49
|
-
const
|
|
50
|
-
.uniqueProperty
|
|
50
|
+
const upProp = entityManager.config.entities[entityToken]
|
|
51
|
+
.uniqueProperty;
|
|
52
|
+
const uniqueId = item[upProp];
|
|
51
53
|
if (entityTools.isNil(uniqueId))
|
|
52
54
|
throw new Error(`missing item unique property`);
|
|
53
55
|
hashKey += (stringHash(uniqueId) % space)
|
|
@@ -4,11 +4,11 @@ var entityTools = require('@karmaniverous/entity-tools');
|
|
|
4
4
|
var validateEntityToken = require('./validateEntityToken.js');
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Update the range key on an {@link
|
|
7
|
+
* Update the range key on an {@link EntityItemPartial | `EntityItemPartial`} object.
|
|
8
8
|
*
|
|
9
9
|
* @param entityManager - {@link EntityManager | `EntityManager`} instance.
|
|
10
10
|
* @param entityToken - {@link Config.entities | `this.config.entities`} key.
|
|
11
|
-
* @param item - {@link
|
|
11
|
+
* @param item - {@link StorageItem | `StorageItem`} object.
|
|
12
12
|
* @param overwrite - Overwrite existing {@link ConfigKeys.rangeKey | `this.config.rangeKey`} property value (default `false`).
|
|
13
13
|
*
|
|
14
14
|
* @returns Shallow clone of `item` with updated range key.
|
|
@@ -21,8 +21,8 @@ function updateItemRangeKey(entityManager, entityToken, item, overwrite = false)
|
|
|
21
21
|
// Validate params.
|
|
22
22
|
validateEntityToken.validateEntityToken(entityManager, entityToken);
|
|
23
23
|
// Return current item if rangeKey exists and overwrite is false.
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
const rkProp = entityManager.config.rangeKey;
|
|
25
|
+
if (item[rkProp] && !overwrite) {
|
|
26
26
|
entityManager.logger.debug('did not overwrite existing entity item range key', {
|
|
27
27
|
entityToken,
|
|
28
28
|
item,
|
|
@@ -31,15 +31,16 @@ function updateItemRangeKey(entityManager, entityToken, item, overwrite = false)
|
|
|
31
31
|
return { ...item };
|
|
32
32
|
}
|
|
33
33
|
// Get item unique property & validate.
|
|
34
|
-
const
|
|
35
|
-
.uniqueProperty
|
|
36
|
-
|
|
34
|
+
const upProp = entityManager.config.entities[entityToken]
|
|
35
|
+
.uniqueProperty;
|
|
36
|
+
const uniqueValue = item[upProp];
|
|
37
|
+
if (entityTools.isNil(uniqueValue))
|
|
37
38
|
throw new Error(`missing item unique property`);
|
|
38
39
|
// Update range key.
|
|
39
40
|
const newItem = Object.assign({ ...item }, {
|
|
40
41
|
[entityManager.config.rangeKey]: [
|
|
41
42
|
entityManager.config.entities[entityToken].uniqueProperty,
|
|
42
|
-
|
|
43
|
+
uniqueValue,
|
|
43
44
|
].join(entityManager.config.generatedValueDelimiter),
|
|
44
45
|
});
|
|
45
46
|
entityManager.logger.debug('updated entity item range key', {
|
package/dist/index.d.ts
CHANGED
|
@@ -58,8 +58,8 @@ type Config<C extends BaseConfigMap = BaseConfigMap> = ConditionalProperty<'enti
|
|
|
58
58
|
defaultLimit?: number;
|
|
59
59
|
defaultPageSize?: number;
|
|
60
60
|
shardBumps?: ShardBump[];
|
|
61
|
-
timestampProperty: C['TranscodedProperties']
|
|
62
|
-
uniqueProperty: C['TranscodedProperties']
|
|
61
|
+
timestampProperty: Extract<Extract<C['TranscodedProperties'], PropertiesOfType<C['EntityMap'][E], number>>, TranscodableProperties<C['EntityMap'], C['TranscodeRegistry']>>;
|
|
62
|
+
uniqueProperty: Extract<Extract<C['TranscodedProperties'], keyof C['EntityMap'][E]>, TranscodableProperties<C['EntityMap'], C['TranscodeRegistry']>>;
|
|
63
63
|
};
|
|
64
64
|
}> & ConditionalProperty<'generatedProperties', C['ShardedKeys'] | C['UnshardedKeys'], ConditionalProperty<'sharded', C['ShardedKeys'], Record<C['ShardedKeys'], (C['TranscodedProperties'] & TranscodableProperties<C['EntityMap'], C['TranscodeRegistry']>)[]>> & ConditionalProperty<'unsharded', C['UnshardedKeys'], Record<C['UnshardedKeys'], (C['TranscodedProperties'] & TranscodableProperties<C['EntityMap'], C['TranscodeRegistry']>)[]>>> & ConditionalProperty<'propertyTranscodes', C['TranscodedProperties'] & TranscodableProperties<C['EntityMap'], C['TranscodeRegistry']>, {
|
|
65
65
|
[P in C['TranscodedProperties'] & TranscodableProperties<C['EntityMap'], C['TranscodeRegistry']>]: PropertiesOfType<C['TranscodeRegistry'], FlattenEntityMap<C['EntityMap']>[P]>;
|
|
@@ -119,44 +119,46 @@ type ConfigMap<M extends Partial<BaseConfigMap> = Partial<BaseConfigMap>> = Vali
|
|
|
119
119
|
}>;
|
|
120
120
|
|
|
121
121
|
/**
|
|
122
|
-
*
|
|
122
|
+
* Database-facing record key type from a {@link BaseConfigMap | `ConfigMap`} with required hash & range keys.
|
|
123
123
|
*
|
|
124
124
|
* @typeParam CC - {@link ConfigMap | `ConfigMap`} that defines an {@link Config | `EntityManager configuration`}'s {@link EntityMap | `EntityMap`}, key properties, and {@link TranscodeRegistry | `TranscodeRegistry`}. If omitted, defaults to {@link BaseConfigMap | `BaseConfigMap`}.
|
|
125
125
|
*
|
|
126
|
-
* @category
|
|
126
|
+
* @category EntityClient
|
|
127
127
|
* @protected
|
|
128
128
|
*/
|
|
129
|
-
type
|
|
129
|
+
type EntityKey<CC extends BaseConfigMap> = Record<CC['HashKey'] | CC['RangeKey'], string>;
|
|
130
130
|
|
|
131
131
|
/**
|
|
132
|
-
*
|
|
132
|
+
* Extracts entity tokens from a {@link ConfigMap | `ConfigMap`}.
|
|
133
133
|
*
|
|
134
134
|
* @typeParam CC - {@link ConfigMap | `ConfigMap`} that defines an {@link Config | `EntityManager configuration`}'s {@link EntityMap | `EntityMap`}, key properties, and {@link TranscodeRegistry | `TranscodeRegistry`}. If omitted, defaults to {@link BaseConfigMap | `BaseConfigMap`}.
|
|
135
135
|
*
|
|
136
|
-
* @category
|
|
136
|
+
* @category EntityManager
|
|
137
137
|
* @protected
|
|
138
138
|
*/
|
|
139
|
-
type
|
|
139
|
+
type EntityToken<CC extends BaseConfigMap> = Extract<keyof Exactify<CC['EntityMap']>, string>;
|
|
140
140
|
|
|
141
141
|
/**
|
|
142
|
-
*
|
|
142
|
+
* Storage-facing partial item type from a {@link BaseConfigMap | `ConfigMap`}.
|
|
143
|
+
*
|
|
144
|
+
* Token-agnostic shape used by encoding/decoding, key updates, and
|
|
145
|
+
* (de)hydration services.
|
|
143
146
|
*
|
|
144
147
|
* @typeParam CC - {@link ConfigMap | `ConfigMap`} that defines an {@link Config | `EntityManager configuration`}'s {@link EntityMap | `EntityMap`}, key properties, and {@link TranscodeRegistry | `TranscodeRegistry`}. If omitted, defaults to {@link BaseConfigMap | `BaseConfigMap`}.
|
|
145
148
|
*
|
|
146
149
|
* @category EntityManager
|
|
147
|
-
* @protected
|
|
148
150
|
*/
|
|
149
|
-
type
|
|
151
|
+
type StorageItem<CC extends BaseConfigMap> = Partial<FlattenEntityMap<CC['EntityMap']> & Record<CC['HashKey'] | CC['RangeKey'] | CC['ShardedKeys'] | CC['UnshardedKeys'], string>> & Record<string, unknown>;
|
|
150
152
|
|
|
151
153
|
/**
|
|
152
|
-
* A partial {@link
|
|
154
|
+
* A partial {@link StorageItem | `StorageItem`} restricted to keys defined in `C`.
|
|
153
155
|
*
|
|
154
156
|
* @typeParam CC - {@link ConfigMap | `ConfigMap`} that defines an {@link Config | `EntityManager configuration`}'s {@link EntityMap | `EntityMap`}, key properties, and {@link TranscodeRegistry | `TranscodeRegistry`}. If omitted, defaults to {@link BaseConfigMap | `BaseConfigMap`}.
|
|
155
157
|
*
|
|
156
158
|
* @category QueryBuilder
|
|
157
159
|
* @protected
|
|
158
160
|
*/
|
|
159
|
-
type PageKey<CC extends BaseConfigMap> = Pick<
|
|
161
|
+
type PageKey<CC extends BaseConfigMap> = Pick<StorageItem<CC>, CC['HashKey'] | CC['RangeKey'] | CC['ShardedKeys'] | CC['UnshardedKeys'] | CC['TranscodedProperties']>;
|
|
160
162
|
/**
|
|
161
163
|
* Internal helpers to safely derive index component tokens for an index IT.
|
|
162
164
|
*
|
|
@@ -182,11 +184,39 @@ type IndexRangeKeyOf<CF, IT extends string> = CF extends {
|
|
|
182
184
|
*/
|
|
183
185
|
type IndexTokensOf<CF> = CF extends {
|
|
184
186
|
indexes?: infer I;
|
|
185
|
-
} ? I extends Record<string, unknown> ? keyof I
|
|
187
|
+
} ? I extends Record<string, unknown> ? Extract<keyof I, string> : string : string;
|
|
186
188
|
type HasIndexFor<CF, IT extends string> = CF extends {
|
|
187
189
|
indexes?: infer I;
|
|
188
190
|
} ? I extends Record<string, unknown> ? IT extends keyof I ? true : false : false : false;
|
|
189
|
-
|
|
191
|
+
/**
|
|
192
|
+
* Base index component tokens shared by all indexes
|
|
193
|
+
* (the global hashKey and rangeKey defined in the Config).
|
|
194
|
+
*
|
|
195
|
+
* @category QueryBuilder
|
|
196
|
+
*/
|
|
197
|
+
type BaseKeyTokens<CC extends BaseConfigMap> = CC['HashKey'] | CC['RangeKey'];
|
|
198
|
+
/**
|
|
199
|
+
* Key set for index component tokens when CF/IT identify a concrete index.
|
|
200
|
+
* - Always includes base key tokens (global hash/range).
|
|
201
|
+
* - Conditionally includes index hashKey/rangeKey when they do not collapse
|
|
202
|
+
* to the base key union.
|
|
203
|
+
*
|
|
204
|
+
* @category QueryBuilder
|
|
205
|
+
*/
|
|
206
|
+
type PresentIndexTokenSet<CC extends BaseConfigMap, CF, IT extends string> = Record<BaseKeyTokens<CC>, true> & {
|
|
207
|
+
[K in IndexHashKeyOf<CF, IT> as K extends BaseKeyTokens<CC> ? never : K]: true;
|
|
208
|
+
} & {
|
|
209
|
+
[K in IndexRangeKeyOf<CF, IT> as K extends BaseKeyTokens<CC> ? never : K]: true;
|
|
210
|
+
};
|
|
211
|
+
/**
|
|
212
|
+
* Key set for index component tokens when CF does not carry an `indexes` map
|
|
213
|
+
* or IT is unknown. Includes global keys, generated keys, and transcodable
|
|
214
|
+
* properties.
|
|
215
|
+
*
|
|
216
|
+
* @category QueryBuilder
|
|
217
|
+
*/
|
|
218
|
+
type FallbackIndexTokenSet<CC extends BaseConfigMap> = Record<CC['HashKey'] | CC['RangeKey'] | CC['ShardedKeys'] | CC['UnshardedKeys'] | CC['TranscodedProperties'], true>;
|
|
219
|
+
type IndexComponentTokens<CC extends BaseConfigMap, CF, IT extends string> = HasIndexFor<CF, IT> extends true ? keyof PresentIndexTokenSet<CC, CF, IT> : keyof FallbackIndexTokenSet<CC>;
|
|
190
220
|
/**
|
|
191
221
|
* Page key typed for a specific index token.
|
|
192
222
|
*
|
|
@@ -194,7 +224,7 @@ type IndexComponentTokens<CC extends BaseConfigMap, CF, IT extends string> = Has
|
|
|
194
224
|
* shape narrows to exactly the component tokens of IT.
|
|
195
225
|
* - Without CF, falls back to the broad PageKey<CC> shape.
|
|
196
226
|
*/
|
|
197
|
-
type PageKeyByIndex<CC extends BaseConfigMap, ET extends EntityToken<CC>, IT extends string = string, CF = unknown> = Pick<
|
|
227
|
+
type PageKeyByIndex<CC extends BaseConfigMap, ET extends EntityToken<CC>, IT extends string = string, CF = unknown> = Pick<StorageItem<CC>, IndexComponentTokens<CC, CF, IT>>;
|
|
198
228
|
|
|
199
229
|
declare const configSchema: z$1.ZodObject<{
|
|
200
230
|
entities: z$1.ZodDefault<z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodObject<{
|
|
@@ -247,15 +277,11 @@ type ParsedConfig = z$1.infer<typeof configSchema>;
|
|
|
247
277
|
/** EntityOfToken — resolves the concrete entity shape for a specific entity token. */
|
|
248
278
|
type EntityOfToken<CC extends BaseConfigMap, ET extends EntityToken<CC>> = Exactify<CC['EntityMap']>[ET];
|
|
249
279
|
/**
|
|
250
|
-
*
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
* Note: If using createEntityManager with entitiesSchema, the schema must declare
|
|
254
|
-
* only base (non-generated) properties. Generated keys/tokens are layered by EntityManager.
|
|
280
|
+
* EntityItem — domain-facing item narrowed to a specific entity token, plus
|
|
281
|
+
* optional key/token properties. Required fields per captured entitiesSchema
|
|
282
|
+
* (when present); no string index signature.
|
|
255
283
|
*/
|
|
256
|
-
type
|
|
257
|
-
/** EntityRecordByToken — database-facing record (keys required) narrowed to a specific entity token. */
|
|
258
|
-
type EntityRecordByToken<CC extends BaseConfigMap, ET extends EntityToken<CC>> = EntityItemByToken<CC, ET> & EntityKey<CC>;
|
|
284
|
+
type EntityItem<CC extends BaseConfigMap, ET extends EntityToken<CC>> = EntityOfToken<CC, ET> & Partial<Record<CC['HashKey'] | CC['RangeKey'] | CC['ShardedKeys'] | CC['UnshardedKeys'], string>>;
|
|
259
285
|
/**
|
|
260
286
|
* Normalize literals: string | readonly string[] -\> union of strings.
|
|
261
287
|
*/
|
|
@@ -264,10 +290,15 @@ type KeysFrom<K> = K extends readonly (infer E)[] ? Extract<E, string> : K exten
|
|
|
264
290
|
* Project item shape by keys; if K is never/unknown, fall back to T.
|
|
265
291
|
*/
|
|
266
292
|
type Projected<T, K> = [KeysFrom<K>] extends [never] ? T : T extends object ? Pick<T, Extract<KeysFrom<K>, keyof Exactify<T>>> : T;
|
|
267
|
-
/**
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
293
|
+
/** EntityRecord — DB-facing record (keys required), narrowed to a specific entity token. */
|
|
294
|
+
type EntityRecord<CC extends BaseConfigMap, ET extends EntityToken<CC>> = Partial<EntityItem<CC, ET>> & EntityKey<CC>;
|
|
295
|
+
/** EntityItemPartial — projected/seed domain shape by token.
|
|
296
|
+
* - If K provided: required projected keys (`Projected<EntityItem<CC, ET>, K>`).
|
|
297
|
+
* - If K omitted: permissive seed (`Partial<EntityItem<CC, ET>>`).
|
|
298
|
+
*/
|
|
299
|
+
type EntityItemPartial<CC extends BaseConfigMap, ET extends EntityToken<CC>, K = unknown> = [KeysFrom<K>] extends [never] ? Partial<EntityItem<CC, ET>> : Projected<EntityItem<CC, ET>, K>;
|
|
300
|
+
/** EntityRecordPartial — projected DB record shape by token. */
|
|
301
|
+
type EntityRecordPartial<CC extends BaseConfigMap, ET extends EntityToken<CC>, K = unknown> = Projected<EntityRecord<CC, ET>, K>;
|
|
271
302
|
|
|
272
303
|
/**
|
|
273
304
|
* A result returned by a {@link ShardQueryFunction | `ShardQueryFunction`} querying an individual shard.
|
|
@@ -285,7 +316,7 @@ interface ShardQueryResult<CC extends BaseConfigMap, ET extends EntityToken<CC>,
|
|
|
285
316
|
/** The number of records returned. */
|
|
286
317
|
count: number;
|
|
287
318
|
/** The returned records. */
|
|
288
|
-
items:
|
|
319
|
+
items: EntityItemPartial<CC, ET, K>[];
|
|
289
320
|
/** The page key for the next query on this shard. */
|
|
290
321
|
pageKey?: PageKeyByIndex<CC, ET, IT, CF>;
|
|
291
322
|
}
|
|
@@ -310,7 +341,7 @@ interface ShardQueryResult<CC extends BaseConfigMap, ET extends EntityToken<CC>,
|
|
|
310
341
|
*/
|
|
311
342
|
type ShardQueryFunction<CC extends BaseConfigMap, ET extends EntityToken<CC>, IT extends string, CF = unknown, K = unknown> = CF extends {
|
|
312
343
|
indexes?: infer I;
|
|
313
|
-
} ? I extends Record<string, unknown> ? IT extends keyof I
|
|
344
|
+
} ? I extends Record<string, unknown> ? IT extends Extract<keyof I, string> ? (hashKey: string, pageKey?: PageKeyByIndex<CC, ET, IT, CF>, pageSize?: number) => Promise<ShardQueryResult<CC, ET, IT, CF, K>> : never : (hashKey: string, pageKey?: PageKeyByIndex<CC, ET, IT, CF>, pageSize?: number) => Promise<ShardQueryResult<CC, ET, IT, CF, K>> : (hashKey: string, pageKey?: PageKeyByIndex<CC, ET, IT, CF>, pageSize?: number) => Promise<ShardQueryResult<CC, ET, IT, CF, K>>;
|
|
314
345
|
|
|
315
346
|
/**
|
|
316
347
|
* Relates a specific index token to a {@link ShardQueryFunction | `ShardQueryFunction`} to be performed on that index.
|
|
@@ -330,7 +361,7 @@ type ShardQueryFunction<CC extends BaseConfigMap, ET extends EntityToken<CC>, IT
|
|
|
330
361
|
*/
|
|
331
362
|
type ShardQueryMap<CC extends BaseConfigMap, ET extends EntityToken<CC>, ITS extends string, CF = unknown, K = unknown> = CF extends {
|
|
332
363
|
indexes?: infer I;
|
|
333
|
-
} ? I extends Record<string, unknown> ? Record<ITS
|
|
364
|
+
} ? I extends Record<string, unknown> ? Record<Extract<ITS, Extract<keyof I, string>>, ShardQueryFunction<CC, ET, Extract<ITS, Extract<keyof I, string>>, CF, K>> : Record<ITS, ShardQueryFunction<CC, ET, ITS, CF, K>> : Record<ITS, ShardQueryFunction<CC, ET, ITS, CF, K>>;
|
|
334
365
|
/**
|
|
335
366
|
* Convenience alias for ShardQueryMap that derives ITS (index token subset)
|
|
336
367
|
* from a values-first captured config CC (e.g., your config literal type).
|
|
@@ -373,7 +404,7 @@ interface QueryOptions<CC extends BaseConfigMap, ET extends EntityToken<CC> = En
|
|
|
373
404
|
/**
|
|
374
405
|
* Partial item object sufficiently populated to generate index hash keys.
|
|
375
406
|
*/
|
|
376
|
-
item:
|
|
407
|
+
item: EntityItemPartial<CC, ET>;
|
|
377
408
|
/**
|
|
378
409
|
* The target maximum number of records to be returned by the query across
|
|
379
410
|
* all shards.
|
|
@@ -409,7 +440,7 @@ interface QueryOptions<CC extends BaseConfigMap, ET extends EntityToken<CC> = En
|
|
|
409
440
|
/**
|
|
410
441
|
* A {@link SortOrder | `SortOrder`} object specifying the sort order of the result set. Defaults to `[]`. Aligned with the projected item shape when K is provided.
|
|
411
442
|
*/
|
|
412
|
-
sortOrder?: SortOrder<
|
|
443
|
+
sortOrder?: SortOrder<EntityItemPartial<CC, ET, K>> | undefined;
|
|
413
444
|
/**
|
|
414
445
|
* Lower limit to query shard space.
|
|
415
446
|
*
|
|
@@ -476,7 +507,7 @@ interface QueryResult<CC extends BaseConfigMap, ET extends EntityToken<CC>, ITS
|
|
|
476
507
|
/** Total number of records returned across all shards. */
|
|
477
508
|
count: number;
|
|
478
509
|
/** The returned records. */
|
|
479
|
-
items:
|
|
510
|
+
items: EntityItemPartial<CC, ET, K>[];
|
|
480
511
|
/**
|
|
481
512
|
* A compressed, two-layer map of page keys, used to query the next page of
|
|
482
513
|
* data for a given sort key on each shard of a given hash key.
|
|
@@ -526,13 +557,13 @@ declare class EntityManager<CC extends BaseConfigMap, CF = unknown> {
|
|
|
526
557
|
* Encode a generated property value. Returns a string or undefined if atomicity requirement of sharded properties not met.
|
|
527
558
|
*
|
|
528
559
|
* @param property - {@link Config | Config} `generatedProperties` key.
|
|
529
|
-
* @param item - {@link
|
|
560
|
+
* @param item - {@link StorageItem | `StorageItem`} object.
|
|
530
561
|
*
|
|
531
562
|
* @returns Encoded generated property value.
|
|
532
563
|
*
|
|
533
564
|
* @throws `Error` if `property` is not a {@link Config | Config} `generatedProperties` key.
|
|
534
565
|
*/
|
|
535
|
-
encodeGeneratedProperty(property: CC['ShardedKeys'] | CC['UnshardedKeys'], item:
|
|
566
|
+
encodeGeneratedProperty(property: CC['ShardedKeys'] | CC['UnshardedKeys'], item: StorageItem<CC>): string | undefined;
|
|
536
567
|
/**
|
|
537
568
|
* Update generated properties, hash key, and range key on an {@link EntityItem | `EntityItem`} object.
|
|
538
569
|
*
|
|
@@ -546,28 +577,27 @@ declare class EntityManager<CC extends BaseConfigMap, CF = unknown> {
|
|
|
546
577
|
*
|
|
547
578
|
* @overload
|
|
548
579
|
*/
|
|
549
|
-
addKeys<ET extends EntityToken<CC>>(entityToken: ET, item:
|
|
580
|
+
addKeys<ET extends EntityToken<CC>>(entityToken: ET, item: EntityItemPartial<CC, ET>, overwrite?: boolean): EntityRecordPartial<CC, ET>;
|
|
550
581
|
/**
|
|
551
582
|
* @overload
|
|
552
583
|
*/
|
|
553
|
-
addKeys<ET extends EntityToken<CC>>(entityToken: ET, item:
|
|
584
|
+
addKeys<ET extends EntityToken<CC>>(entityToken: ET, item: EntityItemPartial<CC, ET>[], overwrite?: boolean): EntityRecordPartial<CC, ET>[];
|
|
554
585
|
/**
|
|
555
586
|
* Convert one or more {@link EntityItem | `EntityItem`} objects into an array of {@link EntityKey | `EntityKey`} values.
|
|
556
587
|
*
|
|
557
588
|
* @param entityToken - {@link Config | `Config`} `entities` key.
|
|
558
|
-
* @param item - {@link EntityItem | `EntityItem`} object
|
|
589
|
+
* @param item - {@link EntityItem | `EntityItem`} object.
|
|
559
590
|
* @param overwrite - Overwrite existing properties (default `false`).
|
|
560
591
|
*
|
|
561
|
-
* @returns
|
|
562
|
-
* For an array input, returns a single flattened array of keys across all inputs.
|
|
592
|
+
* @returns Array of {@link EntityKey | `EntityKey`} values derived from `item`.
|
|
563
593
|
*
|
|
564
594
|
* @throws `Error` if `entityToken` is invalid.
|
|
565
595
|
*/
|
|
566
|
-
getPrimaryKey<ET extends EntityToken<CC>>(entityToken: ET, item:
|
|
596
|
+
getPrimaryKey<ET extends EntityToken<CC>>(entityToken: ET, item: EntityItemPartial<CC, ET>, overwrite?: boolean): EntityKey<CC>[];
|
|
567
597
|
/**
|
|
568
598
|
* @overload
|
|
569
599
|
*/
|
|
570
|
-
getPrimaryKey<ET extends EntityToken<CC>>(entityToken: ET, items:
|
|
600
|
+
getPrimaryKey<ET extends EntityToken<CC>>(entityToken: ET, items: EntityItemPartial<CC, ET>[], overwrite?: boolean): EntityKey<CC>[];
|
|
571
601
|
/**
|
|
572
602
|
* Strips generated properties, hash key, and range key from an {@link EntityRecord | `EntityRecord`} object.
|
|
573
603
|
*
|
|
@@ -578,13 +608,12 @@ declare class EntityManager<CC extends BaseConfigMap, CF = unknown> {
|
|
|
578
608
|
*
|
|
579
609
|
* @throws `Error` if `entityToken` is invalid.
|
|
580
610
|
*
|
|
581
|
-
*
|
|
611
|
+
* Overloads:
|
|
582
612
|
*/
|
|
583
|
-
removeKeys<ET extends EntityToken<CC>>(entityToken: ET, item:
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
removeKeys<ET extends EntityToken<CC>>(entityToken: ET, items: EntityRecordByToken<CC, ET>[]): EntityItemByToken<CC, ET>[];
|
|
613
|
+
removeKeys<ET extends EntityToken<CC>>(entityToken: ET, item: EntityRecord<CC, ET>): EntityItem<CC, ET>;
|
|
614
|
+
removeKeys<ET extends EntityToken<CC>, K = unknown>(entityToken: ET, item: EntityRecordPartial<CC, ET, K>): EntityItemPartial<CC, ET, K>;
|
|
615
|
+
removeKeys<ET extends EntityToken<CC>>(entityToken: ET, items: EntityRecord<CC, ET>[]): EntityItem<CC, ET>[];
|
|
616
|
+
removeKeys<ET extends EntityToken<CC>, K = unknown>(entityToken: ET, items: EntityRecordPartial<CC, ET, K>[]): EntityItemPartial<CC, ET, K>[];
|
|
588
617
|
/**
|
|
589
618
|
* Find an index token based on the configured hash and range key tokens.
|
|
590
619
|
*
|
|
@@ -683,7 +712,7 @@ type TranscodedPropertiesFrom<CC> = CC extends {
|
|
|
683
712
|
type EntitiesFromSchema<CC> = CC extends {
|
|
684
713
|
entitiesSchema?: infer S;
|
|
685
714
|
} ? S extends Record<string, ZodType> ? {
|
|
686
|
-
[K in keyof S
|
|
715
|
+
[K in Extract<keyof S, string>]: z.infer<S[K]>;
|
|
687
716
|
} & EntityMap : EntityMap : EntityMap;
|
|
688
717
|
/**
|
|
689
718
|
* Derive the union of index token names from a values-first config input.
|
|
@@ -699,7 +728,7 @@ type IndexTokensFrom<CC> = CC extends {
|
|
|
699
728
|
* Captures a BaseConfigMap-compatible type from a literal ConfigInput value
|
|
700
729
|
* and an EntityMap (defaults to MinimalEntityMapFrom<CC>).
|
|
701
730
|
*/
|
|
702
|
-
|
|
731
|
+
interface CapturedConfigMapFrom<CC, EM extends EntityMap> extends BaseConfigMap {
|
|
703
732
|
EntityMap: EM;
|
|
704
733
|
HashKey: HashKeyFrom<CC>;
|
|
705
734
|
RangeKey: RangeKeyFrom<CC>;
|
|
@@ -707,7 +736,7 @@ type CapturedConfigMapFrom<CC, EM extends EntityMap> = {
|
|
|
707
736
|
UnshardedKeys: UnshardedKeysFrom<CC>;
|
|
708
737
|
TranscodedProperties: TranscodedPropertiesFrom<CC>;
|
|
709
738
|
TranscodeRegistry: DefaultTranscodeRegistry;
|
|
710
|
-
}
|
|
739
|
+
}
|
|
711
740
|
/**
|
|
712
741
|
* Values-first factory that captures literal tokens and index names directly
|
|
713
742
|
* from the provided config value. Runtime config parsing/validation is
|
|
@@ -725,14 +754,13 @@ type CapturedConfigMapFrom<CC, EM extends EntityMap> = {
|
|
|
725
754
|
declare function createEntityManager<const CC extends ConfigInput, EM extends EntityMap = EntitiesFromSchema<CC>>(config: CC, logger?: Pick<Console, 'debug' | 'error'>): EntityManager<CapturedConfigMapFrom<CC, EM>, CC>;
|
|
726
755
|
|
|
727
756
|
/**
|
|
728
|
-
*
|
|
757
|
+
* Storage-facing record type with required keys.
|
|
729
758
|
*
|
|
730
759
|
* @typeParam CC - {@link ConfigMap | `ConfigMap`} that defines an {@link Config | `EntityManager configuration`}'s {@link EntityMap | `EntityMap`}, key properties, and {@link TranscodeRegistry | `TranscodeRegistry`}. If omitted, defaults to {@link BaseConfigMap | `BaseConfigMap`}.
|
|
731
760
|
*
|
|
732
761
|
* @category EntityManager
|
|
733
|
-
* @protected
|
|
734
762
|
*/
|
|
735
|
-
type
|
|
763
|
+
type StorageRecord<CC extends BaseConfigMap> = StorageItem<CC> & EntityKey<CC>;
|
|
736
764
|
|
|
737
765
|
/**
|
|
738
766
|
* Base EntityClient options.
|
|
@@ -777,8 +805,8 @@ declare abstract class BaseEntityClient<CC extends BaseConfigMap, CF = unknown>
|
|
|
777
805
|
}
|
|
778
806
|
|
|
779
807
|
type ConfigOfClient<EC> = EC extends BaseEntityClient<infer CC> ? CC : never;
|
|
780
|
-
type EntityClientRecordByToken<EC, ET extends EntityToken<ConfigOfClient<EC>>> =
|
|
781
|
-
type EntityClientItemByToken<EC, ET extends EntityToken<ConfigOfClient<EC>>> =
|
|
808
|
+
type EntityClientRecordByToken<EC, ET extends EntityToken<ConfigOfClient<EC>>> = EntityRecord<ConfigOfClient<EC>, ET>;
|
|
809
|
+
type EntityClientItemByToken<EC, ET extends EntityToken<ConfigOfClient<EC>>> = EntityItem<ConfigOfClient<EC>, ET>;
|
|
782
810
|
|
|
783
811
|
/**
|
|
784
812
|
* Constructor options for {@link BaseQueryBuilder | `BaseQueryBuilder`}.
|
|
@@ -850,4 +878,4 @@ declare abstract class BaseQueryBuilder<CC extends BaseConfigMap, EntityClient e
|
|
|
850
878
|
}
|
|
851
879
|
|
|
852
880
|
export { BaseEntityClient, BaseQueryBuilder, EntityManager, configSchema, createEntityManager };
|
|
853
|
-
export type { BaseConfigMap, BaseEntityClientOptions, BaseQueryBuilderOptions, CapturedConfigMapFrom, Config, ConfigInput, ConfigMap, ConfigOfClient, EntitiesFromSchema, EntityClientItemByToken, EntityClientRecordByToken, EntityItem,
|
|
881
|
+
export type { BaseConfigMap, BaseEntityClientOptions, BaseKeyTokens, BaseQueryBuilderOptions, CapturedConfigMapFrom, Config, ConfigInput, ConfigMap, ConfigOfClient, EntitiesFromSchema, EntityClientItemByToken, EntityClientRecordByToken, EntityItem, EntityItemPartial, EntityKey, EntityOfToken, EntityRecord, EntityRecordPartial, EntityToken, FallbackIndexTokenSet, HasIndexFor, HashKeyFrom, IndexComponentTokens, IndexHashKeyOf, IndexRangeKeyOf, IndexTokensFrom, IndexTokensOf, KeysFrom, PageKey, PageKeyByIndex, ParsedConfig, PresentIndexTokenSet, Projected, QueryBuilderQueryOptions, QueryOptions, QueryOptionsByCC, QueryOptionsByCF, QueryResult, RangeKeyFrom, ShardBump, ShardQueryFunction, ShardQueryMap, ShardQueryMapByCC, ShardQueryMapByCF, ShardQueryResult, ShardedKeysFrom, StorageItem, StorageRecord, TranscodedPropertiesFrom, UnshardedKeysFrom, ValidateConfigMap };
|
|
@@ -62,7 +62,7 @@ class EntityManager {
|
|
|
62
62
|
* Encode a generated property value. Returns a string or undefined if atomicity requirement of sharded properties not met.
|
|
63
63
|
*
|
|
64
64
|
* @param property - {@link Config | Config} `generatedProperties` key.
|
|
65
|
-
* @param item - {@link
|
|
65
|
+
* @param item - {@link StorageItem | `StorageItem`} object.
|
|
66
66
|
*
|
|
67
67
|
* @returns Encoded generated property value.
|
|
68
68
|
*
|
|
@@ -85,9 +85,11 @@ class EntityManager {
|
|
|
85
85
|
}
|
|
86
86
|
removeKeys(entityToken, i) {
|
|
87
87
|
if (Array.isArray(i)) {
|
|
88
|
-
|
|
88
|
+
const out = i.map((item) => removeKeys(this, entityToken, item));
|
|
89
|
+
return out;
|
|
89
90
|
}
|
|
90
|
-
|
|
91
|
+
const out = removeKeys(this, entityToken, i);
|
|
92
|
+
return out;
|
|
91
93
|
}
|
|
92
94
|
findIndexToken(hashKeyToken, rangeKeyToken, suppressError) {
|
|
93
95
|
// Dispatch with a literal to satisfy overload selection.
|
|
@@ -118,7 +120,8 @@ class EntityManager {
|
|
|
118
120
|
* @protected
|
|
119
121
|
*/
|
|
120
122
|
async query(options) {
|
|
121
|
-
|
|
123
|
+
const result = await query(this, options);
|
|
124
|
+
return result;
|
|
122
125
|
}
|
|
123
126
|
}
|
|
124
127
|
_EntityManager_config = new WeakMap();
|
|
@@ -6,7 +6,7 @@ import { validateGeneratedProperty } from './validateGeneratedProperty.js';
|
|
|
6
6
|
*
|
|
7
7
|
* @param entityManager - {@link EntityManager | `EntityManager`} instance.
|
|
8
8
|
* @param property - {@link Config.generatedProperties | Generated property} key.
|
|
9
|
-
* @param item - {@link
|
|
9
|
+
* @param item - {@link StorageItem | `StorageItem`} object.
|
|
10
10
|
*
|
|
11
11
|
* @returns Encoded generated property value.
|
|
12
12
|
*
|
|
@@ -19,7 +19,10 @@ function encodeGeneratedProperty(entityManager, property, item) {
|
|
|
19
19
|
const sharded = property in entityManager.config.generatedProperties.sharded;
|
|
20
20
|
const elements = entityManager.config.generatedProperties[sharded ? 'sharded' : 'unsharded'][property];
|
|
21
21
|
// Map elements to [element, value] pairs.
|
|
22
|
-
const elementMap = elements.map((element) => [
|
|
22
|
+
const elementMap = elements.map((element) => [
|
|
23
|
+
element,
|
|
24
|
+
item[element],
|
|
25
|
+
]);
|
|
23
26
|
// Return undefined if sharded & atomicity requirement fails.
|
|
24
27
|
if (sharded && elementMap.some(([, value]) => isNil(value)))
|
|
25
28
|
return;
|
|
@@ -50,7 +50,7 @@ function getHashKeySpace(entityManager, entityToken, hashKeyToken, item, timesta
|
|
|
50
50
|
// Map shard keys to hash keys.
|
|
51
51
|
.map((shardKey) => {
|
|
52
52
|
// Calculate record hash key.
|
|
53
|
-
let hashKey = `${entityToken}${entityManager.config.shardKeyDelimiter}${shardKey}`;
|
|
53
|
+
let hashKey = `${String(entityToken)}${entityManager.config.shardKeyDelimiter}${shardKey}`;
|
|
54
54
|
// If hash key space basis is a different property, encode it.
|
|
55
55
|
if (hashKeyToken !== entityManager.config.hashKey)
|
|
56
56
|
hashKey = encodeGeneratedProperty(entityManager, hashKeyToken, {
|
|
@@ -25,11 +25,14 @@ import { updateItemRangeKey } from './updateItemRangeKey.js';
|
|
|
25
25
|
function getPrimaryKey(entityManager, entityToken, item, overwrite = false) {
|
|
26
26
|
const { hashKey, rangeKey } = entityManager.config;
|
|
27
27
|
// If both keys are present and we're not overwriting, return the exact pair.
|
|
28
|
-
|
|
28
|
+
const rec = item;
|
|
29
|
+
const hk = hashKey;
|
|
30
|
+
const rk = rangeKey;
|
|
31
|
+
if (!overwrite && rec[hk] && rec[rk]) {
|
|
29
32
|
return [
|
|
30
33
|
{
|
|
31
|
-
[hashKey]:
|
|
32
|
-
[rangeKey]:
|
|
34
|
+
[hashKey]: rec[hk],
|
|
35
|
+
[rangeKey]: rec[rk],
|
|
33
36
|
},
|
|
34
37
|
];
|
|
35
38
|
}
|
|
@@ -38,6 +41,7 @@ function getPrimaryKey(entityManager, entityToken, item, overwrite = false) {
|
|
|
38
41
|
// If timestamp present, compute exactly one hash key and return single pair.
|
|
39
42
|
const tsProp = entityManager.config.entities[entityToken].timestampProperty;
|
|
40
43
|
if (withRangeKey[tsProp] !== undefined) {
|
|
44
|
+
// Note: use StorageItem here
|
|
41
45
|
const withHashKey = updateItemHashKey(entityManager, entityToken, withRangeKey, true);
|
|
42
46
|
return [
|
|
43
47
|
{
|
|
@@ -49,12 +53,15 @@ function getPrimaryKey(entityManager, entityToken, item, overwrite = false) {
|
|
|
49
53
|
// No timestamp: enumerate hash-key space across all shard bumps (0..Infinity).
|
|
50
54
|
const hashKeys = getHashKeySpace(entityManager, entityToken, hashKey, withRangeKey, 0, Infinity);
|
|
51
55
|
// Map to keys and de-duplicate.
|
|
52
|
-
const
|
|
56
|
+
const rangeKeyValue = withRangeKey[rangeKey];
|
|
53
57
|
const seen = new Set();
|
|
54
58
|
const keys = hashKeys
|
|
55
59
|
.map((hk) => {
|
|
56
|
-
const key = {
|
|
57
|
-
|
|
60
|
+
const key = {
|
|
61
|
+
[hashKey]: hk,
|
|
62
|
+
[rangeKey]: rangeKeyValue,
|
|
63
|
+
};
|
|
64
|
+
const sig = `${hk}|${rangeKeyValue}`;
|
|
58
65
|
if (seen.has(sig))
|
|
59
66
|
return undefined;
|
|
60
67
|
seen.add(sig);
|
|
@@ -23,14 +23,21 @@ function removeKeys(entityManager, entityToken, item) {
|
|
|
23
23
|
...Object.keys(sharded),
|
|
24
24
|
...Object.keys(unsharded),
|
|
25
25
|
]);
|
|
26
|
-
// Create a shallow copy of item omitting the keys above (no delete operator)
|
|
27
|
-
|
|
26
|
+
// Create a shallow copy of item omitting the keys above (no delete operator),
|
|
27
|
+
// avoiding any-typed assignments.
|
|
28
|
+
const source = item;
|
|
29
|
+
const newItemObj = {};
|
|
30
|
+
for (const [key, value] of Object.entries(source)) {
|
|
31
|
+
if (!keysToStrip.has(key)) {
|
|
32
|
+
newItemObj[key] = value;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
28
35
|
entityManager.logger.debug('stripped entity item generated properties', {
|
|
29
36
|
entityToken,
|
|
30
37
|
item,
|
|
31
|
-
newItem,
|
|
38
|
+
newItem: newItemObj,
|
|
32
39
|
});
|
|
33
|
-
return
|
|
40
|
+
return newItemObj;
|
|
34
41
|
}
|
|
35
42
|
catch (error) {
|
|
36
43
|
if (error instanceof Error)
|
|
@@ -4,11 +4,11 @@ import { getShardBump } from './getShardBump.js';
|
|
|
4
4
|
import { validateEntityToken } from './validateEntityToken.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Update the hash key on an
|
|
7
|
+
* Update the hash key on an {@link EntityItemPartial | `EntityItemPartial`} object.
|
|
8
8
|
*
|
|
9
9
|
* @param entityManager - {@link EntityManager | `EntityManager`} instance.
|
|
10
10
|
* @param entityToken - {@link Config.entities | `this.config.entities`} key.
|
|
11
|
-
* @param item - {@link
|
|
11
|
+
* @param item - {@link StorageItem | `StorageItem`} object.
|
|
12
12
|
* @param overwrite - Overwrite existing {@link ConfigKeys.hashKey | `this.config.hashKey`} property value (default `false`).
|
|
13
13
|
*
|
|
14
14
|
* @returns Shallow clone of `item` with updated hash key.
|
|
@@ -30,13 +30,14 @@ function updateItemHashKey(entityManager, entityToken, item, overwrite = false)
|
|
|
30
30
|
return { ...item };
|
|
31
31
|
}
|
|
32
32
|
// Get item timestamp property & validate.
|
|
33
|
-
const
|
|
34
|
-
.timestampProperty
|
|
33
|
+
const tsProp = entityManager.config.entities[entityToken]
|
|
34
|
+
.timestampProperty;
|
|
35
|
+
const timestamp = item[tsProp];
|
|
35
36
|
if (isNil(timestamp))
|
|
36
37
|
throw new Error(`missing item timestamp property`);
|
|
37
38
|
// Find first entity sharding bump before timestamp.
|
|
38
39
|
const { charBits, chars } = getShardBump(entityManager, entityToken, timestamp);
|
|
39
|
-
let hashKey = `${entityToken}${entityManager.config.shardKeyDelimiter}`;
|
|
40
|
+
let hashKey = `${String(entityToken)}${entityManager.config.shardKeyDelimiter}`;
|
|
40
41
|
if (chars) {
|
|
41
42
|
// Radix is the numerical base of the shardKey.
|
|
42
43
|
const radix = 2 ** charBits;
|
|
@@ -44,8 +45,9 @@ function updateItemHashKey(entityManager, entityToken, item, overwrite = false)
|
|
|
44
45
|
// all placeholders are utilized (e.g., chars=2, charBits=2 => 16 combos).
|
|
45
46
|
const space = radix ** chars;
|
|
46
47
|
// Get item unique property & validate.
|
|
47
|
-
const
|
|
48
|
-
.uniqueProperty
|
|
48
|
+
const upProp = entityManager.config.entities[entityToken]
|
|
49
|
+
.uniqueProperty;
|
|
50
|
+
const uniqueId = item[upProp];
|
|
49
51
|
if (isNil(uniqueId))
|
|
50
52
|
throw new Error(`missing item unique property`);
|
|
51
53
|
hashKey += (stringHash(uniqueId) % space)
|
|
@@ -2,11 +2,11 @@ import { isNil } from '@karmaniverous/entity-tools';
|
|
|
2
2
|
import { validateEntityToken } from './validateEntityToken.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Update the range key on an {@link
|
|
5
|
+
* Update the range key on an {@link EntityItemPartial | `EntityItemPartial`} object.
|
|
6
6
|
*
|
|
7
7
|
* @param entityManager - {@link EntityManager | `EntityManager`} instance.
|
|
8
8
|
* @param entityToken - {@link Config.entities | `this.config.entities`} key.
|
|
9
|
-
* @param item - {@link
|
|
9
|
+
* @param item - {@link StorageItem | `StorageItem`} object.
|
|
10
10
|
* @param overwrite - Overwrite existing {@link ConfigKeys.rangeKey | `this.config.rangeKey`} property value (default `false`).
|
|
11
11
|
*
|
|
12
12
|
* @returns Shallow clone of `item` with updated range key.
|
|
@@ -19,8 +19,8 @@ function updateItemRangeKey(entityManager, entityToken, item, overwrite = false)
|
|
|
19
19
|
// Validate params.
|
|
20
20
|
validateEntityToken(entityManager, entityToken);
|
|
21
21
|
// Return current item if rangeKey exists and overwrite is false.
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
const rkProp = entityManager.config.rangeKey;
|
|
23
|
+
if (item[rkProp] && !overwrite) {
|
|
24
24
|
entityManager.logger.debug('did not overwrite existing entity item range key', {
|
|
25
25
|
entityToken,
|
|
26
26
|
item,
|
|
@@ -29,15 +29,16 @@ function updateItemRangeKey(entityManager, entityToken, item, overwrite = false)
|
|
|
29
29
|
return { ...item };
|
|
30
30
|
}
|
|
31
31
|
// Get item unique property & validate.
|
|
32
|
-
const
|
|
33
|
-
.uniqueProperty
|
|
34
|
-
|
|
32
|
+
const upProp = entityManager.config.entities[entityToken]
|
|
33
|
+
.uniqueProperty;
|
|
34
|
+
const uniqueValue = item[upProp];
|
|
35
|
+
if (isNil(uniqueValue))
|
|
35
36
|
throw new Error(`missing item unique property`);
|
|
36
37
|
// Update range key.
|
|
37
38
|
const newItem = Object.assign({ ...item }, {
|
|
38
39
|
[entityManager.config.rangeKey]: [
|
|
39
40
|
entityManager.config.entities[entityToken].uniqueProperty,
|
|
40
|
-
|
|
41
|
+
uniqueValue,
|
|
41
42
|
].join(entityManager.config.generatedValueDelimiter),
|
|
42
43
|
});
|
|
43
44
|
entityManager.logger.debug('updated entity item range key', {
|
package/package.json
CHANGED
|
@@ -11,12 +11,12 @@
|
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@karmaniverous/batch-process": "^0.1.0",
|
|
14
|
-
"@karmaniverous/entity-tools": "^0.
|
|
15
|
-
"@karmaniverous/string-utilities": "^0.2.
|
|
14
|
+
"@karmaniverous/entity-tools": "^0.8.0",
|
|
15
|
+
"@karmaniverous/string-utilities": "^0.2.2",
|
|
16
16
|
"lz-string": "^1.5.0",
|
|
17
17
|
"radash": "^12.1.1",
|
|
18
18
|
"string-hash": "^1.1.3",
|
|
19
|
-
"zod": "^4.1.
|
|
19
|
+
"zod": "^4.1.13"
|
|
20
20
|
},
|
|
21
21
|
"description": "Rational indexing & cross-shard querying at scale in your NoSQL database so you can focus on your application logic.",
|
|
22
22
|
"devDependencies": {
|
|
@@ -39,24 +39,24 @@
|
|
|
39
39
|
"eslint-plugin-prettier": "^5.5.4",
|
|
40
40
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
41
41
|
"eslint-plugin-tsdoc": "^0.5.0",
|
|
42
|
-
"knip": "^5.
|
|
42
|
+
"knip": "^5.70.2",
|
|
43
43
|
"lefthook": "^2.0.4",
|
|
44
|
-
"prettier": "^3.
|
|
44
|
+
"prettier": "^3.7.3",
|
|
45
45
|
"release-it": "^19.0.6",
|
|
46
|
-
"rimraf": "^6.1.
|
|
47
|
-
"rollup": "^4.53.
|
|
48
|
-
"rollup-plugin-dts": "^6.
|
|
46
|
+
"rimraf": "^6.1.2",
|
|
47
|
+
"rollup": "^4.53.3",
|
|
48
|
+
"rollup-plugin-dts": "^6.3.0",
|
|
49
49
|
"tsd": "^0.33.0",
|
|
50
50
|
"tslib": "^2.8.1",
|
|
51
|
-
"typedoc": "^0.28.
|
|
51
|
+
"typedoc": "^0.28.15",
|
|
52
52
|
"typedoc-plugin-mdn-links": "^5.0.10",
|
|
53
53
|
"typedoc-plugin-replace-text": "^4.2.0",
|
|
54
54
|
"typedoc-plugin-zod": "^1.4.3",
|
|
55
|
-
"@vitest/coverage-v8": "^4.0.
|
|
56
|
-
"@vitest/eslint-plugin": "^1.
|
|
57
|
-
"vitest": "^4.0.
|
|
55
|
+
"@vitest/coverage-v8": "^4.0.14",
|
|
56
|
+
"@vitest/eslint-plugin": "^1.5.1",
|
|
57
|
+
"vitest": "^4.0.14",
|
|
58
58
|
"typescript": "^5.9.3",
|
|
59
|
-
"typescript-eslint": "^8.
|
|
59
|
+
"typescript-eslint": "^8.48.0"
|
|
60
60
|
},
|
|
61
61
|
"exports": {
|
|
62
62
|
".": {
|
|
@@ -134,5 +134,5 @@
|
|
|
134
134
|
},
|
|
135
135
|
"type": "module",
|
|
136
136
|
"types": "dist/index.d.ts",
|
|
137
|
-
"version": "
|
|
137
|
+
"version": "8.0.0"
|
|
138
138
|
}
|