@karmaniverous/entity-manager 6.7.5 → 6.8.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/dist/cjs/BaseEntityClient.js +1 -1
- package/dist/cjs/BaseQueryBuilder.js +1 -1
- package/dist/cjs/EntityManager.js +8 -8
- package/dist/cjs/ParsedConfig.js +143 -113
- package/dist/cjs/addKeys.js +6 -6
- package/dist/{mjs/decodeEntityElement.js → cjs/decodeElement.js} +10 -12
- package/dist/cjs/decodeGeneratedProperty.js +6 -10
- package/dist/cjs/dehydrateIndexItem.js +12 -11
- package/dist/cjs/dehydratePageKeyMap.js +10 -7
- package/dist/{mjs/encodeEntityElement.js → cjs/encodeElement.js} +8 -10
- package/dist/cjs/encodeGeneratedProperty.js +13 -14
- package/dist/cjs/getHashKeySpace.js +6 -6
- package/dist/cjs/getIndexComponents.js +6 -8
- package/dist/cjs/getShardBump.js +1 -1
- package/dist/cjs/query.js +1 -1
- package/dist/cjs/rehydrateIndexItem.js +12 -10
- package/dist/cjs/rehydratePageKeyMap.js +18 -11
- package/dist/cjs/removeKeys.js +3 -2
- package/dist/cjs/unwrapIndex.js +25 -11
- package/dist/cjs/updateItemHashKey.js +5 -3
- package/dist/cjs/updateItemRangeKey.js +6 -4
- package/dist/cjs/validateGeneratedProperty.js +23 -0
- package/dist/cjs/validateIndexToken.js +16 -0
- package/dist/cjs/validateTranscodedProperty.js +16 -0
- package/dist/index.d.ts +176 -529
- package/dist/mjs/BaseEntityClient.js +1 -1
- package/dist/mjs/BaseQueryBuilder.js +1 -1
- package/dist/mjs/EntityManager.js +8 -8
- package/dist/mjs/ParsedConfig.js +143 -113
- package/dist/mjs/addKeys.js +6 -6
- package/dist/{cjs/decodeEntityElement.js → mjs/decodeElement.js} +8 -14
- package/dist/mjs/decodeGeneratedProperty.js +6 -10
- package/dist/mjs/dehydrateIndexItem.js +12 -11
- package/dist/mjs/dehydratePageKeyMap.js +10 -7
- package/dist/{cjs/encodeEntityElement.js → mjs/encodeElement.js} +7 -13
- package/dist/mjs/encodeGeneratedProperty.js +13 -14
- package/dist/mjs/getHashKeySpace.js +6 -6
- package/dist/mjs/getIndexComponents.js +6 -8
- package/dist/mjs/getShardBump.js +1 -1
- package/dist/mjs/query.js +1 -1
- package/dist/mjs/rehydrateIndexItem.js +12 -10
- package/dist/mjs/rehydratePageKeyMap.js +18 -11
- package/dist/mjs/removeKeys.js +3 -2
- package/dist/mjs/unwrapIndex.js +26 -12
- package/dist/mjs/updateItemHashKey.js +5 -3
- package/dist/mjs/updateItemRangeKey.js +6 -4
- package/dist/mjs/validateGeneratedProperty.js +21 -0
- package/dist/mjs/validateIndexToken.js +14 -0
- package/dist/mjs/validateTranscodedProperty.js +14 -0
- package/package.json +5 -5
- package/dist/cjs/validateEntityGeneratedProperty.js +0 -29
- package/dist/cjs/validateEntityIndexToken.js +0 -22
- package/dist/mjs/validateEntityGeneratedProperty.js +0 -27
- package/dist/mjs/validateEntityIndexToken.js +0 -20
|
@@ -9,7 +9,7 @@ class BaseEntityClient {
|
|
|
9
9
|
/**
|
|
10
10
|
* DynamoDB EntityClient constructor.
|
|
11
11
|
*
|
|
12
|
-
* @param options - {@link
|
|
12
|
+
* @param options - {@link BaseEntityClientOptions | `BaseEntityClientOptions`} object.
|
|
13
13
|
*/
|
|
14
14
|
constructor(options) {
|
|
15
15
|
const { batchProcessOptions = {}, logger = console } = options;
|
|
@@ -5,7 +5,7 @@ var radash = require('radash');
|
|
|
5
5
|
/**
|
|
6
6
|
* Abstract base class supporting a fluent API for building a {@link ShardQueryMap | `ShardQueryMap`} using a database client.
|
|
7
7
|
*
|
|
8
|
-
* @category
|
|
8
|
+
* @category QueryBuilder
|
|
9
9
|
*/
|
|
10
10
|
class BaseQueryBuilder {
|
|
11
11
|
/** BaseQueryBuilder constructor. */
|
|
@@ -42,10 +42,10 @@ class EntityManager {
|
|
|
42
42
|
tslib.__classPrivateFieldSet(this, _EntityManager_config, ParsedConfig.configSchema.parse(value), "f");
|
|
43
43
|
}
|
|
44
44
|
/**
|
|
45
|
-
* Update generated properties, hash key, and range key on an {@link
|
|
45
|
+
* Update generated properties, hash key, and range key on an {@link EntityItem | `EntityItem`} object.
|
|
46
46
|
*
|
|
47
|
-
* @param entityToken - {@link
|
|
48
|
-
* @param item - {@link
|
|
47
|
+
* @param entityToken - {@link Config | `Config`} `entities` key.
|
|
48
|
+
* @param item - {@link EntityItem | `EntityItem`} object.
|
|
49
49
|
* @param overwrite - Overwrite existing properties (default `false`).
|
|
50
50
|
*
|
|
51
51
|
* @returns Shallow clone of `item` with updated properties.
|
|
@@ -56,10 +56,10 @@ class EntityManager {
|
|
|
56
56
|
return addKeys.addKeys(this, entityToken, item, overwrite);
|
|
57
57
|
}
|
|
58
58
|
/**
|
|
59
|
-
* Strips generated properties, hash key, and range key from an {@link
|
|
59
|
+
* Strips generated properties, hash key, and range key from an {@link EntityItem | `EntityItem`} object.
|
|
60
60
|
*
|
|
61
|
-
* @param entityToken - {@link
|
|
62
|
-
* @param item - {@link
|
|
61
|
+
* @param entityToken - {@link Config | `Config`} `entities` key.
|
|
62
|
+
* @param item - {@link EntityItem | `EntityItem`} object.
|
|
63
63
|
*
|
|
64
64
|
* @returns Shallow clone of `item` without generated properties, hash key or range key.
|
|
65
65
|
*
|
|
@@ -74,7 +74,7 @@ class EntityManager {
|
|
|
74
74
|
* @remarks
|
|
75
75
|
* The provided `shardQueryMap` performs the actual query of individual data pages on individual index/shard combinations.
|
|
76
76
|
*
|
|
77
|
-
* Individual shard query results will be combined, deduped by {@link
|
|
77
|
+
* Individual shard query results will be combined, deduped by {@link Config | `Config`} `uniqueProperty` value, and sorted by {@link QueryOptions.sortOrder | `sortOrder`}.
|
|
78
78
|
*
|
|
79
79
|
* In queries on sharded data, expect the leading and trailing edges of returned data pages to interleave somewhat with preceding & following pages.
|
|
80
80
|
*
|
|
@@ -84,7 +84,7 @@ class EntityManager {
|
|
|
84
84
|
*
|
|
85
85
|
* @returns {@link QueryResult} object.
|
|
86
86
|
*
|
|
87
|
-
* @throws Error if {@link QueryOptions.
|
|
87
|
+
* @throws Error if `options` {@link QueryOptions.pageKeyMap | `pageKeyMap`} `pageKeyMap` keys do not match {@link QueryOptions.shardQueryMap | `shardQueryMap`} keys.
|
|
88
88
|
*/
|
|
89
89
|
async query(options) {
|
|
90
90
|
return await query.query(this, options);
|
package/dist/cjs/ParsedConfig.js
CHANGED
|
@@ -11,16 +11,18 @@ const validateArrayUnique = (arr, ctx, identity = (item) => item, path = []) =>
|
|
|
11
11
|
if (count > 1)
|
|
12
12
|
ctx.addIssue({
|
|
13
13
|
code: zod.z.ZodIssueCode.custom,
|
|
14
|
-
message: `duplicate array element
|
|
14
|
+
message: `duplicate array element`,
|
|
15
|
+
params: { element },
|
|
15
16
|
path,
|
|
16
17
|
});
|
|
17
18
|
}
|
|
18
19
|
};
|
|
19
|
-
const
|
|
20
|
-
|
|
20
|
+
const validateKeysExclusive = (keys, label, ref, ctx) => {
|
|
21
|
+
const intersection = keys.filter((key) => ref.includes(key));
|
|
22
|
+
if (intersection.length)
|
|
21
23
|
ctx.addIssue({
|
|
22
24
|
code: zod.z.ZodIssueCode.custom,
|
|
23
|
-
message: `${label}
|
|
25
|
+
message: `${label} key collision: ${intersection.toString()}`,
|
|
24
26
|
});
|
|
25
27
|
};
|
|
26
28
|
const componentArray = zod.z
|
|
@@ -46,25 +48,6 @@ const configSchema = zod.z
|
|
|
46
48
|
.safe()
|
|
47
49
|
.optional()
|
|
48
50
|
.default(10),
|
|
49
|
-
generated: zod.z
|
|
50
|
-
.record(zod.z
|
|
51
|
-
.object({
|
|
52
|
-
atomic: zod.z.boolean().optional().default(false),
|
|
53
|
-
elements: componentArray,
|
|
54
|
-
sharded: zod.z.boolean().optional().default(false),
|
|
55
|
-
})
|
|
56
|
-
.optional())
|
|
57
|
-
.optional()
|
|
58
|
-
.default({}),
|
|
59
|
-
elementTranscodes: zod.z.record(zod.z.string()).optional().default({}),
|
|
60
|
-
indexes: zod.z
|
|
61
|
-
.record(zod.z.object({
|
|
62
|
-
hashKey: zod.z.string().min(1),
|
|
63
|
-
rangeKey: zod.z.string().min(1),
|
|
64
|
-
projections: componentArray.optional(),
|
|
65
|
-
}))
|
|
66
|
-
.optional()
|
|
67
|
-
.default({}),
|
|
68
51
|
shardBumps: zod.z
|
|
69
52
|
.array(zod.z
|
|
70
53
|
.object({
|
|
@@ -105,21 +88,30 @@ const configSchema = zod.z
|
|
|
105
88
|
timestampProperty: zod.z.string().min(1),
|
|
106
89
|
uniqueProperty: zod.z.string().min(1),
|
|
107
90
|
})
|
|
108
|
-
.strict()
|
|
109
|
-
.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
91
|
+
.strict())
|
|
92
|
+
.optional()
|
|
93
|
+
.default({}),
|
|
94
|
+
generatedProperties: zod.z
|
|
95
|
+
.object({
|
|
96
|
+
sharded: zod.z.record(componentArray).optional().default({}),
|
|
97
|
+
unsharded: zod.z.record(componentArray).optional().default({}),
|
|
98
|
+
})
|
|
99
|
+
.optional()
|
|
100
|
+
.default({ sharded: {}, unsharded: {} }),
|
|
101
|
+
hashKey: zod.z.string(),
|
|
102
|
+
indexes: zod.z
|
|
103
|
+
.record(zod.z.object({
|
|
104
|
+
hashKey: zod.z.string().min(1),
|
|
105
|
+
rangeKey: zod.z.string().min(1),
|
|
106
|
+
projections: componentArray.optional(),
|
|
115
107
|
}))
|
|
116
108
|
.optional()
|
|
117
109
|
.default({}),
|
|
118
110
|
generatedKeyDelimiter: zod.z.string().regex(/\W+/).optional().default('|'),
|
|
119
111
|
generatedValueDelimiter: zod.z.string().regex(/\W+/).optional().default('#'),
|
|
112
|
+
propertyTranscodes: zod.z.record(zod.z.string()).optional().default({}),
|
|
113
|
+
rangeKey: zod.z.string(),
|
|
120
114
|
shardKeyDelimiter: zod.z.string().regex(/\W+/).optional().default('!'),
|
|
121
|
-
hashKey: zod.z.string().optional().default('hashKey'),
|
|
122
|
-
rangeKey: zod.z.string().optional().default('rangeKey'),
|
|
123
115
|
throttle: zod.z.number().int().positive().safe().optional().default(10),
|
|
124
116
|
transcodes: zod.z
|
|
125
117
|
.record(zod.z
|
|
@@ -138,12 +130,20 @@ const configSchema = zod.z
|
|
|
138
130
|
ctx.addIssue({
|
|
139
131
|
code: zod.z.ZodIssueCode.custom,
|
|
140
132
|
message: 'generatedKeyDelimiter contains generatedValueDelimiter',
|
|
133
|
+
params: {
|
|
134
|
+
generatedKeyDelimiter: data.generatedKeyDelimiter,
|
|
135
|
+
generatedValueDelimiter: data.generatedValueDelimiter,
|
|
136
|
+
},
|
|
141
137
|
path: ['generatedKeyDelimiter'],
|
|
142
138
|
});
|
|
143
139
|
if (data.generatedKeyDelimiter.includes(data.shardKeyDelimiter))
|
|
144
140
|
ctx.addIssue({
|
|
145
141
|
code: zod.z.ZodIssueCode.custom,
|
|
146
142
|
message: 'generatedKeyDelimiter contains shardKeyDelimiter',
|
|
143
|
+
params: {
|
|
144
|
+
generatedKeyDelimiter: data.generatedKeyDelimiter,
|
|
145
|
+
shardKeyDelimiter: data.shardKeyDelimiter,
|
|
146
|
+
},
|
|
147
147
|
path: ['generatedKeyDelimiter'],
|
|
148
148
|
});
|
|
149
149
|
// validate no generated value delimiter collision
|
|
@@ -151,12 +151,20 @@ const configSchema = zod.z
|
|
|
151
151
|
ctx.addIssue({
|
|
152
152
|
code: zod.z.ZodIssueCode.custom,
|
|
153
153
|
message: 'generatedValueDelimiter contains generatedKeyDelimiter',
|
|
154
|
+
params: {
|
|
155
|
+
generatedValueDelimiter: data.generatedValueDelimiter,
|
|
156
|
+
generatedKeyDelimiter: data.generatedKeyDelimiter,
|
|
157
|
+
},
|
|
154
158
|
path: ['generatedValueDelimiter'],
|
|
155
159
|
});
|
|
156
160
|
if (data.generatedValueDelimiter.includes(data.shardKeyDelimiter))
|
|
157
161
|
ctx.addIssue({
|
|
158
162
|
code: zod.z.ZodIssueCode.custom,
|
|
159
163
|
message: 'generatedValueDelimiter contains shardKeyDelimiter',
|
|
164
|
+
params: {
|
|
165
|
+
generatedValueDelimiter: data.generatedValueDelimiter,
|
|
166
|
+
shardKeyDelimiter: data.shardKeyDelimiter,
|
|
167
|
+
},
|
|
160
168
|
path: ['generatedValueDelimiter'],
|
|
161
169
|
});
|
|
162
170
|
// validate no shard key delimiter collision
|
|
@@ -164,103 +172,125 @@ const configSchema = zod.z
|
|
|
164
172
|
ctx.addIssue({
|
|
165
173
|
code: zod.z.ZodIssueCode.custom,
|
|
166
174
|
message: 'shardKeyDelimiter contains generatedKeyDelimiter',
|
|
175
|
+
params: {
|
|
176
|
+
generatedKeyDelimiter: data.generatedKeyDelimiter,
|
|
177
|
+
shardKeyDelimiter: data.shardKeyDelimiter,
|
|
178
|
+
},
|
|
167
179
|
path: ['shardKeyDelimiter'],
|
|
168
180
|
});
|
|
169
181
|
if (data.shardKeyDelimiter.includes(data.generatedValueDelimiter))
|
|
170
182
|
ctx.addIssue({
|
|
171
183
|
code: zod.z.ZodIssueCode.custom,
|
|
172
184
|
message: 'shardKeyDelimiter contains generatedValueDelimiter',
|
|
185
|
+
params: {
|
|
186
|
+
generatedValueDelimiter: data.generatedValueDelimiter,
|
|
187
|
+
shardKeyDelimiter: data.shardKeyDelimiter,
|
|
188
|
+
},
|
|
173
189
|
path: ['shardKeyDelimiter'],
|
|
174
190
|
});
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
]
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
191
|
+
// get reserved keys
|
|
192
|
+
const shardedKeys = Object.keys(data.generatedProperties.sharded);
|
|
193
|
+
const unshardedKeys = Object.keys(data.generatedProperties.unsharded);
|
|
194
|
+
const transcodedProperties = Object.keys(data.propertyTranscodes);
|
|
195
|
+
// validate hashKey exclusive.
|
|
196
|
+
validateKeysExclusive([data.hashKey], 'hashKey', [
|
|
197
|
+
data.rangeKey,
|
|
198
|
+
...shardedKeys,
|
|
199
|
+
...unshardedKeys,
|
|
200
|
+
...transcodedProperties,
|
|
201
|
+
], ctx);
|
|
202
|
+
// validate rangeKey exclusive.
|
|
203
|
+
validateKeysExclusive([data.rangeKey], 'rangeKey', [...shardedKeys, ...unshardedKeys, ...transcodedProperties], ctx);
|
|
204
|
+
// validate shardedKeys exclusive.
|
|
205
|
+
validateKeysExclusive(shardedKeys, 'shardedKeys', [...unshardedKeys, ...transcodedProperties], ctx);
|
|
206
|
+
// validate unshardedKeys exclusive.
|
|
207
|
+
validateKeysExclusive(unshardedKeys, 'unshardedKeys', transcodedProperties, ctx);
|
|
208
|
+
// validate all propertyTranscode values are transcode keys.
|
|
186
209
|
const transcodes = Object.keys(data.transcodes);
|
|
187
|
-
for (const [
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
210
|
+
for (const [property, transcode] of Object.entries(data.propertyTranscodes))
|
|
211
|
+
if (!transcodes.includes(transcode))
|
|
212
|
+
ctx.addIssue({
|
|
213
|
+
code: zod.z.ZodIssueCode.invalid_enum_value,
|
|
214
|
+
options: transcodes,
|
|
215
|
+
path: ['propertyTranscodes', property],
|
|
216
|
+
received: transcode,
|
|
217
|
+
});
|
|
218
|
+
// Validate all sharded property elements are transcoded properties.
|
|
219
|
+
for (const [property, elements] of Object.entries(data.generatedProperties.sharded))
|
|
220
|
+
for (const element of elements)
|
|
221
|
+
if (!transcodedProperties.includes(element))
|
|
191
222
|
ctx.addIssue({
|
|
192
223
|
code: zod.z.ZodIssueCode.invalid_enum_value,
|
|
193
|
-
options:
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
});
|
|
197
|
-
// validate all entity generated property elements have a corresponding entity element type.
|
|
198
|
-
const typedElements = Object.keys(entity.elementTranscodes);
|
|
199
|
-
for (const [generatedKey, generated] of Object.entries(entity.generated))
|
|
200
|
-
for (const element of generated?.elements ?? [])
|
|
201
|
-
if (!typedElements.includes(element))
|
|
202
|
-
ctx.addIssue({
|
|
203
|
-
code: zod.z.ZodIssueCode.invalid_enum_value,
|
|
204
|
-
options: typedElements,
|
|
205
|
-
path: [
|
|
206
|
-
'entities',
|
|
207
|
-
entityToken,
|
|
208
|
-
'generated',
|
|
209
|
-
generatedKey,
|
|
210
|
-
'elements',
|
|
211
|
-
],
|
|
212
|
-
received: element,
|
|
213
|
-
});
|
|
214
|
-
// validate indexes.
|
|
215
|
-
const generatedProperties = Object.keys(entity.generated);
|
|
216
|
-
for (const [indexKey, { hashKey, rangeKey, projections },] of Object.entries(entity.indexes)) {
|
|
217
|
-
// validate index hash key is sharded
|
|
218
|
-
if (hashKey !== data.hashKey && !entity.generated[hashKey]?.sharded)
|
|
219
|
-
ctx.addIssue({
|
|
220
|
-
code: zod.z.ZodIssueCode.custom,
|
|
221
|
-
message: 'index hash key is not sharded',
|
|
222
|
-
path: ['entities', entityToken, 'indexes', indexKey, 'hashKey'],
|
|
224
|
+
options: transcodedProperties,
|
|
225
|
+
received: element,
|
|
226
|
+
path: ['generatedProperties', 'sharded', property],
|
|
223
227
|
});
|
|
224
|
-
|
|
225
|
-
|
|
228
|
+
// Validate all unsharded property elements are transcoded properties.
|
|
229
|
+
for (const [property, elements] of Object.entries(data.generatedProperties.unsharded))
|
|
230
|
+
for (const element of elements)
|
|
231
|
+
if (!transcodedProperties.includes(element))
|
|
226
232
|
ctx.addIssue({
|
|
227
|
-
code: zod.z.ZodIssueCode.
|
|
228
|
-
|
|
229
|
-
|
|
233
|
+
code: zod.z.ZodIssueCode.invalid_enum_value,
|
|
234
|
+
options: transcodedProperties,
|
|
235
|
+
received: element,
|
|
236
|
+
path: ['generatedProperties', 'unsharded', property],
|
|
230
237
|
});
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
238
|
+
// Validate indexes.
|
|
239
|
+
for (const [indexKey, { hashKey, rangeKey, projections }] of Object.entries(data.indexes)) {
|
|
240
|
+
// Validate hash key is sharded.
|
|
241
|
+
if (![data.hashKey, ...shardedKeys].includes(hashKey)) {
|
|
242
|
+
ctx.addIssue({
|
|
243
|
+
code: zod.z.ZodIssueCode.invalid_enum_value,
|
|
244
|
+
options: [data.hashKey, ...shardedKeys],
|
|
245
|
+
path: ['indexes', indexKey, 'hashKey'],
|
|
246
|
+
received: hashKey,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
// Validate range key is unsharded or transcodable.
|
|
250
|
+
if (![data.rangeKey, ...unshardedKeys, ...transcodedProperties].includes(rangeKey)) {
|
|
251
|
+
ctx.addIssue({
|
|
252
|
+
code: zod.z.ZodIssueCode.invalid_enum_value,
|
|
253
|
+
options: [data.rangeKey, ...unshardedKeys],
|
|
254
|
+
path: ['indexes', indexKey, 'rangeKey'],
|
|
255
|
+
received: rangeKey,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
// Validate no index projections are keys.
|
|
259
|
+
if (projections)
|
|
260
|
+
for (const projection of projections)
|
|
261
|
+
if ([
|
|
262
|
+
data.hashKey,
|
|
263
|
+
data.rangeKey,
|
|
264
|
+
hashKey,
|
|
265
|
+
rangeKey,
|
|
266
|
+
...shardedKeys,
|
|
267
|
+
...unshardedKeys,
|
|
268
|
+
].includes(projection))
|
|
235
269
|
ctx.addIssue({
|
|
236
|
-
code: zod.z.ZodIssueCode.
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
entityToken,
|
|
241
|
-
'indexes',
|
|
242
|
-
indexKey,
|
|
243
|
-
'components',
|
|
244
|
-
],
|
|
245
|
-
received: component,
|
|
270
|
+
code: zod.z.ZodIssueCode.custom,
|
|
271
|
+
message: 'index projection is a key',
|
|
272
|
+
params: { projection },
|
|
273
|
+
path: ['indexes', indexKey, 'projections'],
|
|
246
274
|
});
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
275
|
+
}
|
|
276
|
+
// validate entities
|
|
277
|
+
for (const [entityToken, { timestampProperty, uniqueProperty },] of Object.entries(data.entities)) {
|
|
278
|
+
// validate timestampProperty is a transcoded property.
|
|
279
|
+
if (!transcodedProperties.includes(timestampProperty))
|
|
280
|
+
ctx.addIssue({
|
|
281
|
+
code: zod.z.ZodIssueCode.invalid_enum_value,
|
|
282
|
+
options: transcodedProperties,
|
|
283
|
+
path: ['entities', entityToken, 'timestampProperty'],
|
|
284
|
+
received: timestampProperty,
|
|
285
|
+
});
|
|
286
|
+
// validate uniqueProperty is a transcoded property.
|
|
287
|
+
if (!transcodedProperties.includes(uniqueProperty))
|
|
288
|
+
ctx.addIssue({
|
|
289
|
+
code: zod.z.ZodIssueCode.invalid_enum_value,
|
|
290
|
+
options: transcodedProperties,
|
|
291
|
+
path: ['entities', entityToken, 'uniqueProperty'],
|
|
292
|
+
received: uniqueProperty,
|
|
293
|
+
});
|
|
264
294
|
}
|
|
265
295
|
});
|
|
266
296
|
|
package/dist/cjs/addKeys.js
CHANGED
|
@@ -7,11 +7,11 @@ var updateItemRangeKey = require('./updateItemRangeKey.js');
|
|
|
7
7
|
var validateEntityToken = require('./validateEntityToken.js');
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Update generated properties, hash key, and range key on an {@link
|
|
10
|
+
* Update generated properties, hash key, and range key on an {@link EntityItem | `EntityItem`} object.
|
|
11
11
|
*
|
|
12
12
|
* @param entityManager - {@link EntityManager | `EntityManager`} instance.
|
|
13
|
-
* @param entityToken - {@link
|
|
14
|
-
* @param item - {@link
|
|
13
|
+
* @param entityToken - {@link ConfigEntity.uniqueProperty | `this.config.entities`} key.
|
|
14
|
+
* @param item - {@link EntityItem | `EntityItem`} object.
|
|
15
15
|
* @param overwrite - Overwrite existing properties (default `false`).
|
|
16
16
|
*
|
|
17
17
|
* @returns Shallow clone of `item` with updated properties.
|
|
@@ -27,10 +27,10 @@ function addKeys(entityManager, entityToken, item, overwrite = false) {
|
|
|
27
27
|
// Update range key.
|
|
28
28
|
newItem = updateItemRangeKey.updateItemRangeKey(entityManager, entityToken, newItem, overwrite);
|
|
29
29
|
// Update generated properties.
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
const { sharded, unsharded } = entityManager.config.generatedProperties;
|
|
31
|
+
for (const property in { ...sharded, ...unsharded }) {
|
|
32
32
|
if (overwrite || entityTools.isNil(item[property])) {
|
|
33
|
-
const encoded = encodeGeneratedProperty.encodeGeneratedProperty(entityManager,
|
|
33
|
+
const encoded = encodeGeneratedProperty.encodeGeneratedProperty(entityManager, property, newItem);
|
|
34
34
|
if (encoded)
|
|
35
35
|
Object.assign(newItem, { [property]: encoded });
|
|
36
36
|
else
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var validateTranscodedProperty = require('./validateTranscodedProperty.js');
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
|
-
* Decode an {@link
|
|
6
|
+
* Decode an {@link EntityItem | `EntityItem`} generated property element or ungenerated index component using the associated {@link Transcodes | Transcodes} `encode` function.
|
|
5
7
|
*
|
|
6
8
|
* Returns all `undefined` values.
|
|
7
9
|
*
|
|
8
10
|
* If `element` is the {@link Config.hashKey | `hashKey`} or {@link Config.rangeKey | `rangeKey`}, returns the value as-is.
|
|
9
11
|
*
|
|
10
12
|
* @param entityManager - {@link EntityManager | `EntityManager`} instance.
|
|
11
|
-
* @param entityToken - {@link ConfigKeys.entities | `entityManager.config.entities`} key.
|
|
12
13
|
* @param element - The {@link Entity | `Entity`} generated property element or ungenerated index component to encode.
|
|
13
14
|
* @param value - Encoded entity element.
|
|
14
15
|
*
|
|
@@ -16,17 +17,15 @@ import { validateEntityToken } from './validateEntityToken.js';
|
|
|
16
17
|
*
|
|
17
18
|
* @throws `Error` if `entityToken` is invalid.
|
|
18
19
|
*/
|
|
19
|
-
function
|
|
20
|
+
function decodeElement(entityManager, element, value) {
|
|
20
21
|
try {
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
// Validate params.
|
|
23
|
+
validateTranscodedProperty.validateTranscodedProperty(entityManager, element);
|
|
23
24
|
if (!value)
|
|
24
25
|
return;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const decoded = transcodes[entities[entityToken].elementTranscodes[element]].decode(value);
|
|
26
|
+
const { propertyTranscodes, transcodes } = entityManager.config;
|
|
27
|
+
const decoded = transcodes[propertyTranscodes[element]].decode(value);
|
|
28
28
|
entityManager.logger.debug('decoded entity element', {
|
|
29
|
-
entityToken,
|
|
30
29
|
element,
|
|
31
30
|
value,
|
|
32
31
|
decoded,
|
|
@@ -36,7 +35,6 @@ function decodeEntityElement(entityManager, entityToken, element, value) {
|
|
|
36
35
|
catch (error) {
|
|
37
36
|
if (error instanceof Error)
|
|
38
37
|
entityManager.logger.error(error.message, {
|
|
39
|
-
entityToken,
|
|
40
38
|
element,
|
|
41
39
|
value,
|
|
42
40
|
});
|
|
@@ -44,4 +42,4 @@ function decodeEntityElement(entityManager, entityToken, element, value) {
|
|
|
44
42
|
}
|
|
45
43
|
}
|
|
46
44
|
|
|
47
|
-
|
|
45
|
+
exports.decodeElement = decodeElement;
|
|
@@ -1,25 +1,22 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var radash = require('radash');
|
|
4
|
-
var
|
|
5
|
-
var validateEntityToken = require('./validateEntityToken.js');
|
|
4
|
+
var decodeElement = require('./decodeElement.js');
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
|
-
* Decode a generated property value. Returns
|
|
7
|
+
* Decode a generated property value. Returns an {@link EntityItem | `EntityItem`}.
|
|
9
8
|
*
|
|
10
9
|
* @param entityManager - {@link EntityManager | `EntityManager`} instance.
|
|
11
10
|
* @param entityToken - `entityManager.config.entities` key.
|
|
12
11
|
* @param encoded - Encoded generated property value.
|
|
13
12
|
*
|
|
14
|
-
* @returns
|
|
13
|
+
* @returns {@link EntityItem | `EntityItem`} object with updated properties decoded from `encoded`.
|
|
15
14
|
*
|
|
16
15
|
* @throws `Error` if `entityToken` is invalid.
|
|
17
16
|
*/
|
|
18
|
-
function decodeGeneratedProperty(entityManager,
|
|
17
|
+
function decodeGeneratedProperty(entityManager, encoded) {
|
|
19
18
|
try {
|
|
20
19
|
const { generatedKeyDelimiter, generatedValueDelimiter, hashKey, shardKeyDelimiter, } = entityManager.config;
|
|
21
|
-
// Validate params.
|
|
22
|
-
validateEntityToken.validateEntityToken(entityManager, entityToken);
|
|
23
20
|
// Handle degenerate case.
|
|
24
21
|
if (!encoded)
|
|
25
22
|
return {};
|
|
@@ -37,9 +34,8 @@ function decodeGeneratedProperty(entityManager, entityToken, encoded) {
|
|
|
37
34
|
return pair;
|
|
38
35
|
});
|
|
39
36
|
// Assign decoded properties.
|
|
40
|
-
Object.assign(decoded, radash.objectify(values, ([key]) => key, ([key, value]) =>
|
|
37
|
+
Object.assign(decoded, radash.objectify(values, ([key]) => key, ([key, value]) => decodeElement.decodeElement(entityManager, key, value)));
|
|
41
38
|
entityManager.logger.debug('decoded generated property', {
|
|
42
|
-
entityToken,
|
|
43
39
|
encoded,
|
|
44
40
|
decoded,
|
|
45
41
|
});
|
|
@@ -47,7 +43,7 @@ function decodeGeneratedProperty(entityManager, entityToken, encoded) {
|
|
|
47
43
|
}
|
|
48
44
|
catch (error) {
|
|
49
45
|
if (error instanceof Error)
|
|
50
|
-
entityManager.logger.error(error.message, {
|
|
46
|
+
entityManager.logger.error(error.message, { encoded });
|
|
51
47
|
throw error;
|
|
52
48
|
}
|
|
53
49
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var encodeElement = require('./encodeElement.js');
|
|
4
4
|
var unwrapIndex = require('./unwrapIndex.js');
|
|
5
|
-
var
|
|
5
|
+
var validateEntityToken = require('./validateEntityToken.js');
|
|
6
|
+
var validateIndexToken = require('./validateIndexToken.js');
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
|
-
* Condense
|
|
9
|
+
* Condense an {@link EntityItem | `EntityItem`} into a delimited string representing the deduped, sorted, ungenerated component elements of an {@link Config.indexes | index}, leaving out those of the index hash key.
|
|
9
10
|
*
|
|
10
11
|
* @remarks
|
|
11
12
|
* Reverses {@link EntityManager.rehydrateIndexItem | `rehydrateIndexItem`}.
|
|
@@ -18,31 +19,31 @@ var validateEntityIndexToken = require('./validateEntityIndexToken.js');
|
|
|
18
19
|
* `item` must be populated with all required index component elements!
|
|
19
20
|
*
|
|
20
21
|
* @param entityManager - {@link EntityManager | `EntityManager`} instance.
|
|
21
|
-
* @param entityToken - {@link
|
|
22
|
-
* @param indexToken - {@link ConfigEntity.indexes | `entityManager.config.
|
|
23
|
-
* @param item -
|
|
22
|
+
* @param entityToken - {@link Config.entities | `entityManager.config.entities`} key.
|
|
23
|
+
* @param indexToken - {@link ConfigEntity.indexes | `entityManager.config.indexes`} key.
|
|
24
|
+
* @param item - {@link EntityItem | `EntityItem`} object.
|
|
24
25
|
*
|
|
25
26
|
* @returns Dehydrated index value.
|
|
26
27
|
*
|
|
27
|
-
* @throws `Error` if `entityToken` is invalid.
|
|
28
28
|
* @throws `Error` if `indexToken` is invalid.
|
|
29
29
|
*/
|
|
30
30
|
function dehydrateIndexItem(entityManager, entityToken, indexToken, item) {
|
|
31
31
|
try {
|
|
32
|
-
const { generatedKeyDelimiter } = entityManager.config;
|
|
33
32
|
// Validate params.
|
|
34
|
-
|
|
33
|
+
validateEntityToken.validateEntityToken(entityManager, entityToken);
|
|
34
|
+
validateIndexToken.validateIndexToken(entityManager, indexToken);
|
|
35
35
|
// Handle degenerate case.
|
|
36
36
|
if (!item)
|
|
37
37
|
return '';
|
|
38
38
|
// Unwrap index elements.
|
|
39
|
-
const { hashKey } = entityManager.config.
|
|
39
|
+
const { hashKey } = entityManager.config.indexes[indexToken];
|
|
40
40
|
const elements = unwrapIndex.unwrapIndex(entityManager, entityToken, indexToken, [
|
|
41
41
|
hashKey,
|
|
42
42
|
]);
|
|
43
43
|
// Join index element values.
|
|
44
|
+
const { generatedKeyDelimiter } = entityManager.config;
|
|
44
45
|
const dehydrated = elements
|
|
45
|
-
.map((element) =>
|
|
46
|
+
.map((element) => encodeElement.encodeElement(entityManager, element, item))
|
|
46
47
|
.join(generatedKeyDelimiter);
|
|
47
48
|
entityManager.logger.debug('dehydrated index', {
|
|
48
49
|
item,
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
var decodeGeneratedProperty = require('./decodeGeneratedProperty.js');
|
|
4
4
|
var dehydrateIndexItem = require('./dehydrateIndexItem.js');
|
|
5
|
-
var validateEntityIndexToken = require('./validateEntityIndexToken.js');
|
|
6
5
|
var validateEntityToken = require('./validateEntityToken.js');
|
|
6
|
+
var validateIndexToken = require('./validateIndexToken.js');
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Dehydrate a {@link PageKeyMap | `PageKeyMap`} object into an array of dehydrated page keys.
|
|
@@ -11,7 +11,7 @@ var validateEntityToken = require('./validateEntityToken.js');
|
|
|
11
11
|
* Reverses {@link EntityManager.rehydratePageKeyMap | `rehydratePageKeyMap`}.
|
|
12
12
|
*
|
|
13
13
|
* @param entityManager - {@link EntityManager | `EntityManager`} instance.
|
|
14
|
-
* @param entityToken - {@link
|
|
14
|
+
* @param entityToken - {@link Config.entities | `entityManager.config.entities`} key.
|
|
15
15
|
* @param pageKeyMap - {@link PageKeyMap | `PageKeyMap`} object to dehydrate.
|
|
16
16
|
*
|
|
17
17
|
* @returns Array of dehydrated page keys.
|
|
@@ -40,7 +40,7 @@ function dehydratePageKeyMap(entityManager, entityToken, pageKeyMap) {
|
|
|
40
40
|
}
|
|
41
41
|
// Extract, sort & validate indexs.
|
|
42
42
|
const indexes = Object.keys(pageKeyMap).sort();
|
|
43
|
-
indexes.map((index) =>
|
|
43
|
+
indexes.map((index) => validateIndexToken.validateIndexToken(entityManager, index));
|
|
44
44
|
// Extract & sort hash keys.
|
|
45
45
|
const hashKeys = Object.keys(pageKeyMap[indexes[0]]);
|
|
46
46
|
// Dehydrate page keys.
|
|
@@ -54,13 +54,16 @@ function dehydratePageKeyMap(entityManager, entityToken, pageKeyMap) {
|
|
|
54
54
|
}
|
|
55
55
|
// Compose item from page key
|
|
56
56
|
const item = Object.entries(pageKeyMap[index][hashKey]).reduce((item, [property, value]) => {
|
|
57
|
-
if (property
|
|
58
|
-
property
|
|
59
|
-
|
|
57
|
+
if (property === entityManager.config.rangeKey ||
|
|
58
|
+
property in entityManager.config.generatedProperties.sharded ||
|
|
59
|
+
property in entityManager.config.generatedProperties.unsharded)
|
|
60
|
+
Object.assign(item, decodeGeneratedProperty.decodeGeneratedProperty(entityManager, value));
|
|
60
61
|
else
|
|
61
62
|
Object.assign(item, { [property]: value });
|
|
62
63
|
return item;
|
|
63
|
-
},
|
|
64
|
+
},
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/prefer-reduce-type-parameter
|
|
66
|
+
{});
|
|
64
67
|
// Dehydrate index from item.
|
|
65
68
|
dehydrated.push(dehydrateIndexItem.dehydrateIndexItem(entityManager, entityToken, index, item));
|
|
66
69
|
}
|