@powersync/service-module-mongodb-storage 0.0.0-dev-20260203155513 → 0.0.0-dev-20260223080959
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/CHANGELOG.md +56 -10
- package/dist/migrations/db/migrations/1770213298299-storage-version.js +29 -0
- package/dist/migrations/db/migrations/1770213298299-storage-version.js.map +1 -0
- package/dist/storage/MongoBucketStorage.d.ts +7 -15
- package/dist/storage/MongoBucketStorage.js +12 -51
- package/dist/storage/MongoBucketStorage.js.map +1 -1
- package/dist/storage/MongoReportStorage.d.ts +1 -11
- package/dist/storage/MongoReportStorage.js +1 -321
- package/dist/storage/MongoReportStorage.js.map +1 -1
- package/dist/storage/implementation/MongoChecksums.d.ts +5 -2
- package/dist/storage/implementation/MongoChecksums.js +7 -4
- package/dist/storage/implementation/MongoChecksums.js.map +1 -1
- package/dist/storage/implementation/MongoCompactor.d.ts +16 -1
- package/dist/storage/implementation/MongoCompactor.js +80 -23
- package/dist/storage/implementation/MongoCompactor.js.map +1 -1
- package/dist/storage/implementation/MongoPersistedSyncRulesContent.d.ts +2 -12
- package/dist/storage/implementation/MongoPersistedSyncRulesContent.js +23 -24
- package/dist/storage/implementation/MongoPersistedSyncRulesContent.js.map +1 -1
- package/dist/storage/implementation/MongoSyncBucketStorage.d.ts +5 -2
- package/dist/storage/implementation/MongoSyncBucketStorage.js +42 -40
- package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
- package/dist/storage/implementation/db.d.ts +0 -10
- package/dist/storage/implementation/db.js +0 -30
- package/dist/storage/implementation/db.js.map +1 -1
- package/dist/storage/implementation/models.d.ts +11 -0
- package/dist/storage/implementation/models.js +9 -1
- package/dist/storage/implementation/models.js.map +1 -1
- package/dist/storage/storage-index.d.ts +0 -1
- package/dist/storage/storage-index.js +0 -1
- package/dist/storage/storage-index.js.map +1 -1
- package/dist/utils/test-utils.d.ts +3 -4
- package/dist/utils/test-utils.js +2 -2
- package/dist/utils/test-utils.js.map +1 -1
- package/dist/utils/util.d.ts +0 -7
- package/dist/utils/util.js +3 -27
- package/dist/utils/util.js.map +1 -1
- package/package.json +7 -7
- package/src/migrations/db/migrations/1770213298299-storage-version.ts +44 -0
- package/src/storage/MongoBucketStorage.ts +20 -59
- package/src/storage/MongoReportStorage.ts +4 -369
- package/src/storage/implementation/MongoChecksums.ts +14 -6
- package/src/storage/implementation/MongoCompactor.ts +94 -25
- package/src/storage/implementation/MongoPersistedSyncRulesContent.ts +25 -32
- package/src/storage/implementation/MongoSyncBucketStorage.ts +60 -44
- package/src/storage/implementation/db.ts +0 -32
- package/src/storage/implementation/models.ts +23 -0
- package/src/storage/storage-index.ts +0 -1
- package/src/utils/test-utils.ts +3 -4
- package/src/utils/util.ts +3 -36
- package/test/src/__snapshots__/storage_sync.test.ts.snap +1116 -21
- package/test/src/compression.test.ts +17 -0
- package/test/src/connection-report-storage.test.ts +6 -2
- package/test/src/storage_compacting.test.ts +29 -22
- package/test/src/storage_sync.test.ts +27 -14
- package/test/src/util.ts +3 -0
- package/test/tsconfig.json +3 -7
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/migrations/db/migrations/1770037239303-sync-reporting.js +0 -44
- package/dist/migrations/db/migrations/1770037239303-sync-reporting.js.map +0 -1
- package/dist/storage/implementation/MongoPersistedSyncRules.d.ts +0 -10
- package/dist/storage/implementation/MongoPersistedSyncRules.js +0 -17
- package/dist/storage/implementation/MongoPersistedSyncRules.js.map +0 -1
- package/src/migrations/db/migrations/1770037239303-sync-reporting.ts +0 -74
- package/src/storage/implementation/MongoPersistedSyncRules.ts +0 -20
- package/test/src/__snapshots__/storage.test.ts.snap +0 -25
- /package/dist/migrations/db/migrations/{1770037239303-sync-reporting.d.ts → 1770213298299-storage-version.d.ts} +0 -0
|
@@ -1,48 +1,41 @@
|
|
|
1
1
|
import { mongo } from '@powersync/lib-service-mongodb';
|
|
2
2
|
import { storage } from '@powersync/service-core';
|
|
3
|
-
import { SqlSyncRules } from '@powersync/service-sync-rules';
|
|
4
|
-
import { MongoPersistedSyncRules } from './MongoPersistedSyncRules.js';
|
|
5
3
|
import { MongoSyncRulesLock } from './MongoSyncRulesLock.js';
|
|
6
4
|
import { PowerSyncMongo } from './db.js';
|
|
7
|
-
import { SyncRuleDocument } from './models.js';
|
|
8
|
-
|
|
9
|
-
export class MongoPersistedSyncRulesContent implements storage.PersistedSyncRulesContent {
|
|
10
|
-
public readonly slot_name: string;
|
|
11
|
-
|
|
12
|
-
public readonly id: number;
|
|
13
|
-
public readonly sync_rules_content: string;
|
|
14
|
-
public readonly last_checkpoint_lsn: string | null;
|
|
15
|
-
public readonly last_fatal_error: string | null;
|
|
16
|
-
public readonly last_fatal_error_ts: Date | null;
|
|
17
|
-
public readonly last_keepalive_ts: Date | null;
|
|
18
|
-
public readonly last_checkpoint_ts: Date | null;
|
|
19
|
-
public readonly active: boolean;
|
|
5
|
+
import { getMongoStorageConfig, SyncRuleDocument } from './models.js';
|
|
6
|
+
import { ErrorCode, ServiceError } from '@powersync/lib-services-framework';
|
|
20
7
|
|
|
8
|
+
export class MongoPersistedSyncRulesContent extends storage.PersistedSyncRulesContent {
|
|
21
9
|
public current_lock: MongoSyncRulesLock | null = null;
|
|
22
10
|
|
|
23
11
|
constructor(
|
|
24
12
|
private db: PowerSyncMongo,
|
|
25
13
|
doc: mongo.WithId<SyncRuleDocument>
|
|
26
14
|
) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
15
|
+
super({
|
|
16
|
+
id: doc._id,
|
|
17
|
+
sync_rules_content: doc.content,
|
|
18
|
+
last_checkpoint_lsn: doc.last_checkpoint_lsn,
|
|
19
|
+
// Handle legacy values
|
|
20
|
+
slot_name: doc.slot_name ?? `powersync_${doc._id}`,
|
|
21
|
+
last_fatal_error: doc.last_fatal_error,
|
|
22
|
+
last_fatal_error_ts: doc.last_fatal_error_ts,
|
|
23
|
+
last_checkpoint_ts: doc.last_checkpoint_ts,
|
|
24
|
+
last_keepalive_ts: doc.last_keepalive_ts,
|
|
25
|
+
active: doc.state == 'ACTIVE',
|
|
26
|
+
storageVersion: doc.storage_version ?? storage.LEGACY_STORAGE_VERSION
|
|
27
|
+
});
|
|
37
28
|
}
|
|
38
29
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
30
|
+
getStorageConfig() {
|
|
31
|
+
const storageConfig = getMongoStorageConfig(this.storageVersion);
|
|
32
|
+
if (storageConfig == null) {
|
|
33
|
+
throw new ServiceError(
|
|
34
|
+
ErrorCode.PSYNC_S1005,
|
|
35
|
+
`Unsupported storage version ${this.storageVersion} for sync rules ${this.id}`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
return storageConfig;
|
|
46
39
|
}
|
|
47
40
|
|
|
48
41
|
async lock() {
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
InternalOpId,
|
|
16
16
|
internalToExternalOpId,
|
|
17
17
|
maxLsn,
|
|
18
|
+
mergeAsyncIterables,
|
|
18
19
|
PopulateChecksumCacheOptions,
|
|
19
20
|
PopulateChecksumCacheResults,
|
|
20
21
|
ProtocolOpId,
|
|
@@ -31,7 +32,14 @@ import * as timers from 'timers/promises';
|
|
|
31
32
|
import { idPrefixFilter, mapOpEntry, readSingleBatch, setSessionSnapshotTime } from '../../utils/util.js';
|
|
32
33
|
import { MongoBucketStorage } from '../MongoBucketStorage.js';
|
|
33
34
|
import { PowerSyncMongo } from './db.js';
|
|
34
|
-
import {
|
|
35
|
+
import {
|
|
36
|
+
BucketDataDocument,
|
|
37
|
+
BucketDataKey,
|
|
38
|
+
BucketStateDocument,
|
|
39
|
+
SourceKey,
|
|
40
|
+
SourceTableDocument,
|
|
41
|
+
StorageConfig
|
|
42
|
+
} from './models.js';
|
|
35
43
|
import { MongoBucketBatch } from './MongoBucketBatch.js';
|
|
36
44
|
import { MongoChecksumOptions, MongoChecksums } from './MongoChecksums.js';
|
|
37
45
|
import { MongoCompactor } from './MongoCompactor.js';
|
|
@@ -39,7 +47,8 @@ import { MongoParameterCompactor } from './MongoParameterCompactor.js';
|
|
|
39
47
|
import { MongoWriteCheckpointAPI } from './MongoWriteCheckpointAPI.js';
|
|
40
48
|
|
|
41
49
|
export interface MongoSyncBucketStorageOptions {
|
|
42
|
-
checksumOptions?: MongoChecksumOptions
|
|
50
|
+
checksumOptions?: Omit<MongoChecksumOptions, 'storageConfig'>;
|
|
51
|
+
storageConfig: StorageConfig;
|
|
43
52
|
}
|
|
44
53
|
|
|
45
54
|
/**
|
|
@@ -68,12 +77,15 @@ export class MongoSyncBucketStorage
|
|
|
68
77
|
public readonly group_id: number,
|
|
69
78
|
private readonly sync_rules: storage.PersistedSyncRulesContent,
|
|
70
79
|
public readonly slot_name: string,
|
|
71
|
-
writeCheckpointMode
|
|
72
|
-
options
|
|
80
|
+
writeCheckpointMode: storage.WriteCheckpointMode | undefined,
|
|
81
|
+
options: MongoSyncBucketStorageOptions
|
|
73
82
|
) {
|
|
74
83
|
super();
|
|
75
84
|
this.db = factory.db;
|
|
76
|
-
this.checksums = new MongoChecksums(this.db, this.group_id,
|
|
85
|
+
this.checksums = new MongoChecksums(this.db, this.group_id, {
|
|
86
|
+
...options.checksumOptions,
|
|
87
|
+
storageConfig: options?.storageConfig
|
|
88
|
+
});
|
|
77
89
|
this.writeCheckpointAPI = new MongoWriteCheckpointAPI({
|
|
78
90
|
db: this.db,
|
|
79
91
|
mode: writeCheckpointMode ?? storage.WriteCheckpointMode.MANAGED,
|
|
@@ -694,53 +706,39 @@ export class MongoSyncBucketStorage
|
|
|
694
706
|
* Instance-wide watch on the latest available checkpoint (op_id + lsn).
|
|
695
707
|
*/
|
|
696
708
|
private async *watchActiveCheckpoint(signal: AbortSignal): AsyncIterable<ReplicationCheckpoint> {
|
|
697
|
-
const stream = this.checkpointChangesStream(signal);
|
|
698
|
-
|
|
699
709
|
if (signal.aborted) {
|
|
700
710
|
return;
|
|
701
711
|
}
|
|
702
712
|
|
|
713
|
+
// If the stream is idle, we wait a max of a minute (CHECKPOINT_TIMEOUT_MS) before we get another checkpoint,
|
|
714
|
+
// to avoid stale checkpoint snapshots. This is what checkpointTimeoutStream() is for.
|
|
715
|
+
// Essentially, even if there are no actual checkpoint changes, we want a new snapshotTime every minute or so,
|
|
716
|
+
// to ensure that any new clients connecting will get a valid snapshotTime.
|
|
717
|
+
const stream = mergeAsyncIterables(
|
|
718
|
+
[this.checkpointChangesStream(signal), this.checkpointTimeoutStream(signal)],
|
|
719
|
+
signal
|
|
720
|
+
);
|
|
721
|
+
|
|
703
722
|
// We only watch changes to the active sync rules.
|
|
704
723
|
// If it changes to inactive, we abort and restart with the new sync rules.
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
//
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
.setTimeout(CHECKPOINT_TIMEOUT_MS, { done: false }, { signal })
|
|
711
|
-
.catch(() => ({ done: true }));
|
|
712
|
-
try {
|
|
713
|
-
const result = await Promise.race([stream.next(), timeout]);
|
|
714
|
-
if (result.done) {
|
|
715
|
-
break;
|
|
716
|
-
}
|
|
717
|
-
} catch (e) {
|
|
718
|
-
if (e.name == 'AbortError') {
|
|
719
|
-
break;
|
|
720
|
-
}
|
|
721
|
-
throw e;
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
if (signal.aborted) {
|
|
725
|
-
// Would likely have been caught by the signal on the timeout or the upstream stream, but we check here anyway
|
|
726
|
-
break;
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
const op = await this.getCheckpointInternal();
|
|
730
|
-
if (op == null) {
|
|
731
|
-
// Sync rules have changed - abort and restart.
|
|
732
|
-
// We do a soft close of the stream here - no error
|
|
733
|
-
break;
|
|
734
|
-
}
|
|
724
|
+
for await (const _ of stream) {
|
|
725
|
+
if (signal.aborted) {
|
|
726
|
+
// Would likely have been caught by the signal on the timeout or the upstream stream, but we check here anyway
|
|
727
|
+
break;
|
|
728
|
+
}
|
|
735
729
|
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
//
|
|
739
|
-
//
|
|
740
|
-
|
|
730
|
+
const op = await this.getCheckpointInternal();
|
|
731
|
+
if (op == null) {
|
|
732
|
+
// Sync rules have changed - abort and restart.
|
|
733
|
+
// We do a soft close of the stream here - no error
|
|
734
|
+
break;
|
|
741
735
|
}
|
|
742
|
-
|
|
743
|
-
|
|
736
|
+
|
|
737
|
+
// Previously, we only yielded when the checkpoint or lsn changed.
|
|
738
|
+
// However, we always want to use the latest snapshotTime, so we skip that filtering here.
|
|
739
|
+
// That filtering could be added in the per-user streams if needed, but in general the capped collection
|
|
740
|
+
// should already only contain useful changes in most cases.
|
|
741
|
+
yield op;
|
|
744
742
|
}
|
|
745
743
|
}
|
|
746
744
|
|
|
@@ -900,6 +898,24 @@ export class MongoSyncBucketStorage
|
|
|
900
898
|
}
|
|
901
899
|
}
|
|
902
900
|
|
|
901
|
+
private async *checkpointTimeoutStream(signal: AbortSignal): AsyncGenerator<void> {
|
|
902
|
+
while (!signal.aborted) {
|
|
903
|
+
try {
|
|
904
|
+
await timers.setTimeout(CHECKPOINT_TIMEOUT_MS, undefined, { signal });
|
|
905
|
+
} catch (e) {
|
|
906
|
+
if (e.name == 'AbortError') {
|
|
907
|
+
// This is how we typically abort this stream, when all listeners are done
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
throw e;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
if (!signal.aborted) {
|
|
914
|
+
yield;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
|
|
903
919
|
private async getDataBucketChanges(
|
|
904
920
|
options: GetCheckpointChangesOptions
|
|
905
921
|
): Promise<Pick<CheckpointChanges, 'updatedDataBuckets' | 'invalidateDataBuckets'>> {
|
|
@@ -39,8 +39,6 @@ export class PowerSyncMongo {
|
|
|
39
39
|
readonly bucket_state: mongo.Collection<BucketStateDocument>;
|
|
40
40
|
readonly checkpoint_events: mongo.Collection<CheckpointEventDocument>;
|
|
41
41
|
readonly connection_report_events: mongo.Collection<ClientConnectionDocument>;
|
|
42
|
-
readonly sync_report_events: mongo.Collection<any>;
|
|
43
|
-
readonly bucket_report_events: mongo.Collection<any>;
|
|
44
42
|
|
|
45
43
|
readonly client: mongo.MongoClient;
|
|
46
44
|
readonly db: mongo.Db;
|
|
@@ -66,8 +64,6 @@ export class PowerSyncMongo {
|
|
|
66
64
|
this.bucket_state = this.db.collection('bucket_state');
|
|
67
65
|
this.checkpoint_events = this.db.collection('checkpoint_events');
|
|
68
66
|
this.connection_report_events = this.db.collection('connection_report_events');
|
|
69
|
-
this.sync_report_events = this.db.collection('sync_report_events');
|
|
70
|
-
this.bucket_report_events = this.db.collection('bucket_report_events');
|
|
71
67
|
}
|
|
72
68
|
|
|
73
69
|
/**
|
|
@@ -149,34 +145,6 @@ export class PowerSyncMongo {
|
|
|
149
145
|
await this.db.createCollection('connection_report_events');
|
|
150
146
|
}
|
|
151
147
|
|
|
152
|
-
/**
|
|
153
|
-
* Only use in migrations and tests.
|
|
154
|
-
*/
|
|
155
|
-
async createSyncReportingCollection() {
|
|
156
|
-
const existingCollections = await this.db
|
|
157
|
-
.listCollections({ name: 'sync_report_events' }, { nameOnly: false })
|
|
158
|
-
.toArray();
|
|
159
|
-
const collection = existingCollections[0];
|
|
160
|
-
if (collection != null) {
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
await this.db.createCollection('sync_report_events');
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Only use in migrations and tests.
|
|
168
|
-
*/
|
|
169
|
-
async createBucketReportingCollection() {
|
|
170
|
-
const existingCollections = await this.db
|
|
171
|
-
.listCollections({ name: 'bucket_report_events' }, { nameOnly: false })
|
|
172
|
-
.toArray();
|
|
173
|
-
const collection = existingCollections[0];
|
|
174
|
-
if (collection != null) {
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
await this.db.createCollection('bucket_report_events');
|
|
178
|
-
}
|
|
179
|
-
|
|
180
148
|
/**
|
|
181
149
|
* Only use in migrations and tests.
|
|
182
150
|
*/
|
|
@@ -204,6 +204,29 @@ export interface SyncRuleDocument {
|
|
|
204
204
|
id: string;
|
|
205
205
|
expires_at: Date;
|
|
206
206
|
} | null;
|
|
207
|
+
|
|
208
|
+
storage_version?: number;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export interface StorageConfig extends storage.StorageVersionConfig {
|
|
212
|
+
/**
|
|
213
|
+
* When true, bucket_data.checksum is guaranteed to be persisted as a Long.
|
|
214
|
+
*
|
|
215
|
+
* When false, it could also have been persisted as an Int32 or Double, in which case it must be converted to
|
|
216
|
+
* a Long before summing.
|
|
217
|
+
*/
|
|
218
|
+
longChecksums: boolean;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const LONG_CHECKSUMS_STORAGE_VERSION = 2;
|
|
222
|
+
|
|
223
|
+
export function getMongoStorageConfig(storageVersion: number): StorageConfig | undefined {
|
|
224
|
+
const baseConfig = storage.STORAGE_VERSION_CONFIG[storageVersion];
|
|
225
|
+
if (baseConfig == null) {
|
|
226
|
+
return undefined;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return { ...baseConfig, longChecksums: storageVersion >= LONG_CHECKSUMS_STORAGE_VERSION };
|
|
207
230
|
}
|
|
208
231
|
|
|
209
232
|
export interface CheckpointEventDocument {
|
|
@@ -2,7 +2,6 @@ export * from './implementation/db.js';
|
|
|
2
2
|
export * from './implementation/models.js';
|
|
3
3
|
export * from './implementation/MongoBucketBatch.js';
|
|
4
4
|
export * from './implementation/MongoIdSequence.js';
|
|
5
|
-
export * from './implementation/MongoPersistedSyncRules.js';
|
|
6
5
|
export * from './implementation/MongoPersistedSyncRulesContent.js';
|
|
7
6
|
export * from './implementation/MongoStorageProvider.js';
|
|
8
7
|
export * from './implementation/MongoSyncBucketStorage.js';
|
package/src/utils/test-utils.ts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { mongo } from '@powersync/lib-service-mongodb';
|
|
2
|
-
import { PowerSyncMongo } from '../storage/implementation/db.js';
|
|
3
2
|
import { TestStorageOptions } from '@powersync/service-core';
|
|
3
|
+
import { MongoBucketStorage, MongoBucketStorageOptions } from '../storage/MongoBucketStorage.js';
|
|
4
4
|
import { MongoReportStorage } from '../storage/MongoReportStorage.js';
|
|
5
|
-
import {
|
|
6
|
-
import { MongoSyncBucketStorageOptions } from '../storage/implementation/MongoSyncBucketStorage.js';
|
|
5
|
+
import { PowerSyncMongo } from '../storage/implementation/db.js';
|
|
7
6
|
|
|
8
7
|
export type MongoTestStorageOptions = {
|
|
9
8
|
url: string;
|
|
10
9
|
isCI: boolean;
|
|
11
|
-
internalOptions?:
|
|
10
|
+
internalOptions?: MongoBucketStorageOptions;
|
|
12
11
|
};
|
|
13
12
|
|
|
14
13
|
export function mongoTestStorageFactoryGenerator(factoryOptions: MongoTestStorageOptions) {
|
package/src/utils/util.ts
CHANGED
|
@@ -142,6 +142,9 @@ export const createPaginatedConnectionQuery = async <T extends mongo.Document>(
|
|
|
142
142
|
|
|
143
143
|
const items = await findCursor.limit(limit).toArray();
|
|
144
144
|
const count = items.length;
|
|
145
|
+
/** The returned total has been defaulted to 0 due to the overhead using documentCount from the mogo driver.
|
|
146
|
+
* cursor.count has been deprecated.
|
|
147
|
+
* */
|
|
145
148
|
return {
|
|
146
149
|
items,
|
|
147
150
|
count,
|
|
@@ -150,39 +153,3 @@ export const createPaginatedConnectionQuery = async <T extends mongo.Document>(
|
|
|
150
153
|
more: !(count !== limit)
|
|
151
154
|
};
|
|
152
155
|
};
|
|
153
|
-
|
|
154
|
-
export const createPaginatedSyncCheckpointQuery = async <T extends mongo.Document>(
|
|
155
|
-
query: mongo.Filter<T>,
|
|
156
|
-
collection: mongo.Collection<T>,
|
|
157
|
-
limit: number,
|
|
158
|
-
cursor?: string
|
|
159
|
-
) => {
|
|
160
|
-
const createQuery = (cursor?: string) => {
|
|
161
|
-
if (!cursor) {
|
|
162
|
-
return query;
|
|
163
|
-
}
|
|
164
|
-
const date = { $lt: new Date(cursor), $gte: query.date.$gte };
|
|
165
|
-
|
|
166
|
-
return {
|
|
167
|
-
...query,
|
|
168
|
-
...date
|
|
169
|
-
} as mongo.Filter<T>;
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
const findCursor = collection.find(createQuery(cursor), {
|
|
173
|
-
sort: {
|
|
174
|
-
/** We are sorting by date at date descending to match cursor Postgres implementation */
|
|
175
|
-
date: -1
|
|
176
|
-
}
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
const items = await findCursor.limit(limit).toArray();
|
|
180
|
-
const count = items.length;
|
|
181
|
-
return {
|
|
182
|
-
items,
|
|
183
|
-
count,
|
|
184
|
-
/** Setting the cursor to the connected at date of the last item in the list */
|
|
185
|
-
cursor: count === limit ? items[items.length - 1].date.toISOString() : undefined,
|
|
186
|
-
more: !(count !== limit)
|
|
187
|
-
};
|
|
188
|
-
};
|