@powersync/service-core 0.0.0-dev-20240718134716 → 0.0.0-dev-20240918082156
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 +89 -6
- package/dist/api/RouteAPI.d.ts +68 -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 +11 -65
- package/dist/api/diagnostics.js.map +1 -1
- package/dist/api/schema.d.ts +3 -5
- package/dist/api/schema.js +9 -79
- package/dist/api/schema.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/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/entry/cli-entry.js +4 -2
- package/dist/entry/cli-entry.js.map +1 -1
- package/dist/entry/commands/compact-action.d.ts +2 -0
- package/dist/entry/commands/compact-action.js +52 -0
- package/dist/entry/commands/compact-action.js.map +1 -0
- 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/entry/entry-index.d.ts +1 -0
- package/dist/entry/entry-index.js +1 -0
- package/dist/entry/entry-index.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/metrics/Metrics.d.ts +6 -5
- package/dist/metrics/Metrics.js +53 -10
- 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/migrations.d.ts +8 -0
- package/dist/migrations/migrations.js +19 -7
- package/dist/migrations/migrations.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 +38 -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 +187 -0
- package/dist/replication/AbstractReplicator.js.map +1 -0
- package/dist/replication/ErrorRateLimiter.d.ts +0 -9
- 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 +39 -0
- package/dist/replication/ReplicationModule.js +65 -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 +737 -0
- package/dist/routes/configure-fastify.js +57 -0
- package/dist/routes/configure-fastify.js.map +1 -0
- package/dist/routes/configure-rsocket.d.ts +13 -0
- package/dist/routes/configure-rsocket.js +47 -0
- package/dist/routes/configure-rsocket.js.map +1 -0
- package/dist/routes/endpoints/admin.d.ts +0 -34
- package/dist/routes/endpoints/admin.js +48 -89
- package/dist/routes/endpoints/admin.js.map +1 -1
- package/dist/routes/endpoints/checkpointing.d.ts +56 -16
- package/dist/routes/endpoints/checkpointing.js +33 -12
- package/dist/routes/endpoints/checkpointing.js.map +1 -1
- package/dist/routes/endpoints/route-endpoints-index.d.ts +0 -1
- package/dist/routes/endpoints/route-endpoints-index.js +0 -1
- package/dist/routes/endpoints/route-endpoints-index.js.map +1 -1
- package/dist/routes/endpoints/socket-route.js +46 -39
- 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 +10 -0
- package/dist/routes/endpoints/sync-stream.js +17 -13
- package/dist/routes/endpoints/sync-stream.js.map +1 -1
- package/dist/routes/route-register.d.ts +1 -1
- package/dist/routes/route-register.js +1 -1
- package/dist/routes/route-register.js.map +1 -1
- package/dist/routes/router-socket.d.ts +5 -4
- package/dist/routes/router-socket.js +2 -1
- package/dist/routes/router-socket.js.map +1 -1
- package/dist/routes/router.d.ts +7 -2
- package/dist/routes/router.js.map +1 -1
- package/dist/routes/routes-index.d.ts +3 -0
- package/dist/routes/routes-index.js +3 -0
- package/dist/routes/routes-index.js.map +1 -1
- package/dist/runner/teardown.js +47 -76
- package/dist/runner/teardown.js.map +1 -1
- package/dist/storage/BucketStorage.d.ts +61 -20
- package/dist/storage/BucketStorage.js +0 -10
- package/dist/storage/BucketStorage.js.map +1 -1
- package/dist/storage/MongoBucketStorage.d.ts +4 -4
- package/dist/storage/MongoBucketStorage.js +19 -24
- package/dist/storage/MongoBucketStorage.js.map +1 -1
- 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 +4 -5
- package/dist/storage/SourceTable.js +3 -4
- package/dist/storage/SourceTable.js.map +1 -1
- package/dist/storage/StorageEngine.d.ts +24 -0
- package/dist/storage/StorageEngine.js +43 -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/mongo/MongoBucketBatch.d.ts +1 -1
- package/dist/storage/mongo/MongoBucketBatch.js +6 -7
- package/dist/storage/mongo/MongoBucketBatch.js.map +1 -1
- package/dist/storage/mongo/MongoCompactor.d.ts +40 -0
- package/dist/storage/mongo/MongoCompactor.js +293 -0
- package/dist/storage/mongo/MongoCompactor.js.map +1 -0
- 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 +9 -7
- package/dist/storage/mongo/MongoSyncBucketStorage.js +43 -28
- 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/OperationBatch.d.ts +7 -3
- package/dist/storage/mongo/OperationBatch.js +16 -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/models.d.ts +17 -7
- package/dist/storage/mongo/models.js.map +1 -1
- package/dist/storage/mongo/util.d.ts +14 -0
- package/dist/storage/mongo/util.js +70 -0
- package/dist/storage/mongo/util.js.map +1 -1
- package/dist/storage/storage-index.d.ts +5 -2
- package/dist/storage/storage-index.js +5 -2
- package/dist/storage/storage-index.js.map +1 -1
- package/dist/sync/RequestTracker.js +2 -3
- package/dist/sync/RequestTracker.js.map +1 -1
- package/dist/sync/sync-index.d.ts +1 -0
- package/dist/sync/sync-index.js +1 -0
- package/dist/sync/sync-index.js.map +1 -1
- package/dist/sync/sync.d.ts +2 -1
- package/dist/sync/sync.js +56 -17
- package/dist/sync/sync.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/config/collectors/config-collector.d.ts +12 -0
- package/dist/util/config/collectors/config-collector.js +43 -0
- package/dist/util/config/collectors/config-collector.js.map +1 -1
- package/dist/util/config/compound-config-collector.d.ts +10 -29
- package/dist/util/config/compound-config-collector.js +28 -84
- package/dist/util/config/compound-config-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 +6 -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/protocol-types.d.ts +4 -0
- package/dist/util/protocol-types.js +5 -1
- package/dist/util/protocol-types.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 -6
- package/dist/util/utils.js +45 -25
- package/dist/util/utils.js.map +1 -1
- package/package.json +7 -7
- package/src/api/RouteAPI.ts +78 -0
- package/src/api/api-index.ts +1 -0
- package/src/api/diagnostics.ts +16 -71
- package/src/api/schema.ts +13 -89
- package/src/auth/KeyStore.ts +9 -6
- package/src/auth/auth-index.ts +0 -1
- package/src/entry/cli-entry.ts +4 -2
- package/src/entry/commands/compact-action.ts +57 -0
- package/src/entry/commands/migrate-action.ts +5 -8
- package/src/entry/commands/teardown-action.ts +2 -2
- package/src/entry/entry-index.ts +1 -0
- package/src/index.ts +5 -2
- package/src/metrics/Metrics.ts +70 -15
- 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/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 +227 -0
- package/src/replication/ErrorRateLimiter.ts +0 -44
- package/src/replication/ReplicationEngine.ts +43 -0
- package/src/replication/ReplicationModule.ts +101 -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 +101 -0
- package/src/routes/configure-rsocket.ts +60 -0
- package/src/routes/endpoints/admin.ts +74 -100
- package/src/routes/endpoints/checkpointing.ts +46 -12
- package/src/routes/endpoints/route-endpoints-index.ts +0 -1
- package/src/routes/endpoints/socket-route.ts +50 -42
- package/src/routes/endpoints/sync-rules.ts +41 -25
- package/src/routes/endpoints/sync-stream.ts +17 -13
- package/src/routes/route-register.ts +2 -2
- package/src/routes/router-socket.ts +6 -5
- package/src/routes/router.ts +7 -2
- package/src/routes/routes-index.ts +3 -0
- package/src/runner/teardown.ts +50 -88
- package/src/storage/BucketStorage.ts +74 -26
- package/src/storage/MongoBucketStorage.ts +23 -26
- package/src/storage/SourceEntity.ts +22 -0
- package/src/storage/SourceTable.ts +4 -6
- package/src/storage/StorageEngine.ts +55 -0
- package/src/storage/StorageProvider.ts +27 -0
- package/src/storage/mongo/MongoBucketBatch.ts +8 -8
- package/src/storage/mongo/MongoCompactor.ts +372 -0
- package/src/storage/mongo/MongoPersistedSyncRulesContent.ts +3 -3
- package/src/storage/mongo/MongoStorageProvider.ts +31 -0
- package/src/storage/mongo/MongoSyncBucketStorage.ts +64 -34
- package/src/storage/mongo/MongoSyncRulesLock.ts +1 -1
- package/src/storage/mongo/OperationBatch.ts +18 -11
- package/src/storage/mongo/PersistedBatch.ts +6 -5
- package/src/storage/mongo/models.ts +17 -7
- package/src/storage/mongo/util.ts +71 -1
- package/src/storage/storage-index.ts +5 -2
- package/src/sync/RequestTracker.ts +3 -3
- package/src/sync/sync-index.ts +1 -0
- package/src/sync/sync.ts +66 -17
- package/src/system/ServiceContext.ts +68 -0
- package/src/system/system-index.ts +1 -1
- package/src/util/config/collectors/config-collector.ts +48 -0
- package/src/util/config/compound-config-collector.ts +45 -110
- package/src/util/config/sync-rules/sync-rules-provider.ts +18 -0
- package/src/util/config/types.ts +6 -5
- package/src/util/config.ts +6 -23
- package/src/util/protocol-types.ts +6 -1
- package/src/util/util-index.ts +3 -6
- package/src/util/utils.ts +55 -39
- package/test/src/__snapshots__/sync.test.ts.snap +90 -5
- package/test/src/auth.test.ts +7 -7
- package/test/src/broadcast_iterable.test.ts +1 -1
- package/test/src/bucket_validation.test.ts +142 -0
- package/test/src/bucket_validation.ts +116 -0
- package/test/src/checksum_cache.test.ts +3 -3
- package/test/src/compacting.test.ts +216 -0
- package/test/src/data_storage.test.ts +275 -204
- package/test/src/env.ts +1 -3
- package/test/src/merge_iterable.test.ts +1 -6
- package/test/src/setup.ts +1 -1
- package/test/src/stream_utils.ts +42 -0
- package/test/src/sync.test.ts +209 -48
- package/test/src/util.ts +110 -55
- package/test/tsconfig.json +1 -1
- package/tsconfig.tsbuildinfo +1 -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 -517
- 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/routes/endpoints/dev.d.ts +0 -312
- package/dist/routes/endpoints/dev.js +0 -172
- package/dist/routes/endpoints/dev.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 -628
- package/src/replication/WalStreamManager.ts +0 -213
- package/src/replication/WalStreamRunner.ts +0 -180
- package/src/replication/util.ts +0 -76
- package/src/routes/endpoints/dev.ts +0 -199
- 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 -296
- package/test/src/validation.test.ts +0 -63
- package/test/src/wal_stream.test.ts +0 -314
- package/test/src/wal_stream_utils.ts +0 -147
package/test/src/env.ts
CHANGED
|
@@ -2,7 +2,5 @@ import { utils } from '@powersync/lib-services-framework';
|
|
|
2
2
|
|
|
3
3
|
export const env = utils.collectEnvironmentVariables({
|
|
4
4
|
MONGO_TEST_URL: utils.type.string.default('mongodb://localhost:27017/powersync_test'),
|
|
5
|
-
|
|
6
|
-
CI: utils.type.boolean.default('false'),
|
|
7
|
-
SLOW_TESTS: utils.type.boolean.default('false')
|
|
5
|
+
CI: utils.type.boolean.default('false')
|
|
8
6
|
});
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
+
import { mergeAsyncIterablesNew, mergeAsyncIterablesOld } from '@/sync/merge.js';
|
|
1
2
|
import * as timers from 'timers/promises';
|
|
2
3
|
import { describe, expect, test } from 'vitest';
|
|
3
|
-
import {
|
|
4
|
-
FixedMergeAsyncIterable,
|
|
5
|
-
mergeAsyncIterables,
|
|
6
|
-
mergeAsyncIterablesNew,
|
|
7
|
-
mergeAsyncIterablesOld
|
|
8
|
-
} from '../../src/sync/merge.js';
|
|
9
4
|
|
|
10
5
|
type MergeIteratorFunction = <T>(source: AsyncIterable<T>[]) => AsyncIterable<T>;
|
|
11
6
|
|
package/test/src/setup.ts
CHANGED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { OplogEntry } from '@/util/protocol-types.js';
|
|
2
|
+
import { JSONBig } from '@powersync/service-jsonbig';
|
|
3
|
+
|
|
4
|
+
export function putOp(table: string, data: Record<string, any>): Partial<OplogEntry> {
|
|
5
|
+
return {
|
|
6
|
+
op: 'PUT',
|
|
7
|
+
object_type: table,
|
|
8
|
+
object_id: data.id,
|
|
9
|
+
data: JSONBig.stringify(data)
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function removeOp(table: string, id: string): Partial<OplogEntry> {
|
|
14
|
+
return {
|
|
15
|
+
op: 'REMOVE',
|
|
16
|
+
object_type: table,
|
|
17
|
+
object_id: id
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function compareIds(a: OplogEntry, b: OplogEntry) {
|
|
22
|
+
return a.object_id!.localeCompare(b.object_id!);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function oneFromAsync<T>(source: Iterable<T> | AsyncIterable<T>): Promise<T> {
|
|
26
|
+
const items: T[] = [];
|
|
27
|
+
for await (const item of source) {
|
|
28
|
+
items.push(item);
|
|
29
|
+
}
|
|
30
|
+
if (items.length != 1) {
|
|
31
|
+
throw new Error(`One item expected, got: ${items.length}`);
|
|
32
|
+
}
|
|
33
|
+
return items[0];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function fromAsync<T>(source: Iterable<T> | AsyncIterable<T>): Promise<T[]> {
|
|
37
|
+
const items: T[] = [];
|
|
38
|
+
for await (const item of source) {
|
|
39
|
+
items.push(item);
|
|
40
|
+
}
|
|
41
|
+
return items;
|
|
42
|
+
}
|
package/test/src/sync.test.ts
CHANGED
|
@@ -1,34 +1,24 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { SourceTable } from '../../src/storage/SourceTable.js';
|
|
5
|
-
import { hashData } from '../../src/util/utils.js';
|
|
6
|
-
import { MONGO_STORAGE_FACTORY, StorageFactory } from './util.js';
|
|
1
|
+
import { RequestTracker } from '@/sync/RequestTracker.js';
|
|
2
|
+
import { streamResponse } from '@/sync/sync.js';
|
|
3
|
+
import { StreamingSyncLine } from '@/util/protocol-types.js';
|
|
7
4
|
import { JSONBig } from '@powersync/service-jsonbig';
|
|
8
|
-
import { streamResponse } from '../../src/sync/sync.js';
|
|
9
|
-
import * as timers from 'timers/promises';
|
|
10
|
-
import { lsnMakeComparable } from '@powersync/service-jpgwire';
|
|
11
5
|
import { RequestParameters } from '@powersync/service-sync-rules';
|
|
12
|
-
import
|
|
6
|
+
import * as timers from 'timers/promises';
|
|
7
|
+
import { describe, expect, test } from 'vitest';
|
|
8
|
+
import {
|
|
9
|
+
BATCH_OPTIONS,
|
|
10
|
+
makeTestTable,
|
|
11
|
+
MONGO_STORAGE_FACTORY,
|
|
12
|
+
PARSE_OPTIONS,
|
|
13
|
+
StorageFactory,
|
|
14
|
+
ZERO_LSN
|
|
15
|
+
} from './util.js';
|
|
16
|
+
import { ParseSyncRulesOptions, StartBatchOptions } from '@/storage/BucketStorage.js';
|
|
13
17
|
|
|
14
18
|
describe('sync - mongodb', function () {
|
|
15
19
|
defineTests(MONGO_STORAGE_FACTORY);
|
|
16
20
|
});
|
|
17
21
|
|
|
18
|
-
function makeTestTable(name: string, columns?: string[] | undefined) {
|
|
19
|
-
const relId = hashData('table', name, (columns ?? ['id']).join(','));
|
|
20
|
-
const id = new bson.ObjectId('6544e3899293153fa7b38331');
|
|
21
|
-
return new SourceTable(
|
|
22
|
-
id,
|
|
23
|
-
SourceTable.DEFAULT_TAG,
|
|
24
|
-
relId,
|
|
25
|
-
SourceTable.DEFAULT_SCHEMA,
|
|
26
|
-
name,
|
|
27
|
-
(columns ?? ['id']).map((column) => ({ name: column, typeOid: 25 })),
|
|
28
|
-
true
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
22
|
const TEST_TABLE = makeTestTable('test', ['id']);
|
|
33
23
|
|
|
34
24
|
const BASIC_SYNC_RULES = `
|
|
@@ -48,18 +38,19 @@ function defineTests(factory: StorageFactory) {
|
|
|
48
38
|
content: BASIC_SYNC_RULES
|
|
49
39
|
});
|
|
50
40
|
|
|
51
|
-
const storage = await f.getInstance(syncRules
|
|
41
|
+
const storage = await f.getInstance(syncRules);
|
|
52
42
|
await storage.setSnapshotDone(ZERO_LSN);
|
|
53
43
|
await storage.autoActivate();
|
|
54
44
|
|
|
55
|
-
const result = await storage.startBatch(
|
|
45
|
+
const result = await storage.startBatch(BATCH_OPTIONS, async (batch) => {
|
|
56
46
|
await batch.save({
|
|
57
47
|
sourceTable: TEST_TABLE,
|
|
58
48
|
tag: 'insert',
|
|
59
49
|
after: {
|
|
60
50
|
id: 't1',
|
|
61
51
|
description: 'Test 1'
|
|
62
|
-
}
|
|
52
|
+
},
|
|
53
|
+
afterReplicaId: 't1'
|
|
63
54
|
});
|
|
64
55
|
|
|
65
56
|
await batch.save({
|
|
@@ -68,10 +59,11 @@ function defineTests(factory: StorageFactory) {
|
|
|
68
59
|
after: {
|
|
69
60
|
id: 't2',
|
|
70
61
|
description: 'Test 2'
|
|
71
|
-
}
|
|
62
|
+
},
|
|
63
|
+
afterReplicaId: 't2'
|
|
72
64
|
});
|
|
73
65
|
|
|
74
|
-
await batch.commit(
|
|
66
|
+
await batch.commit('0/1');
|
|
75
67
|
});
|
|
76
68
|
|
|
77
69
|
const stream = streamResponse({
|
|
@@ -81,6 +73,7 @@ function defineTests(factory: StorageFactory) {
|
|
|
81
73
|
include_checksum: true,
|
|
82
74
|
raw_data: true
|
|
83
75
|
},
|
|
76
|
+
parseOptions: PARSE_OPTIONS,
|
|
84
77
|
tracker,
|
|
85
78
|
syncParams: new RequestParameters({ sub: '' }, {}),
|
|
86
79
|
token: { exp: Date.now() / 1000 + 10 } as any
|
|
@@ -97,11 +90,11 @@ function defineTests(factory: StorageFactory) {
|
|
|
97
90
|
content: BASIC_SYNC_RULES
|
|
98
91
|
});
|
|
99
92
|
|
|
100
|
-
const storage = await f.getInstance(syncRules
|
|
93
|
+
const storage = await f.getInstance(syncRules);
|
|
101
94
|
await storage.setSnapshotDone(ZERO_LSN);
|
|
102
95
|
await storage.autoActivate();
|
|
103
96
|
|
|
104
|
-
const result = await storage.startBatch(
|
|
97
|
+
const result = await storage.startBatch(BATCH_OPTIONS, async (batch) => {
|
|
105
98
|
await batch.save({
|
|
106
99
|
sourceTable: TEST_TABLE,
|
|
107
100
|
tag: 'insert',
|
|
@@ -109,10 +102,11 @@ function defineTests(factory: StorageFactory) {
|
|
|
109
102
|
id: 't1',
|
|
110
103
|
description: 'Test\n"string"',
|
|
111
104
|
large_num: 12345678901234567890n
|
|
112
|
-
}
|
|
105
|
+
},
|
|
106
|
+
afterReplicaId: 't1'
|
|
113
107
|
});
|
|
114
108
|
|
|
115
|
-
await batch.commit(
|
|
109
|
+
await batch.commit('0/1');
|
|
116
110
|
});
|
|
117
111
|
|
|
118
112
|
const stream = streamResponse({
|
|
@@ -122,6 +116,7 @@ function defineTests(factory: StorageFactory) {
|
|
|
122
116
|
include_checksum: true,
|
|
123
117
|
raw_data: false
|
|
124
118
|
},
|
|
119
|
+
parseOptions: PARSE_OPTIONS,
|
|
125
120
|
tracker,
|
|
126
121
|
syncParams: new RequestParameters({ sub: '' }, {}),
|
|
127
122
|
token: { exp: Date.now() / 1000 + 10 } as any
|
|
@@ -140,7 +135,7 @@ function defineTests(factory: StorageFactory) {
|
|
|
140
135
|
content: BASIC_SYNC_RULES
|
|
141
136
|
});
|
|
142
137
|
|
|
143
|
-
const storage = await f.getInstance(syncRules
|
|
138
|
+
const storage = await f.getInstance(syncRules);
|
|
144
139
|
await storage.setSnapshotDone(ZERO_LSN);
|
|
145
140
|
await storage.autoActivate();
|
|
146
141
|
|
|
@@ -151,6 +146,7 @@ function defineTests(factory: StorageFactory) {
|
|
|
151
146
|
include_checksum: true,
|
|
152
147
|
raw_data: true
|
|
153
148
|
},
|
|
149
|
+
parseOptions: PARSE_OPTIONS,
|
|
154
150
|
tracker,
|
|
155
151
|
syncParams: new RequestParameters({ sub: '' }, {}),
|
|
156
152
|
token: { exp: 0 } as any
|
|
@@ -167,7 +163,7 @@ function defineTests(factory: StorageFactory) {
|
|
|
167
163
|
content: BASIC_SYNC_RULES
|
|
168
164
|
});
|
|
169
165
|
|
|
170
|
-
const storage = await f.getInstance(syncRules
|
|
166
|
+
const storage = await f.getInstance(syncRules);
|
|
171
167
|
await storage.setSnapshotDone(ZERO_LSN);
|
|
172
168
|
await storage.autoActivate();
|
|
173
169
|
|
|
@@ -178,6 +174,7 @@ function defineTests(factory: StorageFactory) {
|
|
|
178
174
|
include_checksum: true,
|
|
179
175
|
raw_data: true
|
|
180
176
|
},
|
|
177
|
+
parseOptions: PARSE_OPTIONS,
|
|
181
178
|
tracker,
|
|
182
179
|
syncParams: new RequestParameters({ sub: '' }, {}),
|
|
183
180
|
token: { exp: Date.now() / 1000 + 10 } as any
|
|
@@ -186,32 +183,34 @@ function defineTests(factory: StorageFactory) {
|
|
|
186
183
|
|
|
187
184
|
expect(await getCheckpointLines(iter)).toMatchSnapshot();
|
|
188
185
|
|
|
189
|
-
await storage.startBatch(
|
|
186
|
+
await storage.startBatch(BATCH_OPTIONS, async (batch) => {
|
|
190
187
|
await batch.save({
|
|
191
188
|
sourceTable: TEST_TABLE,
|
|
192
189
|
tag: 'insert',
|
|
193
190
|
after: {
|
|
194
191
|
id: 't1',
|
|
195
192
|
description: 'Test 1'
|
|
196
|
-
}
|
|
193
|
+
},
|
|
194
|
+
afterReplicaId: 't1'
|
|
197
195
|
});
|
|
198
196
|
|
|
199
|
-
await batch.commit(
|
|
197
|
+
await batch.commit('0/1');
|
|
200
198
|
});
|
|
201
199
|
|
|
202
200
|
expect(await getCheckpointLines(iter)).toMatchSnapshot();
|
|
203
201
|
|
|
204
|
-
await storage.startBatch(
|
|
202
|
+
await storage.startBatch(BATCH_OPTIONS, async (batch) => {
|
|
205
203
|
await batch.save({
|
|
206
204
|
sourceTable: TEST_TABLE,
|
|
207
205
|
tag: 'insert',
|
|
208
206
|
after: {
|
|
209
207
|
id: 't2',
|
|
210
208
|
description: 'Test 2'
|
|
211
|
-
}
|
|
209
|
+
},
|
|
210
|
+
afterReplicaId: 't2'
|
|
212
211
|
});
|
|
213
212
|
|
|
214
|
-
await batch.commit(
|
|
213
|
+
await batch.commit('0/2');
|
|
215
214
|
});
|
|
216
215
|
|
|
217
216
|
expect(await getCheckpointLines(iter)).toMatchSnapshot();
|
|
@@ -226,7 +225,7 @@ function defineTests(factory: StorageFactory) {
|
|
|
226
225
|
content: BASIC_SYNC_RULES
|
|
227
226
|
});
|
|
228
227
|
|
|
229
|
-
const storage = await f.getInstance(syncRules
|
|
228
|
+
const storage = await f.getInstance(syncRules);
|
|
230
229
|
await storage.setSnapshotDone(ZERO_LSN);
|
|
231
230
|
await storage.autoActivate();
|
|
232
231
|
|
|
@@ -239,6 +238,7 @@ function defineTests(factory: StorageFactory) {
|
|
|
239
238
|
include_checksum: true,
|
|
240
239
|
raw_data: true
|
|
241
240
|
},
|
|
241
|
+
parseOptions: PARSE_OPTIONS,
|
|
242
242
|
tracker,
|
|
243
243
|
syncParams: new RequestParameters({ sub: '' }, {}),
|
|
244
244
|
token: { exp: exp } as any
|
|
@@ -251,15 +251,161 @@ function defineTests(factory: StorageFactory) {
|
|
|
251
251
|
const expLines = await getCheckpointLines(iter);
|
|
252
252
|
expect(expLines).toMatchSnapshot();
|
|
253
253
|
});
|
|
254
|
+
|
|
255
|
+
test('compacting data - invalidate checkpoint', async () => {
|
|
256
|
+
// This tests a case of a compact operation invalidating a checkpoint in the
|
|
257
|
+
// middle of syncing data.
|
|
258
|
+
// This is expected to be rare in practice, but it is important to handle
|
|
259
|
+
// this case correctly to maintain consistency on the client.
|
|
260
|
+
|
|
261
|
+
const f = await factory();
|
|
262
|
+
|
|
263
|
+
const syncRules = await f.updateSyncRules({
|
|
264
|
+
content: BASIC_SYNC_RULES
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
const storage = await f.getInstance(syncRules);
|
|
268
|
+
await storage.setSnapshotDone(ZERO_LSN);
|
|
269
|
+
await storage.autoActivate();
|
|
270
|
+
|
|
271
|
+
await storage.startBatch(BATCH_OPTIONS, async (batch) => {
|
|
272
|
+
await batch.save({
|
|
273
|
+
sourceTable: TEST_TABLE,
|
|
274
|
+
tag: 'insert',
|
|
275
|
+
after: {
|
|
276
|
+
id: 't1',
|
|
277
|
+
description: 'Test 1'
|
|
278
|
+
},
|
|
279
|
+
afterReplicaId: 't1'
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
await batch.save({
|
|
283
|
+
sourceTable: TEST_TABLE,
|
|
284
|
+
tag: 'insert',
|
|
285
|
+
after: {
|
|
286
|
+
id: 't2',
|
|
287
|
+
description: 'Test 2'
|
|
288
|
+
},
|
|
289
|
+
afterReplicaId: 't2'
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
await batch.commit('0/1');
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
const stream = streamResponse({
|
|
296
|
+
storage: f,
|
|
297
|
+
params: {
|
|
298
|
+
buckets: [],
|
|
299
|
+
include_checksum: true,
|
|
300
|
+
raw_data: true
|
|
301
|
+
},
|
|
302
|
+
parseOptions: PARSE_OPTIONS,
|
|
303
|
+
tracker,
|
|
304
|
+
syncParams: new RequestParameters({ sub: '' }, {}),
|
|
305
|
+
token: { exp: Date.now() / 1000 + 10 } as any
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
const iter = stream[Symbol.asyncIterator]();
|
|
309
|
+
|
|
310
|
+
// Only consume the first "checkpoint" message, and pause before receiving data.
|
|
311
|
+
const lines = await consumeIterator(iter, { consume: false, isDone: (line) => (line as any)?.checkpoint != null });
|
|
312
|
+
expect(lines).toMatchSnapshot();
|
|
313
|
+
expect(lines[0]).toEqual({
|
|
314
|
+
checkpoint: expect.objectContaining({
|
|
315
|
+
last_op_id: '2'
|
|
316
|
+
})
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
// Now we save additional data AND compact before continuing.
|
|
320
|
+
// This invalidates the checkpoint we've received above.
|
|
321
|
+
|
|
322
|
+
await storage.startBatch(BATCH_OPTIONS, async (batch) => {
|
|
323
|
+
await batch.save({
|
|
324
|
+
sourceTable: TEST_TABLE,
|
|
325
|
+
tag: 'update',
|
|
326
|
+
after: {
|
|
327
|
+
id: 't1',
|
|
328
|
+
description: 'Test 1b'
|
|
329
|
+
},
|
|
330
|
+
afterReplicaId: 't1'
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
await batch.save({
|
|
334
|
+
sourceTable: TEST_TABLE,
|
|
335
|
+
tag: 'update',
|
|
336
|
+
after: {
|
|
337
|
+
id: 't2',
|
|
338
|
+
description: 'Test 2b'
|
|
339
|
+
},
|
|
340
|
+
afterReplicaId: 't2'
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
await batch.commit('0/2');
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
await storage.compact();
|
|
347
|
+
|
|
348
|
+
const lines2 = await getCheckpointLines(iter, { consume: true });
|
|
349
|
+
|
|
350
|
+
// Snapshot test checks for changes in general.
|
|
351
|
+
// The tests after that documents the specific things we're looking for
|
|
352
|
+
// in this test.
|
|
353
|
+
expect(lines2).toMatchSnapshot();
|
|
354
|
+
|
|
355
|
+
expect(lines2[0]).toEqual({
|
|
356
|
+
data: expect.objectContaining({
|
|
357
|
+
has_more: false,
|
|
358
|
+
data: [
|
|
359
|
+
// The first two ops have been replaced by a single CLEAR op
|
|
360
|
+
expect.objectContaining({
|
|
361
|
+
op: 'CLEAR'
|
|
362
|
+
})
|
|
363
|
+
]
|
|
364
|
+
})
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
// Note: No checkpoint_complete here, since the checkpoint has been
|
|
368
|
+
// invalidated by the CLEAR op.
|
|
369
|
+
|
|
370
|
+
expect(lines2[1]).toEqual({
|
|
371
|
+
checkpoint_diff: expect.objectContaining({
|
|
372
|
+
last_op_id: '4'
|
|
373
|
+
})
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
expect(lines2[2]).toEqual({
|
|
377
|
+
data: expect.objectContaining({
|
|
378
|
+
has_more: false,
|
|
379
|
+
data: [
|
|
380
|
+
expect.objectContaining({
|
|
381
|
+
op: 'PUT'
|
|
382
|
+
}),
|
|
383
|
+
expect.objectContaining({
|
|
384
|
+
op: 'PUT'
|
|
385
|
+
})
|
|
386
|
+
]
|
|
387
|
+
})
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
// Now we get a checkpoint_complete
|
|
391
|
+
expect(lines2[3]).toEqual({
|
|
392
|
+
checkpoint_complete: expect.objectContaining({
|
|
393
|
+
last_op_id: '4'
|
|
394
|
+
})
|
|
395
|
+
});
|
|
396
|
+
});
|
|
254
397
|
}
|
|
255
398
|
|
|
256
399
|
/**
|
|
257
|
-
* Get lines on an iterator until
|
|
400
|
+
* Get lines on an iterator until isDone(line) == true.
|
|
258
401
|
*
|
|
259
|
-
* Does not stop the iterator.
|
|
402
|
+
* Does not stop the iterator unless options.consume is true.
|
|
260
403
|
*/
|
|
261
|
-
async function
|
|
262
|
-
|
|
404
|
+
async function consumeIterator<T>(
|
|
405
|
+
iter: AsyncIterator<T>,
|
|
406
|
+
options: { isDone: (line: T) => boolean; consume?: boolean }
|
|
407
|
+
) {
|
|
408
|
+
let lines: T[] = [];
|
|
263
409
|
try {
|
|
264
410
|
const controller = new AbortController();
|
|
265
411
|
const timeout = timers.setTimeout(1500, { value: null, done: 'timeout' }, { signal: controller.signal });
|
|
@@ -274,7 +420,7 @@ async function getCheckpointLines(iter: AsyncIterator<any>, options?: { consume?
|
|
|
274
420
|
if (value) {
|
|
275
421
|
lines.push(value);
|
|
276
422
|
}
|
|
277
|
-
if (done || value
|
|
423
|
+
if (done || options.isDone(value)) {
|
|
278
424
|
break;
|
|
279
425
|
}
|
|
280
426
|
}
|
|
@@ -292,11 +438,26 @@ async function getCheckpointLines(iter: AsyncIterator<any>, options?: { consume?
|
|
|
292
438
|
}
|
|
293
439
|
}
|
|
294
440
|
|
|
441
|
+
/**
|
|
442
|
+
* Get lines on an iterator until the next checkpoint_complete.
|
|
443
|
+
*
|
|
444
|
+
* Does not stop the iterator unless options.consume is true.
|
|
445
|
+
*/
|
|
446
|
+
async function getCheckpointLines(
|
|
447
|
+
iter: AsyncIterator<StreamingSyncLine | string | null>,
|
|
448
|
+
options?: { consume?: boolean }
|
|
449
|
+
) {
|
|
450
|
+
return consumeIterator(iter, {
|
|
451
|
+
consume: options?.consume,
|
|
452
|
+
isDone: (line) => (line as any)?.checkpoint_complete
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
|
|
295
456
|
/**
|
|
296
457
|
* Get lines on an iterator until the next checkpoint_complete.
|
|
297
458
|
*
|
|
298
459
|
* Stops the iterator afterwards.
|
|
299
460
|
*/
|
|
300
|
-
async function consumeCheckpointLines(iterable: AsyncIterable<
|
|
461
|
+
async function consumeCheckpointLines(iterable: AsyncIterable<StreamingSyncLine | string | null>): Promise<any[]> {
|
|
301
462
|
return getCheckpointLines(iterable[Symbol.asyncIterator](), { consume: true });
|
|
302
463
|
}
|
package/test/src/util.ts
CHANGED
|
@@ -1,28 +1,29 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import { Metrics } from '@/metrics/Metrics.js';
|
|
2
|
+
import {
|
|
3
|
+
BucketStorageFactory,
|
|
4
|
+
ParseSyncRulesOptions,
|
|
5
|
+
PersistedSyncRulesContent,
|
|
6
|
+
StartBatchOptions,
|
|
7
|
+
SyncBucketDataBatch
|
|
8
|
+
} from '@/storage/BucketStorage.js';
|
|
9
|
+
import { MongoBucketStorage } from '@/storage/MongoBucketStorage.js';
|
|
10
|
+
import { SourceTable } from '@/storage/SourceTable.js';
|
|
11
|
+
import { PowerSyncMongo } from '@/storage/mongo/db.js';
|
|
12
|
+
import { SyncBucketData } from '@/util/protocol-types.js';
|
|
13
|
+
import { getUuidReplicaIdentityBson, hashData } from '@/util/utils.js';
|
|
14
|
+
import * as bson from 'bson';
|
|
3
15
|
import * as mongo from 'mongodb';
|
|
4
|
-
import { BucketStorageFactory } from '../../src/storage/BucketStorage.js';
|
|
5
|
-
import { MongoBucketStorage } from '../../src/storage/MongoBucketStorage.js';
|
|
6
|
-
import { PowerSyncMongo } from '../../src/storage/mongo/db.js';
|
|
7
|
-
import { escapeIdentifier } from '../../src/util/pgwire_utils.js';
|
|
8
16
|
import { env } from './env.js';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { MeterProvider } from '@opentelemetry/sdk-metrics';
|
|
12
|
-
import { PrometheusExporter } from '@opentelemetry/exporter-prometheus';
|
|
17
|
+
import { SqlSyncRules } from '@powersync/service-sync-rules';
|
|
18
|
+
import { ReplicaId } from '@/storage/storage-index.js';
|
|
13
19
|
|
|
14
20
|
// The metrics need to be initialised before they can be used
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
);
|
|
22
|
-
container.register(Metrics, metrics);
|
|
23
|
-
metrics.resetCounters();
|
|
24
|
-
|
|
25
|
-
export const TEST_URI = env.PG_TEST_URL;
|
|
21
|
+
await Metrics.initialise({
|
|
22
|
+
disable_telemetry_sharing: true,
|
|
23
|
+
powersync_instance_id: 'test',
|
|
24
|
+
internal_metrics_endpoint: 'unused.for.tests.com'
|
|
25
|
+
});
|
|
26
|
+
Metrics.getInstance().resetCounters();
|
|
26
27
|
|
|
27
28
|
export type StorageFactory = () => Promise<BucketStorageFactory>;
|
|
28
29
|
|
|
@@ -32,41 +33,33 @@ export const MONGO_STORAGE_FACTORY: StorageFactory = async () => {
|
|
|
32
33
|
return new MongoBucketStorage(db, { slot_name_prefix: 'test_' });
|
|
33
34
|
};
|
|
34
35
|
|
|
35
|
-
export
|
|
36
|
-
await db.query(`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`);
|
|
37
|
-
try {
|
|
38
|
-
await db.query(`DROP PUBLICATION powersync`);
|
|
39
|
-
} catch (e) {
|
|
40
|
-
// Ignore
|
|
41
|
-
}
|
|
36
|
+
export const ZERO_LSN = '0/0';
|
|
42
37
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
await db.query(`SELECT table_name FROM information_schema.tables where table_schema = 'public'`)
|
|
47
|
-
);
|
|
48
|
-
for (let row of tableRows) {
|
|
49
|
-
const name = row.table_name;
|
|
50
|
-
if (name.startsWith('test_')) {
|
|
51
|
-
await db.query(`DROP TABLE public.${escapeIdentifier(name)}`);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export const TEST_CONNECTION_OPTIONS = normalizeConnection({
|
|
57
|
-
type: 'postgresql',
|
|
58
|
-
uri: TEST_URI,
|
|
59
|
-
sslmode: 'disable'
|
|
60
|
-
});
|
|
38
|
+
export const PARSE_OPTIONS: ParseSyncRulesOptions = {
|
|
39
|
+
defaultSchema: 'public'
|
|
40
|
+
};
|
|
61
41
|
|
|
62
|
-
export
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
42
|
+
export const BATCH_OPTIONS: StartBatchOptions = {
|
|
43
|
+
...PARSE_OPTIONS,
|
|
44
|
+
zeroLSN: ZERO_LSN
|
|
45
|
+
};
|
|
66
46
|
|
|
67
|
-
export function
|
|
68
|
-
|
|
69
|
-
|
|
47
|
+
export function testRules(content: string): PersistedSyncRulesContent {
|
|
48
|
+
return {
|
|
49
|
+
id: 1,
|
|
50
|
+
sync_rules_content: content,
|
|
51
|
+
slot_name: 'test',
|
|
52
|
+
parsed(options) {
|
|
53
|
+
return {
|
|
54
|
+
id: 1,
|
|
55
|
+
sync_rules: SqlSyncRules.fromYaml(content, PARSE_OPTIONS),
|
|
56
|
+
slot_name: 'test'
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
lock() {
|
|
60
|
+
throw new Error('Not implemented');
|
|
61
|
+
}
|
|
62
|
+
};
|
|
70
63
|
}
|
|
71
64
|
|
|
72
65
|
export async function connectMongo() {
|
|
@@ -77,6 +70,68 @@ export async function connectMongo() {
|
|
|
77
70
|
socketTimeoutMS: env.CI ? 15_000 : 5_000,
|
|
78
71
|
serverSelectionTimeoutMS: env.CI ? 15_000 : 2_500
|
|
79
72
|
});
|
|
80
|
-
|
|
81
|
-
|
|
73
|
+
return new PowerSyncMongo(client);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function makeTestTable(name: string, columns?: string[] | undefined) {
|
|
77
|
+
const relId = hashData('table', name, (columns ?? ['id']).join(','));
|
|
78
|
+
const id = new bson.ObjectId('6544e3899293153fa7b38331');
|
|
79
|
+
return new SourceTable(
|
|
80
|
+
id,
|
|
81
|
+
SourceTable.DEFAULT_TAG,
|
|
82
|
+
relId,
|
|
83
|
+
'public',
|
|
84
|
+
name,
|
|
85
|
+
(columns ?? ['id']).map((column) => ({ name: column, type: 'VARCHAR', typeId: 25 })),
|
|
86
|
+
true
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function getBatchData(batch: SyncBucketData[] | SyncBucketDataBatch[] | SyncBucketDataBatch) {
|
|
91
|
+
const first = getFirst(batch);
|
|
92
|
+
if (first == null) {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
return first.data.map((d) => {
|
|
96
|
+
return {
|
|
97
|
+
op_id: d.op_id,
|
|
98
|
+
op: d.op,
|
|
99
|
+
object_id: d.object_id,
|
|
100
|
+
checksum: d.checksum
|
|
101
|
+
};
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function getBatchMeta(batch: SyncBucketData[] | SyncBucketDataBatch[] | SyncBucketDataBatch) {
|
|
106
|
+
const first = getFirst(batch);
|
|
107
|
+
if (first == null) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
has_more: first.has_more,
|
|
112
|
+
after: first.after,
|
|
113
|
+
next_after: first.next_after
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function getFirst(batch: SyncBucketData[] | SyncBucketDataBatch[] | SyncBucketDataBatch): SyncBucketData | null {
|
|
118
|
+
if (!Array.isArray(batch)) {
|
|
119
|
+
return batch.batch;
|
|
120
|
+
}
|
|
121
|
+
if (batch.length == 0) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
let first = batch[0];
|
|
125
|
+
if ((first as SyncBucketDataBatch).batch != null) {
|
|
126
|
+
return (first as SyncBucketDataBatch).batch;
|
|
127
|
+
} else {
|
|
128
|
+
return first as SyncBucketData;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Replica id in the old Postgres format, for backwards-compatible tests.
|
|
134
|
+
*/
|
|
135
|
+
export function rid(id: string): bson.UUID {
|
|
136
|
+
return getUuidReplicaIdentityBson({ id: id }, [{ name: 'id', type: 'VARCHAR', typeId: 25 }]);
|
|
82
137
|
}
|