@powersync/service-module-postgres 0.0.0-dev-20250507154604 → 0.0.0-dev-20250611110033
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 +47 -8
- package/dist/api/PostgresRouteAPIAdapter.d.ts +1 -1
- package/dist/api/PostgresRouteAPIAdapter.js +5 -1
- package/dist/api/PostgresRouteAPIAdapter.js.map +1 -1
- package/dist/auth/SupabaseKeyCollector.d.ts +3 -10
- package/dist/auth/SupabaseKeyCollector.js +6 -4
- package/dist/auth/SupabaseKeyCollector.js.map +1 -1
- package/dist/replication/SnapshotQuery.d.ts +75 -0
- package/dist/replication/SnapshotQuery.js +172 -0
- package/dist/replication/SnapshotQuery.js.map +1 -0
- package/dist/replication/WalStream.d.ts +37 -4
- package/dist/replication/WalStream.js +284 -88
- package/dist/replication/WalStream.js.map +1 -1
- package/dist/replication/WalStreamReplicationJob.d.ts +2 -0
- package/dist/replication/WalStreamReplicationJob.js +10 -3
- package/dist/replication/WalStreamReplicationJob.js.map +1 -1
- package/dist/replication/WalStreamReplicator.d.ts +1 -0
- package/dist/replication/WalStreamReplicator.js +22 -0
- package/dist/replication/WalStreamReplicator.js.map +1 -1
- package/package.json +12 -12
- package/src/api/PostgresRouteAPIAdapter.ts +5 -1
- package/src/auth/SupabaseKeyCollector.ts +14 -5
- package/src/replication/SnapshotQuery.ts +206 -0
- package/src/replication/WalStream.ts +338 -95
- package/src/replication/WalStreamReplicationJob.ts +11 -3
- package/src/replication/WalStreamReplicator.ts +26 -0
- package/test/src/__snapshots__/schema_changes.test.ts.snap +2 -2
- package/test/src/checkpoints.test.ts +10 -3
- package/test/src/chunked_snapshots.test.ts +156 -0
- package/test/src/large_batch.test.ts +5 -154
- package/test/src/resuming_snapshots.test.ts +150 -0
- package/test/src/schema_changes.test.ts +5 -10
- package/test/src/slow_tests.test.ts +13 -30
- package/test/src/util.ts +12 -1
- package/test/src/validation.test.ts +0 -1
- package/test/src/wal_stream.test.ts +4 -9
- package/test/src/wal_stream_utils.ts +15 -7
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -5,9 +5,8 @@ import { env } from './env.js';
|
|
|
5
5
|
import {
|
|
6
6
|
clearTestDb,
|
|
7
7
|
connectPgPool,
|
|
8
|
+
describeWithStorage,
|
|
8
9
|
getClientCheckpoint,
|
|
9
|
-
INITIALIZED_MONGO_STORAGE_FACTORY,
|
|
10
|
-
INITIALIZED_POSTGRES_STORAGE_FACTORY,
|
|
11
10
|
TEST_CONNECTION_OPTIONS
|
|
12
11
|
} from './util.js';
|
|
13
12
|
|
|
@@ -21,26 +20,10 @@ import * as mongo_storage from '@powersync/service-module-mongodb-storage';
|
|
|
21
20
|
import * as postgres_storage from '@powersync/service-module-postgres-storage';
|
|
22
21
|
import * as timers from 'node:timers/promises';
|
|
23
22
|
|
|
24
|
-
describe.skipIf(!env.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
defineSlowTests(INITIALIZED_MONGO_STORAGE_FACTORY);
|
|
29
|
-
} else {
|
|
30
|
-
// Need something in this file.
|
|
31
|
-
test('no-op', () => {});
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
describe.skipIf(!env.TEST_POSTGRES_STORAGE)('slow tests - postgres', function () {
|
|
36
|
-
// These are slow, inconsistent tests.
|
|
37
|
-
// Not run on every test run, but we do run on CI, or when manually debugging issues.
|
|
38
|
-
if (env.CI || env.SLOW_TESTS) {
|
|
39
|
-
defineSlowTests(INITIALIZED_POSTGRES_STORAGE_FACTORY);
|
|
40
|
-
} else {
|
|
41
|
-
// Need something in this file.
|
|
42
|
-
test('no-op', () => {});
|
|
43
|
-
}
|
|
23
|
+
describe.skipIf(!(env.CI || env.SLOW_TESTS))('slow tests', function () {
|
|
24
|
+
describeWithStorage({ timeout: 120_000 }, function (factory) {
|
|
25
|
+
defineSlowTests(factory);
|
|
26
|
+
});
|
|
44
27
|
});
|
|
45
28
|
|
|
46
29
|
function defineSlowTests(factory: storage.TestStorageFactory) {
|
|
@@ -350,14 +333,14 @@ bucket_definitions:
|
|
|
350
333
|
const connections = new PgManager(TEST_CONNECTION_OPTIONS, {});
|
|
351
334
|
const replicationConnection = await connections.replicationConnection();
|
|
352
335
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
336
|
+
abortController = new AbortController();
|
|
337
|
+
const options: WalStreamOptions = {
|
|
338
|
+
abort_signal: abortController.signal,
|
|
339
|
+
connections,
|
|
340
|
+
storage: storage,
|
|
341
|
+
metrics: METRICS_HELPER.metricsEngine
|
|
342
|
+
};
|
|
343
|
+
walStream = new WalStream(options);
|
|
361
344
|
|
|
362
345
|
await storage.clear();
|
|
363
346
|
|
package/test/src/util.ts
CHANGED
|
@@ -2,11 +2,12 @@ import { PostgresRouteAPIAdapter } from '@module/api/PostgresRouteAPIAdapter.js'
|
|
|
2
2
|
import * as types from '@module/types/types.js';
|
|
3
3
|
import * as lib_postgres from '@powersync/lib-service-postgres';
|
|
4
4
|
import { logger } from '@powersync/lib-services-framework';
|
|
5
|
-
import { BucketStorageFactory, InternalOpId, TestStorageOptions } from '@powersync/service-core';
|
|
5
|
+
import { BucketStorageFactory, InternalOpId, TestStorageFactory, TestStorageOptions } from '@powersync/service-core';
|
|
6
6
|
import * as pgwire from '@powersync/service-jpgwire';
|
|
7
7
|
import * as mongo_storage from '@powersync/service-module-mongodb-storage';
|
|
8
8
|
import * as postgres_storage from '@powersync/service-module-postgres-storage';
|
|
9
9
|
import { env } from './env.js';
|
|
10
|
+
import { describe, TestOptions } from 'vitest';
|
|
10
11
|
|
|
11
12
|
export const TEST_URI = env.PG_TEST_URL;
|
|
12
13
|
|
|
@@ -19,6 +20,16 @@ export const INITIALIZED_POSTGRES_STORAGE_FACTORY = postgres_storage.PostgresTes
|
|
|
19
20
|
url: env.PG_STORAGE_TEST_URL
|
|
20
21
|
});
|
|
21
22
|
|
|
23
|
+
export function describeWithStorage(options: TestOptions, fn: (factory: TestStorageFactory) => void) {
|
|
24
|
+
describe.skipIf(!env.TEST_MONGO_STORAGE)(`mongodb storage`, options, function () {
|
|
25
|
+
fn(INITIALIZED_MONGO_STORAGE_FACTORY);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe.skipIf(!env.TEST_POSTGRES_STORAGE)(`postgres storage`, options, function () {
|
|
29
|
+
fn(INITIALIZED_POSTGRES_STORAGE_FACTORY);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
22
33
|
export const TEST_CONNECTION_OPTIONS = types.normalizeConnectionConfig({
|
|
23
34
|
type: 'postgresql',
|
|
24
35
|
uri: TEST_URI,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { getDebugTablesInfo } from '@module/replication/replication-utils.js';
|
|
2
2
|
import { expect, test } from 'vitest';
|
|
3
3
|
|
|
4
|
-
// Not quite a walStreamTest, but it helps to manage the connection
|
|
5
4
|
import { INITIALIZED_MONGO_STORAGE_FACTORY } from './util.js';
|
|
6
5
|
import { WalStreamTestContext } from './wal_stream_utils.js';
|
|
7
6
|
|
|
@@ -2,12 +2,11 @@ import { MissingReplicationSlotError } from '@module/replication/WalStream.js';
|
|
|
2
2
|
import { storage } from '@powersync/service-core';
|
|
3
3
|
import { METRICS_HELPER, putOp, removeOp } from '@powersync/service-core-tests';
|
|
4
4
|
import { pgwireRows } from '@powersync/service-jpgwire';
|
|
5
|
+
import { ReplicationMetric } from '@powersync/service-types';
|
|
5
6
|
import * as crypto from 'crypto';
|
|
6
7
|
import { describe, expect, test } from 'vitest';
|
|
7
|
-
import {
|
|
8
|
-
import { INITIALIZED_MONGO_STORAGE_FACTORY, INITIALIZED_POSTGRES_STORAGE_FACTORY } from './util.js';
|
|
8
|
+
import { describeWithStorage } from './util.js';
|
|
9
9
|
import { WalStreamTestContext } from './wal_stream_utils.js';
|
|
10
|
-
import { ReplicationMetric } from '@powersync/service-types';
|
|
11
10
|
|
|
12
11
|
const BASIC_SYNC_RULES = `
|
|
13
12
|
bucket_definitions:
|
|
@@ -16,12 +15,8 @@ bucket_definitions:
|
|
|
16
15
|
- SELECT id, description FROM "test_data"
|
|
17
16
|
`;
|
|
18
17
|
|
|
19
|
-
describe
|
|
20
|
-
defineWalStreamTests
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
describe.skipIf(!env.TEST_POSTGRES_STORAGE)('wal stream - postgres', { timeout: 20_000 }, function () {
|
|
24
|
-
defineWalStreamTests(INITIALIZED_POSTGRES_STORAGE_FACTORY);
|
|
18
|
+
describe('wal stream', () => {
|
|
19
|
+
describeWithStorage({ timeout: 20_000 }, defineWalStreamTests);
|
|
25
20
|
});
|
|
26
21
|
|
|
27
22
|
function defineWalStreamTests(factory: storage.TestStorageFactory) {
|
|
@@ -19,6 +19,7 @@ export class WalStreamTestContext implements AsyncDisposable {
|
|
|
19
19
|
private streamPromise?: Promise<void>;
|
|
20
20
|
public storage?: SyncRulesBucketStorage;
|
|
21
21
|
private replicationConnection?: pgwire.PgConnection;
|
|
22
|
+
private snapshotPromise?: Promise<void>;
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* Tests operating on the wal stream need to configure the stream and manage asynchronous
|
|
@@ -28,7 +29,7 @@ export class WalStreamTestContext implements AsyncDisposable {
|
|
|
28
29
|
*/
|
|
29
30
|
static async open(
|
|
30
31
|
factory: (options: storage.TestStorageOptions) => Promise<BucketStorageFactory>,
|
|
31
|
-
options?: { doNotClear?: boolean }
|
|
32
|
+
options?: { doNotClear?: boolean; walStreamOptions?: Partial<WalStreamOptions> }
|
|
32
33
|
) {
|
|
33
34
|
const f = await factory({ doNotClear: options?.doNotClear });
|
|
34
35
|
const connectionManager = new PgManager(TEST_CONNECTION_OPTIONS, {});
|
|
@@ -37,12 +38,13 @@ export class WalStreamTestContext implements AsyncDisposable {
|
|
|
37
38
|
await clearTestDb(connectionManager.pool);
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
return new WalStreamTestContext(f, connectionManager);
|
|
41
|
+
return new WalStreamTestContext(f, connectionManager, options?.walStreamOptions);
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
constructor(
|
|
44
45
|
public factory: BucketStorageFactory,
|
|
45
|
-
public connectionManager: PgManager
|
|
46
|
+
public connectionManager: PgManager,
|
|
47
|
+
private walStreamOptions?: Partial<WalStreamOptions>
|
|
46
48
|
) {
|
|
47
49
|
createCoreReplicationMetrics(METRICS_HELPER.metricsEngine);
|
|
48
50
|
initializeCoreReplicationMetrics(METRICS_HELPER.metricsEngine);
|
|
@@ -54,6 +56,7 @@ export class WalStreamTestContext implements AsyncDisposable {
|
|
|
54
56
|
|
|
55
57
|
async dispose() {
|
|
56
58
|
this.abortController.abort();
|
|
59
|
+
await this.snapshotPromise;
|
|
57
60
|
await this.streamPromise;
|
|
58
61
|
await this.connectionManager.destroy();
|
|
59
62
|
await this.factory?.[Symbol.asyncDispose]();
|
|
@@ -108,16 +111,21 @@ export class WalStreamTestContext implements AsyncDisposable {
|
|
|
108
111
|
storage: this.storage,
|
|
109
112
|
metrics: METRICS_HELPER.metricsEngine,
|
|
110
113
|
connections: this.connectionManager,
|
|
111
|
-
abort_signal: this.abortController.signal
|
|
114
|
+
abort_signal: this.abortController.signal,
|
|
115
|
+
...this.walStreamOptions
|
|
112
116
|
};
|
|
113
117
|
this._walStream = new WalStream(options);
|
|
114
118
|
return this._walStream!;
|
|
115
119
|
}
|
|
116
120
|
|
|
117
121
|
async replicateSnapshot() {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
122
|
+
const promise = (async () => {
|
|
123
|
+
this.replicationConnection = await this.connectionManager.replicationConnection();
|
|
124
|
+
await this.walStream.initReplication(this.replicationConnection);
|
|
125
|
+
await this.storage!.autoActivate();
|
|
126
|
+
})();
|
|
127
|
+
this.snapshotPromise = promise.catch((e) => e);
|
|
128
|
+
await promise;
|
|
121
129
|
}
|
|
122
130
|
|
|
123
131
|
startStreaming() {
|