@powersync/service-module-postgres 0.19.3 → 0.19.4
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/dist/api/PostgresRouteAPIAdapter.d.ts +1 -1
- package/dist/api/PostgresRouteAPIAdapter.js +63 -72
- package/dist/api/PostgresRouteAPIAdapter.js.map +1 -1
- package/dist/module/PostgresModule.js.map +1 -1
- package/dist/replication/MissingReplicationSlotError.d.ts +41 -0
- package/dist/replication/MissingReplicationSlotError.js +33 -0
- package/dist/replication/MissingReplicationSlotError.js.map +1 -0
- package/dist/replication/PostgresErrorRateLimiter.js +1 -1
- package/dist/replication/PostgresErrorRateLimiter.js.map +1 -1
- package/dist/replication/SnapshotQuery.js +2 -2
- package/dist/replication/SnapshotQuery.js.map +1 -1
- package/dist/replication/WalStream.d.ts +35 -3
- package/dist/replication/WalStream.js +135 -9
- package/dist/replication/WalStream.js.map +1 -1
- package/dist/replication/WalStreamReplicationJob.js +6 -3
- package/dist/replication/WalStreamReplicationJob.js.map +1 -1
- package/dist/replication/replication-index.d.ts +3 -1
- package/dist/replication/replication-index.js +3 -1
- package/dist/replication/replication-index.js.map +1 -1
- package/dist/replication/replication-utils.d.ts +3 -11
- package/dist/replication/replication-utils.js +101 -164
- package/dist/replication/replication-utils.js.map +1 -1
- package/dist/replication/wal-budget-utils.d.ts +23 -0
- package/dist/replication/wal-budget-utils.js +57 -0
- package/dist/replication/wal-budget-utils.js.map +1 -0
- package/dist/types/registry.js +1 -1
- package/dist/types/registry.js.map +1 -1
- package/package.json +15 -11
- package/sql/check-source-configuration.plpgsql +13 -0
- package/sql/debug-tables-info-batched.plpgsql +230 -0
- package/CHANGELOG.md +0 -858
- package/src/api/PostgresRouteAPIAdapter.ts +0 -356
- package/src/index.ts +0 -1
- package/src/module/PostgresModule.ts +0 -122
- package/src/replication/ConnectionManagerFactory.ts +0 -33
- package/src/replication/PgManager.ts +0 -122
- package/src/replication/PgRelation.ts +0 -41
- package/src/replication/PostgresErrorRateLimiter.ts +0 -48
- package/src/replication/SnapshotQuery.ts +0 -213
- package/src/replication/WalStream.ts +0 -1137
- package/src/replication/WalStreamReplicationJob.ts +0 -138
- package/src/replication/WalStreamReplicator.ts +0 -53
- package/src/replication/replication-index.ts +0 -5
- package/src/replication/replication-utils.ts +0 -398
- package/src/types/registry.ts +0 -275
- package/src/types/resolver.ts +0 -227
- package/src/types/types.ts +0 -44
- package/src/utils/application-name.ts +0 -8
- package/src/utils/migration_lib.ts +0 -80
- package/src/utils/populate_test_data.ts +0 -37
- package/src/utils/populate_test_data_worker.ts +0 -53
- package/src/utils/postgres_version.ts +0 -8
- package/test/src/checkpoints.test.ts +0 -86
- package/test/src/chunked_snapshots.test.ts +0 -161
- package/test/src/env.ts +0 -11
- package/test/src/large_batch.test.ts +0 -241
- package/test/src/pg_test.test.ts +0 -729
- package/test/src/resuming_snapshots.test.ts +0 -160
- package/test/src/route_api_adapter.test.ts +0 -62
- package/test/src/schema_changes.test.ts +0 -655
- package/test/src/setup.ts +0 -12
- package/test/src/slow_tests.test.ts +0 -519
- package/test/src/storage_combination.test.ts +0 -35
- package/test/src/types/registry.test.ts +0 -149
- package/test/src/util.ts +0 -151
- package/test/src/validation.test.ts +0 -63
- package/test/src/wal_stream.test.ts +0 -607
- package/test/src/wal_stream_utils.ts +0 -284
- package/test/tsconfig.json +0 -27
- package/tsconfig.json +0 -34
- package/tsconfig.tsbuildinfo +0 -1
- package/vitest.config.ts +0 -3
package/test/src/util.ts
DELETED
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import { PostgresRouteAPIAdapter } from '@module/api/PostgresRouteAPIAdapter.js';
|
|
2
|
-
import * as types from '@module/types/types.js';
|
|
3
|
-
import * as lib_postgres from '@powersync/lib-service-postgres';
|
|
4
|
-
import { logger } from '@powersync/lib-services-framework';
|
|
5
|
-
import {
|
|
6
|
-
BucketStorageFactory,
|
|
7
|
-
CURRENT_STORAGE_VERSION,
|
|
8
|
-
InternalOpId,
|
|
9
|
-
LEGACY_STORAGE_VERSION,
|
|
10
|
-
SUPPORTED_STORAGE_VERSIONS,
|
|
11
|
-
TestStorageConfig,
|
|
12
|
-
TestStorageFactory
|
|
13
|
-
} from '@powersync/service-core';
|
|
14
|
-
import * as pgwire from '@powersync/service-jpgwire';
|
|
15
|
-
import * as mongo_storage from '@powersync/service-module-mongodb-storage';
|
|
16
|
-
import * as postgres_storage from '@powersync/service-module-postgres-storage';
|
|
17
|
-
import { describe, TestOptions } from 'vitest';
|
|
18
|
-
import { env } from './env.js';
|
|
19
|
-
|
|
20
|
-
export const TEST_URI = env.PG_TEST_URL;
|
|
21
|
-
|
|
22
|
-
export const INITIALIZED_MONGO_STORAGE_FACTORY = mongo_storage.test_utils.mongoTestStorageFactoryGenerator({
|
|
23
|
-
url: env.MONGO_TEST_URL,
|
|
24
|
-
isCI: env.CI
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
export const INITIALIZED_POSTGRES_STORAGE_FACTORY = postgres_storage.test_utils.postgresTestSetup({
|
|
28
|
-
url: env.PG_STORAGE_TEST_URL
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
const TEST_STORAGE_VERSIONS = SUPPORTED_STORAGE_VERSIONS;
|
|
32
|
-
|
|
33
|
-
export interface StorageVersionTestContext {
|
|
34
|
-
factory: TestStorageFactory;
|
|
35
|
-
storageVersion: number;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function describeWithStorage(
|
|
39
|
-
options: TestOptions & { storageVersions?: number[] },
|
|
40
|
-
fn: (context: StorageVersionTestContext) => void
|
|
41
|
-
) {
|
|
42
|
-
const storageVersions = options.storageVersions ?? TEST_STORAGE_VERSIONS;
|
|
43
|
-
const describeFactory = (storageName: string, config: TestStorageConfig) => {
|
|
44
|
-
describe(`${storageName} storage`, options, function () {
|
|
45
|
-
for (const storageVersion of storageVersions) {
|
|
46
|
-
describe(`storage v${storageVersion}`, function () {
|
|
47
|
-
fn({
|
|
48
|
-
factory: config.factory,
|
|
49
|
-
storageVersion
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
if (env.TEST_MONGO_STORAGE) {
|
|
57
|
-
describeFactory('mongodb', INITIALIZED_MONGO_STORAGE_FACTORY);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (env.TEST_POSTGRES_STORAGE) {
|
|
61
|
-
describeFactory('postgres', INITIALIZED_POSTGRES_STORAGE_FACTORY);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export const TEST_CONNECTION_OPTIONS = types.normalizeConnectionConfig({
|
|
66
|
-
type: 'postgresql',
|
|
67
|
-
uri: TEST_URI,
|
|
68
|
-
sslmode: 'disable'
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
export async function clearTestDb(db: pgwire.PgClient) {
|
|
72
|
-
await db.query(
|
|
73
|
-
"select pg_drop_replication_slot(slot_name) from pg_replication_slots where active = false and slot_name like 'test_%'"
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
await db.query(`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`);
|
|
77
|
-
try {
|
|
78
|
-
await db.query(`DROP PUBLICATION powersync`);
|
|
79
|
-
} catch (e) {
|
|
80
|
-
// Ignore
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
await db.query(`CREATE PUBLICATION powersync FOR ALL TABLES`);
|
|
84
|
-
|
|
85
|
-
const tableRows = pgwire.pgwireRows(
|
|
86
|
-
await db.query(`SELECT table_name FROM information_schema.tables where table_schema = 'public'`)
|
|
87
|
-
);
|
|
88
|
-
for (let row of tableRows) {
|
|
89
|
-
const name = row.table_name;
|
|
90
|
-
if (name.startsWith('test_')) {
|
|
91
|
-
await db.query(`DROP TABLE public.${lib_postgres.escapeIdentifier(name)}`);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const domainRows = pgwire.pgwireRows(
|
|
96
|
-
await db.query(`
|
|
97
|
-
SELECT typname,typtype
|
|
98
|
-
FROM pg_type t
|
|
99
|
-
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
|
|
100
|
-
WHERE n.nspname = 'public' AND typarray != 0
|
|
101
|
-
`)
|
|
102
|
-
);
|
|
103
|
-
for (let row of domainRows) {
|
|
104
|
-
if (row.typtype == 'd') {
|
|
105
|
-
await db.query(`DROP DOMAIN public.${lib_postgres.escapeIdentifier(row.typname)} CASCADE`);
|
|
106
|
-
} else {
|
|
107
|
-
await db.query(`DROP TYPE public.${lib_postgres.escapeIdentifier(row.typname)} CASCADE`);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export async function connectPgWire(type?: 'replication' | 'standard') {
|
|
113
|
-
const db = await pgwire.connectPgWire(TEST_CONNECTION_OPTIONS, { type, applicationName: 'powersync-tests' });
|
|
114
|
-
return db;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export function connectPgPool() {
|
|
118
|
-
const db = pgwire.connectPgWirePool(TEST_CONNECTION_OPTIONS);
|
|
119
|
-
return db;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export async function getClientCheckpoint(
|
|
123
|
-
db: pgwire.PgClient,
|
|
124
|
-
storageFactory: BucketStorageFactory,
|
|
125
|
-
options?: { timeout?: number }
|
|
126
|
-
): Promise<InternalOpId> {
|
|
127
|
-
const start = Date.now();
|
|
128
|
-
|
|
129
|
-
const api = new PostgresRouteAPIAdapter(db);
|
|
130
|
-
const lsn = await api.createReplicationHead(async (lsn) => lsn);
|
|
131
|
-
|
|
132
|
-
// This old API needs a persisted checkpoint id.
|
|
133
|
-
// Since we don't use LSNs anymore, the only way to get that is to wait.
|
|
134
|
-
|
|
135
|
-
const timeout = options?.timeout ?? 50_000;
|
|
136
|
-
|
|
137
|
-
logger.info(`Waiting for LSN checkpoint: ${lsn}`);
|
|
138
|
-
while (Date.now() - start < timeout) {
|
|
139
|
-
const storage = await storageFactory.getActiveStorage();
|
|
140
|
-
const cp = await storage?.getCheckpoint();
|
|
141
|
-
|
|
142
|
-
if (cp?.lsn != null && cp.lsn >= lsn) {
|
|
143
|
-
logger.info(`Got write checkpoint: ${lsn} : ${cp.checkpoint}`);
|
|
144
|
-
return cp.checkpoint;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
throw new Error('Timeout while waiting for checkpoint');
|
|
151
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { getDebugTablesInfo } from '@module/replication/replication-utils.js';
|
|
2
|
-
import { expect, test } from 'vitest';
|
|
3
|
-
|
|
4
|
-
import { INITIALIZED_MONGO_STORAGE_FACTORY } from './util.js';
|
|
5
|
-
import { WalStreamTestContext } from './wal_stream_utils.js';
|
|
6
|
-
import { updateSyncRulesFromYaml } from '@powersync/service-core';
|
|
7
|
-
|
|
8
|
-
test('validate tables', async () => {
|
|
9
|
-
await using context = await WalStreamTestContext.open(INITIALIZED_MONGO_STORAGE_FACTORY.factory);
|
|
10
|
-
const { pool } = context;
|
|
11
|
-
|
|
12
|
-
await pool.query(`CREATE TABLE test_data(id uuid primary key default uuid_generate_v4(), description text)`);
|
|
13
|
-
|
|
14
|
-
const syncRuleContent = `
|
|
15
|
-
bucket_definitions:
|
|
16
|
-
global:
|
|
17
|
-
data:
|
|
18
|
-
- SELECT id, description FROM "test_data"
|
|
19
|
-
- SELECT * FROM "other"
|
|
20
|
-
- SELECT * FROM "other%"
|
|
21
|
-
`;
|
|
22
|
-
|
|
23
|
-
const syncRules = await context.factory.updateSyncRules(updateSyncRulesFromYaml(syncRuleContent));
|
|
24
|
-
|
|
25
|
-
const tablePatterns = syncRules.parsed({ defaultSchema: 'public' }).sync_rules.config.getSourceTables();
|
|
26
|
-
const tableInfo = await getDebugTablesInfo({
|
|
27
|
-
db: pool,
|
|
28
|
-
publicationName: context.publicationName,
|
|
29
|
-
connectionTag: context.connectionTag,
|
|
30
|
-
tablePatterns: tablePatterns,
|
|
31
|
-
syncRules: syncRules.parsed({ defaultSchema: 'public' }).sync_rules.config
|
|
32
|
-
});
|
|
33
|
-
expect(tableInfo).toEqual([
|
|
34
|
-
{
|
|
35
|
-
schema: 'public',
|
|
36
|
-
pattern: 'test_data',
|
|
37
|
-
wildcard: false,
|
|
38
|
-
table: {
|
|
39
|
-
schema: 'public',
|
|
40
|
-
name: 'test_data',
|
|
41
|
-
replication_id: ['id'],
|
|
42
|
-
pattern: undefined,
|
|
43
|
-
data_queries: true,
|
|
44
|
-
parameter_queries: false,
|
|
45
|
-
errors: []
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
schema: 'public',
|
|
50
|
-
pattern: 'other',
|
|
51
|
-
wildcard: false,
|
|
52
|
-
table: {
|
|
53
|
-
schema: 'public',
|
|
54
|
-
name: 'other',
|
|
55
|
-
replication_id: [],
|
|
56
|
-
data_queries: true,
|
|
57
|
-
parameter_queries: false,
|
|
58
|
-
errors: [{ level: 'warning', message: 'Table "public"."other" not found.' }]
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
{ schema: 'public', pattern: 'other%', wildcard: true, tables: [] }
|
|
62
|
-
]);
|
|
63
|
-
});
|