@powersync/service-module-postgres-storage 0.0.0-dev-20260225093637 → 0.0.0-dev-20260313100403

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 (87) hide show
  1. package/CHANGELOG.md +53 -8
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/@types/migrations/scripts/1771424826685-current-data-pending-deletes.d.ts +3 -0
  4. package/dist/@types/migrations/scripts/1771491856000-sync-plan.d.ts +3 -0
  5. package/dist/@types/storage/PostgresBucketStorageFactory.d.ts +4 -0
  6. package/dist/@types/storage/PostgresCompactor.d.ts +8 -2
  7. package/dist/@types/storage/PostgresReportStorage.d.ts +3 -3
  8. package/dist/@types/storage/PostgresSyncRulesStorage.d.ts +10 -4
  9. package/dist/@types/storage/batch/OperationBatch.d.ts +2 -2
  10. package/dist/@types/storage/batch/PostgresBucketBatch.d.ts +13 -9
  11. package/dist/@types/storage/batch/PostgresPersistedBatch.d.ts +17 -5
  12. package/dist/@types/storage/current-data-store.d.ts +85 -0
  13. package/dist/@types/storage/current-data-table.d.ts +9 -0
  14. package/dist/@types/storage/table-id.d.ts +2 -0
  15. package/dist/@types/types/models/CurrentData.d.ts +18 -3
  16. package/dist/@types/types/models/SyncRules.d.ts +9 -0
  17. package/dist/@types/types/models/json.d.ts +11 -0
  18. package/dist/@types/utils/bson.d.ts +1 -1
  19. package/dist/@types/utils/test-utils.d.ts +1 -1
  20. package/dist/migrations/scripts/1771424826685-current-data-pending-deletes.js +8 -0
  21. package/dist/migrations/scripts/1771424826685-current-data-pending-deletes.js.map +1 -0
  22. package/dist/migrations/scripts/1771491856000-sync-plan.js +91 -0
  23. package/dist/migrations/scripts/1771491856000-sync-plan.js.map +1 -0
  24. package/dist/storage/PostgresBucketStorageFactory.js +50 -5
  25. package/dist/storage/PostgresBucketStorageFactory.js.map +1 -1
  26. package/dist/storage/PostgresCompactor.js +14 -6
  27. package/dist/storage/PostgresCompactor.js.map +1 -1
  28. package/dist/storage/PostgresReportStorage.js +7 -7
  29. package/dist/storage/PostgresReportStorage.js.map +1 -1
  30. package/dist/storage/PostgresSyncRulesStorage.js +98 -24
  31. package/dist/storage/PostgresSyncRulesStorage.js.map +1 -1
  32. package/dist/storage/batch/OperationBatch.js +2 -1
  33. package/dist/storage/batch/OperationBatch.js.map +1 -1
  34. package/dist/storage/batch/PostgresBucketBatch.js +295 -213
  35. package/dist/storage/batch/PostgresBucketBatch.js.map +1 -1
  36. package/dist/storage/batch/PostgresPersistedBatch.js +86 -81
  37. package/dist/storage/batch/PostgresPersistedBatch.js.map +1 -1
  38. package/dist/storage/current-data-store.js +270 -0
  39. package/dist/storage/current-data-store.js.map +1 -0
  40. package/dist/storage/current-data-table.js +22 -0
  41. package/dist/storage/current-data-table.js.map +1 -0
  42. package/dist/storage/sync-rules/PostgresPersistedSyncRulesContent.js +1 -0
  43. package/dist/storage/sync-rules/PostgresPersistedSyncRulesContent.js.map +1 -1
  44. package/dist/storage/table-id.js +8 -0
  45. package/dist/storage/table-id.js.map +1 -0
  46. package/dist/types/models/CurrentData.js +11 -2
  47. package/dist/types/models/CurrentData.js.map +1 -1
  48. package/dist/types/models/SyncRules.js +11 -1
  49. package/dist/types/models/SyncRules.js.map +1 -1
  50. package/dist/types/models/json.js +21 -0
  51. package/dist/types/models/json.js.map +1 -0
  52. package/dist/utils/bson.js.map +1 -1
  53. package/dist/utils/db.js +9 -0
  54. package/dist/utils/db.js.map +1 -1
  55. package/dist/utils/test-utils.js +13 -6
  56. package/dist/utils/test-utils.js.map +1 -1
  57. package/package.json +9 -9
  58. package/src/migrations/scripts/1771424826685-current-data-pending-deletes.ts +10 -0
  59. package/src/migrations/scripts/1771491856000-sync-plan.ts +21 -0
  60. package/src/storage/PostgresBucketStorageFactory.ts +62 -7
  61. package/src/storage/PostgresCompactor.ts +17 -8
  62. package/src/storage/PostgresReportStorage.ts +7 -7
  63. package/src/storage/PostgresSyncRulesStorage.ts +47 -31
  64. package/src/storage/batch/OperationBatch.ts +4 -3
  65. package/src/storage/batch/PostgresBucketBatch.ts +316 -238
  66. package/src/storage/batch/PostgresPersistedBatch.ts +92 -84
  67. package/src/storage/current-data-store.ts +326 -0
  68. package/src/storage/current-data-table.ts +26 -0
  69. package/src/storage/sync-rules/PostgresPersistedSyncRulesContent.ts +1 -7
  70. package/src/storage/table-id.ts +9 -0
  71. package/src/types/models/CurrentData.ts +17 -4
  72. package/src/types/models/SyncRules.ts +15 -1
  73. package/src/types/models/json.ts +26 -0
  74. package/src/utils/bson.ts +1 -1
  75. package/src/utils/db.ts +10 -0
  76. package/src/utils/test-utils.ts +14 -7
  77. package/test/src/__snapshots__/{connection-report-storage.test.ts.snap → client-connections-storage.test.ts.snap} +22 -22
  78. package/test/src/__snapshots__/storage.test.ts.snap +151 -0
  79. package/test/src/__snapshots__/storage_compacting.test.ts.snap +17 -0
  80. package/test/src/__snapshots__/storage_sync.test.ts.snap +1111 -16
  81. package/test/src/{connection-report-storage.test.ts → client-connections-storage.test.ts} +1 -1
  82. package/test/src/env.ts +1 -1
  83. package/test/src/migrations.test.ts +1 -1
  84. package/test/src/storage.test.ts +138 -131
  85. package/test/src/storage_compacting.test.ts +80 -11
  86. package/test/src/storage_sync.test.ts +57 -54
  87. package/test/src/util.ts +4 -4
@@ -1,17 +1,16 @@
1
- import { GetIntanceOptions, storage, SyncRulesBucketStorage, UpdateSyncRulesOptions } from '@powersync/service-core';
1
+ import { framework, GetIntanceOptions, storage, SyncRulesBucketStorage } from '@powersync/service-core';
2
2
  import * as pg_wire from '@powersync/service-jpgwire';
3
- import * as sync_rules from '@powersync/service-sync-rules';
4
3
  import crypto from 'crypto';
5
4
  import * as uuid from 'uuid';
6
5
 
7
6
  import * as lib_postgres from '@powersync/lib-service-postgres';
8
7
  import { models, NormalizedPostgresStorageConfig } from '../types/types.js';
9
8
 
9
+ import { getStorageApplicationName } from '../utils/application-name.js';
10
10
  import { NOTIFICATION_CHANNEL, STORAGE_SCHEMA_NAME } from '../utils/db.js';
11
11
  import { notifySyncRulesUpdate } from './batch/PostgresBucketBatch.js';
12
12
  import { PostgresSyncRulesStorage } from './PostgresSyncRulesStorage.js';
13
13
  import { PostgresPersistedSyncRulesContent } from './sync-rules/PostgresPersistedSyncRulesContent.js';
14
- import { getStorageApplicationName } from '../utils/application-name.js';
15
14
 
16
15
  export type PostgresBucketStorageOptions = {
17
16
  config: NormalizedPostgresStorageConfig;
@@ -83,15 +82,27 @@ export class PostgresBucketStorageFactory extends storage.BucketStorageFactory {
83
82
 
84
83
  const sizes = await this.db.sql`
85
84
  SELECT
86
- pg_total_relation_size('current_data') AS current_size_bytes,
85
+ COALESCE(
86
+ pg_total_relation_size(to_regclass('current_data')),
87
+ 0
88
+ ) AS v1_current_size_bytes,
89
+ COALESCE(
90
+ pg_total_relation_size(to_regclass('v3_current_data')),
91
+ 0
92
+ ) AS v3_current_size_bytes,
87
93
  pg_total_relation_size('bucket_parameters') AS parameter_size_bytes,
88
94
  pg_total_relation_size('bucket_data') AS operations_size_bytes;
89
- `.first<{ current_size_bytes: bigint; parameter_size_bytes: bigint; operations_size_bytes: bigint }>();
95
+ `.first<{
96
+ v1_current_size_bytes: bigint;
97
+ v3_current_size_bytes: bigint;
98
+ parameter_size_bytes: bigint;
99
+ operations_size_bytes: bigint;
100
+ }>();
90
101
 
91
102
  return {
92
103
  operations_size_bytes: Number(sizes!.operations_size_bytes),
93
104
  parameters_size_bytes: Number(sizes!.parameter_size_bytes),
94
- replication_size_bytes: Number(sizes!.current_size_bytes)
105
+ replication_size_bytes: Number(sizes!.v1_current_size_bytes) + Number(sizes!.v3_current_size_bytes)
95
106
  };
96
107
  }
97
108
 
@@ -143,6 +154,14 @@ export class PostgresBucketStorageFactory extends storage.BucketStorageFactory {
143
154
 
144
155
  async updateSyncRules(options: storage.UpdateSyncRulesOptions): Promise<PostgresPersistedSyncRulesContent> {
145
156
  const storageVersion = options.storageVersion ?? storage.CURRENT_STORAGE_VERSION;
157
+ const storageConfig = storage.STORAGE_VERSION_CONFIG[storageVersion];
158
+ if (storageConfig == null) {
159
+ throw new framework.ServiceError(
160
+ framework.ErrorCode.PSYNC_S1005,
161
+ `Unsupported storage version ${storageVersion}`
162
+ );
163
+ }
164
+ await this.initializeStorageVersion(storageConfig);
146
165
  return this.db.transaction(async (db) => {
147
166
  await db.sql`
148
167
  UPDATE sync_rules
@@ -159,7 +178,14 @@ export class PostgresBucketStorageFactory extends storage.BucketStorageFactory {
159
178
  nextval('sync_rules_id_sequence') AS id
160
179
  )
161
180
  INSERT INTO
162
- sync_rules (id, content, state, slot_name, storage_version)
181
+ sync_rules (
182
+ id,
183
+ content,
184
+ sync_plan,
185
+ state,
186
+ slot_name,
187
+ storage_version
188
+ )
163
189
  VALUES
164
190
  (
165
191
  (
@@ -169,6 +195,7 @@ export class PostgresBucketStorageFactory extends storage.BucketStorageFactory {
169
195
  next_id
170
196
  ),
171
197
  ${{ type: 'varchar', value: options.config.yaml }},
198
+ ${{ type: 'json', value: options.config.plan }},
172
199
  ${{ type: 'varchar', value: storage.SyncRuleState.PROCESSING }},
173
200
  CONCAT(
174
201
  ${{ type: 'varchar', value: this.slot_name_prefix }},
@@ -195,6 +222,34 @@ export class PostgresBucketStorageFactory extends storage.BucketStorageFactory {
195
222
  });
196
223
  }
197
224
 
225
+ /**
226
+ * Lazy-initializes storage-version-specific structures, if needed.
227
+ */
228
+ private async initializeStorageVersion(storageConfig: storage.StorageVersionConfig) {
229
+ if (!storageConfig.softDeleteCurrentData) {
230
+ return;
231
+ }
232
+
233
+ await this.db.sql`
234
+ CREATE TABLE IF NOT EXISTS v3_current_data (
235
+ group_id integer NOT NULL,
236
+ source_table TEXT NOT NULL,
237
+ source_key bytea NOT NULL,
238
+ CONSTRAINT unique_v3_current_data_id PRIMARY KEY (group_id, source_table, source_key),
239
+ buckets jsonb NOT NULL,
240
+ data bytea NOT NULL,
241
+ lookups bytea[] NOT NULL,
242
+ pending_delete BIGINT NULL
243
+ )
244
+ `.execute();
245
+
246
+ await this.db.sql`
247
+ CREATE INDEX IF NOT EXISTS v3_current_data_pending_deletes ON v3_current_data (group_id, pending_delete)
248
+ WHERE
249
+ pending_delete IS NOT NULL
250
+ `.execute();
251
+ }
252
+
198
253
  async restartReplication(sync_rules_group_id: number): Promise<void> {
199
254
  const next = await this.getNextSyncRulesContent();
200
255
  const active = await this.getActiveSyncRulesContent();
@@ -51,20 +51,20 @@ export class PostgresCompactor {
51
51
  private moveBatchLimit: number;
52
52
  private moveBatchQueryLimit: number;
53
53
  private clearBatchLimit: number;
54
- private maxOpId: InternalOpId | undefined;
54
+ private maxOpId: InternalOpId;
55
55
  private buckets: string[] | undefined;
56
56
 
57
57
  constructor(
58
58
  private db: lib_postgres.DatabaseClient,
59
59
  private group_id: number,
60
- options?: PostgresCompactOptions
60
+ options: PostgresCompactOptions
61
61
  ) {
62
- this.idLimitBytes = (options?.memoryLimitMB ?? DEFAULT_MEMORY_LIMIT_MB) * 1024 * 1024;
63
- this.moveBatchLimit = options?.moveBatchLimit ?? DEFAULT_MOVE_BATCH_LIMIT;
64
- this.moveBatchQueryLimit = options?.moveBatchQueryLimit ?? DEFAULT_MOVE_BATCH_QUERY_LIMIT;
65
- this.clearBatchLimit = options?.clearBatchLimit ?? DEFAULT_CLEAR_BATCH_LIMIT;
66
- this.maxOpId = options?.maxOpId;
67
- this.buckets = options?.compactBuckets;
62
+ this.idLimitBytes = (options.memoryLimitMB ?? DEFAULT_MEMORY_LIMIT_MB) * 1024 * 1024;
63
+ this.moveBatchLimit = options.moveBatchLimit ?? DEFAULT_MOVE_BATCH_LIMIT;
64
+ this.moveBatchQueryLimit = options.moveBatchQueryLimit ?? DEFAULT_MOVE_BATCH_QUERY_LIMIT;
65
+ this.clearBatchLimit = options.clearBatchLimit ?? DEFAULT_CLEAR_BATCH_LIMIT;
66
+ this.maxOpId = options.maxOpId ?? 0n;
67
+ this.buckets = options.compactBuckets;
68
68
  }
69
69
 
70
70
  /**
@@ -240,6 +240,15 @@ export class PostgresCompactor {
240
240
  }
241
241
  }
242
242
 
243
+ /**
244
+ * Expose the internal clearBucket() method to tests.
245
+ *
246
+ * @deprecated Only for tests
247
+ */
248
+ clearBucketForTests(bucket: string, op: InternalOpId) {
249
+ return this.clearBucket(bucket, op);
250
+ }
251
+
243
252
  /**
244
253
  * Perform a CLEAR compact for a bucket.
245
254
  *
@@ -48,13 +48,13 @@ export class PostgresReportStorage implements storage.ReportStorage {
48
48
  ): event_types.ClientConnectionReportResponse {
49
49
  if (!result) {
50
50
  return {
51
- users: 0,
52
- sdks: []
51
+ total_users: 0,
52
+ sdk_breakdown: []
53
53
  };
54
54
  }
55
55
  return {
56
- users: Number(result.users),
57
- sdks: result.sdks?.data || []
56
+ total_users: Number(result.users),
57
+ sdk_breakdown: result.sdks?.data || []
58
58
  };
59
59
  }
60
60
  private async listConnectionsQuery() {
@@ -234,12 +234,12 @@ export class PostgresReportStorage implements storage.ReportStorage {
234
234
  AND connected_at = ${{ type: 1184, value: connectIsoString }}
235
235
  `.execute();
236
236
  }
237
- async getConnectedClients(): Promise<event_types.ClientConnectionReportResponse> {
237
+ async getCurrentConnections(): Promise<event_types.ClientConnectionReportResponse> {
238
238
  const result = await this.listConnectionsQuery();
239
239
  return this.mapListCurrentConnectionsResponse(result);
240
240
  }
241
241
 
242
- async getClientConnectionReports(
242
+ async getClientConnectionsSummary(
243
243
  data: event_types.ClientConnectionReportRequest
244
244
  ): Promise<event_types.ClientConnectionReportResponse> {
245
245
  const { start, end } = data;
@@ -289,7 +289,7 @@ export class PostgresReportStorage implements storage.ReportStorage {
289
289
  return this.mapListCurrentConnectionsResponse(result);
290
290
  }
291
291
 
292
- async getGeneralClientConnectionAnalytics(
292
+ async getClientSessions(
293
293
  data: event_types.ClientConnectionAnalyticsRequest
294
294
  ): Promise<event_types.PaginatedResponse<event_types.ClientConnection>> {
295
295
  const limit = data.limit || 100;
@@ -14,6 +14,7 @@ import {
14
14
  PopulateChecksumCacheResults,
15
15
  ReplicationCheckpoint,
16
16
  storage,
17
+ StorageVersionConfig,
17
18
  utils,
18
19
  WatchWriteCheckpointOptions
19
20
  } from '@powersync/service-core';
@@ -35,6 +36,7 @@ import { PostgresBucketBatch } from './batch/PostgresBucketBatch.js';
35
36
  import { PostgresWriteCheckpointAPI } from './checkpoints/PostgresWriteCheckpointAPI.js';
36
37
  import { PostgresBucketStorageFactory } from './PostgresBucketStorageFactory.js';
37
38
  import { PostgresCompactor } from './PostgresCompactor.js';
39
+ import { PostgresCurrentDataStore } from './current-data-store.js';
38
40
 
39
41
  export type PostgresSyncRulesStorageOptions = {
40
42
  factory: PostgresBucketStorageFactory;
@@ -52,11 +54,13 @@ export class PostgresSyncRulesStorage
52
54
  public readonly sync_rules: storage.PersistedSyncRulesContent;
53
55
  public readonly slot_name: string;
54
56
  public readonly factory: PostgresBucketStorageFactory;
57
+ public readonly storageConfig: StorageVersionConfig;
55
58
 
56
59
  private sharedIterator = new BroadcastIterable((signal) => this.watchActiveCheckpoint(signal));
57
60
 
58
61
  protected db: lib_postgres.DatabaseClient;
59
62
  protected writeCheckpointAPI: PostgresWriteCheckpointAPI;
63
+ private readonly currentDataStore: PostgresCurrentDataStore;
60
64
 
61
65
  // TODO we might be able to share this in an abstract class
62
66
  private parsedSyncRulesCache:
@@ -71,6 +75,8 @@ export class PostgresSyncRulesStorage
71
75
  this.sync_rules = options.sync_rules;
72
76
  this.slot_name = options.sync_rules.slot_name;
73
77
  this.factory = options.factory;
78
+ this.storageConfig = options.sync_rules.getStorageConfig();
79
+ this.currentDataStore = new PostgresCurrentDataStore(this.storageConfig);
74
80
 
75
81
  this.writeCheckpointAPI = new PostgresWriteCheckpointAPI({
76
82
  db: this.db,
@@ -121,8 +127,18 @@ export class PostgresSyncRulesStorage
121
127
  `.execute();
122
128
  }
123
129
 
124
- compact(options?: storage.CompactOptions): Promise<void> {
125
- return new PostgresCompactor(this.db, this.group_id, options).compact();
130
+ async compact(options?: storage.CompactOptions): Promise<void> {
131
+ let maxOpId = options?.maxOpId;
132
+ if (maxOpId == null) {
133
+ const checkpoint = await this.getCheckpoint();
134
+ // Note: If there is no active checkpoint, this will be 0, in which case no compacting is performed
135
+ maxOpId = checkpoint.checkpoint;
136
+ }
137
+
138
+ return new PostgresCompactor(this.db, this.group_id, {
139
+ ...options,
140
+ maxOpId
141
+ }).compact();
126
142
  }
127
143
 
128
144
  async populatePersistentChecksumCache(options: PopulateChecksumCacheOptions): Promise<PopulateChecksumCacheResults> {
@@ -327,10 +343,7 @@ export class PostgresSyncRulesStorage
327
343
  });
328
344
  }
329
345
 
330
- async startBatch(
331
- options: storage.StartBatchOptions,
332
- callback: (batch: storage.BucketStorageBatch) => Promise<void>
333
- ): Promise<storage.FlushedResult | null> {
346
+ async createWriter(options: storage.CreateWriterOptions): Promise<storage.BucketStorageBatch> {
334
347
  const syncRules = await this.db.sql`
335
348
  SELECT
336
349
  last_checkpoint_lsn,
@@ -347,7 +360,7 @@ export class PostgresSyncRulesStorage
347
360
 
348
361
  const checkpoint_lsn = syncRules?.last_checkpoint_lsn ?? null;
349
362
 
350
- const batch = new PostgresBucketBatch({
363
+ const writer = new PostgresBucketBatch({
351
364
  logger: options.logger ?? framework.logger,
352
365
  db: this.db,
353
366
  sync_rules: this.sync_rules.parsed(options).hydratedSyncRules(),
@@ -355,22 +368,28 @@ export class PostgresSyncRulesStorage
355
368
  slot_name: this.slot_name,
356
369
  last_checkpoint_lsn: checkpoint_lsn,
357
370
  keep_alive_op: syncRules?.keepalive_op,
358
- no_checkpoint_before_lsn: syncRules?.no_checkpoint_before ?? options.zeroLSN,
359
371
  resumeFromLsn: maxLsn(syncRules?.snapshot_lsn, checkpoint_lsn),
360
372
  store_current_data: options.storeCurrentData,
361
373
  skip_existing_rows: options.skipExistingRows ?? false,
362
374
  batch_limits: this.options.batchLimits,
363
- markRecordUnavailable: options.markRecordUnavailable
375
+ markRecordUnavailable: options.markRecordUnavailable,
376
+ storageConfig: this.storageConfig
364
377
  });
365
- this.iterateListeners((cb) => cb.batchStarted?.(batch));
366
-
367
- await callback(batch);
368
- await batch.flush();
369
- if (batch.last_flushed_op != null) {
370
- return { flushed_op: batch.last_flushed_op };
371
- } else {
372
- return null;
373
- }
378
+ this.iterateListeners((cb) => cb.batchStarted?.(writer));
379
+ return writer;
380
+ }
381
+
382
+ /**
383
+ * @deprecated Use `createWriter()` with `await using` instead.
384
+ */
385
+ async startBatch(
386
+ options: storage.CreateWriterOptions,
387
+ callback: (batch: storage.BucketStorageBatch) => Promise<void>
388
+ ): Promise<storage.FlushedResult | null> {
389
+ await using writer = await this.createWriter(options);
390
+ await callback(writer);
391
+ await writer.flush();
392
+ return writer.last_flushed_op != null ? { flushed_op: writer.last_flushed_op } : null;
374
393
  }
375
394
 
376
395
  async getParameterSets(
@@ -415,10 +434,10 @@ export class PostgresSyncRulesStorage
415
434
 
416
435
  async *getBucketDataBatch(
417
436
  checkpoint: InternalOpId,
418
- dataBuckets: Map<string, InternalOpId>,
437
+ dataBuckets: storage.BucketDataRequest[],
419
438
  options?: storage.BucketDataBatchOptions
420
439
  ): AsyncIterable<storage.SyncBucketDataChunk> {
421
- if (dataBuckets.size == 0) {
440
+ if (dataBuckets.length == 0) {
422
441
  return;
423
442
  }
424
443
 
@@ -430,10 +449,8 @@ export class PostgresSyncRulesStorage
430
449
  // not match up with chunks.
431
450
 
432
451
  const end = checkpoint ?? BIGINT_MAX;
433
- const filters = Array.from(dataBuckets.entries()).map(([name, start]) => ({
434
- bucket_name: name,
435
- start: start
436
- }));
452
+ const filters = dataBuckets.map((request) => ({ bucket_name: request.bucket, start: request.start }));
453
+ const startOpByBucket = new Map(dataBuckets.map((request) => [request.bucket, request.start]));
437
454
 
438
455
  const batchRowLimit = options?.limit ?? storage.DEFAULT_DOCUMENT_BATCH_LIMIT;
439
456
  const chunkSizeLimitBytes = options?.chunkLimitBytes ?? storage.DEFAULT_DOCUMENT_CHUNK_LIMIT_BYTES;
@@ -533,7 +550,7 @@ export class PostgresSyncRulesStorage
533
550
  }
534
551
 
535
552
  if (start == null) {
536
- const startOpId = dataBuckets.get(bucket_name);
553
+ const startOpId = startOpByBucket.get(bucket_name);
537
554
  if (startOpId == null) {
538
555
  throw new framework.ServiceAssertionError(`data for unexpected bucket: ${bucket_name}`);
539
556
  }
@@ -588,7 +605,10 @@ export class PostgresSyncRulesStorage
588
605
  }
589
606
  }
590
607
 
591
- async getChecksums(checkpoint: utils.InternalOpId, buckets: string[]): Promise<utils.ChecksumMap> {
608
+ async getChecksums(
609
+ checkpoint: utils.InternalOpId,
610
+ buckets: storage.BucketChecksumRequest[]
611
+ ): Promise<utils.ChecksumMap> {
592
612
  return this.checksumCache.getChecksumMap(checkpoint, buckets);
593
613
  }
594
614
 
@@ -662,11 +682,7 @@ export class PostgresSyncRulesStorage
662
682
  group_id = ${{ type: 'int4', value: this.group_id }}
663
683
  `.execute();
664
684
 
665
- await this.db.sql`
666
- DELETE FROM current_data
667
- WHERE
668
- group_id = ${{ type: 'int4', value: this.group_id }}
669
- `.execute();
685
+ await this.currentDataStore.deleteGroupRows(this.db, { groupId: this.group_id });
670
686
 
671
687
  await this.db.sql`
672
688
  DELETE FROM source_tables
@@ -5,6 +5,7 @@
5
5
 
6
6
  import { storage, utils } from '@powersync/service-core';
7
7
  import { RequiredOperationBatchLimits } from '../../types/types.js';
8
+ import { postgresTableId } from '../table-id.js';
8
9
 
9
10
  /**
10
11
  * Batch of input operations.
@@ -89,13 +90,13 @@ export class RecordOperation {
89
90
  /**
90
91
  * In-memory cache key - must not be persisted.
91
92
  */
92
- export function cacheKey(sourceTableId: string, id: storage.ReplicaId) {
93
+ export function cacheKey(sourceTableId: storage.SourceTableId, id: storage.ReplicaId) {
93
94
  return encodedCacheKey(sourceTableId, storage.serializeReplicaId(id));
94
95
  }
95
96
 
96
97
  /**
97
98
  * Calculates a cache key for a stored ReplicaId. This is usually stored as a bytea/Buffer.
98
99
  */
99
- export function encodedCacheKey(sourceTableId: string, storedKey: Buffer) {
100
- return `${sourceTableId}.${storedKey.toString('base64')}`;
100
+ export function encodedCacheKey(sourceTableId: storage.SourceTableId, storedKey: Buffer) {
101
+ return `${postgresTableId(sourceTableId)}.${storedKey.toString('base64')}`;
101
102
  }