@powersync/service-module-postgres-storage 0.14.0 → 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.
- package/CHANGELOG.md +53 -0
- package/dist/{@types/storage → storage}/PostgresBucketStorageFactory.d.ts +12 -12
- package/dist/storage/PostgresBucketStorageFactory.js +57 -52
- package/dist/storage/PostgresBucketStorageFactory.js.map +1 -1
- package/dist/storage/PostgresReportStorage.js.map +1 -1
- package/dist/storage/PostgresStorageProvider.js +1 -1
- package/dist/storage/PostgresStorageProvider.js.map +1 -1
- package/dist/{@types/storage → storage}/PostgresSyncRulesStorage.d.ts +16 -8
- package/dist/storage/PostgresSyncRulesStorage.js +48 -196
- package/dist/storage/PostgresSyncRulesStorage.js.map +1 -1
- package/dist/{@types/storage → storage}/batch/PostgresBucketBatch.d.ts +13 -5
- package/dist/storage/batch/PostgresBucketBatch.js +280 -29
- package/dist/storage/batch/PostgresBucketBatch.js.map +1 -1
- package/dist/{@types/storage → storage}/storage-index.d.ts +1 -0
- package/dist/storage/storage-index.js +1 -0
- package/dist/storage/storage-index.js.map +1 -1
- package/dist/storage/sync-rules/PostgresPersistedSyncConfigContent.d.ts +17 -0
- package/dist/storage/sync-rules/PostgresPersistedSyncConfigContent.js +89 -0
- package/dist/storage/sync-rules/PostgresPersistedSyncConfigContent.js.map +1 -0
- package/dist/utils/test-utils.js +2 -2
- package/dist/utils/test-utils.js.map +1 -1
- package/package.json +10 -22
- package/src/storage/PostgresBucketStorageFactory.ts +64 -54
- package/src/storage/PostgresReportStorage.ts +1 -2
- package/src/storage/PostgresStorageProvider.ts +1 -1
- package/src/storage/PostgresSyncRulesStorage.ts +51 -211
- package/src/storage/batch/PostgresBucketBatch.ts +325 -45
- package/src/storage/storage-index.ts +1 -0
- package/src/storage/sync-rules/PostgresPersistedSyncConfigContent.ts +97 -0
- package/src/utils/test-utils.ts +2 -2
- package/test/src/migrations.test.ts +1 -1
- package/test/src/storage.test.ts +7 -2
- package/test/src/storage_compacting.test.ts +6 -4
- package/test/src/storage_sync.test.ts +2 -1
- package/test/tsconfig.json +0 -2
- package/tsconfig.json +1 -4
- package/tsconfig.tsbuildinfo +1 -0
- package/dist/.tsbuildinfo +0 -1
- package/dist/@types/storage/sync-rules/PostgresPersistedSyncRulesContent.d.ts +0 -9
- package/dist/storage/sync-rules/PostgresPersistedSyncRulesContent.js +0 -49
- package/dist/storage/sync-rules/PostgresPersistedSyncRulesContent.js.map +0 -1
- package/src/storage/sync-rules/PostgresPersistedSyncRulesContent.ts +0 -54
- /package/dist/{@types/index.d.ts → index.d.ts} +0 -0
- /package/dist/{@types/migrations → migrations}/PostgresMigrationAgent.d.ts +0 -0
- /package/dist/{@types/migrations → migrations}/PostgresMigrationStore.d.ts +0 -0
- /package/dist/{@types/migrations → migrations}/migration-utils.d.ts +0 -0
- /package/dist/{@types/migrations → migrations}/scripts/1684951997326-init.d.ts +0 -0
- /package/dist/{@types/migrations → migrations}/scripts/1749024804042-snapshot-progress.d.ts +0 -0
- /package/dist/{@types/migrations → migrations}/scripts/1756282360128-connection-reporting.d.ts +0 -0
- /package/dist/{@types/migrations → migrations}/scripts/1771232439485-storage-version.d.ts +0 -0
- /package/dist/{@types/migrations → migrations}/scripts/1771424826685-current-data-pending-deletes.d.ts +0 -0
- /package/dist/{@types/migrations → migrations}/scripts/1771491856000-sync-plan.d.ts +0 -0
- /package/dist/{@types/module → module}/PostgresStorageModule.d.ts +0 -0
- /package/dist/{@types/storage → storage}/PostgresCompactor.d.ts +0 -0
- /package/dist/{@types/storage → storage}/PostgresReportStorage.d.ts +0 -0
- /package/dist/{@types/storage → storage}/PostgresStorageProvider.d.ts +0 -0
- /package/dist/{@types/storage → storage}/batch/OperationBatch.d.ts +0 -0
- /package/dist/{@types/storage → storage}/batch/PostgresPersistedBatch.d.ts +0 -0
- /package/dist/{@types/storage → storage}/checkpoints/PostgresWriteCheckpointAPI.d.ts +0 -0
- /package/dist/{@types/storage → storage}/current-data-store.d.ts +0 -0
- /package/dist/{@types/storage → storage}/table-id.d.ts +0 -0
- /package/dist/{@types/types → types}/codecs.d.ts +0 -0
- /package/dist/{@types/types → types}/models/ActiveCheckpoint.d.ts +0 -0
- /package/dist/{@types/types → types}/models/ActiveCheckpointNotification.d.ts +0 -0
- /package/dist/{@types/types → types}/models/BucketData.d.ts +0 -0
- /package/dist/{@types/types → types}/models/BucketParameters.d.ts +0 -0
- /package/dist/{@types/types → types}/models/CurrentData.d.ts +0 -0
- /package/dist/{@types/types → types}/models/Instance.d.ts +0 -0
- /package/dist/{@types/types → types}/models/Migration.d.ts +0 -0
- /package/dist/{@types/types → types}/models/SdkReporting.d.ts +0 -0
- /package/dist/{@types/types → types}/models/SourceTable.d.ts +0 -0
- /package/dist/{@types/types → types}/models/SyncRules.d.ts +0 -0
- /package/dist/{@types/types → types}/models/WriteCheckpoint.d.ts +0 -0
- /package/dist/{@types/types → types}/models/json.d.ts +0 -0
- /package/dist/{@types/types → types}/models/models-index.d.ts +0 -0
- /package/dist/{@types/types → types}/types.d.ts +0 -0
- /package/dist/{@types/utils → utils}/application-name.d.ts +0 -0
- /package/dist/{@types/utils → utils}/bson.d.ts +0 -0
- /package/dist/{@types/utils → utils}/bucket-data.d.ts +0 -0
- /package/dist/{@types/utils → utils}/db.d.ts +0 -0
- /package/dist/{@types/utils → utils}/test-utils.d.ts +0 -0
- /package/dist/{@types/utils → utils}/ts-codec.d.ts +0 -0
- /package/dist/{@types/utils → utils}/utils-index.d.ts +0 -0
|
@@ -22,7 +22,6 @@ import {
|
|
|
22
22
|
import { JSONBig } from '@powersync/service-jsonbig';
|
|
23
23
|
import * as sync_rules from '@powersync/service-sync-rules';
|
|
24
24
|
import * as timers from 'timers/promises';
|
|
25
|
-
import * as uuid from 'uuid';
|
|
26
25
|
import { bigint, BIGINT_MAX } from '../types/codecs.js';
|
|
27
26
|
import { models, RequiredOperationBatchLimits } from '../types/types.js';
|
|
28
27
|
import { replicaIdToSubkey } from '../utils/bson.js';
|
|
@@ -32,7 +31,6 @@ import * as framework from '@powersync/lib-services-framework';
|
|
|
32
31
|
import { StatementParam } from '@powersync/service-jpgwire';
|
|
33
32
|
import { wrapWithAbort } from 'ix/asynciterable/operators/withabort.js';
|
|
34
33
|
import * as t from 'ts-codec';
|
|
35
|
-
import { SourceTableDecoded, StoredRelationId } from '../types/models/SourceTable.js';
|
|
36
34
|
import { pick } from '../utils/ts-codec.js';
|
|
37
35
|
import { PostgresBucketBatch } from './batch/PostgresBucketBatch.js';
|
|
38
36
|
import { PostgresWriteCheckpointAPI } from './checkpoints/PostgresWriteCheckpointAPI.js';
|
|
@@ -43,7 +41,7 @@ import { PostgresCompactor } from './PostgresCompactor.js';
|
|
|
43
41
|
export type PostgresSyncRulesStorageOptions = {
|
|
44
42
|
factory: PostgresBucketStorageFactory;
|
|
45
43
|
db: lib_postgres.DatabaseClient;
|
|
46
|
-
|
|
44
|
+
replicationStream: storage.PersistedReplicationStream;
|
|
47
45
|
write_checkpoint_mode?: storage.WriteCheckpointMode;
|
|
48
46
|
batchLimits: RequiredOperationBatchLimits;
|
|
49
47
|
};
|
|
@@ -54,9 +52,10 @@ export class PostgresSyncRulesStorage
|
|
|
54
52
|
{
|
|
55
53
|
[framework.DO_NOT_LOG] = true;
|
|
56
54
|
|
|
57
|
-
public readonly
|
|
58
|
-
public readonly
|
|
59
|
-
public readonly
|
|
55
|
+
public readonly replicationStreamId: number;
|
|
56
|
+
public readonly replicationStream: storage.PersistedReplicationStream;
|
|
57
|
+
public readonly sync_rules: storage.PersistedSyncConfigContent;
|
|
58
|
+
public readonly replicationStreamName: string;
|
|
60
59
|
public readonly factory: PostgresBucketStorageFactory;
|
|
61
60
|
public readonly storageConfig: StorageVersionConfig;
|
|
62
61
|
public readonly logger: framework.Logger;
|
|
@@ -67,22 +66,27 @@ export class PostgresSyncRulesStorage
|
|
|
67
66
|
protected writeCheckpointAPI: PostgresWriteCheckpointAPI;
|
|
68
67
|
private readonly currentDataStore: PostgresCurrentDataStore;
|
|
69
68
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
/**
|
|
70
|
+
* Canonical parsed sync config sets, keyed by defaultSchema. Entries are never evicted,
|
|
71
|
+
* so each parse options value maps to exactly one parsed set for the lifetime of this
|
|
72
|
+
* storage instance.
|
|
73
|
+
*
|
|
74
|
+
* TODO we might be able to share this in an abstract class
|
|
75
|
+
*/
|
|
76
|
+
private readonly parsedSyncConfigSets = new Map<string, storage.ParsedSyncConfigSet>();
|
|
74
77
|
private _checksumCache: storage.ChecksumCache | undefined;
|
|
75
78
|
|
|
76
79
|
constructor(protected options: PostgresSyncRulesStorageOptions) {
|
|
77
80
|
super();
|
|
78
|
-
this.
|
|
81
|
+
this.replicationStream = options.replicationStream;
|
|
82
|
+
this.replicationStreamId = options.replicationStream.replicationStreamId;
|
|
79
83
|
this.db = options.db;
|
|
80
|
-
this.sync_rules = options.
|
|
81
|
-
this.
|
|
84
|
+
this.sync_rules = options.replicationStream.syncConfigContent[0];
|
|
85
|
+
this.replicationStreamName = options.replicationStream.replicationStreamName;
|
|
82
86
|
this.factory = options.factory;
|
|
83
|
-
this.storageConfig = options.
|
|
87
|
+
this.storageConfig = options.replicationStream.getStorageConfig();
|
|
84
88
|
this.currentDataStore = new PostgresCurrentDataStore(this.storageConfig);
|
|
85
|
-
this.logger = options.
|
|
89
|
+
this.logger = options.replicationStream.logger;
|
|
86
90
|
|
|
87
91
|
this.writeCheckpointAPI = new PostgresWriteCheckpointAPI({
|
|
88
92
|
db: this.db,
|
|
@@ -108,18 +112,17 @@ export class PostgresSyncRulesStorage
|
|
|
108
112
|
return this.writeCheckpointAPI.writeCheckpointMode;
|
|
109
113
|
}
|
|
110
114
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
* Parse sync config if the options are different or if there is no cached value.
|
|
117
|
-
*/
|
|
118
|
-
if (!parsed || options.defaultSchema != cachedOptions?.defaultSchema) {
|
|
119
|
-
this.parsedSyncRulesCache = { parsed: this.sync_rules.parsed(options).hydratedSyncRules(), options };
|
|
115
|
+
getParsedSyncConfigSet(options: storage.ParseSyncConfigOptions): storage.ParsedSyncConfigSet {
|
|
116
|
+
let parsed = this.parsedSyncConfigSets.get(options.defaultSchema);
|
|
117
|
+
if (parsed == null) {
|
|
118
|
+
parsed = this.replicationStream.parsed(options);
|
|
119
|
+
this.parsedSyncConfigSets.set(options.defaultSchema, parsed);
|
|
120
120
|
}
|
|
121
|
+
return parsed;
|
|
122
|
+
}
|
|
121
123
|
|
|
122
|
-
|
|
124
|
+
getParsedSyncRules(options: storage.ParseSyncConfigOptions): sync_rules.HydratedSyncConfig {
|
|
125
|
+
return this.getParsedSyncConfigSet(options).hydratedSyncConfig;
|
|
123
126
|
}
|
|
124
127
|
|
|
125
128
|
async reportError(e: any): Promise<void> {
|
|
@@ -129,7 +132,7 @@ export class PostgresSyncRulesStorage
|
|
|
129
132
|
SET
|
|
130
133
|
last_fatal_error = ${{ type: 'varchar', value: message }}
|
|
131
134
|
WHERE
|
|
132
|
-
id = ${{ type: 'int4', value: this.
|
|
135
|
+
id = ${{ type: 'int4', value: this.replicationStreamId }};
|
|
133
136
|
`.execute();
|
|
134
137
|
}
|
|
135
138
|
|
|
@@ -141,7 +144,7 @@ export class PostgresSyncRulesStorage
|
|
|
141
144
|
maxOpId = checkpoint.checkpoint;
|
|
142
145
|
}
|
|
143
146
|
|
|
144
|
-
return new PostgresCompactor(this.db, this.
|
|
147
|
+
return new PostgresCompactor(this.db, this.replicationStreamId, {
|
|
145
148
|
...options,
|
|
146
149
|
maxOpId,
|
|
147
150
|
logger: this.logger
|
|
@@ -156,7 +159,7 @@ export class PostgresSyncRulesStorage
|
|
|
156
159
|
lastWriteCheckpoint(filters: storage.SyncStorageLastWriteCheckpointFilters): Promise<bigint | null> {
|
|
157
160
|
return this.writeCheckpointAPI.lastWriteCheckpoint({
|
|
158
161
|
...filters,
|
|
159
|
-
sync_rules_id: this.
|
|
162
|
+
sync_rules_id: this.replicationStreamId
|
|
160
163
|
});
|
|
161
164
|
}
|
|
162
165
|
|
|
@@ -176,7 +179,7 @@ export class PostgresSyncRulesStorage
|
|
|
176
179
|
FROM
|
|
177
180
|
sync_rules
|
|
178
181
|
WHERE
|
|
179
|
-
id = ${{ type: 'int4', value: this.
|
|
182
|
+
id = ${{ type: 'int4', value: this.replicationStreamId }}
|
|
180
183
|
`
|
|
181
184
|
.decoded(pick(models.SyncRules, ['last_checkpoint', 'last_checkpoint_lsn']))
|
|
182
185
|
.first();
|
|
@@ -188,168 +191,6 @@ export class PostgresSyncRulesStorage
|
|
|
188
191
|
);
|
|
189
192
|
}
|
|
190
193
|
|
|
191
|
-
async resolveTable(options: storage.ResolveTableOptions): Promise<storage.ResolveTableResult> {
|
|
192
|
-
const { group_id, connection_id, connection_tag, entity_descriptor } = options;
|
|
193
|
-
|
|
194
|
-
const { schema, name: table, objectId, replicaIdColumns } = entity_descriptor;
|
|
195
|
-
|
|
196
|
-
const normalizedReplicaIdColumns = replicaIdColumns.map((column) => ({
|
|
197
|
-
name: column.name,
|
|
198
|
-
type: column.type,
|
|
199
|
-
// The PGWire returns this as a BigInt. We want to store this as JSONB
|
|
200
|
-
type_oid: typeof column.typeId !== 'undefined' ? Number(column.typeId) : column.typeId
|
|
201
|
-
}));
|
|
202
|
-
return this.db.transaction(async (db) => {
|
|
203
|
-
let sourceTableRow: SourceTableDecoded | null;
|
|
204
|
-
if (objectId != null) {
|
|
205
|
-
sourceTableRow = await db.sql`
|
|
206
|
-
SELECT
|
|
207
|
-
*
|
|
208
|
-
FROM
|
|
209
|
-
source_tables
|
|
210
|
-
WHERE
|
|
211
|
-
group_id = ${{ type: 'int4', value: group_id }}
|
|
212
|
-
AND connection_id = ${{ type: 'int4', value: connection_id }}
|
|
213
|
-
AND relation_id = ${{ type: 'jsonb', value: { object_id: objectId } satisfies StoredRelationId }}
|
|
214
|
-
AND schema_name = ${{ type: 'varchar', value: schema }}
|
|
215
|
-
AND table_name = ${{ type: 'varchar', value: table }}
|
|
216
|
-
AND replica_id_columns = ${{ type: 'jsonb', value: normalizedReplicaIdColumns }}
|
|
217
|
-
`
|
|
218
|
-
.decoded(models.SourceTable)
|
|
219
|
-
.first();
|
|
220
|
-
} else {
|
|
221
|
-
sourceTableRow = await db.sql`
|
|
222
|
-
SELECT
|
|
223
|
-
*
|
|
224
|
-
FROM
|
|
225
|
-
source_tables
|
|
226
|
-
WHERE
|
|
227
|
-
group_id = ${{ type: 'int4', value: group_id }}
|
|
228
|
-
AND connection_id = ${{ type: 'int4', value: connection_id }}
|
|
229
|
-
AND schema_name = ${{ type: 'varchar', value: schema }}
|
|
230
|
-
AND table_name = ${{ type: 'varchar', value: table }}
|
|
231
|
-
AND replica_id_columns = ${{ type: 'jsonb', value: normalizedReplicaIdColumns }}
|
|
232
|
-
`
|
|
233
|
-
.decoded(models.SourceTable)
|
|
234
|
-
.first();
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
if (sourceTableRow == null) {
|
|
238
|
-
const row = await db.sql`
|
|
239
|
-
INSERT INTO
|
|
240
|
-
source_tables (
|
|
241
|
-
id,
|
|
242
|
-
group_id,
|
|
243
|
-
connection_id,
|
|
244
|
-
relation_id,
|
|
245
|
-
schema_name,
|
|
246
|
-
table_name,
|
|
247
|
-
replica_id_columns
|
|
248
|
-
)
|
|
249
|
-
VALUES
|
|
250
|
-
(
|
|
251
|
-
${{ type: 'varchar', value: uuid.v4() }},
|
|
252
|
-
${{ type: 'int4', value: group_id }},
|
|
253
|
-
${{ type: 'int4', value: connection_id }},
|
|
254
|
-
--- The objectId can be string | number | undefined, we store it as jsonb value
|
|
255
|
-
${{ type: 'jsonb', value: { object_id: objectId } satisfies StoredRelationId }},
|
|
256
|
-
${{ type: 'varchar', value: schema }},
|
|
257
|
-
${{ type: 'varchar', value: table }},
|
|
258
|
-
${{ type: 'jsonb', value: normalizedReplicaIdColumns }}
|
|
259
|
-
)
|
|
260
|
-
RETURNING
|
|
261
|
-
*
|
|
262
|
-
`
|
|
263
|
-
.decoded(models.SourceTable)
|
|
264
|
-
.first();
|
|
265
|
-
sourceTableRow = row;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
const sourceTable = new storage.SourceTable({
|
|
269
|
-
id: sourceTableRow!.id,
|
|
270
|
-
connectionTag: connection_tag,
|
|
271
|
-
objectId: objectId,
|
|
272
|
-
schema: schema,
|
|
273
|
-
name: table,
|
|
274
|
-
replicaIdColumns: replicaIdColumns,
|
|
275
|
-
snapshotComplete: sourceTableRow!.snapshot_done ?? true
|
|
276
|
-
});
|
|
277
|
-
if (!sourceTable.snapshotComplete) {
|
|
278
|
-
sourceTable.snapshotStatus = {
|
|
279
|
-
totalEstimatedCount: Number(sourceTableRow!.snapshot_total_estimated_count ?? -1n),
|
|
280
|
-
replicatedCount: Number(sourceTableRow!.snapshot_replicated_count ?? 0n),
|
|
281
|
-
lastKey: sourceTableRow!.snapshot_last_key
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
sourceTable.syncEvent = options.sync_rules.tableTriggersEvent(sourceTable);
|
|
285
|
-
sourceTable.syncData = options.sync_rules.tableSyncsData(sourceTable);
|
|
286
|
-
sourceTable.syncParameters = options.sync_rules.tableSyncsParameters(sourceTable);
|
|
287
|
-
|
|
288
|
-
let truncatedTables: SourceTableDecoded[] = [];
|
|
289
|
-
if (objectId != null) {
|
|
290
|
-
// relation_id present - check for renamed tables
|
|
291
|
-
truncatedTables = await db.sql`
|
|
292
|
-
SELECT
|
|
293
|
-
*
|
|
294
|
-
FROM
|
|
295
|
-
source_tables
|
|
296
|
-
WHERE
|
|
297
|
-
group_id = ${{ type: 'int4', value: group_id }}
|
|
298
|
-
AND connection_id = ${{ type: 'int4', value: connection_id }}
|
|
299
|
-
AND id != ${{ type: 'varchar', value: sourceTableRow!.id }}
|
|
300
|
-
AND (
|
|
301
|
-
relation_id = ${{ type: 'jsonb', value: { object_id: objectId } satisfies StoredRelationId }}
|
|
302
|
-
OR (
|
|
303
|
-
schema_name = ${{ type: 'varchar', value: schema }}
|
|
304
|
-
AND table_name = ${{ type: 'varchar', value: table }}
|
|
305
|
-
)
|
|
306
|
-
)
|
|
307
|
-
`
|
|
308
|
-
.decoded(models.SourceTable)
|
|
309
|
-
.rows();
|
|
310
|
-
} else {
|
|
311
|
-
// relation_id not present - only check for changed replica_id_columns
|
|
312
|
-
truncatedTables = await db.sql`
|
|
313
|
-
SELECT
|
|
314
|
-
*
|
|
315
|
-
FROM
|
|
316
|
-
source_tables
|
|
317
|
-
WHERE
|
|
318
|
-
group_id = ${{ type: 'int4', value: group_id }}
|
|
319
|
-
AND connection_id = ${{ type: 'int4', value: connection_id }}
|
|
320
|
-
AND id != ${{ type: 'varchar', value: sourceTableRow!.id }}
|
|
321
|
-
AND (
|
|
322
|
-
schema_name = ${{ type: 'varchar', value: schema }}
|
|
323
|
-
AND table_name = ${{ type: 'varchar', value: table }}
|
|
324
|
-
)
|
|
325
|
-
`
|
|
326
|
-
.decoded(models.SourceTable)
|
|
327
|
-
.rows();
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
return {
|
|
331
|
-
table: sourceTable,
|
|
332
|
-
dropTables: truncatedTables.map(
|
|
333
|
-
(doc) =>
|
|
334
|
-
new storage.SourceTable({
|
|
335
|
-
id: doc.id,
|
|
336
|
-
connectionTag: connection_tag,
|
|
337
|
-
objectId: doc.relation_id?.object_id ?? 0,
|
|
338
|
-
schema: doc.schema_name,
|
|
339
|
-
name: doc.table_name,
|
|
340
|
-
replicaIdColumns:
|
|
341
|
-
doc.replica_id_columns?.map((c) => ({
|
|
342
|
-
name: c.name,
|
|
343
|
-
typeOid: c.typeId,
|
|
344
|
-
type: c.type
|
|
345
|
-
})) ?? [],
|
|
346
|
-
snapshotComplete: doc.snapshot_done ?? true
|
|
347
|
-
})
|
|
348
|
-
)
|
|
349
|
-
};
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
|
|
353
194
|
async createWriter(options: storage.CreateWriterOptions): Promise<storage.BucketStorageBatch> {
|
|
354
195
|
const syncRules = await this.db.sql`
|
|
355
196
|
SELECT
|
|
@@ -360,7 +201,7 @@ export class PostgresSyncRulesStorage
|
|
|
360
201
|
FROM
|
|
361
202
|
sync_rules
|
|
362
203
|
WHERE
|
|
363
|
-
id = ${{ type: 'int4', value: this.
|
|
204
|
+
id = ${{ type: 'int4', value: this.replicationStreamId }}
|
|
364
205
|
`
|
|
365
206
|
.decoded(pick(models.SyncRules, ['last_checkpoint_lsn', 'no_checkpoint_before', 'keepalive_op', 'snapshot_lsn']))
|
|
366
207
|
.first();
|
|
@@ -370,9 +211,9 @@ export class PostgresSyncRulesStorage
|
|
|
370
211
|
const writer = new PostgresBucketBatch({
|
|
371
212
|
logger: options.logger ?? this.logger,
|
|
372
213
|
db: this.db,
|
|
373
|
-
sync_rules: this.
|
|
374
|
-
|
|
375
|
-
|
|
214
|
+
sync_rules: this.getParsedSyncRules(options),
|
|
215
|
+
replicationStreamId: this.replicationStreamId,
|
|
216
|
+
replicationStreamName: this.replicationStreamName,
|
|
376
217
|
last_checkpoint_lsn: checkpoint_lsn,
|
|
377
218
|
keep_alive_op: syncRules?.keepalive_op,
|
|
378
219
|
resumeFromLsn: maxLsn(syncRules?.snapshot_lsn, checkpoint_lsn),
|
|
@@ -380,6 +221,7 @@ export class PostgresSyncRulesStorage
|
|
|
380
221
|
skip_existing_rows: options.skipExistingRows ?? false,
|
|
381
222
|
batch_limits: this.options.batchLimits,
|
|
382
223
|
markRecordUnavailable: options.markRecordUnavailable,
|
|
224
|
+
hooks: options.hooks,
|
|
383
225
|
storageConfig: this.storageConfig
|
|
384
226
|
});
|
|
385
227
|
this.iterateListeners((cb) => cb.batchStarted?.(writer));
|
|
@@ -417,7 +259,7 @@ export class PostgresSyncRulesStorage
|
|
|
417
259
|
value: lookups.map((l) => storage.serializeLookupBuffer(l).toString('hex'))
|
|
418
260
|
}}) WITH ORDINALITY AS requested (value, index)
|
|
419
261
|
WHERE
|
|
420
|
-
group_id = ${{ type: 'int4', value: this.
|
|
262
|
+
group_id = ${{ type: 'int4', value: this.replicationStreamId }}
|
|
421
263
|
AND lookup = decode((requested.value ->> 0)::text, 'hex') -- Decode the hex string to bytea
|
|
422
264
|
AND id <= ${{ type: 'int8', value: checkpoint.checkpoint }}
|
|
423
265
|
ORDER BY
|
|
@@ -544,7 +386,7 @@ export class PostgresSyncRulesStorage
|
|
|
544
386
|
LIMIT
|
|
545
387
|
$3;`,
|
|
546
388
|
params: [
|
|
547
|
-
{ type: 'int4', value: this.
|
|
389
|
+
{ type: 'int4', value: this.replicationStreamId },
|
|
548
390
|
{ type: 'int8', value: end },
|
|
549
391
|
{ type: 'int4', value: batchRowLimit },
|
|
550
392
|
...filters.flatMap((f) => [
|
|
@@ -660,11 +502,11 @@ export class PostgresSyncRulesStorage
|
|
|
660
502
|
state = ${{ type: 'varchar', value: storage.SyncRuleState.TERMINATED }},
|
|
661
503
|
snapshot_done = ${{ type: 'bool', value: false }}
|
|
662
504
|
WHERE
|
|
663
|
-
id = ${{ type: 'int4', value: this.
|
|
505
|
+
id = ${{ type: 'int4', value: this.replicationStreamId }}
|
|
664
506
|
`.execute();
|
|
665
507
|
}
|
|
666
508
|
|
|
667
|
-
async getStatus(): Promise<storage.
|
|
509
|
+
async getStatus(): Promise<storage.ReplicationStreamStatus> {
|
|
668
510
|
const syncRulesRow = await this.db.sql`
|
|
669
511
|
SELECT
|
|
670
512
|
snapshot_done,
|
|
@@ -674,9 +516,9 @@ export class PostgresSyncRulesStorage
|
|
|
674
516
|
FROM
|
|
675
517
|
sync_rules
|
|
676
518
|
WHERE
|
|
677
|
-
id = ${{ type: 'int4', value: this.
|
|
519
|
+
id = ${{ type: 'int4', value: this.replicationStreamId }}
|
|
678
520
|
`
|
|
679
|
-
.decoded(pick(models.SyncRules, ['snapshot_done', 'last_checkpoint_lsn', '
|
|
521
|
+
.decoded(pick(models.SyncRules, ['snapshot_done', 'last_checkpoint_lsn', 'snapshot_lsn']))
|
|
680
522
|
.first();
|
|
681
523
|
|
|
682
524
|
if (syncRulesRow == null) {
|
|
@@ -684,10 +526,8 @@ export class PostgresSyncRulesStorage
|
|
|
684
526
|
}
|
|
685
527
|
|
|
686
528
|
return {
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
checkpoint_lsn: syncRulesRow.last_checkpoint_lsn ?? null,
|
|
690
|
-
snapshot_lsn: syncRulesRow.snapshot_lsn ?? null
|
|
529
|
+
snapshotDone: syncRulesRow.snapshot_done && syncRulesRow.last_checkpoint_lsn != null,
|
|
530
|
+
resumeLsn: maxLsn(syncRulesRow.snapshot_lsn, syncRulesRow.last_checkpoint_lsn)
|
|
691
531
|
};
|
|
692
532
|
}
|
|
693
533
|
|
|
@@ -701,27 +541,27 @@ export class PostgresSyncRulesStorage
|
|
|
701
541
|
last_checkpoint = NULL,
|
|
702
542
|
no_checkpoint_before = NULL
|
|
703
543
|
WHERE
|
|
704
|
-
id = ${{ type: 'int4', value: this.
|
|
544
|
+
id = ${{ type: 'int4', value: this.replicationStreamId }}
|
|
705
545
|
`.execute();
|
|
706
546
|
|
|
707
547
|
await this.db.sql`
|
|
708
548
|
DELETE FROM bucket_data
|
|
709
549
|
WHERE
|
|
710
|
-
group_id = ${{ type: 'int4', value: this.
|
|
550
|
+
group_id = ${{ type: 'int4', value: this.replicationStreamId }}
|
|
711
551
|
`.execute();
|
|
712
552
|
|
|
713
553
|
await this.db.sql`
|
|
714
554
|
DELETE FROM bucket_parameters
|
|
715
555
|
WHERE
|
|
716
|
-
group_id = ${{ type: 'int4', value: this.
|
|
556
|
+
group_id = ${{ type: 'int4', value: this.replicationStreamId }}
|
|
717
557
|
`.execute();
|
|
718
558
|
|
|
719
|
-
await this.currentDataStore.deleteGroupRows(this.db, { groupId: this.
|
|
559
|
+
await this.currentDataStore.deleteGroupRows(this.db, { groupId: this.replicationStreamId });
|
|
720
560
|
|
|
721
561
|
await this.db.sql`
|
|
722
562
|
DELETE FROM source_tables
|
|
723
563
|
WHERE
|
|
724
|
-
group_id = ${{ type: 'int4', value: this.
|
|
564
|
+
group_id = ${{ type: 'int4', value: this.replicationStreamId }}
|
|
725
565
|
`.execute();
|
|
726
566
|
}
|
|
727
567
|
|
|
@@ -762,7 +602,7 @@ export class PostgresSyncRulesStorage
|
|
|
762
602
|
AND b.op_id > f.start_op_id
|
|
763
603
|
AND b.op_id <= f.end_op_id
|
|
764
604
|
WHERE
|
|
765
|
-
b.group_id = ${{ type: 'int4', value: this.
|
|
605
|
+
b.group_id = ${{ type: 'int4', value: this.replicationStreamId }}
|
|
766
606
|
GROUP BY
|
|
767
607
|
b.bucket_name;
|
|
768
608
|
`.rows<{ bucket: string; checksum_total: bigint; total: bigint; has_clear_op: number }>();
|