@powersync/service-module-postgres 0.0.0-dev-20241210162153 → 0.0.0-dev-20241219091224

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.
@@ -1,10 +1,11 @@
1
- import { putOp, removeOp } from '@core-tests/stream_utils.js';
2
- import { MONGO_STORAGE_FACTORY } from '@core-tests/util.js';
3
1
  import { BucketStorageFactory, Metrics } from '@powersync/service-core';
2
+ import { putOp, removeOp } from '@powersync/service-core-tests';
4
3
  import { pgwireRows } from '@powersync/service-jpgwire';
5
4
  import * as crypto from 'crypto';
6
5
  import { describe, expect, test } from 'vitest';
6
+ import { INITIALIZED_MONGO_STORAGE_FACTORY } from './util.js';
7
7
  import { WalStreamTestContext } from './wal_stream_utils.js';
8
+ import { MissingReplicationSlotError } from '@module/replication/WalStream.js';
8
9
 
9
10
  type StorageFactory = () => Promise<BucketStorageFactory>;
10
11
 
@@ -16,7 +17,7 @@ bucket_definitions:
16
17
  `;
17
18
 
18
19
  describe('wal stream - mongodb', { timeout: 20_000 }, function () {
19
- defineWalStreamTests(MONGO_STORAGE_FACTORY);
20
+ defineWalStreamTests(INITIALIZED_MONGO_STORAGE_FACTORY);
20
21
  });
21
22
 
22
23
  function defineWalStreamTests(factory: StorageFactory) {
@@ -291,4 +292,52 @@ bucket_definitions:
291
292
  expect(endRowCount - startRowCount).toEqual(0);
292
293
  expect(endTxCount - startTxCount).toEqual(1);
293
294
  });
295
+
296
+ test('reporting slot issues', async () => {
297
+ {
298
+ await using context = await WalStreamTestContext.open(factory);
299
+ const { pool } = context;
300
+ await context.updateSyncRules(`
301
+ bucket_definitions:
302
+ global:
303
+ data:
304
+ - SELECT id, description FROM "test_data"`);
305
+
306
+ await pool.query(
307
+ `CREATE TABLE test_data(id uuid primary key default uuid_generate_v4(), description text, num int8)`
308
+ );
309
+ await pool.query(
310
+ `INSERT INTO test_data(id, description) VALUES('8133cd37-903b-4937-a022-7c8294015a3a', 'test1') returning id as test_id`
311
+ );
312
+ await context.replicateSnapshot();
313
+ await context.startStreaming();
314
+
315
+ const data = await context.getBucketData('global[]');
316
+
317
+ expect(data).toMatchObject([
318
+ putOp('test_data', {
319
+ id: '8133cd37-903b-4937-a022-7c8294015a3a',
320
+ description: 'test1'
321
+ })
322
+ ]);
323
+
324
+ expect(await context.storage!.getStatus()).toMatchObject({ active: true, snapshot_done: true });
325
+ }
326
+
327
+ {
328
+ await using context = await WalStreamTestContext.open(factory, { doNotClear: true });
329
+ const { pool } = context;
330
+ await pool.query('DROP PUBLICATION powersync');
331
+ await pool.query(`UPDATE test_data SET description = 'updated'`);
332
+ await pool.query('CREATE PUBLICATION powersync FOR ALL TABLES');
333
+
334
+ await context.loadActiveSyncRules();
335
+ await expect(async () => {
336
+ await context.replicateSnapshot();
337
+ }).rejects.toThrowError(MissingReplicationSlotError);
338
+
339
+ // The error is handled on a higher level, which triggers
340
+ // creating a new replication slot.
341
+ }
342
+ });
294
343
  }
@@ -1,10 +1,9 @@
1
- import { fromAsync } from '@core-tests/stream_utils.js';
2
1
  import { PgManager } from '@module/replication/PgManager.js';
3
2
  import { PUBLICATION_NAME, WalStream, WalStreamOptions } from '@module/replication/WalStream.js';
4
3
  import { BucketStorageFactory, OplogEntry, SyncRulesBucketStorage } from '@powersync/service-core';
4
+ import { StorageOptions, test_utils } from '@powersync/service-core-tests';
5
5
  import * as pgwire from '@powersync/service-jpgwire';
6
6
  import { clearTestDb, getClientCheckpoint, TEST_CONNECTION_OPTIONS } from './util.js';
7
- import { StorageOptions } from '@core-tests/util.js';
8
7
 
9
8
  export class WalStreamTestContext implements AsyncDisposable {
10
9
  private _walStream?: WalStream;
@@ -77,6 +76,16 @@ export class WalStreamTestContext implements AsyncDisposable {
77
76
  return this.storage!;
78
77
  }
79
78
 
79
+ async loadActiveSyncRules() {
80
+ const syncRules = await this.factory.getActiveSyncRulesContent();
81
+ if (syncRules == null) {
82
+ throw new Error(`Active sync rules not available`);
83
+ }
84
+
85
+ this.storage = this.factory.getInstance(syncRules);
86
+ return this.storage!;
87
+ }
88
+
80
89
  get walStream() {
81
90
  if (this.storage == null) {
82
91
  throw new Error('updateSyncRules() first');
@@ -122,7 +131,7 @@ export class WalStreamTestContext implements AsyncDisposable {
122
131
  async getBucketsDataBatch(buckets: Record<string, string>, options?: { timeout?: number }) {
123
132
  let checkpoint = await this.getCheckpoint(options);
124
133
  const map = new Map<string, string>(Object.entries(buckets));
125
- return fromAsync(this.storage!.getBucketDataBatch(checkpoint, map));
134
+ return test_utils.fromAsync(this.storage!.getBucketDataBatch(checkpoint, map));
126
135
  }
127
136
 
128
137
  /**
@@ -136,7 +145,7 @@ export class WalStreamTestContext implements AsyncDisposable {
136
145
  while (true) {
137
146
  const batch = this.storage!.getBucketDataBatch(checkpoint, map);
138
147
 
139
- const batches = await fromAsync(batch);
148
+ const batches = await test_utils.fromAsync(batch);
140
149
  data = data.concat(batches[0]?.batch.data ?? []);
141
150
  if (batches.length == 0 || !batches[0]!.batch.has_more) {
142
151
  break;
@@ -154,7 +163,7 @@ export class WalStreamTestContext implements AsyncDisposable {
154
163
  const { checkpoint } = await this.storage!.getCheckpoint();
155
164
  const map = new Map<string, string>([[bucket, start]]);
156
165
  const batch = this.storage!.getBucketDataBatch(checkpoint, map);
157
- const batches = await fromAsync(batch);
166
+ const batches = await test_utils.fromAsync(batch);
158
167
  return batches[0]?.batch.data ?? [];
159
168
  }
160
169
  }