@powersync/service-module-postgres-storage 0.0.0-dev-20260203155513 → 0.0.0-dev-20260223080959
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 +55 -9
- package/dist/.tsbuildinfo +1 -1
- package/dist/@types/migrations/scripts/1771232439485-storage-version.d.ts +3 -0
- package/dist/@types/storage/PostgresBucketStorageFactory.d.ts +2 -10
- package/dist/@types/storage/PostgresReportStorage.d.ts +1 -5
- package/dist/@types/storage/sync-rules/PostgresPersistedSyncRulesContent.d.ts +1 -10
- package/dist/@types/types/models/SyncRules.d.ts +3 -2
- package/dist/@types/utils/db.d.ts +9 -0
- package/dist/migrations/scripts/1771232439485-storage-version.js +111 -0
- package/dist/migrations/scripts/1771232439485-storage-version.js.map +1 -0
- package/dist/storage/PostgresBucketStorageFactory.js +8 -55
- package/dist/storage/PostgresBucketStorageFactory.js.map +1 -1
- package/dist/storage/PostgresReportStorage.js +0 -12
- package/dist/storage/PostgresReportStorage.js.map +1 -1
- package/dist/storage/batch/PostgresBucketBatch.js +4 -3
- package/dist/storage/batch/PostgresBucketBatch.js.map +1 -1
- package/dist/storage/sync-rules/PostgresPersistedSyncRulesContent.js +13 -30
- package/dist/storage/sync-rules/PostgresPersistedSyncRulesContent.js.map +1 -1
- package/dist/types/models/SyncRules.js +1 -0
- package/dist/types/models/SyncRules.js.map +1 -1
- package/dist/utils/db.js +32 -0
- package/dist/utils/db.js.map +1 -1
- package/dist/utils/test-utils.js +39 -10
- package/dist/utils/test-utils.js.map +1 -1
- package/package.json +8 -8
- package/src/migrations/scripts/1771232439485-storage-version.ts +44 -0
- package/src/storage/PostgresBucketStorageFactory.ts +9 -63
- package/src/storage/PostgresReportStorage.ts +3 -16
- package/src/storage/batch/PostgresBucketBatch.ts +10 -3
- package/src/storage/sync-rules/PostgresPersistedSyncRulesContent.ts +19 -33
- package/src/types/models/SyncRules.ts +1 -0
- package/src/utils/db.ts +37 -0
- package/src/utils/test-utils.ts +30 -10
- package/test/src/__snapshots__/storage_sync.test.ts.snap +1116 -21
- package/test/src/migrations.test.ts +8 -1
- package/test/src/storage.test.ts +11 -11
- package/test/src/storage_sync.test.ts +146 -4
- package/test/src/util.ts +3 -0
- package/test/tsconfig.json +2 -6
- package/test/src/__snapshots__/storage.test.ts.snap +0 -9
|
@@ -1,39 +1,22 @@
|
|
|
1
1
|
import * as lib_postgres from '@powersync/lib-service-postgres';
|
|
2
2
|
import { ErrorCode, logger, ServiceError } from '@powersync/lib-services-framework';
|
|
3
|
-
import {
|
|
4
|
-
export class PostgresPersistedSyncRulesContent {
|
|
3
|
+
import { storage } from '@powersync/service-core';
|
|
4
|
+
export class PostgresPersistedSyncRulesContent extends storage.PersistedSyncRulesContent {
|
|
5
5
|
db;
|
|
6
|
-
slot_name;
|
|
7
|
-
id;
|
|
8
|
-
sync_rules_content;
|
|
9
|
-
last_checkpoint_lsn;
|
|
10
|
-
last_fatal_error;
|
|
11
|
-
last_keepalive_ts;
|
|
12
|
-
last_checkpoint_ts;
|
|
13
|
-
active;
|
|
14
6
|
current_lock = null;
|
|
15
7
|
constructor(db, row) {
|
|
8
|
+
super({
|
|
9
|
+
id: Number(row.id),
|
|
10
|
+
sync_rules_content: row.content,
|
|
11
|
+
last_checkpoint_lsn: row.last_checkpoint_lsn,
|
|
12
|
+
slot_name: row.slot_name,
|
|
13
|
+
last_fatal_error: row.last_fatal_error,
|
|
14
|
+
last_checkpoint_ts: row.last_checkpoint_ts ? new Date(row.last_checkpoint_ts) : null,
|
|
15
|
+
last_keepalive_ts: row.last_keepalive_ts ? new Date(row.last_keepalive_ts) : null,
|
|
16
|
+
active: row.state == 'ACTIVE',
|
|
17
|
+
storageVersion: row.storage_version ?? storage.LEGACY_STORAGE_VERSION
|
|
18
|
+
});
|
|
16
19
|
this.db = db;
|
|
17
|
-
this.id = Number(row.id);
|
|
18
|
-
this.sync_rules_content = row.content;
|
|
19
|
-
this.last_checkpoint_lsn = row.last_checkpoint_lsn;
|
|
20
|
-
this.slot_name = row.slot_name;
|
|
21
|
-
this.last_fatal_error = row.last_fatal_error;
|
|
22
|
-
this.last_checkpoint_ts = row.last_checkpoint_ts ? new Date(row.last_checkpoint_ts) : null;
|
|
23
|
-
this.last_keepalive_ts = row.last_keepalive_ts ? new Date(row.last_keepalive_ts) : null;
|
|
24
|
-
this.active = row.state == 'ACTIVE';
|
|
25
|
-
}
|
|
26
|
-
parsed(options) {
|
|
27
|
-
return {
|
|
28
|
-
id: this.id,
|
|
29
|
-
slot_name: this.slot_name,
|
|
30
|
-
sync_rules: SqlSyncRules.fromYaml(this.sync_rules_content, options),
|
|
31
|
-
hydratedSyncRules() {
|
|
32
|
-
return this.sync_rules.hydrate({
|
|
33
|
-
hydrationState: versionedHydrationState(this.id)
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
20
|
}
|
|
38
21
|
async lock() {
|
|
39
22
|
const manager = new lib_postgres.PostgresLockManager({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PostgresPersistedSyncRulesContent.js","sourceRoot":"","sources":["../../../src/storage/sync-rules/PostgresPersistedSyncRulesContent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,YAAY,MAAM,iCAAiC,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"PostgresPersistedSyncRulesContent.js","sourceRoot":"","sources":["../../../src/storage/sync-rules/PostgresPersistedSyncRulesContent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,YAAY,MAAM,iCAAiC,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACpF,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAUlD,MAAM,OAAO,iCAAkC,SAAQ,OAAO,CAAC,yBAAyB;IAI5E;IAHV,YAAY,GAAmC,IAAI,CAAC;IAEpD,YACU,EAA+B,EACvC,GAA4B;QAE5B,KAAK,CAAC;YACJ,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YAClB,kBAAkB,EAAE,GAAG,CAAC,OAAO;YAC/B,mBAAmB,EAAE,GAAG,CAAC,mBAAmB;YAC5C,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;YACtC,kBAAkB,EAAE,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,IAAI;YACpF,iBAAiB,EAAE,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,IAAI;YACjF,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,QAAQ;YAC7B,cAAc,EAAE,GAAG,CAAC,eAAe,IAAI,OAAO,CAAC,sBAAsB;SACtE,CAAC,CAAC;QAbK,OAAE,GAAF,EAAE,CAA6B;IAczC,CAAC;IAED,KAAK,CAAC,IAAI;QACR,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,mBAAmB,CAAC;YACnD,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,IAAI,EAAE,cAAc,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,SAAS,EAAE;SAChD,CAAC,CAAC;QACH,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;QAC3C,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,YAAY,CACpB,SAAS,CAAC,WAAW,EACrB,eAAe,IAAI,CAAC,EAAE,uDAAuD,CAC9E,CAAC;QACJ,CAAC;QAED,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;YACtC,IAAI,CAAC;gBACH,MAAM,UAAU,CAAC,OAAO,EAAE,CAAC;YAC7B,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,MAAM,CAAC,KAAK,CAAC,wBAAwB,EAAE,CAAC,CAAC,CAAC;gBAC1C,aAAa,CAAC,QAAQ,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC,EAAE,MAAM,CAAC,CAAC;QAEX,OAAO,CAAC,IAAI,CAAC,YAAY,GAAG;YAC1B,aAAa,EAAE,IAAI,CAAC,EAAE;YACtB,OAAO,EAAE,KAAK,IAAI,EAAE;gBAClB,aAAa,CAAC,QAAQ,CAAC,CAAC;gBACxB,OAAO,UAAU,CAAC,OAAO,EAAE,CAAC;YAC9B,CAAC;SACF,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SyncRules.js","sourceRoot":"","sources":["../../../src/types/models/SyncRules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAErD,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,EAAE,EAAE,aAAa;IACjB,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC;IACpC;;;;OAIG;IACH,aAAa,EAAE,CAAC,CAAC,OAAO;IACxB;;OAEG;IACH,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACjC;;;;OAIG;IACH,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;IAClC;;OAEG;IACH,mBAAmB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACxC;;OAEG;IACH,oBAAoB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACzC,SAAS,EAAE,CAAC,CAAC,MAAM;IACnB;;;;OAIG;IACH,kBAAkB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;IACpD;;;;OAIG;IACH,iBAAiB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;IACnD;;OAEG;IACH,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACrC,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;IAC/B,OAAO,EAAE,CAAC,CAAC,MAAM;CAClB,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"SyncRules.js","sourceRoot":"","sources":["../../../src/types/models/SyncRules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAErD,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,EAAE,EAAE,aAAa;IACjB,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC;IACpC;;;;OAIG;IACH,aAAa,EAAE,CAAC,CAAC,OAAO;IACxB;;OAEG;IACH,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACjC;;;;OAIG;IACH,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;IAClC;;OAEG;IACH,mBAAmB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACxC;;OAEG;IACH,oBAAoB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACzC,SAAS,EAAE,CAAC,CAAC,MAAM;IACnB;;;;OAIG;IACH,kBAAkB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;IACpD;;;;OAIG;IACH,iBAAiB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;IACnD;;OAEG;IACH,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACrC,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;IAC/B,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,QAAQ,EAAE;IACpD,OAAO,EAAE,CAAC,CAAC,MAAM;CAClB,CAAC,CAAC"}
|
package/dist/utils/db.js
CHANGED
|
@@ -5,6 +5,9 @@ export const NOTIFICATION_CHANNEL = 'powersynccheckpoints';
|
|
|
5
5
|
* Re export for prettier to detect the tag better
|
|
6
6
|
*/
|
|
7
7
|
export const sql = lib_postgres.sql;
|
|
8
|
+
/**
|
|
9
|
+
* Drop all Postgres storage tables used by the service, including migrations.
|
|
10
|
+
*/
|
|
8
11
|
export const dropTables = async (client) => {
|
|
9
12
|
// Lock a connection for automatic schema search paths
|
|
10
13
|
await client.lockConnection(async (db) => {
|
|
@@ -19,6 +22,35 @@ export const dropTables = async (client) => {
|
|
|
19
22
|
await db.sql `DROP TABLE IF EXISTS custom_write_checkpoints`.execute();
|
|
20
23
|
await db.sql `DROP SEQUENCE IF EXISTS op_id_sequence`.execute();
|
|
21
24
|
await db.sql `DROP SEQUENCE IF EXISTS sync_rules_id_sequence`.execute();
|
|
25
|
+
await db.sql `DROP TABLE IF EXISTS migrations`.execute();
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Clear all Postgres storage tables and reset sequences.
|
|
30
|
+
*
|
|
31
|
+
* Does not clear migration state.
|
|
32
|
+
*/
|
|
33
|
+
export const truncateTables = async (db) => {
|
|
34
|
+
// Lock a connection for automatic schema search paths
|
|
35
|
+
await db.query({
|
|
36
|
+
statement: `TRUNCATE TABLE bucket_data,
|
|
37
|
+
bucket_parameters,
|
|
38
|
+
sync_rules,
|
|
39
|
+
instance,
|
|
40
|
+
current_data,
|
|
41
|
+
source_tables,
|
|
42
|
+
write_checkpoints,
|
|
43
|
+
custom_write_checkpoints,
|
|
44
|
+
connection_report_events RESTART IDENTITY CASCADE
|
|
45
|
+
`
|
|
46
|
+
}, {
|
|
47
|
+
statement: `ALTER SEQUENCE IF EXISTS op_id_sequence RESTART
|
|
48
|
+
WITH
|
|
49
|
+
1`
|
|
50
|
+
}, {
|
|
51
|
+
statement: `ALTER SEQUENCE IF EXISTS sync_rules_id_sequence RESTART
|
|
52
|
+
WITH
|
|
53
|
+
1`
|
|
22
54
|
});
|
|
23
55
|
};
|
|
24
56
|
//# sourceMappingURL=db.js.map
|
package/dist/utils/db.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/utils/db.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,YAAY,MAAM,iCAAiC,CAAC;AAEhE,MAAM,CAAC,MAAM,mBAAmB,GAAG,WAAW,CAAC;AAE/C,MAAM,CAAC,MAAM,oBAAoB,GAAG,sBAAsB,CAAC;AAE3D;;GAEG;AACH,MAAM,CAAC,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC;AAEpC,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAAE,MAAmC,EAAE,EAAE;IACtE,sDAAsD;IACtD,MAAM,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;QACvC,MAAM,EAAE,CAAC,GAAG,CAAA,kCAAkC,CAAC,OAAO,EAAE,CAAC;QACzD,MAAM,EAAE,CAAC,GAAG,CAAA,wCAAwC,CAAC,OAAO,EAAE,CAAC;QAC/D,MAAM,EAAE,CAAC,GAAG,CAAA,iCAAiC,CAAC,OAAO,EAAE,CAAC;QACxD,MAAM,EAAE,CAAC,GAAG,CAAA,+BAA+B,CAAC,OAAO,EAAE,CAAC;QACtD,MAAM,EAAE,CAAC,GAAG,CAAA,kCAAkC,CAAC,OAAO,EAAE,CAAC;QACzD,MAAM,EAAE,CAAC,GAAG,CAAA,mCAAmC,CAAC,OAAO,EAAE,CAAC;QAC1D,MAAM,EAAE,CAAC,GAAG,CAAA,oCAAoC,CAAC,OAAO,EAAE,CAAC;QAC3D,MAAM,EAAE,CAAC,GAAG,CAAA,wCAAwC,CAAC,OAAO,EAAE,CAAC;QAC/D,MAAM,EAAE,CAAC,GAAG,CAAA,+CAA+C,CAAC,OAAO,EAAE,CAAC;QACtE,MAAM,EAAE,CAAC,GAAG,CAAA,wCAAwC,CAAC,OAAO,EAAE,CAAC;QAC/D,MAAM,EAAE,CAAC,GAAG,CAAA,gDAAgD,CAAC,OAAO,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/utils/db.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,YAAY,MAAM,iCAAiC,CAAC;AAEhE,MAAM,CAAC,MAAM,mBAAmB,GAAG,WAAW,CAAC;AAE/C,MAAM,CAAC,MAAM,oBAAoB,GAAG,sBAAsB,CAAC;AAE3D;;GAEG;AACH,MAAM,CAAC,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC;AAEpC;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAAE,MAAmC,EAAE,EAAE;IACtE,sDAAsD;IACtD,MAAM,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;QACvC,MAAM,EAAE,CAAC,GAAG,CAAA,kCAAkC,CAAC,OAAO,EAAE,CAAC;QACzD,MAAM,EAAE,CAAC,GAAG,CAAA,wCAAwC,CAAC,OAAO,EAAE,CAAC;QAC/D,MAAM,EAAE,CAAC,GAAG,CAAA,iCAAiC,CAAC,OAAO,EAAE,CAAC;QACxD,MAAM,EAAE,CAAC,GAAG,CAAA,+BAA+B,CAAC,OAAO,EAAE,CAAC;QACtD,MAAM,EAAE,CAAC,GAAG,CAAA,kCAAkC,CAAC,OAAO,EAAE,CAAC;QACzD,MAAM,EAAE,CAAC,GAAG,CAAA,mCAAmC,CAAC,OAAO,EAAE,CAAC;QAC1D,MAAM,EAAE,CAAC,GAAG,CAAA,oCAAoC,CAAC,OAAO,EAAE,CAAC;QAC3D,MAAM,EAAE,CAAC,GAAG,CAAA,wCAAwC,CAAC,OAAO,EAAE,CAAC;QAC/D,MAAM,EAAE,CAAC,GAAG,CAAA,+CAA+C,CAAC,OAAO,EAAE,CAAC;QACtE,MAAM,EAAE,CAAC,GAAG,CAAA,wCAAwC,CAAC,OAAO,EAAE,CAAC;QAC/D,MAAM,EAAE,CAAC,GAAG,CAAA,gDAAgD,CAAC,OAAO,EAAE,CAAC;QACvE,MAAM,EAAE,CAAC,GAAG,CAAA,iCAAiC,CAAC,OAAO,EAAE,CAAC;IAC1D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,EAAE,EAA+B,EAAE,EAAE;IACtE,sDAAsD;IACtD,MAAM,EAAE,CAAC,KAAK,CACZ;QACE,SAAS,EAAE;;;;;;;;;KASZ;KACA,EACD;QACE,SAAS,EAAE;;UAEP;KACL,EACD;QACE,SAAS,EAAE;;UAEP;KACL,CACF,CAAC;AACJ,CAAC,CAAC"}
|
package/dist/utils/test-utils.js
CHANGED
|
@@ -55,6 +55,7 @@ import { PostgresMigrationAgent } from '../migrations/PostgresMigrationAgent.js'
|
|
|
55
55
|
import { normalizePostgresStorageConfig } from '../types/types.js';
|
|
56
56
|
import { PostgresReportStorage } from '../storage/PostgresReportStorage.js';
|
|
57
57
|
import { PostgresBucketStorageFactory } from '../storage/PostgresBucketStorageFactory.js';
|
|
58
|
+
import { truncateTables } from './db.js';
|
|
58
59
|
export function postgresTestSetup(factoryOptions) {
|
|
59
60
|
const BASE_CONFIG = {
|
|
60
61
|
type: 'postgresql',
|
|
@@ -62,7 +63,7 @@ export function postgresTestSetup(factoryOptions) {
|
|
|
62
63
|
sslmode: 'disable'
|
|
63
64
|
};
|
|
64
65
|
const TEST_CONNECTION_OPTIONS = normalizePostgresStorageConfig(BASE_CONFIG);
|
|
65
|
-
const
|
|
66
|
+
const runMigrations = async (options) => {
|
|
66
67
|
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
67
68
|
try {
|
|
68
69
|
const migrationManager = __addDisposableResource(env_1, new framework.MigrationManager(), true);
|
|
@@ -71,13 +72,15 @@ export function postgresTestSetup(factoryOptions) {
|
|
|
71
72
|
: new PostgresMigrationAgent(BASE_CONFIG), true);
|
|
72
73
|
migrationManager.registerMigrationAgent(migrationAgent);
|
|
73
74
|
const mockServiceContext = { configuration: { storage: BASE_CONFIG } };
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
75
|
+
if (options.down) {
|
|
76
|
+
await migrationManager.migrate({
|
|
77
|
+
direction: framework.migrations.Direction.Down,
|
|
78
|
+
migrationContext: {
|
|
79
|
+
service_context: mockServiceContext
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
if (options.up) {
|
|
81
84
|
await migrationManager.migrate({
|
|
82
85
|
direction: framework.migrations.Direction.Up,
|
|
83
86
|
migrationContext: {
|
|
@@ -96,11 +99,37 @@ export function postgresTestSetup(factoryOptions) {
|
|
|
96
99
|
await result_1;
|
|
97
100
|
}
|
|
98
101
|
};
|
|
102
|
+
const migrate = async (direction) => {
|
|
103
|
+
await runMigrations({
|
|
104
|
+
down: true,
|
|
105
|
+
up: direction == framework.migrations.Direction.Up
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
const clearStorage = async () => {
|
|
109
|
+
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
110
|
+
try {
|
|
111
|
+
await runMigrations({ down: false, up: true });
|
|
112
|
+
const storageFactory = __addDisposableResource(env_2, new PostgresBucketStorageFactory({
|
|
113
|
+
config: TEST_CONNECTION_OPTIONS,
|
|
114
|
+
slot_name_prefix: 'test_'
|
|
115
|
+
}), true);
|
|
116
|
+
await truncateTables(storageFactory.db);
|
|
117
|
+
}
|
|
118
|
+
catch (e_2) {
|
|
119
|
+
env_2.error = e_2;
|
|
120
|
+
env_2.hasError = true;
|
|
121
|
+
}
|
|
122
|
+
finally {
|
|
123
|
+
const result_2 = __disposeResources(env_2);
|
|
124
|
+
if (result_2)
|
|
125
|
+
await result_2;
|
|
126
|
+
}
|
|
127
|
+
};
|
|
99
128
|
return {
|
|
100
129
|
reportFactory: async (options) => {
|
|
101
130
|
try {
|
|
102
131
|
if (!options?.doNotClear) {
|
|
103
|
-
await
|
|
132
|
+
await clearStorage();
|
|
104
133
|
}
|
|
105
134
|
return new PostgresReportStorage({
|
|
106
135
|
config: TEST_CONNECTION_OPTIONS
|
|
@@ -115,7 +144,7 @@ export function postgresTestSetup(factoryOptions) {
|
|
|
115
144
|
factory: async (options) => {
|
|
116
145
|
try {
|
|
117
146
|
if (!options?.doNotClear) {
|
|
118
|
-
await
|
|
147
|
+
await clearStorage();
|
|
119
148
|
}
|
|
120
149
|
return new PostgresBucketStorageFactory({
|
|
121
150
|
config: TEST_CONNECTION_OPTIONS,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../../src/utils/test-utils.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO,EAAE,SAAS,EAAiE,MAAM,yBAAyB,CAAC;AACnH,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EAAE,8BAA8B,EAAgC,MAAM,mBAAmB,CAAC;AACjG,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAC5E,OAAO,EAAE,4BAA4B,EAAE,MAAM,4CAA4C,CAAC;
|
|
1
|
+
{"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../../src/utils/test-utils.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@powersync/service-module-postgres-storage",
|
|
3
3
|
"repository": "https://github.com/powersync-ja/powersync-service",
|
|
4
4
|
"types": "dist/@types/index.d.ts",
|
|
5
|
-
"version": "0.0.0-dev-
|
|
5
|
+
"version": "0.0.0-dev-20260223080959",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"license": "FSL-1.1-ALv2",
|
|
8
8
|
"type": "module",
|
|
@@ -29,17 +29,17 @@
|
|
|
29
29
|
"p-defer": "^4.0.1",
|
|
30
30
|
"ts-codec": "^1.3.0",
|
|
31
31
|
"uuid": "^11.1.0",
|
|
32
|
-
"@powersync/lib-service-postgres": "0.0.0-dev-
|
|
33
|
-
"@powersync/lib-services-framework": "0.0.0-dev-
|
|
34
|
-
"@powersync/service-core": "0.0.0-dev-
|
|
35
|
-
"@powersync/service-types": "0.0.0-dev-
|
|
36
|
-
"@powersync/service-jpgwire": "0.0.0-dev-
|
|
32
|
+
"@powersync/lib-service-postgres": "0.0.0-dev-20260223080959",
|
|
33
|
+
"@powersync/lib-services-framework": "0.0.0-dev-20260223080959",
|
|
34
|
+
"@powersync/service-core": "0.0.0-dev-20260223080959",
|
|
35
|
+
"@powersync/service-types": "0.0.0-dev-20260223080959",
|
|
36
|
+
"@powersync/service-jpgwire": "0.0.0-dev-20260223080959",
|
|
37
37
|
"@powersync/service-jsonbig": "0.17.12",
|
|
38
|
-
"@powersync/service-sync-rules": "0.0.0-dev-
|
|
38
|
+
"@powersync/service-sync-rules": "0.0.0-dev-20260223080959"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"typescript": "^5.7.3",
|
|
42
|
-
"@powersync/service-core-tests": "0.0.0-dev-
|
|
42
|
+
"@powersync/service-core-tests": "0.0.0-dev-20260223080959"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
45
|
"build": "tsc -b",
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { migrations, storage } from '@powersync/service-core';
|
|
2
|
+
import { openMigrationDB } from '../migration-utils.js';
|
|
3
|
+
|
|
4
|
+
export const up: migrations.PowerSyncMigrationFunction = async (context) => {
|
|
5
|
+
const {
|
|
6
|
+
service_context: { configuration }
|
|
7
|
+
} = context;
|
|
8
|
+
await using client = openMigrationDB(configuration.storage);
|
|
9
|
+
await client.transaction(async (db) => {
|
|
10
|
+
await db.sql`
|
|
11
|
+
ALTER TABLE sync_rules
|
|
12
|
+
ADD COLUMN storage_version integer NOT NULL DEFAULT 1
|
|
13
|
+
`.execute();
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const down: migrations.PowerSyncMigrationFunction = async (context) => {
|
|
18
|
+
const {
|
|
19
|
+
service_context: { configuration }
|
|
20
|
+
} = context;
|
|
21
|
+
await using client = openMigrationDB(configuration.storage);
|
|
22
|
+
await client.transaction(async (db) => {
|
|
23
|
+
const newRules = await db.sql`
|
|
24
|
+
SELECT
|
|
25
|
+
id,
|
|
26
|
+
storage_version
|
|
27
|
+
FROM
|
|
28
|
+
sync_rules
|
|
29
|
+
WHERE
|
|
30
|
+
storage_version > ${{ type: 'int4', value: storage.LEGACY_STORAGE_VERSION }}
|
|
31
|
+
`.rows<{ id: number | bigint; storage_version: number | bigint }>();
|
|
32
|
+
|
|
33
|
+
if (newRules.length > 0) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
`Cannot revert migration due to newer storage versions in use: ${newRules.map((r) => `${r.id}: v${r.storage_version}`).join(', ')}`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
await db.sql`
|
|
40
|
+
ALTER TABLE sync_rules
|
|
41
|
+
DROP COLUMN storage_version
|
|
42
|
+
`.execute();
|
|
43
|
+
});
|
|
44
|
+
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import * as framework from '@powersync/lib-services-framework';
|
|
2
1
|
import { GetIntanceOptions, storage, SyncRulesBucketStorage, UpdateSyncRulesOptions } from '@powersync/service-core';
|
|
3
2
|
import * as pg_wire from '@powersync/service-jpgwire';
|
|
4
3
|
import * as sync_rules from '@powersync/service-sync-rules';
|
|
@@ -19,10 +18,7 @@ export type PostgresBucketStorageOptions = {
|
|
|
19
18
|
slot_name_prefix: string;
|
|
20
19
|
};
|
|
21
20
|
|
|
22
|
-
export class PostgresBucketStorageFactory
|
|
23
|
-
extends framework.BaseObserver<storage.BucketStorageFactoryListener>
|
|
24
|
-
implements storage.BucketStorageFactory
|
|
25
|
-
{
|
|
21
|
+
export class PostgresBucketStorageFactory extends storage.BucketStorageFactory {
|
|
26
22
|
readonly db: lib_postgres.DatabaseClient;
|
|
27
23
|
public readonly slot_name_prefix: string;
|
|
28
24
|
|
|
@@ -145,42 +141,8 @@ export class PostgresBucketStorageFactory
|
|
|
145
141
|
};
|
|
146
142
|
}
|
|
147
143
|
|
|
148
|
-
// TODO possibly share implementation in abstract class
|
|
149
|
-
async configureSyncRules(options: UpdateSyncRulesOptions): Promise<{
|
|
150
|
-
updated: boolean;
|
|
151
|
-
persisted_sync_rules?: storage.PersistedSyncRulesContent;
|
|
152
|
-
lock?: storage.ReplicationLock;
|
|
153
|
-
}> {
|
|
154
|
-
const next = await this.getNextSyncRulesContent();
|
|
155
|
-
const active = await this.getActiveSyncRulesContent();
|
|
156
|
-
|
|
157
|
-
if (next?.sync_rules_content == options.content) {
|
|
158
|
-
framework.logger.info('Sync rules from configuration unchanged');
|
|
159
|
-
return { updated: false };
|
|
160
|
-
} else if (next == null && active?.sync_rules_content == options.content) {
|
|
161
|
-
framework.logger.info('Sync rules from configuration unchanged');
|
|
162
|
-
return { updated: false };
|
|
163
|
-
} else {
|
|
164
|
-
framework.logger.info('Sync rules updated from configuration');
|
|
165
|
-
const persisted_sync_rules = await this.updateSyncRules(options);
|
|
166
|
-
return { updated: true, persisted_sync_rules, lock: persisted_sync_rules.current_lock ?? undefined };
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
144
|
async updateSyncRules(options: storage.UpdateSyncRulesOptions): Promise<PostgresPersistedSyncRulesContent> {
|
|
171
|
-
|
|
172
|
-
if (options.validate) {
|
|
173
|
-
// Parse and validate before applying any changes
|
|
174
|
-
sync_rules.SqlSyncRules.fromYaml(options.content, {
|
|
175
|
-
// No schema-based validation at this point
|
|
176
|
-
schema: undefined,
|
|
177
|
-
defaultSchema: 'not_applicable', // Not needed for validation
|
|
178
|
-
throwOnError: true
|
|
179
|
-
});
|
|
180
|
-
} else {
|
|
181
|
-
// Apply unconditionally. Any errors will be reported via the diagnostics API.
|
|
182
|
-
}
|
|
183
|
-
|
|
145
|
+
const storageVersion = options.storageVersion ?? storage.CURRENT_STORAGE_VERSION;
|
|
184
146
|
return this.db.transaction(async (db) => {
|
|
185
147
|
await db.sql`
|
|
186
148
|
UPDATE sync_rules
|
|
@@ -197,7 +159,7 @@ export class PostgresBucketStorageFactory
|
|
|
197
159
|
nextval('sync_rules_id_sequence') AS id
|
|
198
160
|
)
|
|
199
161
|
INSERT INTO
|
|
200
|
-
sync_rules (id, content, state, slot_name)
|
|
162
|
+
sync_rules (id, content, state, slot_name, storage_version)
|
|
201
163
|
VALUES
|
|
202
164
|
(
|
|
203
165
|
(
|
|
@@ -206,7 +168,7 @@ export class PostgresBucketStorageFactory
|
|
|
206
168
|
FROM
|
|
207
169
|
next_id
|
|
208
170
|
),
|
|
209
|
-
${{ type: 'varchar', value: options.
|
|
171
|
+
${{ type: 'varchar', value: options.config.yaml }},
|
|
210
172
|
${{ type: 'varchar', value: storage.SyncRuleState.PROCESSING }},
|
|
211
173
|
CONCAT(
|
|
212
174
|
${{ type: 'varchar', value: this.slot_name_prefix }},
|
|
@@ -218,7 +180,8 @@ export class PostgresBucketStorageFactory
|
|
|
218
180
|
),
|
|
219
181
|
'_',
|
|
220
182
|
${{ type: 'varchar', value: crypto.randomBytes(2).toString('hex') }}
|
|
221
|
-
)
|
|
183
|
+
),
|
|
184
|
+
${{ type: 'int4', value: storageVersion }}
|
|
222
185
|
)
|
|
223
186
|
RETURNING
|
|
224
187
|
*
|
|
@@ -240,10 +203,8 @@ export class PostgresBucketStorageFactory
|
|
|
240
203
|
// The current one will continue serving sync requests until the next one has finished processing.
|
|
241
204
|
if (next != null && next.id == sync_rules_group_id) {
|
|
242
205
|
// We need to redo the "next" sync rules
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
validate: false
|
|
246
|
-
});
|
|
206
|
+
|
|
207
|
+
await this.updateSyncRules(next.asUpdateOptions());
|
|
247
208
|
// Pro-actively stop replicating
|
|
248
209
|
await this.db.sql`
|
|
249
210
|
UPDATE sync_rules
|
|
@@ -255,10 +216,7 @@ export class PostgresBucketStorageFactory
|
|
|
255
216
|
`.execute();
|
|
256
217
|
} else if (next == null && active?.id == sync_rules_group_id) {
|
|
257
218
|
// Slot removed for "active" sync rules, while there is no "next" one.
|
|
258
|
-
await this.updateSyncRules(
|
|
259
|
-
content: active.sync_rules_content,
|
|
260
|
-
validate: false
|
|
261
|
-
});
|
|
219
|
+
await this.updateSyncRules(active.asUpdateOptions());
|
|
262
220
|
|
|
263
221
|
// Pro-actively stop replicating, but still serve clients with existing data
|
|
264
222
|
await this.db.sql`
|
|
@@ -284,12 +242,6 @@ export class PostgresBucketStorageFactory
|
|
|
284
242
|
}
|
|
285
243
|
}
|
|
286
244
|
|
|
287
|
-
// TODO possibly share via abstract class
|
|
288
|
-
async getActiveSyncRules(options: storage.ParseSyncRulesOptions): Promise<storage.PersistedSyncRules | null> {
|
|
289
|
-
const content = await this.getActiveSyncRulesContent();
|
|
290
|
-
return content?.parsed(options) ?? null;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
245
|
async getActiveSyncRulesContent(): Promise<storage.PersistedSyncRulesContent | null> {
|
|
294
246
|
const activeRow = await this.db.sql`
|
|
295
247
|
SELECT
|
|
@@ -313,12 +265,6 @@ export class PostgresBucketStorageFactory
|
|
|
313
265
|
return new PostgresPersistedSyncRulesContent(this.db, activeRow);
|
|
314
266
|
}
|
|
315
267
|
|
|
316
|
-
// TODO possibly share via abstract class
|
|
317
|
-
async getNextSyncRules(options: storage.ParseSyncRulesOptions): Promise<storage.PersistedSyncRules | null> {
|
|
318
|
-
const content = await this.getNextSyncRulesContent();
|
|
319
|
-
return content?.parsed(options) ?? null;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
268
|
async getNextSyncRulesContent(): Promise<storage.PersistedSyncRulesContent | null> {
|
|
323
269
|
const nextRow = await this.db.sql`
|
|
324
270
|
SELECT
|
|
@@ -28,13 +28,6 @@ export class PostgresReportStorage implements storage.ReportStorage {
|
|
|
28
28
|
connectionCreated: async (connection) => this.prepareStatements(connection)
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
|
-
async getLastSyncReport(data: event_types.LastSyncRequest): Promise<any> {
|
|
32
|
-
throw new Error('Method not implemented.');
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
async getSyncBucketStats(data: event_types.SyncBucketStatsRequest): Promise<any> {
|
|
36
|
-
throw new Error('Method not implemented.');
|
|
37
|
-
}
|
|
38
31
|
|
|
39
32
|
private parseJsDate(date: Date) {
|
|
40
33
|
const year = date.getUTCFullYear();
|
|
@@ -181,14 +174,6 @@ export class PostgresReportStorage implements storage.ReportStorage {
|
|
|
181
174
|
};
|
|
182
175
|
}
|
|
183
176
|
|
|
184
|
-
getSyncCheckpoint(data: event_types.SyncCheckpointRequest): Promise<event_types.PaginatedResponse<any>> {
|
|
185
|
-
throw new Error('Method not implemented.');
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
async reportSyncAnalyticsEvent(data: event_types.SyncAnalyticsEventData): Promise<void> {
|
|
189
|
-
console.log(data);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
177
|
async reportClientConnection(data: event_types.ClientConnectionBucketData): Promise<void> {
|
|
193
178
|
const { sdk, connected_at, user_id, user_agent, jwt_exp, client_id } = data;
|
|
194
179
|
const connectIsoString = connected_at.toISOString();
|
|
@@ -254,7 +239,9 @@ export class PostgresReportStorage implements storage.ReportStorage {
|
|
|
254
239
|
return this.mapListCurrentConnectionsResponse(result);
|
|
255
240
|
}
|
|
256
241
|
|
|
257
|
-
async getClientConnectionReports(
|
|
242
|
+
async getClientConnectionReports(
|
|
243
|
+
data: event_types.ClientConnectionReportRequest
|
|
244
|
+
): Promise<event_types.ClientConnectionReportResponse> {
|
|
258
245
|
const { start, end } = data;
|
|
259
246
|
const result = await this.db.sql`
|
|
260
247
|
WITH
|
|
@@ -9,7 +9,13 @@ import {
|
|
|
9
9
|
ServiceAssertionError,
|
|
10
10
|
ServiceError
|
|
11
11
|
} from '@powersync/lib-services-framework';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
BucketStorageMarkRecordUnavailable,
|
|
14
|
+
deserializeReplicaId,
|
|
15
|
+
InternalOpId,
|
|
16
|
+
storage,
|
|
17
|
+
utils
|
|
18
|
+
} from '@powersync/service-core';
|
|
13
19
|
import * as sync_rules from '@powersync/service-sync-rules';
|
|
14
20
|
import * as timers from 'timers/promises';
|
|
15
21
|
import * as t from 'ts-codec';
|
|
@@ -199,17 +205,18 @@ export class PostgresBucketBatch
|
|
|
199
205
|
|
|
200
206
|
const decodedRows = rows.map((row) => codec.decode(row));
|
|
201
207
|
for (const value of decodedRows) {
|
|
208
|
+
const source_key = deserializeReplicaId(value.source_key);
|
|
202
209
|
persistedBatch.saveBucketData({
|
|
203
210
|
before_buckets: value.buckets,
|
|
204
211
|
evaluated: [],
|
|
205
212
|
table: sourceTable,
|
|
206
|
-
source_key
|
|
213
|
+
source_key
|
|
207
214
|
});
|
|
208
215
|
persistedBatch.saveParameterData({
|
|
209
216
|
existing_lookups: value.lookups,
|
|
210
217
|
evaluated: [],
|
|
211
218
|
table: sourceTable,
|
|
212
|
-
source_key
|
|
219
|
+
source_key
|
|
213
220
|
});
|
|
214
221
|
persistedBatch.deleteCurrentData({
|
|
215
222
|
// This is serialized since we got it from a DB query
|
|
@@ -1,47 +1,33 @@
|
|
|
1
1
|
import * as lib_postgres from '@powersync/lib-service-postgres';
|
|
2
2
|
import { ErrorCode, logger, ServiceError } from '@powersync/lib-services-framework';
|
|
3
3
|
import { storage } from '@powersync/service-core';
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
CompatibilityOption,
|
|
6
|
+
DEFAULT_HYDRATION_STATE,
|
|
7
|
+
HydrationState,
|
|
8
|
+
SqlSyncRules,
|
|
9
|
+
versionedHydrationState
|
|
10
|
+
} from '@powersync/service-sync-rules';
|
|
6
11
|
import { models } from '../../types/types.js';
|
|
7
12
|
|
|
8
|
-
export class PostgresPersistedSyncRulesContent
|
|
9
|
-
public readonly slot_name: string;
|
|
10
|
-
|
|
11
|
-
public readonly id: number;
|
|
12
|
-
public readonly sync_rules_content: string;
|
|
13
|
-
public readonly last_checkpoint_lsn: string | null;
|
|
14
|
-
public readonly last_fatal_error: string | null;
|
|
15
|
-
public readonly last_keepalive_ts: Date | null;
|
|
16
|
-
public readonly last_checkpoint_ts: Date | null;
|
|
17
|
-
public readonly active: boolean;
|
|
13
|
+
export class PostgresPersistedSyncRulesContent extends storage.PersistedSyncRulesContent {
|
|
18
14
|
current_lock: storage.ReplicationLock | null = null;
|
|
19
15
|
|
|
20
16
|
constructor(
|
|
21
17
|
private db: lib_postgres.DatabaseClient,
|
|
22
18
|
row: models.SyncRulesDecoded
|
|
23
19
|
) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return {
|
|
36
|
-
id: this.id,
|
|
37
|
-
slot_name: this.slot_name,
|
|
38
|
-
sync_rules: SqlSyncRules.fromYaml(this.sync_rules_content, options),
|
|
39
|
-
hydratedSyncRules() {
|
|
40
|
-
return this.sync_rules.hydrate({
|
|
41
|
-
hydrationState: versionedHydrationState(this.id)
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
};
|
|
20
|
+
super({
|
|
21
|
+
id: Number(row.id),
|
|
22
|
+
sync_rules_content: row.content,
|
|
23
|
+
last_checkpoint_lsn: row.last_checkpoint_lsn,
|
|
24
|
+
slot_name: row.slot_name,
|
|
25
|
+
last_fatal_error: row.last_fatal_error,
|
|
26
|
+
last_checkpoint_ts: row.last_checkpoint_ts ? new Date(row.last_checkpoint_ts) : null,
|
|
27
|
+
last_keepalive_ts: row.last_keepalive_ts ? new Date(row.last_keepalive_ts) : null,
|
|
28
|
+
active: row.state == 'ACTIVE',
|
|
29
|
+
storageVersion: row.storage_version ?? storage.LEGACY_STORAGE_VERSION
|
|
30
|
+
});
|
|
45
31
|
}
|
|
46
32
|
|
|
47
33
|
async lock(): Promise<storage.ReplicationLock> {
|