@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.
- package/CHANGELOG.md +53 -8
- package/dist/.tsbuildinfo +1 -1
- package/dist/@types/migrations/scripts/1771424826685-current-data-pending-deletes.d.ts +3 -0
- package/dist/@types/migrations/scripts/1771491856000-sync-plan.d.ts +3 -0
- package/dist/@types/storage/PostgresBucketStorageFactory.d.ts +4 -0
- package/dist/@types/storage/PostgresCompactor.d.ts +8 -2
- package/dist/@types/storage/PostgresReportStorage.d.ts +3 -3
- package/dist/@types/storage/PostgresSyncRulesStorage.d.ts +10 -4
- package/dist/@types/storage/batch/OperationBatch.d.ts +2 -2
- package/dist/@types/storage/batch/PostgresBucketBatch.d.ts +13 -9
- package/dist/@types/storage/batch/PostgresPersistedBatch.d.ts +17 -5
- package/dist/@types/storage/current-data-store.d.ts +85 -0
- package/dist/@types/storage/current-data-table.d.ts +9 -0
- package/dist/@types/storage/table-id.d.ts +2 -0
- package/dist/@types/types/models/CurrentData.d.ts +18 -3
- package/dist/@types/types/models/SyncRules.d.ts +9 -0
- package/dist/@types/types/models/json.d.ts +11 -0
- package/dist/@types/utils/bson.d.ts +1 -1
- package/dist/@types/utils/test-utils.d.ts +1 -1
- package/dist/migrations/scripts/1771424826685-current-data-pending-deletes.js +8 -0
- package/dist/migrations/scripts/1771424826685-current-data-pending-deletes.js.map +1 -0
- package/dist/migrations/scripts/1771491856000-sync-plan.js +91 -0
- package/dist/migrations/scripts/1771491856000-sync-plan.js.map +1 -0
- package/dist/storage/PostgresBucketStorageFactory.js +50 -5
- package/dist/storage/PostgresBucketStorageFactory.js.map +1 -1
- package/dist/storage/PostgresCompactor.js +14 -6
- package/dist/storage/PostgresCompactor.js.map +1 -1
- package/dist/storage/PostgresReportStorage.js +7 -7
- package/dist/storage/PostgresReportStorage.js.map +1 -1
- package/dist/storage/PostgresSyncRulesStorage.js +98 -24
- package/dist/storage/PostgresSyncRulesStorage.js.map +1 -1
- package/dist/storage/batch/OperationBatch.js +2 -1
- package/dist/storage/batch/OperationBatch.js.map +1 -1
- package/dist/storage/batch/PostgresBucketBatch.js +295 -213
- package/dist/storage/batch/PostgresBucketBatch.js.map +1 -1
- package/dist/storage/batch/PostgresPersistedBatch.js +86 -81
- package/dist/storage/batch/PostgresPersistedBatch.js.map +1 -1
- package/dist/storage/current-data-store.js +270 -0
- package/dist/storage/current-data-store.js.map +1 -0
- package/dist/storage/current-data-table.js +22 -0
- package/dist/storage/current-data-table.js.map +1 -0
- package/dist/storage/sync-rules/PostgresPersistedSyncRulesContent.js +1 -0
- package/dist/storage/sync-rules/PostgresPersistedSyncRulesContent.js.map +1 -1
- package/dist/storage/table-id.js +8 -0
- package/dist/storage/table-id.js.map +1 -0
- package/dist/types/models/CurrentData.js +11 -2
- package/dist/types/models/CurrentData.js.map +1 -1
- package/dist/types/models/SyncRules.js +11 -1
- package/dist/types/models/SyncRules.js.map +1 -1
- package/dist/types/models/json.js +21 -0
- package/dist/types/models/json.js.map +1 -0
- package/dist/utils/bson.js.map +1 -1
- package/dist/utils/db.js +9 -0
- package/dist/utils/db.js.map +1 -1
- package/dist/utils/test-utils.js +13 -6
- package/dist/utils/test-utils.js.map +1 -1
- package/package.json +9 -9
- package/src/migrations/scripts/1771424826685-current-data-pending-deletes.ts +10 -0
- package/src/migrations/scripts/1771491856000-sync-plan.ts +21 -0
- package/src/storage/PostgresBucketStorageFactory.ts +62 -7
- package/src/storage/PostgresCompactor.ts +17 -8
- package/src/storage/PostgresReportStorage.ts +7 -7
- package/src/storage/PostgresSyncRulesStorage.ts +47 -31
- package/src/storage/batch/OperationBatch.ts +4 -3
- package/src/storage/batch/PostgresBucketBatch.ts +316 -238
- package/src/storage/batch/PostgresPersistedBatch.ts +92 -84
- package/src/storage/current-data-store.ts +326 -0
- package/src/storage/current-data-table.ts +26 -0
- package/src/storage/sync-rules/PostgresPersistedSyncRulesContent.ts +1 -7
- package/src/storage/table-id.ts +9 -0
- package/src/types/models/CurrentData.ts +17 -4
- package/src/types/models/SyncRules.ts +15 -1
- package/src/types/models/json.ts +26 -0
- package/src/utils/bson.ts +1 -1
- package/src/utils/db.ts +10 -0
- package/src/utils/test-utils.ts +14 -7
- package/test/src/__snapshots__/{connection-report-storage.test.ts.snap → client-connections-storage.test.ts.snap} +22 -22
- package/test/src/__snapshots__/storage.test.ts.snap +151 -0
- package/test/src/__snapshots__/storage_compacting.test.ts.snap +17 -0
- package/test/src/__snapshots__/storage_sync.test.ts.snap +1111 -16
- package/test/src/{connection-report-storage.test.ts → client-connections-storage.test.ts} +1 -1
- package/test/src/env.ts +1 -1
- package/test/src/migrations.test.ts +1 -1
- package/test/src/storage.test.ts +138 -131
- package/test/src/storage_compacting.test.ts +80 -11
- package/test/src/storage_sync.test.ts +57 -54
- package/test/src/util.ts +4 -4
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
import { GetIntanceOptions, storage, SyncRulesBucketStorage
|
|
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
|
-
|
|
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<{
|
|
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!.
|
|
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 (
|
|
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
|
|
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
|
|
60
|
+
options: PostgresCompactOptions
|
|
61
61
|
) {
|
|
62
|
-
this.idLimitBytes = (options
|
|
63
|
-
this.moveBatchLimit = options
|
|
64
|
-
this.moveBatchQueryLimit = options
|
|
65
|
-
this.clearBatchLimit = options
|
|
66
|
-
this.maxOpId = options
|
|
67
|
-
this.buckets = options
|
|
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
|
-
|
|
52
|
-
|
|
51
|
+
total_users: 0,
|
|
52
|
+
sdk_breakdown: []
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
55
|
return {
|
|
56
|
-
|
|
57
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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?.(
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
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:
|
|
437
|
+
dataBuckets: storage.BucketDataRequest[],
|
|
419
438
|
options?: storage.BucketDataBatchOptions
|
|
420
439
|
): AsyncIterable<storage.SyncBucketDataChunk> {
|
|
421
|
-
if (dataBuckets.
|
|
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 =
|
|
434
|
-
|
|
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 =
|
|
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(
|
|
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.
|
|
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:
|
|
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:
|
|
100
|
-
return `${sourceTableId}.${storedKey.toString('base64')}`;
|
|
100
|
+
export function encodedCacheKey(sourceTableId: storage.SourceTableId, storedKey: Buffer) {
|
|
101
|
+
return `${postgresTableId(sourceTableId)}.${storedKey.toString('base64')}`;
|
|
101
102
|
}
|