@karmaniverous/entity-manager 7.0.0 → 7.1.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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
# entity-manager
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/@karmaniverous/entity-manager)  <!-- TYPEDOC_EXCLUDE --> [](https://docs.karmanivero.us/entity-manager) [](https://github.com/karmaniverous/entity-manager/tree/main/CHANGELOG.md)<!-- /TYPEDOC_EXCLUDE --> [](https://github.com/karmaniverous/entity-manager/tree/main/LICENSE.md)
|
|
4
|
-
|
|
1
|
+
# entity-manager
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@karmaniverous/entity-manager)  <!-- TYPEDOC_EXCLUDE --> [](https://docs.karmanivero.us/entity-manager) [](https://github.com/karmaniverous/entity-manager/tree/main/CHANGELOG.md)<!-- /TYPEDOC_EXCLUDE --> [](https://github.com/karmaniverous/entity-manager/tree/main/LICENSE.md)
|
|
4
|
+
|
|
5
5
|
Entity Manager implements rational indexing & cross‑shard querying at scale in your NoSQL database so you can focus on application logic. It is provider‑agnostic (great fit for DynamoDB) and TypeScript‑first with strong types and runtime validation.
|
|
6
6
|
|
|
7
7
|
Key links:
|
|
@@ -32,6 +32,12 @@ npm install --save-dev @karmaniverous/mock-db
|
|
|
32
32
|
- Values‑first + schema‑first config:
|
|
33
33
|
- Use a config literal (prefer `as const` and `satisfies`) to preserve literal tokens.
|
|
34
34
|
- Optionally provide Zod schemas (`entitiesSchema`) to infer entity shapes without generics.
|
|
35
|
+
- Projection‑aware typing (type‑only K):
|
|
36
|
+
- Pass attributes as a const tuple (K) through your query types to narrow result items to Pick<…> of those properties.
|
|
37
|
+
- No runtime change; adapters execute projections. Adapters should auto‑include `uniqueProperty` and any explicit sort keys when callers omit them to preserve dedupe/sort invariants.
|
|
38
|
+
- Index‑aware typing (CF/CC helpers):
|
|
39
|
+
- CF: drive index token unions and page‑key narrowing directly from a values‑first config literal (`QueryOptionsByCF`, `ShardQueryMapByCF`).
|
|
40
|
+
- CC: derive index tokens from a captured config type while reusing CF for narrowing (`QueryOptionsByCC`, `ShardQueryMapByCC`).
|
|
35
41
|
- Token‑aware helpers:
|
|
36
42
|
- `addKeys`, `getPrimaryKey`, `removeKeys` narrow types by entity token (no casts).
|
|
37
43
|
- Index‑aware page keys (optional CF channel):
|
|
@@ -41,14 +47,18 @@ npm install --save-dev @karmaniverous/mock-db
|
|
|
41
47
|
- Use `QueryOptionsByCC` and `ShardQueryMapByCC` to derive index token unions from a captured config type (via `IndexTokensFrom`), while still benefiting from page-key narrowing.
|
|
42
48
|
|
|
43
49
|
## Quick start (values‑first + schema‑first)
|
|
44
|
-
|
|
50
|
+
|
|
51
|
+
```ts
|
|
45
52
|
import { z } from 'zod';
|
|
46
|
-
import {
|
|
53
|
+
import {
|
|
54
|
+
createEntityManager,
|
|
55
|
+
defaultTranscodes,
|
|
56
|
+
} from '@karmaniverous/entity-manager';
|
|
47
57
|
|
|
48
58
|
// 1) Schema-first entity shapes (non-generated fields only)
|
|
49
59
|
const userSchema = z.object({
|
|
50
|
-
userId: z.string(),
|
|
51
|
-
created: z.number(),
|
|
60
|
+
userId: z.string(), // unique property
|
|
61
|
+
created: z.number(), // timestamp property
|
|
52
62
|
updated: z.number().optional(),
|
|
53
63
|
firstNameCanonical: z.string(),
|
|
54
64
|
lastNameCanonical: z.string(),
|
|
@@ -137,16 +147,24 @@ import type {
|
|
|
137
147
|
const cf = {
|
|
138
148
|
indexes: {
|
|
139
149
|
firstName: { hashKey: 'hashKey2', rangeKey: 'firstNameRK' },
|
|
140
|
-
lastName:
|
|
150
|
+
lastName: { hashKey: 'hashKey2', rangeKey: 'lastNameRK' },
|
|
141
151
|
},
|
|
142
152
|
} as const;
|
|
143
153
|
type CF = typeof cf;
|
|
144
154
|
|
|
145
155
|
// SQFs are typed; pageKey is narrowed to index components per IT
|
|
146
|
-
const firstNameSQF: ShardQueryFunction<
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
156
|
+
const firstNameSQF: ShardQueryFunction<
|
|
157
|
+
MyConfigMap,
|
|
158
|
+
'user',
|
|
159
|
+
'firstName',
|
|
160
|
+
CF
|
|
161
|
+
> = async (hashKey, pageKey, pageSize) => ({ count: 0, items: [], pageKey });
|
|
162
|
+
const lastNameSQF: ShardQueryFunction<
|
|
163
|
+
MyConfigMap,
|
|
164
|
+
'user',
|
|
165
|
+
'lastName',
|
|
166
|
+
CF
|
|
167
|
+
> = async (hashKey, pageKey, pageSize) => ({ count: 0, items: [], pageKey });
|
|
150
168
|
|
|
151
169
|
// CF-aware shardQueryMap — only 'firstName' | 'lastName' allowed
|
|
152
170
|
const shardQueryMap: ShardQueryMapByCF<MyConfigMap, 'user', CF> = {
|
|
@@ -182,23 +200,35 @@ import type {
|
|
|
182
200
|
const cc = {
|
|
183
201
|
indexes: {
|
|
184
202
|
firstName: { hashKey: 'hashKey2', rangeKey: 'firstNameRK' },
|
|
185
|
-
lastName:
|
|
203
|
+
lastName: { hashKey: 'hashKey2', rangeKey: 'lastNameRK' },
|
|
186
204
|
},
|
|
187
205
|
} as const;
|
|
188
206
|
type CC = typeof cc;
|
|
189
207
|
|
|
190
208
|
// Reuse typed SQFs (pageKey narrowed per index)
|
|
191
|
-
const firstNameSQF: ShardQueryFunction<
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
209
|
+
const firstNameSQF: ShardQueryFunction<
|
|
210
|
+
MyConfigMap,
|
|
211
|
+
'user',
|
|
212
|
+
'firstName',
|
|
213
|
+
CC
|
|
214
|
+
> = async (hashKey, pageKey, pageSize) => ({ count: 0, items: [], pageKey });
|
|
215
|
+
const lastNameSQF: ShardQueryFunction<
|
|
216
|
+
MyConfigMap,
|
|
217
|
+
'user',
|
|
218
|
+
'lastName',
|
|
219
|
+
CC
|
|
220
|
+
> = async (hashKey, pageKey, pageSize) => ({ count: 0, items: [], pageKey });
|
|
195
221
|
|
|
196
222
|
// CC-aware shardQueryMap — only 'firstName' | 'lastName' allowed
|
|
197
223
|
const shardQueryMapCC: ShardQueryMapByCC<MyConfigMap, 'user', CC> = {
|
|
198
224
|
firstName: firstNameSQF,
|
|
199
225
|
lastName: lastNameSQF,
|
|
200
226
|
};
|
|
201
|
-
const optionsCC: QueryOptionsByCC<MyConfigMap, 'user', CC> = {
|
|
227
|
+
const optionsCC: QueryOptionsByCC<MyConfigMap, 'user', CC> = {
|
|
228
|
+
entityToken: 'user',
|
|
229
|
+
item: {},
|
|
230
|
+
shardQueryMap: shardQueryMapCC,
|
|
231
|
+
};
|
|
202
232
|
const resultCC = await manager.query(optionsCC);
|
|
203
233
|
```
|
|
204
234
|
|
|
@@ -206,7 +236,97 @@ Notes:
|
|
|
206
236
|
|
|
207
237
|
- Entity Manager enumerates hash‑key space for the time window, rehydrates page keys (when present), executes shard queries in parallel (throttled), dedupes by unique property, sorts, and dehydrates a new pageKeyMap.
|
|
208
238
|
- For provider integration, the SQF lambda encapsulates the platform‑specific query for one index + shard page. See tests and entity‑client‑dynamodb for examples.
|
|
209
|
-
|
|
239
|
+
|
|
240
|
+
## Projection‑aware typing (K)
|
|
241
|
+
|
|
242
|
+
Entity Manager supports a type‑only projection channel K that narrows result item shapes when a provider adapter projects a subset of attributes at runtime. Pass your attributes as a const tuple and thread K through `ShardQueryFunction/Map`, `QueryOptions`, and `QueryResult`.
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
import type {
|
|
246
|
+
ConfigMap,
|
|
247
|
+
EntityItemByToken,
|
|
248
|
+
QueryOptions,
|
|
249
|
+
QueryResult,
|
|
250
|
+
ShardQueryFunction,
|
|
251
|
+
ShardQueryMap,
|
|
252
|
+
} from '@karmaniverous/entity-manager';
|
|
253
|
+
|
|
254
|
+
// Minimal entities (example)
|
|
255
|
+
interface Email {
|
|
256
|
+
created: number;
|
|
257
|
+
email: string;
|
|
258
|
+
userId: string;
|
|
259
|
+
}
|
|
260
|
+
interface User {
|
|
261
|
+
beneficiaryId: string;
|
|
262
|
+
created: number;
|
|
263
|
+
firstNameCanonical: string;
|
|
264
|
+
lastNameCanonical: string;
|
|
265
|
+
phone?: string;
|
|
266
|
+
updated: number;
|
|
267
|
+
userId: string;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
type MyConfigMap = ConfigMap<{
|
|
271
|
+
EntityMap: { email: Email; user: User };
|
|
272
|
+
HashKey: 'hashKey2';
|
|
273
|
+
RangeKey: 'rangeKey';
|
|
274
|
+
ShardedKeys: 'beneficiaryPK' | 'userPK';
|
|
275
|
+
UnshardedKeys: 'firstNameRK' | 'lastNameRK' | 'phoneRK';
|
|
276
|
+
TranscodedProperties:
|
|
277
|
+
| 'beneficiaryId'
|
|
278
|
+
| 'created'
|
|
279
|
+
| 'email'
|
|
280
|
+
| 'firstNameCanonical'
|
|
281
|
+
| 'lastNameCanonical'
|
|
282
|
+
| 'phone'
|
|
283
|
+
| 'updated'
|
|
284
|
+
| 'userId';
|
|
285
|
+
}>;
|
|
286
|
+
|
|
287
|
+
// CF capturing a single index
|
|
288
|
+
const cf = {
|
|
289
|
+
indexes: {
|
|
290
|
+
firstName: { hashKey: 'hashKey2', rangeKey: 'firstNameRK' },
|
|
291
|
+
},
|
|
292
|
+
} as const;
|
|
293
|
+
type CF = typeof cf;
|
|
294
|
+
|
|
295
|
+
// Projection attributes as const tuple — narrows K.
|
|
296
|
+
const attrs = ['userId', 'created'] as const;
|
|
297
|
+
type K = typeof attrs;
|
|
298
|
+
|
|
299
|
+
// A typed SQF: pageKey narrows via CF; items narrow via K (type-only).
|
|
300
|
+
const sqf: ShardQueryFunction<MyConfigMap, 'user', 'firstName', CF, K> = async (
|
|
301
|
+
_hashKey,
|
|
302
|
+
_pageKey,
|
|
303
|
+
_pageSize,
|
|
304
|
+
) => ({
|
|
305
|
+
count: 0,
|
|
306
|
+
items: [], // never[] is assignable to the projected array
|
|
307
|
+
pageKey: _pageKey,
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
// ShardQueryMap carrying CF and K.
|
|
311
|
+
const map: ShardQueryMap<MyConfigMap, 'user', 'firstName', CF, K> = {
|
|
312
|
+
firstName: sqf,
|
|
313
|
+
};
|
|
314
|
+
const options: QueryOptions<MyConfigMap, 'user', 'firstName', CF, K> = {
|
|
315
|
+
entityToken: 'user',
|
|
316
|
+
item: {},
|
|
317
|
+
shardQueryMap: map,
|
|
318
|
+
};
|
|
319
|
+
const result: QueryResult<MyConfigMap, 'user', 'firstName', K> =
|
|
320
|
+
await manager.query(options);
|
|
321
|
+
// result.items: Pick<EntityItemByToken<MyConfigMap, 'user'>, 'userId' | 'created'>[]
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
Notes:
|
|
325
|
+
|
|
326
|
+
- K is a type‑only channel; it does not change runtime behavior. Providers (e.g., DynamoDB adapters) execute projections.
|
|
327
|
+
- Dedupe/sort invariants: Entity Manager dedupes by `uniqueProperty` and applies `QueryOptions.sortOrder`. If your adapter projects attributes, ensure it auto‑includes `uniqueProperty` and any explicit sort keys when callers omit them from K.
|
|
328
|
+
|
|
329
|
+
## Page keys in a nutshell
|
|
210
330
|
|
|
211
331
|
- `rehydratePageKeyMap` decodes a dehydrated array (compressed string) into a two‑layer map of `{ indexToken: { hashKeyValue: pageKey | undefined } }`.
|
|
212
332
|
- `dehydratePageKeyMap` performs the inverse and emits a compact array (compressed in `query()`).
|
|
@@ -216,10 +336,16 @@ Notes:
|
|
|
216
336
|
|
|
217
337
|
```ts
|
|
218
338
|
// ESM
|
|
219
|
-
import {
|
|
339
|
+
import {
|
|
340
|
+
createEntityManager,
|
|
341
|
+
defaultTranscodes,
|
|
342
|
+
} from '@karmaniverous/entity-manager';
|
|
220
343
|
|
|
221
344
|
// CJS
|
|
222
|
-
const {
|
|
345
|
+
const {
|
|
346
|
+
createEntityManager,
|
|
347
|
+
defaultTranscodes,
|
|
348
|
+
} = require('@karmaniverous/entity-manager');
|
|
223
349
|
```
|
|
224
350
|
|
|
225
351
|
## Logging
|
|
@@ -243,12 +369,17 @@ const manager = createEntityManager(config, logger);
|
|
|
243
369
|
- `ShardQueryFunction<CC, ET, IT, CF>`, `ShardQueryMap<CC, ET, ITS, CF>`
|
|
244
370
|
- `QueryOptions<CC, ET, ITS, CF>`, `QueryResult<CC, ET, ITS>`
|
|
245
371
|
- DX sugar: `IndexTokensOf<CF>`, `QueryOptionsByCF`, `ShardQueryMapByCF`, `IndexTokensFrom<CC>`, `QueryOptionsByCC`, `ShardQueryMapByCC`
|
|
372
|
+
- Projection helpers
|
|
373
|
+
- `KeysFrom<K>`
|
|
374
|
+
- `Projected<T, K>`
|
|
375
|
+
- `ProjectedItemByToken<CC, ET, K>`
|
|
246
376
|
|
|
247
377
|
See the full API: https://docs.karmanivero.us/entity-manager
|
|
248
378
|
|
|
249
379
|
## Scripts (repo)
|
|
250
380
|
|
|
251
|
-
- build: rollup outputs ESM/CJS + .d.ts
|
|
252
|
-
test: vitest with coverage
|
|
381
|
+
- build: rollup outputs ESM/CJS + .d.ts
|
|
382
|
+
- test: vitest with coverage
|
|
253
383
|
- lint: ESLint (type‑aware) + Prettier
|
|
254
384
|
- docs: TypeDoc
|
|
255
385
|
- typecheck: tsc + tsd (type‑level tests)
|
|
@@ -259,4 +390,4 @@ BSD‑3‑Clause (see package.json).
|
|
|
259
390
|
|
|
260
391
|
---
|
|
261
392
|
|
|
262
|
-
Built for you with ❤️ on Bali! Find more great tools & templates on [my GitHub Profile](https://github.com/karmaniverous).
|
|
393
|
+
Built for you with ❤️ on Bali! Find more great tools & templates on [my GitHub Profile](https://github.com/karmaniverous).
|
|
@@ -9,6 +9,7 @@ var radash = require('radash');
|
|
|
9
9
|
* @typeParam EntityClient - {@link BaseEntityClient | `BaseEntityClient`} derived class instance.
|
|
10
10
|
* @typeParam IndexParams - Database platform-specific, index-specific query parameters.
|
|
11
11
|
* @typeParam CF - Optional values-first config literal type for page key narrowing.
|
|
12
|
+
* @typeParam K - Optional projection keys; narrows item shape when provided.
|
|
12
13
|
*
|
|
13
14
|
* @category QueryBuilder
|
|
14
15
|
*/
|
|
@@ -28,8 +28,10 @@ const { compressToEncodedURIComponent, decompressFromEncodedURIComponent } = lzS
|
|
|
28
28
|
*/
|
|
29
29
|
async function query(entityManager, options) {
|
|
30
30
|
try {
|
|
31
|
-
// Get defaults.
|
|
32
|
-
const
|
|
31
|
+
// Get defaults (avoid unsafe destructuring on generic access).
|
|
32
|
+
const entityDefaults = entityManager.config.entities[options.entityToken];
|
|
33
|
+
const defaultLimit = entityDefaults.defaultLimit;
|
|
34
|
+
const defaultPageSize = entityDefaults.defaultPageSize;
|
|
33
35
|
// Extract params.
|
|
34
36
|
const { entityToken, limit = defaultLimit, item, pageKeyMap, pageSize = defaultPageSize, shardQueryMap, sortOrder = [], timestampFrom = 0, timestampTo = Date.now(), throttle = entityManager.config.throttle, } = options;
|
|
35
37
|
// Validate params.
|
|
@@ -98,8 +100,12 @@ async function query(entityManager, options) {
|
|
|
98
100
|
break;
|
|
99
101
|
} while (workingResult.items.length < limit);
|
|
100
102
|
// Dedupe & sort working result.
|
|
101
|
-
|
|
103
|
+
// Note: when projecting, callers may omit uniqueProperty/sort keys.
|
|
104
|
+
// We perform operations on the full item shape and then cast back.
|
|
105
|
+
const itemsForOps = workingResult.items;
|
|
106
|
+
const dedupedSorted = entityTools.sort(radash.unique(itemsForOps, (i) => i[entityManager.config.entities[entityToken]
|
|
102
107
|
.uniqueProperty].toString()), sortOrder);
|
|
108
|
+
workingResult.items = dedupedSorted;
|
|
103
109
|
const result = {
|
|
104
110
|
count: workingResult.items.length,
|
|
105
111
|
items: workingResult.items,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { EntityMap, TranscodeRegistry, ConditionalProperty, Exactify, PropertiesOfType, TranscodableProperties, FlattenEntityMap, Transcodes, MutuallyExclusive, NotNever, DefaultTranscodeRegistry, SortOrder } from '@karmaniverous/entity-tools';
|
|
2
|
-
import
|
|
2
|
+
import * as z from 'zod';
|
|
3
|
+
import { z as z$1, ZodType } from 'zod';
|
|
3
4
|
import { BatchProcessOptions } from '@karmaniverous/batch-process';
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -147,15 +148,15 @@ type EntityKey<CC extends BaseConfigMap> = Record<CC['HashKey'] | CC['RangeKey']
|
|
|
147
148
|
*/
|
|
148
149
|
type EntityToken<CC extends BaseConfigMap> = keyof Exactify<CC['EntityMap']> & string;
|
|
149
150
|
|
|
150
|
-
declare const configSchema: z.ZodObject<{
|
|
151
|
-
entities: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
152
|
-
defaultLimit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
153
|
-
defaultPageSize: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
154
|
-
shardBumps: z.ZodPipe<z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
155
|
-
timestamp: z.ZodNumber;
|
|
156
|
-
charBits: z.ZodNumber;
|
|
157
|
-
chars: z.ZodNumber;
|
|
158
|
-
}, z.core.$strict>>>>, z.ZodTransform<{
|
|
151
|
+
declare const configSchema: z$1.ZodObject<{
|
|
152
|
+
entities: z$1.ZodDefault<z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodObject<{
|
|
153
|
+
defaultLimit: z$1.ZodDefault<z$1.ZodOptional<z$1.ZodNumber>>;
|
|
154
|
+
defaultPageSize: z$1.ZodDefault<z$1.ZodOptional<z$1.ZodNumber>>;
|
|
155
|
+
shardBumps: z$1.ZodPipe<z$1.ZodDefault<z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
|
|
156
|
+
timestamp: z$1.ZodNumber;
|
|
157
|
+
charBits: z$1.ZodNumber;
|
|
158
|
+
chars: z$1.ZodNumber;
|
|
159
|
+
}, z$1.core.$strict>>>>, z$1.ZodTransform<{
|
|
159
160
|
timestamp: number;
|
|
160
161
|
charBits: number;
|
|
161
162
|
chars: number;
|
|
@@ -164,36 +165,36 @@ declare const configSchema: z.ZodObject<{
|
|
|
164
165
|
charBits: number;
|
|
165
166
|
chars: number;
|
|
166
167
|
}[]>>;
|
|
167
|
-
timestampProperty: z.ZodString;
|
|
168
|
-
uniqueProperty: z.ZodString;
|
|
169
|
-
}, z.core.$strict>>>>;
|
|
170
|
-
generatedProperties: z.ZodDefault<z.ZodOptional<z.ZodObject<{
|
|
171
|
-
sharded: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>>;
|
|
172
|
-
unsharded: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>>;
|
|
173
|
-
}, z.core.$strip>>>;
|
|
174
|
-
hashKey: z.ZodString;
|
|
175
|
-
indexes: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
176
|
-
hashKey: z.ZodString;
|
|
177
|
-
rangeKey: z.ZodString;
|
|
178
|
-
projections: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
179
|
-
}, z.core.$strip>>>>;
|
|
180
|
-
generatedKeyDelimiter: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
181
|
-
generatedValueDelimiter: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
182
|
-
propertyTranscodes: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>>;
|
|
183
|
-
rangeKey: z.ZodString;
|
|
184
|
-
shardKeyDelimiter: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
185
|
-
throttle: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
186
|
-
transcodes: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
187
|
-
encode: z.ZodCustom<unknown, unknown>;
|
|
188
|
-
decode: z.ZodCustom<unknown, unknown>;
|
|
189
|
-
}, z.core.$strict>>>>;
|
|
190
|
-
}, z.core.$strict>;
|
|
168
|
+
timestampProperty: z$1.ZodString;
|
|
169
|
+
uniqueProperty: z$1.ZodString;
|
|
170
|
+
}, z$1.core.$strict>>>>;
|
|
171
|
+
generatedProperties: z$1.ZodDefault<z$1.ZodOptional<z$1.ZodObject<{
|
|
172
|
+
sharded: z$1.ZodDefault<z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodArray<z$1.ZodString>>>>;
|
|
173
|
+
unsharded: z$1.ZodDefault<z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodArray<z$1.ZodString>>>>;
|
|
174
|
+
}, z$1.core.$strip>>>;
|
|
175
|
+
hashKey: z$1.ZodString;
|
|
176
|
+
indexes: z$1.ZodDefault<z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodObject<{
|
|
177
|
+
hashKey: z$1.ZodString;
|
|
178
|
+
rangeKey: z$1.ZodString;
|
|
179
|
+
projections: z$1.ZodOptional<z$1.ZodArray<z$1.ZodString>>;
|
|
180
|
+
}, z$1.core.$strip>>>>;
|
|
181
|
+
generatedKeyDelimiter: z$1.ZodDefault<z$1.ZodOptional<z$1.ZodString>>;
|
|
182
|
+
generatedValueDelimiter: z$1.ZodDefault<z$1.ZodOptional<z$1.ZodString>>;
|
|
183
|
+
propertyTranscodes: z$1.ZodDefault<z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodString>>>;
|
|
184
|
+
rangeKey: z$1.ZodString;
|
|
185
|
+
shardKeyDelimiter: z$1.ZodDefault<z$1.ZodOptional<z$1.ZodString>>;
|
|
186
|
+
throttle: z$1.ZodDefault<z$1.ZodOptional<z$1.ZodNumber>>;
|
|
187
|
+
transcodes: z$1.ZodDefault<z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodObject<{
|
|
188
|
+
encode: z$1.ZodCustom<unknown, unknown>;
|
|
189
|
+
decode: z$1.ZodCustom<unknown, unknown>;
|
|
190
|
+
}, z$1.core.$strict>>>>;
|
|
191
|
+
}, z$1.core.$strict>;
|
|
191
192
|
/**
|
|
192
193
|
* Simplified type taken on by a {@link Config | `Config`} object after parsing in the {@link EntityManager | `EntityManager`} constructor.
|
|
193
194
|
*
|
|
194
195
|
* @category EntityManager
|
|
195
196
|
*/
|
|
196
|
-
type ParsedConfig = z.infer<typeof configSchema>;
|
|
197
|
+
type ParsedConfig = z$1.infer<typeof configSchema>;
|
|
197
198
|
|
|
198
199
|
/**
|
|
199
200
|
* A partial {@link EntityItem | `EntityItem`} restricted to keys defined in `C`.
|
|
@@ -255,6 +256,18 @@ type EntityOfToken<CC extends BaseConfigMap, ET extends EntityToken<CC>> = Exact
|
|
|
255
256
|
type EntityItemByToken<CC extends BaseConfigMap, ET extends EntityToken<CC>> = Partial<EntityOfToken<CC, ET> & Record<CC['HashKey'] | CC['RangeKey'] | CC['ShardedKeys'] | CC['UnshardedKeys'], string>> & Record<string, unknown>;
|
|
256
257
|
/** EntityRecordByToken — database-facing record (keys required) narrowed to a specific entity token. */
|
|
257
258
|
type EntityRecordByToken<CC extends BaseConfigMap, ET extends EntityToken<CC>> = EntityItemByToken<CC, ET> & EntityKey<CC>;
|
|
259
|
+
/**
|
|
260
|
+
* Normalize literals: string | readonly string[] -\> union of strings.
|
|
261
|
+
*/
|
|
262
|
+
type KeysFrom<K> = K extends readonly (infer E)[] ? Extract<E, string> : K extends string ? K : never;
|
|
263
|
+
/**
|
|
264
|
+
* Project item shape by keys; if K is never/unknown, fall back to T.
|
|
265
|
+
*/
|
|
266
|
+
type Projected<T, K> = [KeysFrom<K>] extends [never] ? T : T extends object ? Pick<T, Extract<KeysFrom<K>, keyof Exactify<T>>> : T;
|
|
267
|
+
/**
|
|
268
|
+
* Projected item by token — narrows EntityItemByToken by K when provided.
|
|
269
|
+
*/
|
|
270
|
+
type ProjectedItemByToken<CC extends BaseConfigMap, ET extends EntityToken<CC>, K = unknown> = Projected<EntityItemByToken<CC, ET>, K>;
|
|
258
271
|
|
|
259
272
|
/**
|
|
260
273
|
* A result returned by a {@link ShardQueryFunction | `ShardQueryFunction`} querying an individual shard.
|
|
@@ -263,15 +276,16 @@ type EntityRecordByToken<CC extends BaseConfigMap, ET extends EntityToken<CC>> =
|
|
|
263
276
|
* @typeParam ET - Entity token narrowing the item type.
|
|
264
277
|
* @typeParam IT - Index token (for page key typing).
|
|
265
278
|
* @typeParam CF - Optional values-first config literal type for narrowing.
|
|
279
|
+
* @typeParam K - Optional projection keys; narrows item shape when provided.
|
|
266
280
|
*
|
|
267
281
|
* @category EntityManager
|
|
268
282
|
* @protected
|
|
269
283
|
*/
|
|
270
|
-
interface ShardQueryResult<CC extends BaseConfigMap, ET extends EntityToken<CC>, IT extends string, CF = unknown> {
|
|
284
|
+
interface ShardQueryResult<CC extends BaseConfigMap, ET extends EntityToken<CC>, IT extends string, CF = unknown, K = unknown> {
|
|
271
285
|
/** The number of records returned. */
|
|
272
286
|
count: number;
|
|
273
287
|
/** The returned records. */
|
|
274
|
-
items:
|
|
288
|
+
items: ProjectedItemByToken<CC, ET, K>[];
|
|
275
289
|
/** The page key for the next query on this shard. */
|
|
276
290
|
pageKey?: PageKeyByIndex<CC, ET, IT, CF>;
|
|
277
291
|
}
|
|
@@ -289,13 +303,14 @@ interface ShardQueryResult<CC extends BaseConfigMap, ET extends EntityToken<CC>,
|
|
|
289
303
|
* @typeParam ET - Entity token narrowing the item/record types.
|
|
290
304
|
* @typeParam IT - Index token (inferred from shardQueryMap keys).
|
|
291
305
|
* @typeParam CF - Optional values-first config literal type for narrowing.
|
|
306
|
+
* @typeParam K - Optional projection keys; narrows item shape when provided.
|
|
292
307
|
*
|
|
293
308
|
* @category EntityManager
|
|
294
309
|
* @protected
|
|
295
310
|
*/
|
|
296
|
-
type ShardQueryFunction<CC extends BaseConfigMap, ET extends EntityToken<CC>, IT extends string, CF = unknown> = CF extends {
|
|
311
|
+
type ShardQueryFunction<CC extends BaseConfigMap, ET extends EntityToken<CC>, IT extends string, CF = unknown, K = unknown> = CF extends {
|
|
297
312
|
indexes?: infer I;
|
|
298
|
-
} ? I extends Record<string, unknown> ? IT extends keyof I & string ? (hashKey: string, pageKey?: PageKeyByIndex<CC, ET, IT, CF>, pageSize?: number) => Promise<ShardQueryResult<CC, ET, IT, CF>> : never : (hashKey: string, pageKey?: PageKeyByIndex<CC, ET, IT, CF>, pageSize?: number) => Promise<ShardQueryResult<CC, ET, IT, CF>> : (hashKey: string, pageKey?: PageKeyByIndex<CC, ET, IT, CF>, pageSize?: number) => Promise<ShardQueryResult<CC, ET, IT, CF>>;
|
|
313
|
+
} ? I extends Record<string, unknown> ? IT extends 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>>;
|
|
299
314
|
|
|
300
315
|
/**
|
|
301
316
|
* Relates a specific index token to a {@link ShardQueryFunction | `ShardQueryFunction`} to be performed on that index.
|
|
@@ -308,13 +323,14 @@ type ShardQueryFunction<CC extends BaseConfigMap, ET extends EntityToken<CC>, IT
|
|
|
308
323
|
* literal keys (prefer `as const` at call sites), the map keys
|
|
309
324
|
* are constrained to that set. Excess keys are rejected by
|
|
310
325
|
* excess property checks on object literals.
|
|
326
|
+
* @typeParam K - Optional projection keys; narrows item shape when provided.
|
|
311
327
|
*
|
|
312
328
|
* @category EntityManager
|
|
313
329
|
* @protected
|
|
314
330
|
*/
|
|
315
|
-
type ShardQueryMap<CC extends BaseConfigMap, ET extends EntityToken<CC>, ITS extends string, CF = unknown> = CF extends {
|
|
331
|
+
type ShardQueryMap<CC extends BaseConfigMap, ET extends EntityToken<CC>, ITS extends string, CF = unknown, K = unknown> = CF extends {
|
|
316
332
|
indexes?: infer I;
|
|
317
|
-
} ? I extends Record<string, unknown> ? Record<ITS & (keyof I & string), ShardQueryFunction<CC, ET, ITS & (keyof I & string), CF>> : Record<ITS, ShardQueryFunction<CC, ET, ITS, CF>> : Record<ITS, ShardQueryFunction<CC, ET, ITS, CF>>;
|
|
333
|
+
} ? I extends Record<string, unknown> ? Record<ITS & (keyof I & string), ShardQueryFunction<CC, ET, ITS & (keyof I & string), CF, K>> : Record<ITS, ShardQueryFunction<CC, ET, ITS, CF, K>> : Record<ITS, ShardQueryFunction<CC, ET, ITS, CF, K>>;
|
|
318
334
|
/**
|
|
319
335
|
* Convenience alias for ShardQueryMap that derives ITS (index token subset)
|
|
320
336
|
* from a values-first captured config CC (e.g., your config literal type).
|
|
@@ -327,7 +343,7 @@ type ShardQueryMap<CC extends BaseConfigMap, ET extends EntityToken<CC>, ITS ext
|
|
|
327
343
|
*
|
|
328
344
|
* This is optional DX sugar; it does not change runtime behavior.
|
|
329
345
|
*/
|
|
330
|
-
type ShardQueryMapByCC<CC extends BaseConfigMap, ET extends EntityToken<CC>, CCLit = unknown> = ShardQueryMap<CC, ET, IndexTokensFrom<CCLit>, CCLit>;
|
|
346
|
+
type ShardQueryMapByCC<CC extends BaseConfigMap, ET extends EntityToken<CC>, CCLit = unknown, K = unknown> = ShardQueryMap<CC, ET, IndexTokensFrom<CCLit>, CCLit, K>;
|
|
331
347
|
/**
|
|
332
348
|
* Convenience alias for ShardQueryMap that derives ITS (index token subset)
|
|
333
349
|
* directly from a values-first config literal CF when it carries `indexes`.
|
|
@@ -337,7 +353,7 @@ type ShardQueryMapByCC<CC extends BaseConfigMap, ET extends EntityToken<CC>, CCL
|
|
|
337
353
|
*
|
|
338
354
|
* This is optional DX sugar; it does not change runtime behavior.
|
|
339
355
|
*/
|
|
340
|
-
type ShardQueryMapByCF<CC extends BaseConfigMap, ET extends EntityToken<CC>, CF = unknown> = ShardQueryMap<CC, ET, IndexTokensOf<CF>, CF>;
|
|
356
|
+
type ShardQueryMapByCF<CC extends BaseConfigMap, ET extends EntityToken<CC>, CF = unknown, K = unknown> = ShardQueryMap<CC, ET, IndexTokensOf<CF>, CF, K>;
|
|
341
357
|
|
|
342
358
|
/**
|
|
343
359
|
* Options passed to the {@link EntityManager.query | `EntityManager.query`} method.
|
|
@@ -346,11 +362,12 @@ type ShardQueryMapByCF<CC extends BaseConfigMap, ET extends EntityToken<CC>, CF
|
|
|
346
362
|
* @typeParam ET - Entity token narrowing the item types.
|
|
347
363
|
* @typeParam ITS - Index token subset (inferred from shardQueryMap keys).
|
|
348
364
|
* @typeParam CF - Optional values-first config literal type used for index-aware narrowing.
|
|
365
|
+
* @typeParam K - Optional projection keys; narrows item/sort shapes when provided.
|
|
349
366
|
*
|
|
350
367
|
* @category EntityManager
|
|
351
368
|
* @protected
|
|
352
369
|
*/
|
|
353
|
-
interface QueryOptions<CC extends BaseConfigMap, ET extends EntityToken<CC> = EntityToken<CC>, ITS extends string = string, CF = unknown> {
|
|
370
|
+
interface QueryOptions<CC extends BaseConfigMap, ET extends EntityToken<CC> = EntityToken<CC>, ITS extends string = string, CF = unknown, K = unknown> {
|
|
354
371
|
/** Identifies the entity to be queried. Key of {@link Config | `Config`} `entities`. */
|
|
355
372
|
entityToken: ET;
|
|
356
373
|
/**
|
|
@@ -388,11 +405,11 @@ interface QueryOptions<CC extends BaseConfigMap, ET extends EntityToken<CC> = En
|
|
|
388
405
|
* page key, e.g. to match the same string against `firstName` and `lastName`
|
|
389
406
|
* properties without performing a table scan for either.
|
|
390
407
|
*/
|
|
391
|
-
shardQueryMap: ShardQueryMap<CC, ET, ITS, CF>;
|
|
408
|
+
shardQueryMap: ShardQueryMap<CC, ET, ITS, CF, K>;
|
|
392
409
|
/**
|
|
393
|
-
* A {@link SortOrder | `SortOrder`} object specifying the sort order of the result set. Defaults to `[]`.
|
|
410
|
+
* 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.
|
|
394
411
|
*/
|
|
395
|
-
sortOrder?: SortOrder<
|
|
412
|
+
sortOrder?: SortOrder<ProjectedItemByToken<CC, ET, K>>;
|
|
396
413
|
/**
|
|
397
414
|
* Lower limit to query shard space.
|
|
398
415
|
*
|
|
@@ -429,7 +446,7 @@ interface QueryOptions<CC extends BaseConfigMap, ET extends EntityToken<CC> = En
|
|
|
429
446
|
*
|
|
430
447
|
* This is optional DX sugar; it does not change runtime behavior.
|
|
431
448
|
*/
|
|
432
|
-
type QueryOptionsByCF<CC extends BaseConfigMap, ET extends EntityToken<CC> = EntityToken<CC>, CF = unknown> = QueryOptions<CC, ET, IndexTokensOf<CF>, CF>;
|
|
449
|
+
type QueryOptionsByCF<CC extends BaseConfigMap, ET extends EntityToken<CC> = EntityToken<CC>, CF = unknown, K = unknown> = QueryOptions<CC, ET, IndexTokensOf<CF>, CF, K>;
|
|
433
450
|
/**
|
|
434
451
|
* Convenience alias for QueryOptions that derives ITS (index token subset)
|
|
435
452
|
* from a values-first captured config CC (e.g., your config literal type).
|
|
@@ -442,7 +459,7 @@ type QueryOptionsByCF<CC extends BaseConfigMap, ET extends EntityToken<CC> = Ent
|
|
|
442
459
|
*
|
|
443
460
|
* This is optional DX sugar; it does not change runtime behavior.
|
|
444
461
|
*/
|
|
445
|
-
type QueryOptionsByCC<CCMap extends BaseConfigMap, ET extends EntityToken<CCMap> = EntityToken<CCMap>, CC = unknown> = QueryOptions<CCMap, ET, IndexTokensFrom<CC>, CC>;
|
|
462
|
+
type QueryOptionsByCC<CCMap extends BaseConfigMap, ET extends EntityToken<CCMap> = EntityToken<CCMap>, CC = unknown, K = unknown> = QueryOptions<CCMap, ET, IndexTokensFrom<CC>, CC, K>;
|
|
446
463
|
|
|
447
464
|
/**
|
|
448
465
|
* A result returned by a query across multiple shards, where each shard may receive multiple page queries via a dynamically-generated {@link ShardQueryFunction | `ShardQueryFunction`}.
|
|
@@ -450,15 +467,16 @@ type QueryOptionsByCC<CCMap extends BaseConfigMap, ET extends EntityToken<CCMap>
|
|
|
450
467
|
* @typeParam CC - {@link ConfigMap | `ConfigMap`}.
|
|
451
468
|
* @typeParam ET - Entity token narrowing the result item type.
|
|
452
469
|
* @typeParam ITS - Index token subset (carried for symmetry; not represented in the shape).
|
|
470
|
+
* @typeParam K - Optional projection keys; narrows item shape when provided.
|
|
453
471
|
*
|
|
454
472
|
* @category EntityManager
|
|
455
473
|
* @protected
|
|
456
474
|
*/
|
|
457
|
-
interface QueryResult<CC extends BaseConfigMap, ET extends EntityToken<CC>, ITS extends string> {
|
|
475
|
+
interface QueryResult<CC extends BaseConfigMap, ET extends EntityToken<CC>, ITS extends string, K = unknown> {
|
|
458
476
|
/** Total number of records returned across all shards. */
|
|
459
477
|
count: number;
|
|
460
478
|
/** The returned records. */
|
|
461
|
-
items:
|
|
479
|
+
items: ProjectedItemByToken<CC, ET, K>[];
|
|
462
480
|
/**
|
|
463
481
|
* A compressed, two-layer map of page keys, used to query the next page of
|
|
464
482
|
* data for a given sort key on each shard of a given hash key.
|
|
@@ -597,7 +615,7 @@ declare class EntityManager<CC extends BaseConfigMap> {
|
|
|
597
615
|
*
|
|
598
616
|
* @protected
|
|
599
617
|
*/
|
|
600
|
-
query<ET extends EntityToken<CC>, ITS extends string, CF = unknown>(options: QueryOptions<CC, ET, ITS, CF>): Promise<QueryResult<CC, ET, ITS>>;
|
|
618
|
+
query<ET extends EntityToken<CC>, ITS extends string, CF = unknown, K = unknown>(options: QueryOptions<CC, ET, ITS, CF, K>): Promise<QueryResult<CC, ET, ITS, K>>;
|
|
601
619
|
}
|
|
602
620
|
|
|
603
621
|
/**
|
|
@@ -660,7 +678,7 @@ type TranscodedPropertiesFrom<CC> = CC extends {
|
|
|
660
678
|
type EntitiesFromSchema<CC> = CC extends {
|
|
661
679
|
entitiesSchema?: infer S;
|
|
662
680
|
} ? S extends Record<string, ZodType> ? {
|
|
663
|
-
[K in keyof S & string]: infer<S[K]>;
|
|
681
|
+
[K in keyof S & string]: z.infer<S[K]>;
|
|
664
682
|
} & EntityMap : EntityMap : EntityMap;
|
|
665
683
|
/**
|
|
666
684
|
* Derive the union of index token names from a values-first config input.
|
|
@@ -782,10 +800,11 @@ type QueryBuilderQueryOptions<CC extends BaseConfigMap, CF = unknown> = Omit<Que
|
|
|
782
800
|
* @typeParam EntityClient - {@link BaseEntityClient | `BaseEntityClient`} derived class instance.
|
|
783
801
|
* @typeParam IndexParams - Database platform-specific, index-specific query parameters.
|
|
784
802
|
* @typeParam CF - Optional values-first config literal type for page key narrowing.
|
|
803
|
+
* @typeParam K - Optional projection keys; narrows item shape when provided.
|
|
785
804
|
*
|
|
786
805
|
* @category QueryBuilder
|
|
787
806
|
*/
|
|
788
|
-
declare abstract class BaseQueryBuilder<CC extends BaseConfigMap, EntityClient extends BaseEntityClient<CC>, IndexParams, ET extends EntityToken<CC> = EntityToken<CC>, ITS extends string = string, CF = unknown> {
|
|
807
|
+
declare abstract class BaseQueryBuilder<CC extends BaseConfigMap, EntityClient extends BaseEntityClient<CC>, IndexParams, ET extends EntityToken<CC> = EntityToken<CC>, ITS extends string = string, CF = unknown, K = unknown> {
|
|
789
808
|
/** {@link BaseEntityClient | `EntityClient`} instance. */
|
|
790
809
|
readonly entityClient: EntityClient;
|
|
791
810
|
/** Entity token. */
|
|
@@ -802,15 +821,15 @@ declare abstract class BaseQueryBuilder<CC extends BaseConfigMap, EntityClient e
|
|
|
802
821
|
readonly indexParamsMap: Record<ITS, IndexParams>;
|
|
803
822
|
/** BaseQueryBuilder constructor. */
|
|
804
823
|
constructor(options: BaseQueryBuilderOptions<CC, EntityClient>);
|
|
805
|
-
protected abstract getShardQueryFunction(indexToken: ITS): ShardQueryFunction<CC, ET, ITS, CF>;
|
|
824
|
+
protected abstract getShardQueryFunction(indexToken: ITS): ShardQueryFunction<CC, ET, ITS, CF, K>;
|
|
806
825
|
/**
|
|
807
826
|
* Builds a {@link ShardQueryMap | `ShardQueryMap`} object.
|
|
808
827
|
*
|
|
809
828
|
* @returns - The {@link ShardQueryMap | `ShardQueryMap`} object.
|
|
810
829
|
*/
|
|
811
|
-
build(): ShardQueryMap<CC, ET, ITS, CF>;
|
|
812
|
-
query(options: QueryBuilderQueryOptions<CC, CF>): Promise<QueryResult<CC, ET, ITS>>;
|
|
830
|
+
build(): ShardQueryMap<CC, ET, ITS, CF, K>;
|
|
831
|
+
query(options: QueryBuilderQueryOptions<CC, CF>): Promise<QueryResult<CC, ET, ITS, K>>;
|
|
813
832
|
}
|
|
814
833
|
|
|
815
834
|
export { BaseEntityClient, BaseQueryBuilder, EntityManager, configSchema, createEntityManager };
|
|
816
|
-
export type { BaseConfigMap, BaseEntityClientOptions, BaseQueryBuilderOptions, CapturedConfigMapFrom, Config, ConfigInput, ConfigMap, EntitiesFromSchema, EntityItem, EntityItemByToken, EntityKey, EntityOfToken, EntityRecord, EntityRecordByToken, EntityToken, HasIndexFor, HashKeyFrom, IndexComponentTokens, IndexHashKeyOf, IndexRangeKeyOf, IndexTokensFrom, IndexTokensOf, PageKey, PageKeyByIndex, ParsedConfig, QueryBuilderQueryOptions, QueryOptions, QueryOptionsByCC, QueryOptionsByCF, QueryResult, RangeKeyFrom, ShardBump, ShardQueryFunction, ShardQueryMap, ShardQueryMapByCC, ShardQueryMapByCF, ShardQueryResult, ShardedKeysFrom, TranscodedPropertiesFrom, UnshardedKeysFrom, ValidateConfigMap };
|
|
835
|
+
export type { BaseConfigMap, BaseEntityClientOptions, BaseQueryBuilderOptions, CapturedConfigMapFrom, Config, ConfigInput, ConfigMap, EntitiesFromSchema, EntityItem, EntityItemByToken, EntityKey, EntityOfToken, EntityRecord, EntityRecordByToken, EntityToken, HasIndexFor, HashKeyFrom, IndexComponentTokens, IndexHashKeyOf, IndexRangeKeyOf, IndexTokensFrom, IndexTokensOf, KeysFrom, PageKey, PageKeyByIndex, ParsedConfig, Projected, ProjectedItemByToken, QueryBuilderQueryOptions, QueryOptions, QueryOptionsByCC, QueryOptionsByCF, QueryResult, RangeKeyFrom, ShardBump, ShardQueryFunction, ShardQueryMap, ShardQueryMapByCC, ShardQueryMapByCF, ShardQueryResult, ShardedKeysFrom, TranscodedPropertiesFrom, UnshardedKeysFrom, ValidateConfigMap };
|
|
@@ -7,6 +7,7 @@ import { mapValues } from 'radash';
|
|
|
7
7
|
* @typeParam EntityClient - {@link BaseEntityClient | `BaseEntityClient`} derived class instance.
|
|
8
8
|
* @typeParam IndexParams - Database platform-specific, index-specific query parameters.
|
|
9
9
|
* @typeParam CF - Optional values-first config literal type for page key narrowing.
|
|
10
|
+
* @typeParam K - Optional projection keys; narrows item shape when provided.
|
|
10
11
|
*
|
|
11
12
|
* @category QueryBuilder
|
|
12
13
|
*/
|
|
@@ -26,8 +26,10 @@ const { compressToEncodedURIComponent, decompressFromEncodedURIComponent } = lzS
|
|
|
26
26
|
*/
|
|
27
27
|
async function query(entityManager, options) {
|
|
28
28
|
try {
|
|
29
|
-
// Get defaults.
|
|
30
|
-
const
|
|
29
|
+
// Get defaults (avoid unsafe destructuring on generic access).
|
|
30
|
+
const entityDefaults = entityManager.config.entities[options.entityToken];
|
|
31
|
+
const defaultLimit = entityDefaults.defaultLimit;
|
|
32
|
+
const defaultPageSize = entityDefaults.defaultPageSize;
|
|
31
33
|
// Extract params.
|
|
32
34
|
const { entityToken, limit = defaultLimit, item, pageKeyMap, pageSize = defaultPageSize, shardQueryMap, sortOrder = [], timestampFrom = 0, timestampTo = Date.now(), throttle = entityManager.config.throttle, } = options;
|
|
33
35
|
// Validate params.
|
|
@@ -96,8 +98,12 @@ async function query(entityManager, options) {
|
|
|
96
98
|
break;
|
|
97
99
|
} while (workingResult.items.length < limit);
|
|
98
100
|
// Dedupe & sort working result.
|
|
99
|
-
|
|
101
|
+
// Note: when projecting, callers may omit uniqueProperty/sort keys.
|
|
102
|
+
// We perform operations on the full item shape and then cast back.
|
|
103
|
+
const itemsForOps = workingResult.items;
|
|
104
|
+
const dedupedSorted = sort(unique(itemsForOps, (i) => i[entityManager.config.entities[entityToken]
|
|
100
105
|
.uniqueProperty].toString()), sortOrder);
|
|
106
|
+
workingResult.items = dedupedSorted;
|
|
101
107
|
const result = {
|
|
102
108
|
count: workingResult.items.length,
|
|
103
109
|
items: workingResult.items,
|
package/package.json
CHANGED