@powersync/service-core 0.8.7 → 0.9.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/CHANGELOG.md +37 -0
- package/dist/api/RouteAPI.d.ts +67 -0
- package/dist/api/RouteAPI.js +2 -0
- package/dist/api/RouteAPI.js.map +1 -0
- package/dist/api/api-index.d.ts +1 -0
- package/dist/api/api-index.js +1 -0
- package/dist/api/api-index.js.map +1 -1
- package/dist/api/diagnostics.d.ts +4 -4
- package/dist/api/diagnostics.js +170 -158
- package/dist/api/diagnostics.js.map +1 -1
- package/dist/api/schema.d.ts +3 -5
- package/dist/api/schema.js +14 -80
- package/dist/api/schema.js.map +1 -1
- package/dist/auth/CachedKeyCollector.js.map +1 -1
- package/dist/auth/KeySpec.js.map +1 -1
- package/dist/auth/KeyStore.d.ts +7 -4
- package/dist/auth/KeyStore.js +1 -1
- package/dist/auth/KeyStore.js.map +1 -1
- package/dist/auth/LeakyBucket.js.map +1 -1
- package/dist/auth/RemoteJWKSCollector.d.ts +0 -2
- package/dist/auth/RemoteJWKSCollector.js.map +1 -1
- package/dist/auth/auth-index.d.ts +0 -1
- package/dist/auth/auth-index.js +0 -1
- package/dist/auth/auth-index.js.map +1 -1
- package/dist/db/mongo.js +5 -3
- package/dist/db/mongo.js.map +1 -1
- package/dist/entry/cli-entry.js +3 -2
- package/dist/entry/cli-entry.js.map +1 -1
- package/dist/entry/commands/compact-action.js +90 -14
- package/dist/entry/commands/compact-action.js.map +1 -1
- package/dist/entry/commands/migrate-action.js +4 -5
- package/dist/entry/commands/migrate-action.js.map +1 -1
- package/dist/entry/commands/teardown-action.js +2 -2
- package/dist/entry/commands/teardown-action.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/locks/MongoLocks.js.map +1 -1
- package/dist/metrics/Metrics.d.ts +2 -2
- package/dist/metrics/Metrics.js +5 -13
- package/dist/metrics/Metrics.js.map +1 -1
- package/dist/migrations/db/migrations/1684951997326-init.d.ts +2 -2
- package/dist/migrations/db/migrations/1684951997326-init.js +4 -2
- package/dist/migrations/db/migrations/1684951997326-init.js.map +1 -1
- package/dist/migrations/db/migrations/1702295701188-sync-rule-state.d.ts +2 -2
- package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js +4 -2
- package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js.map +1 -1
- package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.d.ts +2 -2
- package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js +4 -2
- package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js.map +1 -1
- package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.d.ts +3 -0
- package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.js +31 -0
- package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.js.map +1 -0
- package/dist/migrations/executor.js.map +1 -1
- package/dist/migrations/migrations.d.ts +8 -0
- package/dist/migrations/migrations.js +19 -7
- package/dist/migrations/migrations.js.map +1 -1
- package/dist/migrations/store/migration-store.js.map +1 -1
- package/dist/modules/AbstractModule.d.ts +26 -0
- package/dist/modules/AbstractModule.js +11 -0
- package/dist/modules/AbstractModule.js.map +1 -0
- package/dist/modules/ModuleManager.d.ts +11 -0
- package/dist/modules/ModuleManager.js +32 -0
- package/dist/modules/ModuleManager.js.map +1 -0
- package/dist/modules/modules-index.d.ts +2 -0
- package/dist/modules/modules-index.js +3 -0
- package/dist/modules/modules-index.js.map +1 -0
- package/dist/replication/AbstractReplicationJob.d.ts +37 -0
- package/dist/replication/AbstractReplicationJob.js +51 -0
- package/dist/replication/AbstractReplicationJob.js.map +1 -0
- package/dist/replication/AbstractReplicator.d.ts +53 -0
- package/dist/replication/AbstractReplicator.js +250 -0
- package/dist/replication/AbstractReplicator.js.map +1 -0
- package/dist/replication/ErrorRateLimiter.d.ts +0 -10
- package/dist/replication/ErrorRateLimiter.js +1 -42
- package/dist/replication/ErrorRateLimiter.js.map +1 -1
- package/dist/replication/ReplicationEngine.d.ts +18 -0
- package/dist/replication/ReplicationEngine.js +41 -0
- package/dist/replication/ReplicationEngine.js.map +1 -0
- package/dist/replication/ReplicationModule.d.ts +51 -0
- package/dist/replication/ReplicationModule.js +68 -0
- package/dist/replication/ReplicationModule.js.map +1 -0
- package/dist/replication/replication-index.d.ts +4 -6
- package/dist/replication/replication-index.js +4 -6
- package/dist/replication/replication-index.js.map +1 -1
- package/dist/routes/RouterEngine.d.ts +42 -0
- package/dist/routes/RouterEngine.js +80 -0
- package/dist/routes/RouterEngine.js.map +1 -0
- package/dist/routes/auth.d.ts +2 -2
- package/dist/routes/auth.js +11 -11
- package/dist/routes/auth.js.map +1 -1
- package/dist/routes/configure-fastify.d.ts +37 -7
- package/dist/routes/configure-fastify.js +20 -19
- package/dist/routes/configure-fastify.js.map +1 -1
- package/dist/routes/configure-rsocket.d.ts +3 -4
- package/dist/routes/configure-rsocket.js +7 -4
- package/dist/routes/configure-rsocket.js.map +1 -1
- package/dist/routes/endpoints/admin.d.ts +30 -0
- package/dist/routes/endpoints/admin.js +46 -67
- package/dist/routes/endpoints/admin.js.map +1 -1
- package/dist/routes/endpoints/checkpointing.js +103 -15
- package/dist/routes/endpoints/checkpointing.js.map +1 -1
- package/dist/routes/endpoints/probes.d.ts +74 -0
- package/dist/routes/endpoints/probes.js +51 -0
- package/dist/routes/endpoints/probes.js.map +1 -0
- package/dist/routes/endpoints/socket-route.js +8 -6
- package/dist/routes/endpoints/socket-route.js.map +1 -1
- package/dist/routes/endpoints/sync-rules.d.ts +1 -1
- package/dist/routes/endpoints/sync-rules.js +32 -23
- package/dist/routes/endpoints/sync-rules.js.map +1 -1
- package/dist/routes/endpoints/sync-stream.d.ts +0 -1
- package/dist/routes/endpoints/sync-stream.js +8 -8
- package/dist/routes/endpoints/sync-stream.js.map +1 -1
- package/dist/routes/hooks.js.map +1 -1
- package/dist/routes/route-register.js.map +1 -1
- package/dist/routes/router.d.ts +11 -4
- package/dist/routes/router.js.map +1 -1
- package/dist/routes/routes-index.d.ts +1 -0
- package/dist/routes/routes-index.js +1 -0
- package/dist/routes/routes-index.js.map +1 -1
- package/dist/runner/teardown.js +109 -76
- package/dist/runner/teardown.js.map +1 -1
- package/dist/storage/BucketStorage.d.ts +86 -36
- package/dist/storage/BucketStorage.js +6 -10
- package/dist/storage/BucketStorage.js.map +1 -1
- package/dist/storage/ChecksumCache.js.map +1 -1
- package/dist/storage/MongoBucketStorage.d.ts +7 -11
- package/dist/storage/MongoBucketStorage.js +48 -41
- package/dist/storage/MongoBucketStorage.js.map +1 -1
- package/dist/storage/ReplicationEventPayload.d.ts +14 -0
- package/dist/storage/ReplicationEventPayload.js +2 -0
- package/dist/storage/ReplicationEventPayload.js.map +1 -0
- package/dist/storage/SourceEntity.d.ts +20 -0
- package/dist/storage/SourceEntity.js +2 -0
- package/dist/storage/SourceEntity.js.map +1 -0
- package/dist/storage/SourceTable.d.ts +12 -5
- package/dist/storage/SourceTable.js +12 -5
- package/dist/storage/SourceTable.js.map +1 -1
- package/dist/storage/StorageEngine.d.ts +28 -0
- package/dist/storage/StorageEngine.js +45 -0
- package/dist/storage/StorageEngine.js.map +1 -0
- package/dist/storage/StorageProvider.d.ts +21 -0
- package/dist/storage/StorageProvider.js +2 -0
- package/dist/storage/StorageProvider.js.map +1 -0
- package/dist/storage/WriteCheckpointAPI.d.ts +74 -0
- package/dist/storage/WriteCheckpointAPI.js +16 -0
- package/dist/storage/WriteCheckpointAPI.js.map +1 -0
- package/dist/storage/mongo/MongoBucketBatch.d.ts +24 -5
- package/dist/storage/mongo/MongoBucketBatch.js +119 -62
- package/dist/storage/mongo/MongoBucketBatch.js.map +1 -1
- package/dist/storage/mongo/MongoCompactor.js +20 -3
- package/dist/storage/mongo/MongoCompactor.js.map +1 -1
- package/dist/storage/mongo/MongoIdSequence.js.map +1 -1
- package/dist/storage/mongo/MongoPersistedSyncRulesContent.d.ts +2 -2
- package/dist/storage/mongo/MongoPersistedSyncRulesContent.js +2 -2
- package/dist/storage/mongo/MongoPersistedSyncRulesContent.js.map +1 -1
- package/dist/storage/mongo/MongoStorageProvider.d.ts +5 -0
- package/dist/storage/mongo/MongoStorageProvider.js +26 -0
- package/dist/storage/mongo/MongoStorageProvider.js.map +1 -0
- package/dist/storage/mongo/MongoSyncBucketStorage.d.ts +18 -10
- package/dist/storage/mongo/MongoSyncBucketStorage.js +140 -25
- package/dist/storage/mongo/MongoSyncBucketStorage.js.map +1 -1
- package/dist/storage/mongo/MongoSyncRulesLock.js +1 -1
- package/dist/storage/mongo/MongoSyncRulesLock.js.map +1 -1
- package/dist/storage/mongo/MongoWriteCheckpointAPI.d.ts +20 -0
- package/dist/storage/mongo/MongoWriteCheckpointAPI.js +103 -0
- package/dist/storage/mongo/MongoWriteCheckpointAPI.js.map +1 -0
- package/dist/storage/mongo/OperationBatch.d.ts +13 -4
- package/dist/storage/mongo/OperationBatch.js +25 -7
- package/dist/storage/mongo/OperationBatch.js.map +1 -1
- package/dist/storage/mongo/PersistedBatch.d.ts +3 -3
- package/dist/storage/mongo/PersistedBatch.js +2 -2
- package/dist/storage/mongo/PersistedBatch.js.map +1 -1
- package/dist/storage/mongo/config.d.ts +19 -0
- package/dist/storage/mongo/config.js +26 -0
- package/dist/storage/mongo/config.js.map +1 -0
- package/dist/storage/mongo/db.d.ts +3 -2
- package/dist/storage/mongo/db.js +1 -0
- package/dist/storage/mongo/db.js.map +1 -1
- package/dist/storage/mongo/models.d.ts +20 -5
- package/dist/storage/mongo/models.js.map +1 -1
- package/dist/storage/mongo/util.d.ts +12 -1
- package/dist/storage/mongo/util.js +50 -2
- package/dist/storage/mongo/util.js.map +1 -1
- package/dist/storage/storage-index.d.ts +8 -2
- package/dist/storage/storage-index.js +8 -2
- package/dist/storage/storage-index.js.map +1 -1
- package/dist/sync/BroadcastIterable.d.ts +0 -1
- package/dist/sync/BroadcastIterable.js.map +1 -1
- package/dist/sync/LastValueSink.d.ts +0 -1
- package/dist/sync/LastValueSink.js.map +1 -1
- package/dist/sync/merge.d.ts +0 -1
- package/dist/sync/merge.js.map +1 -1
- package/dist/sync/safeRace.js.map +1 -1
- package/dist/sync/sync.d.ts +1 -1
- package/dist/sync/sync.js +5 -5
- package/dist/sync/sync.js.map +1 -1
- package/dist/sync/util.d.ts +0 -2
- package/dist/sync/util.js.map +1 -1
- package/dist/system/ServiceContext.d.ts +37 -0
- package/dist/system/ServiceContext.js +48 -0
- package/dist/system/ServiceContext.js.map +1 -0
- package/dist/system/system-index.d.ts +1 -1
- package/dist/system/system-index.js +1 -1
- package/dist/system/system-index.js.map +1 -1
- package/dist/util/Mutex.js.map +1 -1
- package/dist/util/config/collectors/config-collector.js.map +1 -1
- package/dist/util/config/collectors/impl/base64-config-collector.js.map +1 -1
- package/dist/util/config/collectors/impl/filesystem-config-collector.js.map +1 -1
- package/dist/util/config/compound-config-collector.d.ts +9 -2
- package/dist/util/config/compound-config-collector.js +16 -24
- package/dist/util/config/compound-config-collector.js.map +1 -1
- package/dist/util/config/sync-rules/impl/base64-sync-rules-collector.js.map +1 -1
- package/dist/util/config/sync-rules/impl/filesystem-sync-rules-collector.js.map +1 -1
- package/dist/util/config/sync-rules/impl/inline-sync-rules-collector.js.map +1 -1
- package/dist/util/config/sync-rules/sync-rules-provider.d.ts +9 -0
- package/dist/util/config/sync-rules/sync-rules-provider.js +15 -0
- package/dist/util/config/sync-rules/sync-rules-provider.js.map +1 -0
- package/dist/util/config/types.d.ts +7 -4
- package/dist/util/config/types.js.map +1 -1
- package/dist/util/config.d.ts +3 -4
- package/dist/util/config.js +5 -20
- package/dist/util/config.js.map +1 -1
- package/dist/util/memory-tracking.js.map +1 -1
- package/dist/util/secs.js.map +1 -1
- package/dist/util/util-index.d.ts +3 -6
- package/dist/util/util-index.js +3 -6
- package/dist/util/util-index.js.map +1 -1
- package/dist/util/utils.d.ts +10 -7
- package/dist/util/utils.js +36 -25
- package/dist/util/utils.js.map +1 -1
- package/package.json +8 -12
- package/src/api/RouteAPI.ts +78 -0
- package/src/api/api-index.ts +1 -0
- package/src/api/diagnostics.ts +18 -70
- package/src/api/schema.ts +18 -90
- package/src/auth/KeyStore.ts +9 -6
- package/src/auth/RemoteJWKSCollector.ts +4 -1
- package/src/auth/auth-index.ts +0 -1
- package/src/db/mongo.ts +5 -3
- package/src/entry/cli-entry.ts +3 -2
- package/src/entry/commands/compact-action.ts +24 -12
- package/src/entry/commands/migrate-action.ts +5 -8
- package/src/entry/commands/teardown-action.ts +2 -2
- package/src/index.ts +5 -2
- package/src/metrics/Metrics.ts +6 -16
- package/src/migrations/db/migrations/1684951997326-init.ts +9 -4
- package/src/migrations/db/migrations/1702295701188-sync-rule-state.ts +7 -4
- package/src/migrations/db/migrations/1711543888062-write-checkpoint-index.ts +6 -4
- package/src/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.ts +37 -0
- package/src/migrations/migrations.ts +24 -8
- package/src/modules/AbstractModule.ts +37 -0
- package/src/modules/ModuleManager.ts +34 -0
- package/src/modules/modules-index.ts +2 -0
- package/src/replication/AbstractReplicationJob.ts +79 -0
- package/src/replication/AbstractReplicator.ts +228 -0
- package/src/replication/ErrorRateLimiter.ts +0 -44
- package/src/replication/ReplicationEngine.ts +43 -0
- package/src/replication/ReplicationModule.ts +122 -0
- package/src/replication/replication-index.ts +4 -6
- package/src/routes/RouterEngine.ts +120 -0
- package/src/routes/auth.ts +21 -12
- package/src/routes/configure-fastify.ts +28 -28
- package/src/routes/configure-rsocket.ts +13 -8
- package/src/routes/endpoints/admin.ts +72 -76
- package/src/routes/endpoints/checkpointing.ts +51 -11
- package/src/routes/endpoints/probes.ts +58 -0
- package/src/routes/endpoints/socket-route.ts +10 -6
- package/src/routes/endpoints/sync-rules.ts +41 -25
- package/src/routes/endpoints/sync-stream.ts +8 -8
- package/src/routes/router.ts +10 -5
- package/src/routes/routes-index.ts +1 -0
- package/src/runner/teardown.ts +50 -88
- package/src/storage/BucketStorage.ts +103 -41
- package/src/storage/MongoBucketStorage.ts +65 -53
- package/src/storage/ReplicationEventPayload.ts +16 -0
- package/src/storage/SourceEntity.ts +22 -0
- package/src/storage/SourceTable.ts +14 -7
- package/src/storage/StorageEngine.ts +62 -0
- package/src/storage/StorageProvider.ts +27 -0
- package/src/storage/WriteCheckpointAPI.ts +85 -0
- package/src/storage/mongo/MongoBucketBatch.ts +164 -84
- package/src/storage/mongo/MongoCompactor.ts +25 -4
- package/src/storage/mongo/MongoPersistedSyncRulesContent.ts +7 -4
- package/src/storage/mongo/MongoStorageProvider.ts +31 -0
- package/src/storage/mongo/MongoSyncBucketStorage.ts +118 -41
- package/src/storage/mongo/MongoSyncRulesLock.ts +7 -3
- package/src/storage/mongo/MongoWriteCheckpointAPI.ts +151 -0
- package/src/storage/mongo/OperationBatch.ts +28 -12
- package/src/storage/mongo/PersistedBatch.ts +10 -6
- package/src/storage/mongo/config.ts +40 -0
- package/src/storage/mongo/db.ts +4 -1
- package/src/storage/mongo/models.ts +21 -5
- package/src/storage/mongo/util.ts +48 -3
- package/src/storage/storage-index.ts +8 -2
- package/src/sync/sync.ts +7 -4
- package/src/sync/util.ts +0 -1
- package/src/system/ServiceContext.ts +68 -0
- package/src/system/system-index.ts +1 -1
- package/src/util/config/compound-config-collector.ts +31 -31
- package/src/util/config/sync-rules/sync-rules-provider.ts +18 -0
- package/src/util/config/types.ts +7 -5
- package/src/util/config.ts +6 -23
- package/src/util/util-index.ts +3 -6
- package/src/util/utils.ts +48 -41
- package/test/src/__snapshots__/sync.test.ts.snap +14 -14
- package/test/src/auth.test.ts +7 -7
- package/test/src/broadcast_iterable.test.ts +1 -1
- package/test/src/compacting.test.ts +50 -40
- package/test/src/data_storage.test.ts +382 -202
- package/test/src/env.ts +1 -3
- package/test/src/merge_iterable.test.ts +1 -6
- package/test/src/routes/probes.integration.test.ts +235 -0
- package/test/src/routes/probes.test.ts +153 -0
- package/test/src/setup.ts +1 -1
- package/test/src/stream_utils.ts +42 -0
- package/test/src/sync.test.ts +115 -39
- package/test/src/util.ts +48 -51
- package/test/tsconfig.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/vitest.config.ts +7 -1
- package/dist/auth/SupabaseKeyCollector.d.ts +0 -22
- package/dist/auth/SupabaseKeyCollector.js +0 -61
- package/dist/auth/SupabaseKeyCollector.js.map +0 -1
- package/dist/replication/PgRelation.d.ts +0 -16
- package/dist/replication/PgRelation.js +0 -26
- package/dist/replication/PgRelation.js.map +0 -1
- package/dist/replication/WalConnection.d.ts +0 -34
- package/dist/replication/WalConnection.js +0 -190
- package/dist/replication/WalConnection.js.map +0 -1
- package/dist/replication/WalStream.d.ts +0 -57
- package/dist/replication/WalStream.js +0 -519
- package/dist/replication/WalStream.js.map +0 -1
- package/dist/replication/WalStreamManager.d.ts +0 -30
- package/dist/replication/WalStreamManager.js +0 -198
- package/dist/replication/WalStreamManager.js.map +0 -1
- package/dist/replication/WalStreamRunner.d.ts +0 -38
- package/dist/replication/WalStreamRunner.js +0 -155
- package/dist/replication/WalStreamRunner.js.map +0 -1
- package/dist/replication/util.d.ts +0 -9
- package/dist/replication/util.js +0 -62
- package/dist/replication/util.js.map +0 -1
- package/dist/system/CorePowerSyncSystem.d.ts +0 -23
- package/dist/system/CorePowerSyncSystem.js +0 -52
- package/dist/system/CorePowerSyncSystem.js.map +0 -1
- package/dist/util/PgManager.d.ts +0 -24
- package/dist/util/PgManager.js +0 -55
- package/dist/util/PgManager.js.map +0 -1
- package/dist/util/migration_lib.d.ts +0 -11
- package/dist/util/migration_lib.js +0 -64
- package/dist/util/migration_lib.js.map +0 -1
- package/dist/util/pgwire_utils.d.ts +0 -24
- package/dist/util/pgwire_utils.js +0 -117
- package/dist/util/pgwire_utils.js.map +0 -1
- package/dist/util/populate_test_data.d.ts +0 -8
- package/dist/util/populate_test_data.js +0 -65
- package/dist/util/populate_test_data.js.map +0 -1
- package/src/auth/SupabaseKeyCollector.ts +0 -67
- package/src/replication/PgRelation.ts +0 -42
- package/src/replication/WalConnection.ts +0 -227
- package/src/replication/WalStream.ts +0 -631
- package/src/replication/WalStreamManager.ts +0 -213
- package/src/replication/WalStreamRunner.ts +0 -180
- package/src/replication/util.ts +0 -76
- package/src/system/CorePowerSyncSystem.ts +0 -64
- package/src/util/PgManager.ts +0 -64
- package/src/util/migration_lib.ts +0 -79
- package/src/util/pgwire_utils.ts +0 -139
- package/src/util/populate_test_data.ts +0 -78
- package/test/src/__snapshots__/pg_test.test.ts.snap +0 -256
- package/test/src/large_batch.test.ts +0 -194
- package/test/src/pg_test.test.ts +0 -450
- package/test/src/schema_changes.test.ts +0 -545
- package/test/src/slow_tests.test.ts +0 -338
- package/test/src/validation.test.ts +0 -63
- package/test/src/wal_stream.test.ts +0 -319
- package/test/src/wal_stream_utils.ts +0 -156
|
@@ -2,8 +2,9 @@ import { SqliteJsonRow, SqliteJsonValue, SqlSyncRules } from '@powersync/service
|
|
|
2
2
|
import * as bson from 'bson';
|
|
3
3
|
import * as mongo from 'mongodb';
|
|
4
4
|
|
|
5
|
+
import { DisposableObserver, logger } from '@powersync/lib-services-framework';
|
|
6
|
+
import * as timers from 'timers/promises';
|
|
5
7
|
import * as db from '../../db/db-index.js';
|
|
6
|
-
import * as replication from '../../replication/WalStream.js';
|
|
7
8
|
import * as util from '../../util/util-index.js';
|
|
8
9
|
import {
|
|
9
10
|
BucketDataBatchOptions,
|
|
@@ -12,24 +13,39 @@ import {
|
|
|
12
13
|
DEFAULT_DOCUMENT_BATCH_LIMIT,
|
|
13
14
|
DEFAULT_DOCUMENT_CHUNK_LIMIT_BYTES,
|
|
14
15
|
FlushedResult,
|
|
16
|
+
ParseSyncRulesOptions,
|
|
17
|
+
PersistedSyncRulesContent,
|
|
18
|
+
ReplicationCheckpoint,
|
|
15
19
|
ResolveTableOptions,
|
|
16
20
|
ResolveTableResult,
|
|
21
|
+
StartBatchOptions,
|
|
17
22
|
SyncBucketDataBatch,
|
|
18
23
|
SyncRulesBucketStorage,
|
|
19
|
-
|
|
24
|
+
SyncRulesBucketStorageListener,
|
|
25
|
+
SyncRuleStatus,
|
|
26
|
+
TerminateOptions
|
|
20
27
|
} from '../BucketStorage.js';
|
|
21
28
|
import { ChecksumCache, FetchPartialBucketChecksum, PartialChecksum, PartialChecksumMap } from '../ChecksumCache.js';
|
|
22
29
|
import { MongoBucketStorage } from '../MongoBucketStorage.js';
|
|
23
30
|
import { SourceTable } from '../SourceTable.js';
|
|
31
|
+
import {
|
|
32
|
+
BatchedCustomWriteCheckpointOptions,
|
|
33
|
+
ManagedWriteCheckpointOptions,
|
|
34
|
+
SyncStorageLastWriteCheckpointFilters,
|
|
35
|
+
WriteCheckpointAPI,
|
|
36
|
+
WriteCheckpointMode
|
|
37
|
+
} from '../WriteCheckpointAPI.js';
|
|
24
38
|
import { PowerSyncMongo } from './db.js';
|
|
25
39
|
import { BucketDataDocument, BucketDataKey, SourceKey, SyncRuleState } from './models.js';
|
|
26
40
|
import { MongoBucketBatch } from './MongoBucketBatch.js';
|
|
27
41
|
import { MongoCompactor } from './MongoCompactor.js';
|
|
42
|
+
import { MongoWriteCheckpointAPI } from './MongoWriteCheckpointAPI.js';
|
|
28
43
|
import { BSON_DESERIALIZE_OPTIONS, idPrefixFilter, mapOpEntry, readSingleBatch, serializeLookup } from './util.js';
|
|
29
|
-
import { logger } from '@powersync/lib-services-framework';
|
|
30
|
-
import * as timers from 'timers/promises';
|
|
31
44
|
|
|
32
|
-
export class MongoSyncBucketStorage
|
|
45
|
+
export class MongoSyncBucketStorage
|
|
46
|
+
extends DisposableObserver<SyncRulesBucketStorageListener>
|
|
47
|
+
implements SyncRulesBucketStorage
|
|
48
|
+
{
|
|
33
49
|
private readonly db: PowerSyncMongo;
|
|
34
50
|
private checksumCache = new ChecksumCache({
|
|
35
51
|
fetchChecksums: (batch) => {
|
|
@@ -37,16 +53,70 @@ export class MongoSyncBucketStorage implements SyncRulesBucketStorage {
|
|
|
37
53
|
}
|
|
38
54
|
});
|
|
39
55
|
|
|
56
|
+
private parsedSyncRulesCache: { parsed: SqlSyncRules; options: ParseSyncRulesOptions } | undefined;
|
|
57
|
+
private writeCheckpointAPI: WriteCheckpointAPI;
|
|
58
|
+
|
|
40
59
|
constructor(
|
|
41
60
|
public readonly factory: MongoBucketStorage,
|
|
42
61
|
public readonly group_id: number,
|
|
43
|
-
|
|
44
|
-
public readonly slot_name: string
|
|
62
|
+
private readonly sync_rules: PersistedSyncRulesContent,
|
|
63
|
+
public readonly slot_name: string,
|
|
64
|
+
writeCheckpointMode: WriteCheckpointMode = WriteCheckpointMode.MANAGED
|
|
45
65
|
) {
|
|
66
|
+
super();
|
|
46
67
|
this.db = factory.db;
|
|
68
|
+
this.writeCheckpointAPI = new MongoWriteCheckpointAPI({
|
|
69
|
+
db: this.db,
|
|
70
|
+
mode: writeCheckpointMode
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
get writeCheckpointMode() {
|
|
75
|
+
return this.writeCheckpointAPI.writeCheckpointMode;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
setWriteCheckpointMode(mode: WriteCheckpointMode): void {
|
|
79
|
+
this.writeCheckpointAPI.setWriteCheckpointMode(mode);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
batchCreateCustomWriteCheckpoints(checkpoints: BatchedCustomWriteCheckpointOptions[]): Promise<void> {
|
|
83
|
+
return this.writeCheckpointAPI.batchCreateCustomWriteCheckpoints(
|
|
84
|
+
checkpoints.map((checkpoint) => ({ ...checkpoint, sync_rules_id: this.group_id }))
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
createCustomWriteCheckpoint(checkpoint: BatchedCustomWriteCheckpointOptions): Promise<bigint> {
|
|
89
|
+
return this.writeCheckpointAPI.createCustomWriteCheckpoint({
|
|
90
|
+
...checkpoint,
|
|
91
|
+
sync_rules_id: this.group_id
|
|
92
|
+
});
|
|
47
93
|
}
|
|
48
94
|
|
|
49
|
-
|
|
95
|
+
createManagedWriteCheckpoint(checkpoint: ManagedWriteCheckpointOptions): Promise<bigint> {
|
|
96
|
+
return this.writeCheckpointAPI.createManagedWriteCheckpoint(checkpoint);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
lastWriteCheckpoint(filters: SyncStorageLastWriteCheckpointFilters): Promise<bigint | null> {
|
|
100
|
+
return this.writeCheckpointAPI.lastWriteCheckpoint({
|
|
101
|
+
...filters,
|
|
102
|
+
sync_rules_id: this.group_id
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
getParsedSyncRules(options: ParseSyncRulesOptions): SqlSyncRules {
|
|
107
|
+
const { parsed, options: cachedOptions } = this.parsedSyncRulesCache ?? {};
|
|
108
|
+
/**
|
|
109
|
+
* Check if the cached sync rules, if present, had the same options.
|
|
110
|
+
* Parse sync rules if the options are different or if there is no cached value.
|
|
111
|
+
*/
|
|
112
|
+
if (!parsed || options.defaultSchema != cachedOptions?.defaultSchema) {
|
|
113
|
+
this.parsedSyncRulesCache = { parsed: this.sync_rules.parsed(options).sync_rules, options };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return this.parsedSyncRulesCache!.parsed;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async getCheckpoint(): Promise<ReplicationCheckpoint> {
|
|
50
120
|
const doc = await this.db.sync_rules.findOne(
|
|
51
121
|
{ _id: this.group_id },
|
|
52
122
|
{
|
|
@@ -55,11 +125,14 @@ export class MongoSyncBucketStorage implements SyncRulesBucketStorage {
|
|
|
55
125
|
);
|
|
56
126
|
return {
|
|
57
127
|
checkpoint: util.timestampToOpId(doc?.last_checkpoint ?? 0n),
|
|
58
|
-
lsn: doc?.last_checkpoint_lsn ??
|
|
128
|
+
lsn: doc?.last_checkpoint_lsn ?? null
|
|
59
129
|
};
|
|
60
130
|
}
|
|
61
131
|
|
|
62
|
-
async startBatch(
|
|
132
|
+
async startBatch(
|
|
133
|
+
options: StartBatchOptions,
|
|
134
|
+
callback: (batch: BucketStorageBatch) => Promise<void>
|
|
135
|
+
): Promise<FlushedResult | null> {
|
|
63
136
|
const doc = await this.db.sync_rules.findOne(
|
|
64
137
|
{
|
|
65
138
|
_id: this.group_id
|
|
@@ -68,35 +141,36 @@ export class MongoSyncBucketStorage implements SyncRulesBucketStorage {
|
|
|
68
141
|
);
|
|
69
142
|
const checkpoint_lsn = doc?.last_checkpoint_lsn ?? null;
|
|
70
143
|
|
|
71
|
-
|
|
72
|
-
this.db,
|
|
73
|
-
this.sync_rules,
|
|
74
|
-
this.group_id,
|
|
75
|
-
this.slot_name,
|
|
76
|
-
checkpoint_lsn,
|
|
77
|
-
doc?.no_checkpoint_before ??
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
} catch (e) {
|
|
89
|
-
await batch.abort();
|
|
90
|
-
throw e;
|
|
144
|
+
await using batch = new MongoBucketBatch({
|
|
145
|
+
db: this.db,
|
|
146
|
+
syncRules: this.sync_rules.parsed(options).sync_rules,
|
|
147
|
+
groupId: this.group_id,
|
|
148
|
+
slotName: this.slot_name,
|
|
149
|
+
lastCheckpointLsn: checkpoint_lsn,
|
|
150
|
+
noCheckpointBeforeLsn: doc?.no_checkpoint_before ?? options.zeroLSN,
|
|
151
|
+
storeCurrentData: options.storeCurrentData
|
|
152
|
+
});
|
|
153
|
+
this.iterateListeners((cb) => cb.batchStarted?.(batch));
|
|
154
|
+
|
|
155
|
+
await callback(batch);
|
|
156
|
+
await batch.flush();
|
|
157
|
+
if (batch.last_flushed_op) {
|
|
158
|
+
return { flushed_op: String(batch.last_flushed_op) };
|
|
159
|
+
} else {
|
|
160
|
+
return null;
|
|
91
161
|
}
|
|
92
162
|
}
|
|
93
163
|
|
|
94
164
|
async resolveTable(options: ResolveTableOptions): Promise<ResolveTableResult> {
|
|
95
|
-
const { group_id, connection_id, connection_tag,
|
|
165
|
+
const { group_id, connection_id, connection_tag, entity_descriptor } = options;
|
|
96
166
|
|
|
97
|
-
const { schema, name: table,
|
|
167
|
+
const { schema, name: table, objectId, replicationColumns } = entity_descriptor;
|
|
98
168
|
|
|
99
|
-
const columns = replicationColumns.map((column) => ({
|
|
169
|
+
const columns = replicationColumns.map((column) => ({
|
|
170
|
+
name: column.name,
|
|
171
|
+
type: column.type,
|
|
172
|
+
type_oid: column.typeId
|
|
173
|
+
}));
|
|
100
174
|
let result: ResolveTableResult | null = null;
|
|
101
175
|
await this.db.client.withSession(async (session) => {
|
|
102
176
|
const col = this.db.source_tables;
|
|
@@ -104,7 +178,7 @@ export class MongoSyncBucketStorage implements SyncRulesBucketStorage {
|
|
|
104
178
|
{
|
|
105
179
|
group_id: group_id,
|
|
106
180
|
connection_id: connection_id,
|
|
107
|
-
relation_id:
|
|
181
|
+
relation_id: objectId,
|
|
108
182
|
schema_name: schema,
|
|
109
183
|
table_name: table,
|
|
110
184
|
replica_id_columns2: columns
|
|
@@ -116,7 +190,7 @@ export class MongoSyncBucketStorage implements SyncRulesBucketStorage {
|
|
|
116
190
|
_id: new bson.ObjectId(),
|
|
117
191
|
group_id: group_id,
|
|
118
192
|
connection_id: connection_id,
|
|
119
|
-
relation_id:
|
|
193
|
+
relation_id: objectId,
|
|
120
194
|
schema_name: schema,
|
|
121
195
|
table_name: table,
|
|
122
196
|
replica_id_columns: null,
|
|
@@ -129,12 +203,13 @@ export class MongoSyncBucketStorage implements SyncRulesBucketStorage {
|
|
|
129
203
|
const sourceTable = new SourceTable(
|
|
130
204
|
doc._id,
|
|
131
205
|
connection_tag,
|
|
132
|
-
|
|
206
|
+
objectId,
|
|
133
207
|
schema,
|
|
134
208
|
table,
|
|
135
209
|
replicationColumns,
|
|
136
210
|
doc.snapshot_done ?? true
|
|
137
211
|
);
|
|
212
|
+
sourceTable.syncEvent = options.sync_rules.tableTriggersEvent(sourceTable);
|
|
138
213
|
sourceTable.syncData = options.sync_rules.tableSyncsData(sourceTable);
|
|
139
214
|
sourceTable.syncParameters = options.sync_rules.tableSyncsParameters(sourceTable);
|
|
140
215
|
|
|
@@ -144,7 +219,7 @@ export class MongoSyncBucketStorage implements SyncRulesBucketStorage {
|
|
|
144
219
|
group_id: group_id,
|
|
145
220
|
connection_id: connection_id,
|
|
146
221
|
_id: { $ne: doc._id },
|
|
147
|
-
$or: [{ relation_id:
|
|
222
|
+
$or: [{ relation_id: objectId }, { schema_name: schema, table_name: table }]
|
|
148
223
|
},
|
|
149
224
|
{ session }
|
|
150
225
|
)
|
|
@@ -159,7 +234,7 @@ export class MongoSyncBucketStorage implements SyncRulesBucketStorage {
|
|
|
159
234
|
doc.relation_id ?? 0,
|
|
160
235
|
doc.schema_name,
|
|
161
236
|
doc.table_name,
|
|
162
|
-
doc.replica_id_columns2?.map((c) => ({ name: c.name, typeOid: c.type_oid })) ?? [],
|
|
237
|
+
doc.replica_id_columns2?.map((c) => ({ name: c.name, typeOid: c.type_oid, type: c.type })) ?? [],
|
|
163
238
|
doc.snapshot_done ?? true
|
|
164
239
|
)
|
|
165
240
|
)
|
|
@@ -398,9 +473,11 @@ export class MongoSyncBucketStorage implements SyncRulesBucketStorage {
|
|
|
398
473
|
);
|
|
399
474
|
}
|
|
400
475
|
|
|
401
|
-
async terminate() {
|
|
402
|
-
|
|
403
|
-
|
|
476
|
+
async terminate(options?: TerminateOptions) {
|
|
477
|
+
// Default is to clear the storage except when explicitly requested not to.
|
|
478
|
+
if (!options || options?.clearStorage) {
|
|
479
|
+
await this.clear();
|
|
480
|
+
}
|
|
404
481
|
await this.db.sync_rules.updateOne(
|
|
405
482
|
{
|
|
406
483
|
_id: this.group_id
|
|
@@ -9,7 +9,7 @@ import { logger } from '@powersync/lib-services-framework';
|
|
|
9
9
|
* replicates those sync rules at a time.
|
|
10
10
|
*/
|
|
11
11
|
export class MongoSyncRulesLock implements ReplicationLock {
|
|
12
|
-
private readonly refreshInterval: NodeJS.
|
|
12
|
+
private readonly refreshInterval: NodeJS.Timeout;
|
|
13
13
|
|
|
14
14
|
static async createLock(db: PowerSyncMongo, sync_rules: PersistedSyncRulesContent): Promise<MongoSyncRulesLock> {
|
|
15
15
|
const lockId = crypto.randomBytes(8).toString('hex');
|
|
@@ -30,12 +30,16 @@ export class MongoSyncRulesLock implements ReplicationLock {
|
|
|
30
30
|
);
|
|
31
31
|
|
|
32
32
|
if (doc == null) {
|
|
33
|
-
throw new Error(`
|
|
33
|
+
throw new Error(`Sync rules: ${sync_rules.id} have been locked by another process for replication.`);
|
|
34
34
|
}
|
|
35
35
|
return new MongoSyncRulesLock(db, sync_rules.id, lockId);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
constructor(
|
|
38
|
+
constructor(
|
|
39
|
+
private db: PowerSyncMongo,
|
|
40
|
+
public sync_rules_id: number,
|
|
41
|
+
private lock_id: string
|
|
42
|
+
) {
|
|
39
43
|
this.refreshInterval = setInterval(async () => {
|
|
40
44
|
try {
|
|
41
45
|
await this.refresh();
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import * as framework from '@powersync/lib-services-framework';
|
|
2
|
+
import {
|
|
3
|
+
CustomWriteCheckpointFilters,
|
|
4
|
+
CustomWriteCheckpointOptions,
|
|
5
|
+
LastWriteCheckpointFilters,
|
|
6
|
+
ManagedWriteCheckpointFilters,
|
|
7
|
+
ManagedWriteCheckpointOptions,
|
|
8
|
+
WriteCheckpointAPI,
|
|
9
|
+
WriteCheckpointMode
|
|
10
|
+
} from '../WriteCheckpointAPI.js';
|
|
11
|
+
import { PowerSyncMongo } from './db.js';
|
|
12
|
+
|
|
13
|
+
export type MongoCheckpointAPIOptions = {
|
|
14
|
+
db: PowerSyncMongo;
|
|
15
|
+
mode: WriteCheckpointMode;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export class MongoWriteCheckpointAPI implements WriteCheckpointAPI {
|
|
19
|
+
readonly db: PowerSyncMongo;
|
|
20
|
+
private _mode: WriteCheckpointMode;
|
|
21
|
+
|
|
22
|
+
constructor(options: MongoCheckpointAPIOptions) {
|
|
23
|
+
this.db = options.db;
|
|
24
|
+
this._mode = options.mode;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get writeCheckpointMode() {
|
|
28
|
+
return this._mode;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
setWriteCheckpointMode(mode: WriteCheckpointMode): void {
|
|
32
|
+
this._mode = mode;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async batchCreateCustomWriteCheckpoints(checkpoints: CustomWriteCheckpointOptions[]): Promise<void> {
|
|
36
|
+
return batchCreateCustomWriteCheckpoints(this.db, checkpoints);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async createCustomWriteCheckpoint(options: CustomWriteCheckpointOptions): Promise<bigint> {
|
|
40
|
+
if (this.writeCheckpointMode !== WriteCheckpointMode.CUSTOM) {
|
|
41
|
+
throw new framework.errors.ValidationError(
|
|
42
|
+
`Creating a custom Write Checkpoint when the current Write Checkpoint mode is set to "${this.writeCheckpointMode}"`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const { checkpoint, user_id, sync_rules_id } = options;
|
|
47
|
+
const doc = await this.db.custom_write_checkpoints.findOneAndUpdate(
|
|
48
|
+
{
|
|
49
|
+
user_id: user_id,
|
|
50
|
+
sync_rules_id
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
$set: {
|
|
54
|
+
checkpoint
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
{ upsert: true, returnDocument: 'after' }
|
|
58
|
+
);
|
|
59
|
+
return doc!.checkpoint;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async createManagedWriteCheckpoint(checkpoint: ManagedWriteCheckpointOptions): Promise<bigint> {
|
|
63
|
+
if (this.writeCheckpointMode !== WriteCheckpointMode.MANAGED) {
|
|
64
|
+
throw new framework.errors.ValidationError(
|
|
65
|
+
`Attempting to create a managed Write Checkpoint when the current Write Checkpoint mode is set to "${this.writeCheckpointMode}"`
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const { user_id, heads: lsns } = checkpoint;
|
|
70
|
+
const doc = await this.db.write_checkpoints.findOneAndUpdate(
|
|
71
|
+
{
|
|
72
|
+
user_id: user_id
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
$set: {
|
|
76
|
+
lsns
|
|
77
|
+
},
|
|
78
|
+
$inc: {
|
|
79
|
+
client_id: 1n
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
{ upsert: true, returnDocument: 'after' }
|
|
83
|
+
);
|
|
84
|
+
return doc!.client_id;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async lastWriteCheckpoint(filters: LastWriteCheckpointFilters): Promise<bigint | null> {
|
|
88
|
+
switch (this.writeCheckpointMode) {
|
|
89
|
+
case WriteCheckpointMode.CUSTOM:
|
|
90
|
+
if (false == 'sync_rules_id' in filters) {
|
|
91
|
+
throw new framework.errors.ValidationError(`Sync rules ID is required for custom Write Checkpoint filtering`);
|
|
92
|
+
}
|
|
93
|
+
return this.lastCustomWriteCheckpoint(filters);
|
|
94
|
+
case WriteCheckpointMode.MANAGED:
|
|
95
|
+
if (false == 'heads' in filters) {
|
|
96
|
+
throw new framework.errors.ValidationError(
|
|
97
|
+
`Replication HEAD is required for managed Write Checkpoint filtering`
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
return this.lastManagedWriteCheckpoint(filters);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
protected async lastCustomWriteCheckpoint(filters: CustomWriteCheckpointFilters) {
|
|
105
|
+
const { user_id, sync_rules_id } = filters;
|
|
106
|
+
const lastWriteCheckpoint = await this.db.custom_write_checkpoints.findOne({
|
|
107
|
+
user_id,
|
|
108
|
+
sync_rules_id
|
|
109
|
+
});
|
|
110
|
+
return lastWriteCheckpoint?.checkpoint ?? null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
protected async lastManagedWriteCheckpoint(filters: ManagedWriteCheckpointFilters) {
|
|
114
|
+
const { user_id, heads } = filters;
|
|
115
|
+
// TODO: support multiple heads when we need to support multiple connections
|
|
116
|
+
const lsn = heads['1'];
|
|
117
|
+
if (lsn == null) {
|
|
118
|
+
// Can happen if we haven't replicated anything yet.
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
const lastWriteCheckpoint = await this.db.write_checkpoints.findOne({
|
|
122
|
+
user_id: user_id,
|
|
123
|
+
'lsns.1': { $lte: lsn }
|
|
124
|
+
});
|
|
125
|
+
return lastWriteCheckpoint?.client_id ?? null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export async function batchCreateCustomWriteCheckpoints(
|
|
130
|
+
db: PowerSyncMongo,
|
|
131
|
+
checkpoints: CustomWriteCheckpointOptions[]
|
|
132
|
+
): Promise<void> {
|
|
133
|
+
if (!checkpoints.length) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
await db.custom_write_checkpoints.bulkWrite(
|
|
138
|
+
checkpoints.map((checkpointOptions) => ({
|
|
139
|
+
updateOne: {
|
|
140
|
+
filter: { user_id: checkpointOptions.user_id, sync_rules_id: checkpointOptions.sync_rules_id },
|
|
141
|
+
update: {
|
|
142
|
+
$set: {
|
|
143
|
+
checkpoint: checkpointOptions.checkpoint,
|
|
144
|
+
sync_rules_id: checkpointOptions.sync_rules_id
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
upsert: true
|
|
148
|
+
}
|
|
149
|
+
}))
|
|
150
|
+
);
|
|
151
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import * as bson from 'bson';
|
|
2
1
|
import { ToastableSqliteRow } from '@powersync/service-sync-rules';
|
|
2
|
+
import * as bson from 'bson';
|
|
3
3
|
|
|
4
|
-
import * as util from '../../util/util-index.js';
|
|
5
4
|
import { SaveOptions } from '../BucketStorage.js';
|
|
5
|
+
import { isUUID } from './util.js';
|
|
6
|
+
import { ReplicaId } from './models.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Maximum number of operations in a batch.
|
|
@@ -42,7 +43,16 @@ export class OperationBatch {
|
|
|
42
43
|
return this.batch.length >= MAX_BATCH_COUNT || this.currentSize > MAX_RECORD_BATCH_SIZE;
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
|
|
46
|
+
/**
|
|
47
|
+
*
|
|
48
|
+
* @param sizes Map of source key to estimated size of the current_data document, or undefined if current_data is not persisted.
|
|
49
|
+
*
|
|
50
|
+
*/
|
|
51
|
+
*batched(sizes: Map<string, number> | undefined): Generator<RecordOperation[]> {
|
|
52
|
+
if (sizes == null) {
|
|
53
|
+
yield this.batch;
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
46
56
|
let currentBatch: RecordOperation[] = [];
|
|
47
57
|
let currentBatchSize = 0;
|
|
48
58
|
for (let op of this.batch) {
|
|
@@ -63,18 +73,15 @@ export class OperationBatch {
|
|
|
63
73
|
}
|
|
64
74
|
|
|
65
75
|
export class RecordOperation {
|
|
66
|
-
public readonly afterId:
|
|
67
|
-
public readonly beforeId:
|
|
76
|
+
public readonly afterId: ReplicaId | null;
|
|
77
|
+
public readonly beforeId: ReplicaId;
|
|
68
78
|
public readonly internalBeforeKey: string;
|
|
69
79
|
public readonly internalAfterKey: string | null;
|
|
70
80
|
public readonly estimatedSize: number;
|
|
71
81
|
|
|
72
82
|
constructor(public readonly record: SaveOptions) {
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
-
const beforeId = record.before
|
|
76
|
-
? util.getUuidReplicaIdentityBson(record.before, record.sourceTable.replicaIdColumns!)
|
|
77
|
-
: afterId!;
|
|
83
|
+
const afterId = record.afterReplicaId ?? null;
|
|
84
|
+
const beforeId = record.beforeReplicaId ?? record.afterReplicaId;
|
|
78
85
|
this.afterId = afterId;
|
|
79
86
|
this.beforeId = beforeId;
|
|
80
87
|
this.internalBeforeKey = cacheKey(record.sourceTable.id, beforeId);
|
|
@@ -84,8 +91,17 @@ export class RecordOperation {
|
|
|
84
91
|
}
|
|
85
92
|
}
|
|
86
93
|
|
|
87
|
-
|
|
88
|
-
|
|
94
|
+
/**
|
|
95
|
+
* In-memory cache key - must not be persisted.
|
|
96
|
+
*/
|
|
97
|
+
export function cacheKey(table: bson.ObjectId, id: ReplicaId) {
|
|
98
|
+
if (isUUID(id)) {
|
|
99
|
+
return `${table.toHexString()}.${id.toHexString()}`;
|
|
100
|
+
} else if (typeof id == 'string') {
|
|
101
|
+
return `${table.toHexString()}.${id}`;
|
|
102
|
+
} else {
|
|
103
|
+
return `${table.toHexString()}.${(bson.serialize({ id: id }) as Buffer).toString('base64')}`;
|
|
104
|
+
}
|
|
89
105
|
}
|
|
90
106
|
|
|
91
107
|
/**
|
|
@@ -13,9 +13,10 @@ import {
|
|
|
13
13
|
BucketParameterDocument,
|
|
14
14
|
CurrentBucket,
|
|
15
15
|
CurrentDataDocument,
|
|
16
|
-
SourceKey
|
|
16
|
+
SourceKey,
|
|
17
|
+
ReplicaId
|
|
17
18
|
} from './models.js';
|
|
18
|
-
import { serializeLookup } from './util.js';
|
|
19
|
+
import { replicaIdToSubkey, serializeLookup } from './util.js';
|
|
19
20
|
import { logger } from '@powersync/lib-services-framework';
|
|
20
21
|
|
|
21
22
|
/**
|
|
@@ -53,13 +54,16 @@ export class PersistedBatch {
|
|
|
53
54
|
*/
|
|
54
55
|
currentSize = 0;
|
|
55
56
|
|
|
56
|
-
constructor(
|
|
57
|
+
constructor(
|
|
58
|
+
private group_id: number,
|
|
59
|
+
writtenSize: number
|
|
60
|
+
) {
|
|
57
61
|
this.currentSize = writtenSize;
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
saveBucketData(options: {
|
|
61
65
|
op_seq: MongoIdSequence;
|
|
62
|
-
sourceKey:
|
|
66
|
+
sourceKey: ReplicaId;
|
|
63
67
|
table: SourceTable;
|
|
64
68
|
evaluated: EvaluatedRow[];
|
|
65
69
|
before_buckets: CurrentBucket[];
|
|
@@ -70,7 +74,7 @@ export class PersistedBatch {
|
|
|
70
74
|
remaining_buckets.set(key, b);
|
|
71
75
|
}
|
|
72
76
|
|
|
73
|
-
const dchecksum = util.hashDelete(
|
|
77
|
+
const dchecksum = util.hashDelete(replicaIdToSubkey(options.table.id, options.sourceKey));
|
|
74
78
|
|
|
75
79
|
for (let k of options.evaluated) {
|
|
76
80
|
const key = currentBucketKey(k);
|
|
@@ -134,7 +138,7 @@ export class PersistedBatch {
|
|
|
134
138
|
|
|
135
139
|
saveParameterData(data: {
|
|
136
140
|
op_seq: MongoIdSequence;
|
|
137
|
-
sourceKey:
|
|
141
|
+
sourceKey: ReplicaId;
|
|
138
142
|
sourceTable: SourceTable;
|
|
139
143
|
evaluated: EvaluatedParameters[];
|
|
140
144
|
existing_lookups: bson.Binary[];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as urijs from 'uri-js';
|
|
2
|
+
|
|
3
|
+
export interface MongoConnectionConfig {
|
|
4
|
+
uri: string;
|
|
5
|
+
username?: string;
|
|
6
|
+
password?: string;
|
|
7
|
+
database?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Validate and normalize connection options.
|
|
12
|
+
*
|
|
13
|
+
* Returns destructured options.
|
|
14
|
+
*
|
|
15
|
+
* For use by both storage and mongo module.
|
|
16
|
+
*/
|
|
17
|
+
export function normalizeMongoConfig(options: MongoConnectionConfig) {
|
|
18
|
+
let uri = urijs.parse(options.uri);
|
|
19
|
+
|
|
20
|
+
const database = options.database ?? uri.path?.substring(1) ?? '';
|
|
21
|
+
|
|
22
|
+
const userInfo = uri.userinfo?.split(':');
|
|
23
|
+
|
|
24
|
+
const username = options.username ?? userInfo?.[0];
|
|
25
|
+
const password = options.password ?? userInfo?.[1];
|
|
26
|
+
|
|
27
|
+
if (database == '') {
|
|
28
|
+
throw new Error(`database required`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
delete uri.userinfo;
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
uri: urijs.serialize(uri),
|
|
35
|
+
database,
|
|
36
|
+
|
|
37
|
+
username,
|
|
38
|
+
password
|
|
39
|
+
};
|
|
40
|
+
}
|
package/src/storage/mongo/db.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import * as mongo from 'mongodb';
|
|
2
2
|
|
|
3
|
+
import { configFile } from '@powersync/service-types';
|
|
3
4
|
import * as db from '../../db/db-index.js';
|
|
4
5
|
import * as locks from '../../locks/locks-index.js';
|
|
5
6
|
import {
|
|
6
7
|
BucketDataDocument,
|
|
7
8
|
BucketParameterDocument,
|
|
8
9
|
CurrentDataDocument,
|
|
10
|
+
CustomWriteCheckpointDocument,
|
|
9
11
|
IdSequenceDocument,
|
|
10
12
|
InstanceDocument,
|
|
11
13
|
SourceTableDocument,
|
|
@@ -13,7 +15,6 @@ import {
|
|
|
13
15
|
WriteCheckpointDocument
|
|
14
16
|
} from './models.js';
|
|
15
17
|
import { BSON_DESERIALIZE_OPTIONS } from './util.js';
|
|
16
|
-
import { configFile } from '@powersync/service-types';
|
|
17
18
|
|
|
18
19
|
export interface PowerSyncMongoOptions {
|
|
19
20
|
/**
|
|
@@ -33,6 +34,7 @@ export class PowerSyncMongo {
|
|
|
33
34
|
readonly op_id_sequence: mongo.Collection<IdSequenceDocument>;
|
|
34
35
|
readonly sync_rules: mongo.Collection<SyncRuleDocument>;
|
|
35
36
|
readonly source_tables: mongo.Collection<SourceTableDocument>;
|
|
37
|
+
readonly custom_write_checkpoints: mongo.Collection<CustomWriteCheckpointDocument>;
|
|
36
38
|
readonly write_checkpoints: mongo.Collection<WriteCheckpointDocument>;
|
|
37
39
|
readonly instance: mongo.Collection<InstanceDocument>;
|
|
38
40
|
readonly locks: mongo.Collection<locks.Lock>;
|
|
@@ -54,6 +56,7 @@ export class PowerSyncMongo {
|
|
|
54
56
|
this.op_id_sequence = db.collection('op_id_sequence');
|
|
55
57
|
this.sync_rules = db.collection('sync_rules');
|
|
56
58
|
this.source_tables = db.collection('source_tables');
|
|
59
|
+
this.custom_write_checkpoints = db.collection('custom_write_checkpoints');
|
|
57
60
|
this.write_checkpoints = db.collection('write_checkpoints');
|
|
58
61
|
this.instance = db.collection('instance');
|
|
59
62
|
this.locks = this.db.collection('locks');
|