@travetto/model-mongo 8.0.0-alpha.0 → 8.0.0-alpha.10
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 +4 -3
- package/package.json +7 -6
- package/src/config.ts +3 -1
- package/src/internal/util.ts +38 -33
- package/src/service.ts +108 -41
package/README.md
CHANGED
|
@@ -19,8 +19,8 @@ Supported features:
|
|
|
19
19
|
* [CRUD](https://github.com/travetto/travetto/tree/main/module/model/src/types/crud.ts#L11)
|
|
20
20
|
* [Expiry](https://github.com/travetto/travetto/tree/main/module/model/src/types/expiry.ts#L10)
|
|
21
21
|
* [Bulk](https://github.com/travetto/travetto/tree/main/module/model/src/types/bulk.ts#L64)
|
|
22
|
-
* [Indexed](https://github.com/travetto/travetto/tree/main/module/model/src/types/indexed.ts#L11)
|
|
23
22
|
* [Blob](https://github.com/travetto/travetto/tree/main/module/model/src/types/blob.ts#L8)
|
|
23
|
+
* [Indexed](https://github.com/travetto/travetto/tree/main/module/model-indexed/src/types/service.ts#L23)
|
|
24
24
|
* [Query Crud](https://github.com/travetto/travetto/tree/main/module/model-query/src/types/crud.ts#L11)
|
|
25
25
|
* [Facet](https://github.com/travetto/travetto/tree/main/module/model-query/src/types/facet.ts#L14)
|
|
26
26
|
* [Query](https://github.com/travetto/travetto/tree/main/module/model-query/src/types/query.ts#L10)
|
|
@@ -43,7 +43,7 @@ export class Init {
|
|
|
43
43
|
}
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
where the [MongoModelConfig](https://github.com/travetto/travetto/tree/main/module/model-mongo/src/config.ts#
|
|
46
|
+
where the [MongoModelConfig](https://github.com/travetto/travetto/tree/main/module/model-mongo/src/config.ts#L24) is defined by:
|
|
47
47
|
|
|
48
48
|
**Code: Structure of MongoModelConfig**
|
|
49
49
|
```typescript
|
|
@@ -104,7 +104,8 @@ export class MongoModelConfig {
|
|
|
104
104
|
/**
|
|
105
105
|
* Load all the ssl certs as needed
|
|
106
106
|
*/
|
|
107
|
-
|
|
107
|
+
@PostConstruct()
|
|
108
|
+
async finalizeConfig(): Promise<void> {
|
|
108
109
|
if (this.connectionString) {
|
|
109
110
|
const details = new URL(this.connectionString);
|
|
110
111
|
this.hosts ??= details.hostname.split(',').filter(host => !!host);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/model-mongo",
|
|
3
|
-
"version": "8.0.0-alpha.
|
|
3
|
+
"version": "8.0.0-alpha.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Mongo backing for the travetto model module.",
|
|
6
6
|
"keywords": [
|
|
@@ -26,13 +26,14 @@
|
|
|
26
26
|
"directory": "module/model-mongo"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@travetto/config": "^8.0.0-alpha.
|
|
30
|
-
"@travetto/model": "^8.0.0-alpha.
|
|
31
|
-
"@travetto/model-
|
|
32
|
-
"
|
|
29
|
+
"@travetto/config": "^8.0.0-alpha.10",
|
|
30
|
+
"@travetto/model": "^8.0.0-alpha.10",
|
|
31
|
+
"@travetto/model-indexed": "^8.0.0-alpha.10",
|
|
32
|
+
"@travetto/model-query": "^8.0.0-alpha.10",
|
|
33
|
+
"mongodb": "^7.1.1"
|
|
33
34
|
},
|
|
34
35
|
"peerDependencies": {
|
|
35
|
-
"@travetto/cli": "^8.0.0-alpha.
|
|
36
|
+
"@travetto/cli": "^8.0.0-alpha.15"
|
|
36
37
|
},
|
|
37
38
|
"peerDependenciesMeta": {
|
|
38
39
|
"@travetto/cli": {
|
package/src/config.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type mongo from 'mongodb';
|
|
|
3
3
|
import { type TimeSpan, Runtime, RuntimeResources, BinaryUtil, CodecUtil, type BinaryType, type BinaryArray } from '@travetto/runtime';
|
|
4
4
|
import { Config } from '@travetto/config';
|
|
5
5
|
import { Field } from '@travetto/schema';
|
|
6
|
+
import { PostConstruct } from '@travetto/di';
|
|
6
7
|
|
|
7
8
|
const readCert = async (input: BinaryType | string): Promise<BinaryArray> => {
|
|
8
9
|
if (BinaryUtil.isBinaryType(input)) {
|
|
@@ -76,7 +77,8 @@ export class MongoModelConfig {
|
|
|
76
77
|
/**
|
|
77
78
|
* Load all the ssl certs as needed
|
|
78
79
|
*/
|
|
79
|
-
|
|
80
|
+
@PostConstruct()
|
|
81
|
+
async finalizeConfig(): Promise<void> {
|
|
80
82
|
if (this.connectionString) {
|
|
81
83
|
const details = new URL(this.connectionString);
|
|
82
84
|
this.hosts ??= details.hostname.split(',').filter(host => !!host);
|
package/src/internal/util.ts
CHANGED
|
@@ -3,15 +3,14 @@ import {
|
|
|
3
3
|
type IndexDescriptionInfo
|
|
4
4
|
} from 'mongodb';
|
|
5
5
|
|
|
6
|
-
import { RuntimeError, CodecUtil, castTo, type Class, toConcrete,
|
|
7
|
-
import { type DistanceUnit, type PageableModelQuery, type WhereClause, ModelQueryUtil } from '@travetto/model-query';
|
|
8
|
-
import type
|
|
6
|
+
import { RuntimeError, CodecUtil, castTo, type Class, toConcrete, BinaryUtil } from '@travetto/runtime';
|
|
7
|
+
import { type DistanceUnit, type PageableModelQuery, type WhereClause, isModelQueryIndex, ModelQueryUtil } from '@travetto/model-query';
|
|
8
|
+
import { type ModelType, type IndexConfig, IndexNotSupported } from '@travetto/model';
|
|
9
9
|
import { DataUtil, SchemaRegistryIndex, type Point } from '@travetto/schema';
|
|
10
|
+
import { isModelIndexedIndex } from '@travetto/model-indexed';
|
|
10
11
|
|
|
11
12
|
const PointConcrete = toConcrete<Point>();
|
|
12
13
|
|
|
13
|
-
type IdxConfig = CreateIndexesOptions;
|
|
14
|
-
|
|
15
14
|
/**
|
|
16
15
|
* Converting units to various radians
|
|
17
16
|
*/
|
|
@@ -25,7 +24,19 @@ const RADIANS_TO: Record<DistanceUnit, number> = {
|
|
|
25
24
|
|
|
26
25
|
export type WithId<T, I = unknown> = T & { _id?: I };
|
|
27
26
|
export type BasicIdx = Record<string, IndexDirection>;
|
|
28
|
-
|
|
27
|
+
|
|
28
|
+
function flattenKeys(obj: Record<string, unknown>, prefix = ''): Record<string, 1 | -1> {
|
|
29
|
+
const out: Record<string, 1 | -1> = {};
|
|
30
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
31
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
32
|
+
if (typeof value === 'object' && value !== null) {
|
|
33
|
+
Object.assign(out, flattenKeys(castTo(value), path));
|
|
34
|
+
} else {
|
|
35
|
+
out[path] = typeof value === 'boolean' ? (value ? 1 : -1) : castTo<-1 | 1>(value);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
29
40
|
|
|
30
41
|
/**
|
|
31
42
|
* Basic mongo utils for conforming to the model module
|
|
@@ -36,19 +47,6 @@ export class MongoUtil {
|
|
|
36
47
|
return `${cls.Ⲑid}__${name}`.replace(/[^a-zA-Z0-9_]+/g, '_');
|
|
37
48
|
}
|
|
38
49
|
|
|
39
|
-
static toIndex<T extends ModelType>(field: IndexField<T>): PlainIdx {
|
|
40
|
-
const keys = [];
|
|
41
|
-
while (typeof field !== 'number' && typeof field !== 'boolean' && Object.keys(field)) {
|
|
42
|
-
const key = TypedObject.keys(field)[0];
|
|
43
|
-
field = castTo(field[key]);
|
|
44
|
-
keys.push(key);
|
|
45
|
-
}
|
|
46
|
-
const rf: number | boolean = castTo(field);
|
|
47
|
-
return {
|
|
48
|
-
[keys.join('.')]: typeof rf === 'boolean' ? (rf ? 1 : 0) : castTo<-1 | 1 | 0>(rf)
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
50
|
static uuid(value: string): Binary {
|
|
53
51
|
try {
|
|
54
52
|
return new Binary(
|
|
@@ -166,8 +164,8 @@ export class MongoUtil {
|
|
|
166
164
|
return out;
|
|
167
165
|
}
|
|
168
166
|
|
|
169
|
-
static getExtraIndices<T extends ModelType>(cls: Class<T>): [BasicIdx,
|
|
170
|
-
const out: [BasicIdx,
|
|
167
|
+
static getExtraIndices<T extends ModelType>(cls: Class<T>): [BasicIdx, CreateIndexesOptions][] {
|
|
168
|
+
const out: [BasicIdx, CreateIndexesOptions][] = [];
|
|
171
169
|
const textFields: string[] = [];
|
|
172
170
|
SchemaRegistryIndex.visitFields(cls, (field, path) => {
|
|
173
171
|
if (field.type === PointConcrete) {
|
|
@@ -185,19 +183,26 @@ export class MongoUtil {
|
|
|
185
183
|
return out;
|
|
186
184
|
}
|
|
187
185
|
|
|
188
|
-
static
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
out =
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
186
|
+
static getIndex(cls: Class, idx: IndexConfig): [BasicIdx, CreateIndexesOptions] {
|
|
187
|
+
const name = this.namespaceIndex(cls, idx.name);
|
|
188
|
+
if (isModelQueryIndex(idx)) {
|
|
189
|
+
const out = idx.fields.reduce(
|
|
190
|
+
(acc, field) => ({ ...acc, ...flattenKeys(castTo(field)) }),
|
|
191
|
+
castTo<Record<string, -1 | 0 | 1>>({}));
|
|
195
192
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
193
|
+
return [out, { name, unique: idx.type === 'query:unique', }];
|
|
194
|
+
} else if (isModelIndexedIndex(idx)) {
|
|
195
|
+
const filter = Object.fromEntries([
|
|
196
|
+
...idx.keyTemplate.map(({ path }) => [path.join('.'), 1]),
|
|
197
|
+
...idx.sortTemplate.map(({ path, value }) => [path.join('.'), value === -1 ? -1 : 1])
|
|
198
|
+
]);
|
|
199
|
+
switch (idx.type) {
|
|
200
|
+
case 'indexed:keyed': return [filter, { name, unique: idx.unique }];
|
|
201
|
+
case 'indexed:sorted': return [filter, { name }];
|
|
202
|
+
}
|
|
203
|
+
} else {
|
|
204
|
+
throw new IndexNotSupported(cls, idx);
|
|
205
|
+
}
|
|
201
206
|
}
|
|
202
207
|
|
|
203
208
|
static prepareCursor<T extends ModelType>(cls: Class<T>, cursor: FindCursor<T | MongoWithId<T>>, query: PageableModelQuery<T>): FindCursor<T> {
|
package/src/service.ts
CHANGED
|
@@ -3,13 +3,13 @@ import {
|
|
|
3
3
|
type Db, GridFSBucket, MongoClient, type GridFSFile, type Collection,
|
|
4
4
|
type ObjectId, type RootFilterOperators, type Filter,
|
|
5
5
|
type WithId as MongoWithId,
|
|
6
|
+
type FindCursor,
|
|
6
7
|
} from 'mongodb';
|
|
7
8
|
|
|
8
9
|
import {
|
|
9
|
-
ModelRegistryIndex, type ModelType, type OptionalId, type ModelCrudSupport, type ModelStorageSupport,
|
|
10
|
-
type
|
|
11
|
-
|
|
12
|
-
ModelCrudUtil, ModelIndexedUtil, ModelStorageUtil, ModelExpiryUtil, ModelBulkUtil
|
|
10
|
+
ModelRegistryIndex, type ModelType, type OptionalId, type ModelCrudSupport, type ModelStorageSupport, type ModelExpirySupport,
|
|
11
|
+
type ModelBulkSupport, type BulkOperation, type BulkResponse, NotFoundError, ExistsError, type ModelBlobSupport,
|
|
12
|
+
ModelCrudUtil, ModelStorageUtil, ModelExpiryUtil, ModelBulkUtil,
|
|
13
13
|
} from '@travetto/model';
|
|
14
14
|
import {
|
|
15
15
|
type ModelQuery, type ModelQueryCrudSupport, type ModelQueryFacetSupport, type ModelQuerySupport,
|
|
@@ -17,18 +17,22 @@ import {
|
|
|
17
17
|
QueryVerifier, ModelQueryUtil, ModelQuerySuggestUtil, ModelQueryCrudUtil,
|
|
18
18
|
type ModelQueryFacet,
|
|
19
19
|
} from '@travetto/model-query';
|
|
20
|
+
import {
|
|
21
|
+
type ModelIndexedSupport, type KeyedIndexSelection, type KeyedIndexBody, type ListPageOptions, ModelIndexedUtil,
|
|
22
|
+
type SingleItemIndex, type SortedIndexSelection, type ListPageResult, type SortedIndex, type FullKeyedIndexBody,
|
|
23
|
+
type FullKeyedIndexWithPartialBody, ModelIndexedComputedIndex,
|
|
24
|
+
} from '@travetto/model-indexed';
|
|
20
25
|
|
|
21
26
|
import {
|
|
22
|
-
ShutdownManager, type Class,
|
|
27
|
+
ShutdownManager, type Class, TypedObject,
|
|
23
28
|
castTo, asFull, type BinaryMetadata, type ByteRange, type BinaryType, BinaryUtil, BinaryMetadataUtil,
|
|
29
|
+
JSONUtil,
|
|
24
30
|
} from '@travetto/runtime';
|
|
25
|
-
import { Injectable } from '@travetto/di';
|
|
31
|
+
import { Injectable, PostConstruct } from '@travetto/di';
|
|
26
32
|
|
|
27
|
-
import { MongoUtil, type
|
|
33
|
+
import { MongoUtil, type WithId } from './internal/util.ts';
|
|
28
34
|
import type { MongoModelConfig } from './config.ts';
|
|
29
35
|
|
|
30
|
-
const ListIndexSymbol = Symbol();
|
|
31
|
-
|
|
32
36
|
type BlobRaw = GridFSFile & { metadata?: BinaryMetadata };
|
|
33
37
|
|
|
34
38
|
type MongoTextSearch = RootFilterOperators<unknown>['$text'];
|
|
@@ -54,6 +58,30 @@ export class MongoModelService implements
|
|
|
54
58
|
|
|
55
59
|
constructor(config: MongoModelConfig) { this.config = config; }
|
|
56
60
|
|
|
61
|
+
async #buildIndexQuery<
|
|
62
|
+
T extends ModelType,
|
|
63
|
+
K extends KeyedIndexSelection<T>,
|
|
64
|
+
S extends SortedIndexSelection<T>
|
|
65
|
+
>(
|
|
66
|
+
cls: Class<T>,
|
|
67
|
+
idx: SortedIndex<T, K, S>,
|
|
68
|
+
body: KeyedIndexBody<T, K>
|
|
69
|
+
): Promise<FindCursor> {
|
|
70
|
+
const store = await this.getStore(cls);
|
|
71
|
+
const computed = ModelIndexedComputedIndex.get(idx, body).validate();
|
|
72
|
+
|
|
73
|
+
const where = this.getWhereFilter(cls, castTo(computed.project()));
|
|
74
|
+
|
|
75
|
+
let q = store.find(where, { timeout: true })
|
|
76
|
+
.batchSize(100);
|
|
77
|
+
|
|
78
|
+
// TODO: We could cache this
|
|
79
|
+
if ('sort' in idx) {
|
|
80
|
+
q = q.sort(idx.sortTemplate.map(({ path, value }) => [path.join('.'), value] as const));
|
|
81
|
+
}
|
|
82
|
+
return q;
|
|
83
|
+
}
|
|
84
|
+
|
|
57
85
|
restoreId(item: { id?: string, _id?: unknown }): void {
|
|
58
86
|
if (item._id) {
|
|
59
87
|
item.id ??= MongoUtil.idToString(castTo(item._id));
|
|
@@ -98,7 +126,8 @@ export class MongoModelService implements
|
|
|
98
126
|
return files[0];
|
|
99
127
|
}
|
|
100
128
|
|
|
101
|
-
|
|
129
|
+
@PostConstruct()
|
|
130
|
+
async initializeClient(): Promise<void> {
|
|
102
131
|
this.client = await MongoClient.connect(this.config.url, {
|
|
103
132
|
...this.config.connectionOptions,
|
|
104
133
|
useBigInt64: true,
|
|
@@ -130,7 +159,10 @@ export class MongoModelService implements
|
|
|
130
159
|
|
|
131
160
|
async upsertModel(cls: Class): Promise<void> {
|
|
132
161
|
const col = await this.getStore(cls);
|
|
133
|
-
const indices =
|
|
162
|
+
const indices = [
|
|
163
|
+
...ModelRegistryIndex.getIndices(cls).map(idx => MongoUtil.getIndex(cls, idx)),
|
|
164
|
+
...MongoUtil.getExtraIndices(cls)
|
|
165
|
+
];
|
|
134
166
|
const existingIndices = (await col.indexes().catch(() => [])).filter(idx => idx.name !== '_id_');
|
|
135
167
|
|
|
136
168
|
const pendingMap = Object.fromEntries(indices.map(pair => [pair[1].name!, pair]));
|
|
@@ -404,54 +436,89 @@ export class MongoModelService implements
|
|
|
404
436
|
}
|
|
405
437
|
|
|
406
438
|
// Indexed
|
|
407
|
-
async getByIndex<
|
|
408
|
-
|
|
439
|
+
async getByIndex<
|
|
440
|
+
T extends ModelType,
|
|
441
|
+
K extends KeyedIndexSelection<T>,
|
|
442
|
+
S extends SortedIndexSelection<T>
|
|
443
|
+
>(cls: Class<T>, idx: SingleItemIndex<T, K, S>, body: FullKeyedIndexBody<T, K, S>): Promise<T> {
|
|
409
444
|
const store = await this.getStore(cls);
|
|
445
|
+
|
|
446
|
+
const computed = ModelIndexedComputedIndex.get(idx, body).validate({ sort: true });
|
|
447
|
+
|
|
410
448
|
const result = await store.findOne(
|
|
411
|
-
this.getWhereFilter(
|
|
412
|
-
cls,
|
|
413
|
-
castTo(ModelIndexedUtil.projectIndex(cls, idx, body))
|
|
414
|
-
)
|
|
449
|
+
this.getWhereFilter(cls, castTo(computed.project({ sort: true })))
|
|
415
450
|
);
|
|
416
451
|
if (!result) {
|
|
417
|
-
throw new NotFoundError(`${cls.name}: ${idx}`,
|
|
452
|
+
throw new NotFoundError(`${cls.name}: ${idx}`, computed.getKey({ sort: true }));
|
|
418
453
|
}
|
|
419
454
|
return await this.postLoad(cls, result);
|
|
455
|
+
|
|
420
456
|
}
|
|
421
457
|
|
|
422
|
-
async deleteByIndex<
|
|
423
|
-
|
|
458
|
+
async deleteByIndex<
|
|
459
|
+
T extends ModelType,
|
|
460
|
+
K extends KeyedIndexSelection<T>,
|
|
461
|
+
S extends SortedIndexSelection<T>
|
|
462
|
+
>(cls: Class<T>, idx: SingleItemIndex<T, K, S>, body: FullKeyedIndexBody<T, K, S>): Promise<void> {
|
|
424
463
|
const store = await this.getStore(cls);
|
|
464
|
+
const computed = ModelIndexedComputedIndex.get(idx, body).validate({ sort: true });
|
|
465
|
+
|
|
425
466
|
const result = await store.deleteOne(
|
|
426
|
-
this.getWhereFilter(
|
|
427
|
-
cls,
|
|
428
|
-
castTo(ModelIndexedUtil.projectIndex(cls, idx, body))
|
|
429
|
-
)
|
|
467
|
+
this.getWhereFilter(cls, castTo(computed.project({ sort: true })))
|
|
430
468
|
);
|
|
431
|
-
if (result.deletedCount) {
|
|
432
|
-
|
|
469
|
+
if (!result.deletedCount) {
|
|
470
|
+
throw new NotFoundError(`${cls.name}: ${idx}`, computed.getKey({ sort: true }));
|
|
433
471
|
}
|
|
434
|
-
throw new NotFoundError(`${cls.name}: ${idx}`, key);
|
|
435
472
|
}
|
|
436
473
|
|
|
437
|
-
|
|
474
|
+
upsertByIndex<
|
|
475
|
+
T extends ModelType,
|
|
476
|
+
K extends KeyedIndexSelection<T>,
|
|
477
|
+
S extends SortedIndexSelection<T>
|
|
478
|
+
>(cls: Class<T>, idx: SingleItemIndex<T, K, S>, body: OptionalId<T>): Promise<T> {
|
|
438
479
|
return ModelIndexedUtil.naiveUpsert(this, cls, idx, body);
|
|
439
480
|
}
|
|
440
481
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
482
|
+
updateByIndex<
|
|
483
|
+
T extends ModelType,
|
|
484
|
+
K extends KeyedIndexSelection<T>,
|
|
485
|
+
S extends SortedIndexSelection<T>
|
|
486
|
+
>(cls: Class<T>, idx: SingleItemIndex<T, K, S>, body: T): Promise<T> {
|
|
487
|
+
return ModelIndexedUtil.naiveUpdate(this, cls, idx, body);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
async updatePartialByIndex<
|
|
491
|
+
T extends ModelType,
|
|
492
|
+
K extends KeyedIndexSelection<T>,
|
|
493
|
+
S extends SortedIndexSelection<T>
|
|
494
|
+
>(cls: Class<T>, idx: SingleItemIndex<T, K>, body: FullKeyedIndexWithPartialBody<T, K, S>): Promise<T> {
|
|
495
|
+
const item = await ModelCrudUtil.naivePartialUpdate(cls, () => this.getByIndex(cls, idx, castTo(body)), castTo(body));
|
|
496
|
+
return this.update(cls, item);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
async listByIndex<
|
|
500
|
+
T extends ModelType,
|
|
501
|
+
K extends KeyedIndexSelection<T>,
|
|
502
|
+
S extends SortedIndexSelection<T>
|
|
503
|
+
>(
|
|
504
|
+
cls: Class<T>,
|
|
505
|
+
idx: SortedIndex<T, K, S>,
|
|
506
|
+
body: KeyedIndexBody<T, K>,
|
|
507
|
+
options?: ListPageOptions,
|
|
508
|
+
): Promise<ListPageResult<T>> {
|
|
509
|
+
{
|
|
510
|
+
const offset = options?.offset ? JSONUtil.fromBase64<number>(options.offset) : 0;
|
|
511
|
+
const limit = options?.limit ?? 100;
|
|
512
|
+
const cursor = (await this.#buildIndexQuery(cls, idx, body))
|
|
513
|
+
.limit(limit)
|
|
514
|
+
.skip(offset);
|
|
515
|
+
|
|
516
|
+
const items: T[] = [];
|
|
517
|
+
for await (const item of cursor) {
|
|
518
|
+
items.push(await this.postLoad(cls, item));
|
|
519
|
+
}
|
|
520
|
+
return { items, nextOffset: items.length ? JSONUtil.toBase64(offset + items.length) : undefined };
|
|
452
521
|
|
|
453
|
-
for await (const item of cursor) {
|
|
454
|
-
yield await this.postLoad(cls, item);
|
|
455
522
|
}
|
|
456
523
|
}
|
|
457
524
|
|