@powersync/service-module-postgres 0.14.4 → 0.16.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.
Files changed (38) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/LICENSE +3 -3
  3. package/dist/api/PostgresRouteAPIAdapter.js +1 -1
  4. package/dist/api/PostgresRouteAPIAdapter.js.map +1 -1
  5. package/dist/module/PostgresModule.d.ts +1 -2
  6. package/dist/module/PostgresModule.js +3 -40
  7. package/dist/module/PostgresModule.js.map +1 -1
  8. package/dist/replication/PgRelation.js +1 -1
  9. package/dist/replication/PgRelation.js.map +1 -1
  10. package/dist/replication/SnapshotQuery.js +4 -4
  11. package/dist/replication/SnapshotQuery.js.map +1 -1
  12. package/dist/replication/WalStream.d.ts +3 -2
  13. package/dist/replication/WalStream.js +26 -16
  14. package/dist/replication/WalStream.js.map +1 -1
  15. package/dist/replication/replication-utils.js +10 -2
  16. package/dist/replication/replication-utils.js.map +1 -1
  17. package/dist/utils/pgwire_utils.d.ts +3 -3
  18. package/dist/utils/pgwire_utils.js.map +1 -1
  19. package/package.json +13 -13
  20. package/src/api/PostgresRouteAPIAdapter.ts +4 -1
  21. package/src/module/PostgresModule.ts +2 -43
  22. package/src/replication/PgRelation.ts +2 -2
  23. package/src/replication/SnapshotQuery.ts +4 -4
  24. package/src/replication/WalStream.ts +36 -19
  25. package/src/replication/replication-utils.ts +10 -2
  26. package/src/utils/pgwire_utils.ts +5 -3
  27. package/test/src/checkpoints.test.ts +2 -0
  28. package/test/src/large_batch.test.ts +0 -1
  29. package/test/src/pg_test.test.ts +57 -17
  30. package/test/src/slow_tests.test.ts +0 -2
  31. package/test/src/util.ts +2 -4
  32. package/test/src/wal_stream.test.ts +12 -21
  33. package/test/src/wal_stream_utils.ts +10 -1
  34. package/tsconfig.tsbuildinfo +1 -1
  35. package/dist/auth/SupabaseKeyCollector.d.ts +0 -17
  36. package/dist/auth/SupabaseKeyCollector.js +0 -71
  37. package/dist/auth/SupabaseKeyCollector.js.map +0 -1
  38. package/src/auth/SupabaseKeyCollector.ts +0 -83
@@ -34,13 +34,11 @@ bucket_definitions:
34
34
  `CREATE TABLE test_data(id uuid primary key default uuid_generate_v4(), description text, num int8)`
35
35
  );
36
36
 
37
- await context.replicateSnapshot();
37
+ await context.initializeReplication();
38
38
 
39
39
  const startRowCount = (await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.ROWS_REPLICATED)) ?? 0;
40
40
  const startTxCount = (await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.TRANSACTIONS_REPLICATED)) ?? 0;
41
41
 
42
- context.startStreaming();
43
-
44
42
  const [{ test_id }] = pgwireRows(
45
43
  await pool.query(
46
44
  `INSERT INTO test_data(description, num) VALUES('test1', 1152921504606846976) returning id as test_id`
@@ -53,7 +51,8 @@ bucket_definitions:
53
51
  const endRowCount = (await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.ROWS_REPLICATED)) ?? 0;
54
52
  const endTxCount = (await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.TRANSACTIONS_REPLICATED)) ?? 0;
55
53
  expect(endRowCount - startRowCount).toEqual(1);
56
- expect(endTxCount - startTxCount).toEqual(1);
54
+ // In some rare cases there may be additional empty transactions, so we allow for that.
55
+ expect(endTxCount - startTxCount).toBeGreaterThanOrEqual(1);
57
56
  });
58
57
 
59
58
  test('replicating case sensitive table', async () => {
@@ -69,13 +68,11 @@ bucket_definitions:
69
68
  await pool.query(`DROP TABLE IF EXISTS "test_DATA"`);
70
69
  await pool.query(`CREATE TABLE "test_DATA"(id uuid primary key default uuid_generate_v4(), description text)`);
71
70
 
72
- await context.replicateSnapshot();
71
+ await context.initializeReplication();
73
72
 
74
73
  const startRowCount = (await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.ROWS_REPLICATED)) ?? 0;
75
74
  const startTxCount = (await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.TRANSACTIONS_REPLICATED)) ?? 0;
76
75
 
77
- context.startStreaming();
78
-
79
76
  const [{ test_id }] = pgwireRows(
80
77
  await pool.query(`INSERT INTO "test_DATA"(description) VALUES('test1') returning id as test_id`)
81
78
  );
@@ -86,7 +83,7 @@ bucket_definitions:
86
83
  const endRowCount = (await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.ROWS_REPLICATED)) ?? 0;
87
84
  const endTxCount = (await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.TRANSACTIONS_REPLICATED)) ?? 0;
88
85
  expect(endRowCount - startRowCount).toEqual(1);
89
- expect(endTxCount - startTxCount).toEqual(1);
86
+ expect(endTxCount - startTxCount).toBeGreaterThanOrEqual(1);
90
87
  });
91
88
 
92
89
  test('replicating TOAST values', async () => {
@@ -143,8 +140,7 @@ bucket_definitions:
143
140
  await pool.query(`DROP TABLE IF EXISTS test_data`);
144
141
  await pool.query(`CREATE TABLE test_data(id uuid primary key default uuid_generate_v4(), description text)`);
145
142
 
146
- await context.replicateSnapshot();
147
- context.startStreaming();
143
+ await context.initializeReplication();
148
144
 
149
145
  const [{ test_id }] = pgwireRows(
150
146
  await pool.query(`INSERT INTO test_data(description) VALUES('test1') returning id as test_id`)
@@ -166,8 +162,7 @@ bucket_definitions:
166
162
  await pool.query(`DROP TABLE IF EXISTS test_data`);
167
163
  await pool.query(`CREATE TABLE test_data(id uuid primary key default uuid_generate_v4(), description text)`);
168
164
 
169
- await context.replicateSnapshot();
170
- context.startStreaming();
165
+ await context.initializeReplication();
171
166
 
172
167
  const [{ test_id }] = pgwireRows(
173
168
  await pool.query(`INSERT INTO test_data(description) VALUES('test1') returning id as test_id`)
@@ -179,8 +174,8 @@ bucket_definitions:
179
174
  )
180
175
  );
181
176
 
182
- // This update may fail replicating with:
183
- // Error: Update on missing record public.test_data:074a601e-fc78-4c33-a15d-f89fdd4af31d :: {"g":1,"t":"651e9fbe9fec6155895057ec","k":"1a0b34da-fb8c-5e6f-8421-d7a3c5d4df4f"}
177
+ // Since we don't have an old copy of the record with the new primary key, this
178
+ // may trigger a "resnapshot".
184
179
  await pool.query(`UPDATE test_data SET description = 'test2b' WHERE id = '${test_id2}'`);
185
180
 
186
181
  // Re-use old id again
@@ -264,16 +259,12 @@ bucket_definitions:
264
259
 
265
260
  await pool.query(`CREATE TABLE test_donotsync(id uuid primary key default uuid_generate_v4(), description text)`);
266
261
 
267
- await context.replicateSnapshot();
262
+ await context.initializeReplication();
268
263
 
269
264
  const startRowCount = (await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.ROWS_REPLICATED)) ?? 0;
270
265
  const startTxCount = (await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.TRANSACTIONS_REPLICATED)) ?? 0;
271
266
 
272
- context.startStreaming();
273
-
274
- const [{ test_id }] = pgwireRows(
275
- await pool.query(`INSERT INTO test_donotsync(description) VALUES('test1') returning id as test_id`)
276
- );
267
+ await pool.query(`INSERT INTO test_donotsync(description) VALUES('test1') returning id as test_id`);
277
268
 
278
269
  const data = await context.getBucketData('global[]');
279
270
 
@@ -283,7 +274,7 @@ bucket_definitions:
283
274
 
284
275
  // There was a transaction, but we should not replicate any actual data
285
276
  expect(endRowCount - startRowCount).toEqual(0);
286
- expect(endTxCount - startTxCount).toEqual(1);
277
+ expect(endTxCount - startTxCount).toBeGreaterThanOrEqual(1);
287
278
  });
288
279
 
289
280
  test('reporting slot issues', async () => {
@@ -118,11 +118,20 @@ export class WalStreamTestContext implements AsyncDisposable {
118
118
  return this._walStream!;
119
119
  }
120
120
 
121
+ /**
122
+ * Replicate a snapshot, start streaming, and wait for a consistent checkpoint.
123
+ */
124
+ async initializeReplication() {
125
+ await this.replicateSnapshot();
126
+ this.startStreaming();
127
+ // Make sure we're up to date
128
+ await this.getCheckpoint();
129
+ }
130
+
121
131
  async replicateSnapshot() {
122
132
  const promise = (async () => {
123
133
  this.replicationConnection = await this.connectionManager.replicationConnection();
124
134
  await this.walStream.initReplication(this.replicationConnection);
125
- await this.storage!.autoActivate();
126
135
  })();
127
136
  this.snapshotPromise = promise.catch((e) => e);
128
137
  await promise;