@powersync/service-module-postgres-storage 0.0.0-dev-20260313100403 → 0.0.0-dev-20260511080634
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 +84 -9
- package/dist/.tsbuildinfo +1 -1
- package/dist/@types/storage/PostgresBucketStorageFactory.d.ts +2 -1
- package/dist/@types/storage/PostgresReportStorage.d.ts +4 -4
- package/dist/@types/storage/PostgresSyncRulesStorage.d.ts +4 -2
- package/dist/@types/storage/batch/PostgresBucketBatch.d.ts +1 -1
- package/dist/@types/types/models/SyncRules.d.ts +9 -0
- package/dist/@types/types/models/models-index.d.ts +1 -1
- package/dist/@types/utils/test-utils.d.ts +2 -2
- package/dist/@types/utils/utils-index.d.ts +1 -1
- package/dist/migrations/migration-utils.js +2 -2
- package/dist/migrations/migration-utils.js.map +1 -1
- package/dist/migrations/scripts/1684951997326-init.js +24 -100
- package/dist/migrations/scripts/1684951997326-init.js.map +1 -1
- package/dist/migrations/scripts/1749024804042-snapshot-progress.js +12 -88
- package/dist/migrations/scripts/1749024804042-snapshot-progress.js.map +1 -1
- package/dist/migrations/scripts/1756282360128-connection-reporting.js +12 -88
- package/dist/migrations/scripts/1756282360128-connection-reporting.js.map +1 -1
- package/dist/migrations/scripts/1771232439485-storage-version.js +14 -90
- package/dist/migrations/scripts/1771232439485-storage-version.js.map +1 -1
- package/dist/migrations/scripts/1771424826685-current-data-pending-deletes.js +1 -1
- package/dist/migrations/scripts/1771491856000-sync-plan.js +6 -82
- package/dist/migrations/scripts/1771491856000-sync-plan.js.map +1 -1
- package/dist/storage/PostgresBucketStorageFactory.js +6 -5
- package/dist/storage/PostgresBucketStorageFactory.js.map +1 -1
- package/dist/storage/PostgresReportStorage.js +10 -10
- package/dist/storage/PostgresReportStorage.js.map +1 -1
- package/dist/storage/PostgresSyncRulesStorage.js +63 -104
- package/dist/storage/PostgresSyncRulesStorage.js.map +1 -1
- package/dist/storage/batch/PostgresBucketBatch.js +5 -5
- package/dist/storage/batch/PostgresBucketBatch.js.map +1 -1
- package/dist/storage/checkpoints/PostgresWriteCheckpointAPI.js +1 -1
- package/dist/storage/checkpoints/PostgresWriteCheckpointAPI.js.map +1 -1
- package/dist/storage/current-data-store.js +1 -1
- package/dist/storage/current-data-store.js.map +1 -1
- package/dist/storage/sync-rules/PostgresPersistedSyncRulesContent.js +3 -3
- package/dist/storage/sync-rules/PostgresPersistedSyncRulesContent.js.map +1 -1
- package/dist/types/models/SyncRules.js +3 -1
- package/dist/types/models/SyncRules.js.map +1 -1
- package/dist/types/models/models-index.js +1 -1
- package/dist/types/models/models-index.js.map +1 -1
- package/dist/utils/test-utils.js +36 -112
- package/dist/utils/test-utils.js.map +1 -1
- package/dist/utils/utils-index.js +1 -1
- package/dist/utils/utils-index.js.map +1 -1
- package/package.json +11 -12
- package/src/migrations/migration-utils.ts +2 -2
- package/src/migrations/scripts/1771424826685-current-data-pending-deletes.ts +1 -1
- package/src/storage/PostgresBucketStorageFactory.ts +7 -5
- package/src/storage/PostgresReportStorage.ts +12 -12
- package/src/storage/PostgresSyncRulesStorage.ts +63 -36
- package/src/storage/batch/PostgresBucketBatch.ts +5 -5
- package/src/storage/checkpoints/PostgresWriteCheckpointAPI.ts +3 -1
- package/src/storage/current-data-store.ts +1 -1
- package/src/storage/sync-rules/PostgresPersistedSyncRulesContent.ts +3 -6
- package/src/types/models/SyncRules.ts +3 -1
- package/src/types/models/models-index.ts +1 -1
- package/src/utils/test-utils.ts +3 -3
- package/src/utils/utils-index.ts +1 -1
- package/test/src/__snapshots__/{client-connections-storage.test.ts.snap → connection-report-storage.test.ts.snap} +22 -22
- package/test/src/__snapshots__/storage_sync.test.ts.snap +282 -0
- package/test/src/{client-connections-storage.test.ts → connection-report-storage.test.ts} +5 -5
- package/test/src/setup.ts +1 -1
- package/test/tsconfig.json +0 -1
- package/dist/@types/storage/current-data-table.d.ts +0 -9
- package/dist/storage/current-data-table.js +0 -22
- package/dist/storage/current-data-table.js.map +0 -1
- package/src/storage/current-data-table.ts +0 -26
|
@@ -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;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEhD,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;IACjB,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAClB,mBAAmB,CACjB,CAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,CAAC,CAAC,GAAG;QACX,aAAa,EAAE,CAAC,CAAC,MAAM,CAAC;YACtB,OAAO,EAAE,CAAC,CAAC,MAAM;YACjB,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;YAC9B,qBAAqB,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;SAC3C,CAAC;QACF,gBAAgB,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,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,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEhD,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;IACjB,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAClB,mBAAmB,CACjB,CAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,CAAC,CAAC,GAAG;QACX,aAAa,EAAE,CAAC,CAAC,MAAM,CAAC;YACtB,OAAO,EAAE,CAAC,CAAC,MAAM;YACjB,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;YAC9B,qBAAqB,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;SAC3C,CAAC;QACF,gBAAgB,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAC7C,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,QAAQ,EAAE;KAC7C,CAAC,CACH,CACF;CACF,CAAC,CAAC"}
|
|
@@ -5,8 +5,8 @@ export * from './BucketParameters.js';
|
|
|
5
5
|
export * from './CurrentData.js';
|
|
6
6
|
export * from './Instance.js';
|
|
7
7
|
export * from './Migration.js';
|
|
8
|
+
export * from './SdkReporting.js';
|
|
8
9
|
export * from './SourceTable.js';
|
|
9
10
|
export * from './SyncRules.js';
|
|
10
11
|
export * from './WriteCheckpoint.js';
|
|
11
|
-
export * from './SdkReporting.js';
|
|
12
12
|
//# sourceMappingURL=models-index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"models-index.js","sourceRoot":"","sources":["../../../src/types/models/models-index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,mCAAmC,CAAC;AAClD,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC
|
|
1
|
+
{"version":3,"file":"models-index.js","sourceRoot":"","sources":["../../../src/types/models/models-index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,mCAAmC,CAAC;AAClD,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC"}
|
package/dist/utils/test-utils.js
CHANGED
|
@@ -1,61 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
if (value !== null && value !== void 0) {
|
|
3
|
-
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
4
|
-
var dispose, inner;
|
|
5
|
-
if (async) {
|
|
6
|
-
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
7
|
-
dispose = value[Symbol.asyncDispose];
|
|
8
|
-
}
|
|
9
|
-
if (dispose === void 0) {
|
|
10
|
-
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
11
|
-
dispose = value[Symbol.dispose];
|
|
12
|
-
if (async) inner = dispose;
|
|
13
|
-
}
|
|
14
|
-
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
15
|
-
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
16
|
-
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
17
|
-
}
|
|
18
|
-
else if (async) {
|
|
19
|
-
env.stack.push({ async: true });
|
|
20
|
-
}
|
|
21
|
-
return value;
|
|
22
|
-
};
|
|
23
|
-
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
24
|
-
return function (env) {
|
|
25
|
-
function fail(e) {
|
|
26
|
-
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
27
|
-
env.hasError = true;
|
|
28
|
-
}
|
|
29
|
-
var r, s = 0;
|
|
30
|
-
function next() {
|
|
31
|
-
while (r = env.stack.pop()) {
|
|
32
|
-
try {
|
|
33
|
-
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
34
|
-
if (r.dispose) {
|
|
35
|
-
var result = r.dispose.call(r.value);
|
|
36
|
-
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
37
|
-
}
|
|
38
|
-
else s |= 1;
|
|
39
|
-
}
|
|
40
|
-
catch (e) {
|
|
41
|
-
fail(e);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
45
|
-
if (env.hasError) throw env.error;
|
|
46
|
-
}
|
|
47
|
-
return next();
|
|
48
|
-
};
|
|
49
|
-
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
50
|
-
var e = new Error(message);
|
|
51
|
-
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
|
-
});
|
|
1
|
+
import { createLogger, logger as defaultLogger, transports } from '@powersync/lib-services-framework';
|
|
53
2
|
import { framework } from '@powersync/service-core';
|
|
54
3
|
import { PostgresMigrationAgent } from '../migrations/PostgresMigrationAgent.js';
|
|
55
|
-
import { normalizePostgresStorageConfig } from '../types/types.js';
|
|
56
|
-
import { PostgresReportStorage } from '../storage/PostgresReportStorage.js';
|
|
57
4
|
import { PostgresBucketStorageFactory } from '../storage/PostgresBucketStorageFactory.js';
|
|
58
|
-
import {
|
|
5
|
+
import { PostgresReportStorage } from '../storage/PostgresReportStorage.js';
|
|
6
|
+
import { normalizePostgresStorageConfig } from '../types/types.js';
|
|
59
7
|
import { truncateTables } from './db.js';
|
|
60
8
|
export function postgresTestSetup(factoryOptions) {
|
|
61
9
|
const BASE_CONFIG = {
|
|
@@ -65,47 +13,35 @@ export function postgresTestSetup(factoryOptions) {
|
|
|
65
13
|
};
|
|
66
14
|
const TEST_CONNECTION_OPTIONS = normalizePostgresStorageConfig(BASE_CONFIG);
|
|
67
15
|
const runMigrations = async (options) => {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
16
|
+
await using migrationManager = new framework.MigrationManager();
|
|
17
|
+
await using migrationAgent = factoryOptions.migrationAgent
|
|
18
|
+
? factoryOptions.migrationAgent(BASE_CONFIG)
|
|
19
|
+
: new PostgresMigrationAgent(BASE_CONFIG);
|
|
20
|
+
migrationManager.registerMigrationAgent(migrationAgent);
|
|
21
|
+
const mockServiceContext = { configuration: { storage: BASE_CONFIG } };
|
|
22
|
+
// Migration logs can get really verbose in tests, so only log warnings and up.
|
|
23
|
+
const logger = createLogger({
|
|
24
|
+
level: 'warn',
|
|
25
|
+
format: defaultLogger.format,
|
|
26
|
+
transports: [new transports.Console()]
|
|
27
|
+
});
|
|
28
|
+
if (options.down) {
|
|
29
|
+
await migrationManager.migrate({
|
|
30
|
+
direction: framework.migrations.Direction.Down,
|
|
31
|
+
migrationContext: {
|
|
32
|
+
service_context: mockServiceContext
|
|
33
|
+
},
|
|
34
|
+
logger
|
|
81
35
|
});
|
|
82
|
-
if (options.down) {
|
|
83
|
-
await migrationManager.migrate({
|
|
84
|
-
direction: framework.migrations.Direction.Down,
|
|
85
|
-
migrationContext: {
|
|
86
|
-
service_context: mockServiceContext
|
|
87
|
-
},
|
|
88
|
-
logger
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
if (options.up) {
|
|
92
|
-
await migrationManager.migrate({
|
|
93
|
-
direction: framework.migrations.Direction.Up,
|
|
94
|
-
migrationContext: {
|
|
95
|
-
service_context: mockServiceContext
|
|
96
|
-
},
|
|
97
|
-
logger
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
catch (e_1) {
|
|
102
|
-
env_1.error = e_1;
|
|
103
|
-
env_1.hasError = true;
|
|
104
36
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
37
|
+
if (options.up) {
|
|
38
|
+
await migrationManager.migrate({
|
|
39
|
+
direction: framework.migrations.Direction.Up,
|
|
40
|
+
migrationContext: {
|
|
41
|
+
service_context: mockServiceContext
|
|
42
|
+
},
|
|
43
|
+
logger
|
|
44
|
+
});
|
|
109
45
|
}
|
|
110
46
|
};
|
|
111
47
|
const migrate = async (direction) => {
|
|
@@ -115,24 +51,12 @@ export function postgresTestSetup(factoryOptions) {
|
|
|
115
51
|
});
|
|
116
52
|
};
|
|
117
53
|
const clearStorage = async () => {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}), true);
|
|
125
|
-
await truncateTables(storageFactory.db);
|
|
126
|
-
}
|
|
127
|
-
catch (e_2) {
|
|
128
|
-
env_2.error = e_2;
|
|
129
|
-
env_2.hasError = true;
|
|
130
|
-
}
|
|
131
|
-
finally {
|
|
132
|
-
const result_2 = __disposeResources(env_2);
|
|
133
|
-
if (result_2)
|
|
134
|
-
await result_2;
|
|
135
|
-
}
|
|
54
|
+
await runMigrations({ down: false, up: true });
|
|
55
|
+
await using storageFactory = new PostgresBucketStorageFactory({
|
|
56
|
+
config: TEST_CONNECTION_OPTIONS,
|
|
57
|
+
slot_name_prefix: 'test_'
|
|
58
|
+
});
|
|
59
|
+
await truncateTables(storageFactory.db);
|
|
136
60
|
};
|
|
137
61
|
return {
|
|
138
62
|
reportFactory: async (options) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../../src/utils/test-utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../../src/utils/test-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils-index.js","sourceRoot":"","sources":["../../src/utils/utils-index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC;AACxB,
|
|
1
|
+
{"version":3,"file":"utils-index.js","sourceRoot":"","sources":["../../src/utils/utils-index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC;AACxB,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAC;AAC9C,cAAc,eAAe,CAAC"}
|
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-20260511080634",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"license": "FSL-1.1-ALv2",
|
|
8
8
|
"type": "module",
|
|
@@ -26,20 +26,19 @@
|
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"ix": "^5.0.0",
|
|
28
28
|
"lru-cache": "^10.2.2",
|
|
29
|
-
"p-defer": "^4.0.1",
|
|
30
29
|
"ts-codec": "^1.3.0",
|
|
31
|
-
"uuid": "^
|
|
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-
|
|
37
|
-
"@powersync/service-jsonbig": "0.
|
|
38
|
-
"@powersync/service-sync-rules": "0.0.0-dev-
|
|
30
|
+
"uuid": "^14.0.0",
|
|
31
|
+
"@powersync/lib-service-postgres": "0.0.0-dev-20260511080634",
|
|
32
|
+
"@powersync/lib-services-framework": "0.0.0-dev-20260511080634",
|
|
33
|
+
"@powersync/service-core": "0.0.0-dev-20260511080634",
|
|
34
|
+
"@powersync/service-types": "0.0.0-dev-20260511080634",
|
|
35
|
+
"@powersync/service-jpgwire": "0.0.0-dev-20260511080634",
|
|
36
|
+
"@powersync/service-jsonbig": "0.0.0-dev-20260511080634",
|
|
37
|
+
"@powersync/service-sync-rules": "0.0.0-dev-20260511080634"
|
|
39
38
|
},
|
|
40
39
|
"devDependencies": {
|
|
41
|
-
"typescript": "
|
|
42
|
-
"@powersync/service-core-tests": "0.0.0-dev-
|
|
40
|
+
"typescript": "~6.0.3",
|
|
41
|
+
"@powersync/service-core-tests": "0.0.0-dev-20260511080634"
|
|
43
42
|
},
|
|
44
43
|
"scripts": {
|
|
45
44
|
"build": "tsc -b",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as lib_postgres from '@powersync/lib-service-postgres';
|
|
2
|
+
import { ServiceAssertionError } from '@powersync/lib-services-framework';
|
|
2
3
|
import { configFile } from '@powersync/service-types';
|
|
3
4
|
import { isPostgresStorageConfig, normalizePostgresStorageConfig, PostgresStorageConfig } from '../types/types.js';
|
|
4
|
-
import { STORAGE_SCHEMA_NAME } from '../utils/db.js';
|
|
5
|
-
import { ServiceAssertionError } from '@powersync/lib-services-framework';
|
|
6
5
|
import { getStorageApplicationName } from '../utils/application-name.js';
|
|
6
|
+
import { STORAGE_SCHEMA_NAME } from '../utils/db.js';
|
|
7
7
|
|
|
8
8
|
export const openMigrationDB = (config: configFile.BaseStorageConfig) => {
|
|
9
9
|
if (!isPostgresStorageConfig(config)) {
|
|
@@ -2,7 +2,7 @@ import { migrations } from '@powersync/service-core';
|
|
|
2
2
|
|
|
3
3
|
export const up: migrations.PowerSyncMigrationFunction = async (_context) => {
|
|
4
4
|
// No-op.
|
|
5
|
-
// Pending-delete support is now storage-version specific and initialized when v3 sync
|
|
5
|
+
// Pending-delete support is now storage-version specific and initialized when v3 sync config is deployed.
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
export const down: migrations.PowerSyncMigrationFunction = async (_context) => {
|
|
@@ -18,6 +18,7 @@ export type PostgresBucketStorageOptions = {
|
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
export class PostgresBucketStorageFactory extends storage.BucketStorageFactory {
|
|
21
|
+
[framework.DO_NOT_LOG] = true;
|
|
21
22
|
readonly db: lib_postgres.DatabaseClient;
|
|
22
23
|
public readonly slot_name_prefix: string;
|
|
23
24
|
|
|
@@ -153,7 +154,8 @@ export class PostgresBucketStorageFactory extends storage.BucketStorageFactory {
|
|
|
153
154
|
}
|
|
154
155
|
|
|
155
156
|
async updateSyncRules(options: storage.UpdateSyncRulesOptions): Promise<PostgresPersistedSyncRulesContent> {
|
|
156
|
-
const storageVersion =
|
|
157
|
+
const storageVersion =
|
|
158
|
+
options.storageVersion ?? options.config.parsed.config.storageVersion ?? storage.CURRENT_STORAGE_VERSION;
|
|
157
159
|
const storageConfig = storage.STORAGE_VERSION_CONFIG[storageVersion];
|
|
158
160
|
if (storageConfig == null) {
|
|
159
161
|
throw new framework.ServiceError(
|
|
@@ -254,10 +256,10 @@ export class PostgresBucketStorageFactory extends storage.BucketStorageFactory {
|
|
|
254
256
|
const next = await this.getNextSyncRulesContent();
|
|
255
257
|
const active = await this.getActiveSyncRulesContent();
|
|
256
258
|
|
|
257
|
-
// In both the below cases, we create a new
|
|
259
|
+
// In both the below cases, we create a new replication stream.
|
|
258
260
|
// The current one will continue serving sync requests until the next one has finished processing.
|
|
259
261
|
if (next != null && next.id == sync_rules_group_id) {
|
|
260
|
-
// We need to redo the "next"
|
|
262
|
+
// We need to redo the "next" replication stream
|
|
261
263
|
|
|
262
264
|
await this.updateSyncRules(next.asUpdateOptions());
|
|
263
265
|
// Pro-actively stop replicating
|
|
@@ -270,7 +272,7 @@ export class PostgresBucketStorageFactory extends storage.BucketStorageFactory {
|
|
|
270
272
|
AND state = ${{ value: storage.SyncRuleState.PROCESSING, type: 'varchar' }}
|
|
271
273
|
`.execute();
|
|
272
274
|
} else if (next == null && active?.id == sync_rules_group_id) {
|
|
273
|
-
// Slot removed for "active"
|
|
275
|
+
// Slot removed for "active" replication stream, while there is no "next" one.
|
|
274
276
|
await this.updateSyncRules(active.asUpdateOptions());
|
|
275
277
|
|
|
276
278
|
// Pro-actively stop replicating, but still serve clients with existing data
|
|
@@ -283,7 +285,7 @@ export class PostgresBucketStorageFactory extends storage.BucketStorageFactory {
|
|
|
283
285
|
AND state = ${{ value: storage.SyncRuleState.ACTIVE, type: 'varchar' }}
|
|
284
286
|
`.execute();
|
|
285
287
|
} else if (next != null && active?.id == sync_rules_group_id) {
|
|
286
|
-
// Already have "next"
|
|
288
|
+
// Already have "next" replication stream - don't update any.
|
|
287
289
|
|
|
288
290
|
// Pro-actively stop replicating, but still serve clients with existing data
|
|
289
291
|
await this.db.sql`
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
+
import * as lib_postgres from '@powersync/lib-service-postgres';
|
|
2
|
+
import { logger } from '@powersync/lib-services-framework';
|
|
1
3
|
import { storage } from '@powersync/service-core';
|
|
2
4
|
import * as pg_wire from '@powersync/service-jpgwire';
|
|
3
5
|
import { event_types } from '@powersync/service-types';
|
|
6
|
+
import { ClientConnectionResponse } from '@powersync/service-types/dist/reports.js';
|
|
7
|
+
import { toInteger } from 'ix/util/tointeger.js';
|
|
4
8
|
import { v4 } from 'uuid';
|
|
5
|
-
import * as lib_postgres from '@powersync/lib-service-postgres';
|
|
6
|
-
import { NormalizedPostgresStorageConfig } from '../types/types.js';
|
|
7
9
|
import { SdkReporting, SdkReportingDecoded } from '../types/models/SdkReporting.js';
|
|
8
|
-
import {
|
|
9
|
-
import { logger } from '@powersync/lib-services-framework';
|
|
10
|
+
import { NormalizedPostgresStorageConfig } from '../types/types.js';
|
|
10
11
|
import { getStorageApplicationName } from '../utils/application-name.js';
|
|
11
12
|
import { STORAGE_SCHEMA_NAME } from '../utils/db.js';
|
|
12
|
-
import { ClientConnectionResponse } from '@powersync/service-types/dist/reports.js';
|
|
13
13
|
|
|
14
14
|
export type PostgresReportStorageOptions = {
|
|
15
15
|
config: NormalizedPostgresStorageConfig;
|
|
@@ -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
|
+
users: 0,
|
|
52
|
+
sdks: []
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
55
|
return {
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
users: Number(result.users),
|
|
57
|
+
sdks: 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 getConnectedClients(): 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 getClientConnectionReports(
|
|
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 getGeneralClientConnectionAnalytics(
|
|
293
293
|
data: event_types.ClientConnectionAnalyticsRequest
|
|
294
294
|
): Promise<event_types.PaginatedResponse<event_types.ClientConnection>> {
|
|
295
295
|
const limit = data.limit || 100;
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
internalToExternalOpId,
|
|
10
10
|
LastValueSink,
|
|
11
11
|
maxLsn,
|
|
12
|
+
ParameterSetLimitExceededError,
|
|
12
13
|
PartialChecksum,
|
|
13
14
|
PopulateChecksumCacheOptions,
|
|
14
15
|
PopulateChecksumCacheResults,
|
|
@@ -34,9 +35,9 @@ import { SourceTableDecoded, StoredRelationId } from '../types/models/SourceTabl
|
|
|
34
35
|
import { pick } from '../utils/ts-codec.js';
|
|
35
36
|
import { PostgresBucketBatch } from './batch/PostgresBucketBatch.js';
|
|
36
37
|
import { PostgresWriteCheckpointAPI } from './checkpoints/PostgresWriteCheckpointAPI.js';
|
|
38
|
+
import { PostgresCurrentDataStore } from './current-data-store.js';
|
|
37
39
|
import { PostgresBucketStorageFactory } from './PostgresBucketStorageFactory.js';
|
|
38
40
|
import { PostgresCompactor } from './PostgresCompactor.js';
|
|
39
|
-
import { PostgresCurrentDataStore } from './current-data-store.js';
|
|
40
41
|
|
|
41
42
|
export type PostgresSyncRulesStorageOptions = {
|
|
42
43
|
factory: PostgresBucketStorageFactory;
|
|
@@ -50,11 +51,14 @@ export class PostgresSyncRulesStorage
|
|
|
50
51
|
extends framework.BaseObserver<storage.SyncRulesBucketStorageListener>
|
|
51
52
|
implements storage.SyncRulesBucketStorage
|
|
52
53
|
{
|
|
54
|
+
[framework.DO_NOT_LOG] = true;
|
|
55
|
+
|
|
53
56
|
public readonly group_id: number;
|
|
54
57
|
public readonly sync_rules: storage.PersistedSyncRulesContent;
|
|
55
58
|
public readonly slot_name: string;
|
|
56
59
|
public readonly factory: PostgresBucketStorageFactory;
|
|
57
60
|
public readonly storageConfig: StorageVersionConfig;
|
|
61
|
+
public readonly logger: framework.Logger;
|
|
58
62
|
|
|
59
63
|
private sharedIterator = new BroadcastIterable((signal) => this.watchActiveCheckpoint(signal));
|
|
60
64
|
|
|
@@ -77,6 +81,7 @@ export class PostgresSyncRulesStorage
|
|
|
77
81
|
this.factory = options.factory;
|
|
78
82
|
this.storageConfig = options.sync_rules.getStorageConfig();
|
|
79
83
|
this.currentDataStore = new PostgresCurrentDataStore(this.storageConfig);
|
|
84
|
+
this.logger = options.sync_rules.logger;
|
|
80
85
|
|
|
81
86
|
this.writeCheckpointAPI = new PostgresWriteCheckpointAPI({
|
|
82
87
|
db: this.db,
|
|
@@ -106,8 +111,8 @@ export class PostgresSyncRulesStorage
|
|
|
106
111
|
getParsedSyncRules(options: storage.ParseSyncRulesOptions): sync_rules.HydratedSyncRules {
|
|
107
112
|
const { parsed, options: cachedOptions } = this.parsedSyncRulesCache ?? {};
|
|
108
113
|
/**
|
|
109
|
-
* Check if the cached sync
|
|
110
|
-
* Parse sync
|
|
114
|
+
* Check if the cached sync config, if present, had the same options.
|
|
115
|
+
* Parse sync config if the options are different or if there is no cached value.
|
|
111
116
|
*/
|
|
112
117
|
if (!parsed || options.defaultSchema != cachedOptions?.defaultSchema) {
|
|
113
118
|
this.parsedSyncRulesCache = { parsed: this.sync_rules.parsed(options).hydratedSyncRules(), options };
|
|
@@ -137,11 +142,12 @@ export class PostgresSyncRulesStorage
|
|
|
137
142
|
|
|
138
143
|
return new PostgresCompactor(this.db, this.group_id, {
|
|
139
144
|
...options,
|
|
140
|
-
maxOpId
|
|
145
|
+
maxOpId,
|
|
146
|
+
logger: this.logger
|
|
141
147
|
}).compact();
|
|
142
148
|
}
|
|
143
149
|
|
|
144
|
-
async populatePersistentChecksumCache(
|
|
150
|
+
async populatePersistentChecksumCache(_options: PopulateChecksumCacheOptions): Promise<PopulateChecksumCacheResults> {
|
|
145
151
|
// no-op - checksum cache is not implemented for Postgres yet
|
|
146
152
|
return { buckets: 0 };
|
|
147
153
|
}
|
|
@@ -361,7 +367,7 @@ export class PostgresSyncRulesStorage
|
|
|
361
367
|
const checkpoint_lsn = syncRules?.last_checkpoint_lsn ?? null;
|
|
362
368
|
|
|
363
369
|
const writer = new PostgresBucketBatch({
|
|
364
|
-
logger: options.logger ??
|
|
370
|
+
logger: options.logger ?? this.logger,
|
|
365
371
|
db: this.db,
|
|
366
372
|
sync_rules: this.sync_rules.parsed(options).hydratedSyncRules(),
|
|
367
373
|
group_id: this.group_id,
|
|
@@ -394,42 +400,63 @@ export class PostgresSyncRulesStorage
|
|
|
394
400
|
|
|
395
401
|
async getParameterSets(
|
|
396
402
|
checkpoint: ReplicationCheckpoint,
|
|
397
|
-
lookups: sync_rules.ScopedParameterLookup[]
|
|
403
|
+
lookups: sync_rules.ScopedParameterLookup[],
|
|
404
|
+
limit: number
|
|
398
405
|
): Promise<sync_rules.SqliteJsonRow[]> {
|
|
399
406
|
const rows = await this.db.sql`
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
WHERE
|
|
409
|
-
group_id = ${{ type: 'int4', value: this.group_id }}
|
|
410
|
-
AND lookup = ANY (
|
|
411
|
-
SELECT
|
|
412
|
-
decode((FILTER ->> 0)::text, 'hex') -- Decode the hex string to bytea
|
|
407
|
+
WITH
|
|
408
|
+
rows AS (
|
|
409
|
+
SELECT DISTINCT
|
|
410
|
+
ON (lookup, source_table, source_key) lookup,
|
|
411
|
+
source_table,
|
|
412
|
+
source_key,
|
|
413
|
+
id,
|
|
414
|
+
bucket_parameters
|
|
413
415
|
FROM
|
|
414
|
-
|
|
416
|
+
bucket_parameters
|
|
417
|
+
WHERE
|
|
418
|
+
group_id = ${{ type: 'int4', value: this.group_id }}
|
|
419
|
+
AND lookup = ANY (
|
|
420
|
+
SELECT
|
|
421
|
+
decode((FILTER ->> 0)::text, 'hex') -- Decode the hex string to bytea
|
|
422
|
+
FROM
|
|
423
|
+
jsonb_array_elements(${{
|
|
415
424
|
type: 'jsonb',
|
|
416
425
|
value: lookups.map((l) => storage.serializeLookupBuffer(l).toString('hex'))
|
|
417
426
|
}}) AS FILTER
|
|
427
|
+
)
|
|
428
|
+
AND id <= ${{ type: 'int8', value: checkpoint.checkpoint }}
|
|
429
|
+
ORDER BY
|
|
430
|
+
lookup,
|
|
431
|
+
source_table,
|
|
432
|
+
source_key,
|
|
433
|
+
id DESC
|
|
418
434
|
)
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
435
|
+
SELECT
|
|
436
|
+
bucket_parameters
|
|
437
|
+
FROM
|
|
438
|
+
rows
|
|
439
|
+
WHERE
|
|
440
|
+
bucket_parameters != '[]'
|
|
441
|
+
LIMIT
|
|
442
|
+
${{ type: 'int4', value: limit + 1 }}
|
|
425
443
|
`
|
|
426
444
|
.decoded(pick(models.BucketParameters, ['bucket_parameters']))
|
|
427
445
|
.rows();
|
|
428
446
|
|
|
429
|
-
const
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
447
|
+
const parameters = rows
|
|
448
|
+
.map((row) => {
|
|
449
|
+
return JSONBig.parse(row.bucket_parameters) as sync_rules.SqliteJsonRow[];
|
|
450
|
+
})
|
|
451
|
+
.flat();
|
|
452
|
+
|
|
453
|
+
if (parameters.length > limit) {
|
|
454
|
+
// Note that the LIMIT in the query allows more rows than parameters (because each row stores an array of
|
|
455
|
+
// parameter results). That array is very small though, and it doesn't allow fewer rows (due to the != []), so
|
|
456
|
+
// the SQL limit is good enough.
|
|
457
|
+
throw new ParameterSetLimitExceededError(limit);
|
|
458
|
+
}
|
|
459
|
+
return parameters;
|
|
433
460
|
}
|
|
434
461
|
|
|
435
462
|
async *getBucketDataBatch(
|
|
@@ -646,7 +673,7 @@ export class PostgresSyncRulesStorage
|
|
|
646
673
|
.first();
|
|
647
674
|
|
|
648
675
|
if (syncRulesRow == null) {
|
|
649
|
-
throw new Error('Cannot find
|
|
676
|
+
throw new Error('Cannot find replication stream status');
|
|
650
677
|
}
|
|
651
678
|
|
|
652
679
|
return {
|
|
@@ -839,7 +866,7 @@ export class PostgresSyncRulesStorage
|
|
|
839
866
|
|
|
840
867
|
if (doc == null) {
|
|
841
868
|
// Abort the connections - clients will have to retry later.
|
|
842
|
-
throw new framework.ServiceError(framework.ErrorCode.PSYNC_S2302, 'No active
|
|
869
|
+
throw new framework.ServiceError(framework.ErrorCode.PSYNC_S2302, 'No active replication stream available');
|
|
843
870
|
}
|
|
844
871
|
|
|
845
872
|
const sink = new LastValueSink<string>(undefined);
|
|
@@ -866,7 +893,7 @@ export class PostgresSyncRulesStorage
|
|
|
866
893
|
continue;
|
|
867
894
|
}
|
|
868
895
|
if (Number(notification.active_checkpoint.id) != doc.id) {
|
|
869
|
-
// Active
|
|
896
|
+
// Active replication stream changed - abort and restart the stream
|
|
870
897
|
break;
|
|
871
898
|
}
|
|
872
899
|
|
|
@@ -896,7 +923,7 @@ class PostgresReplicationCheckpoint implements storage.ReplicationCheckpoint {
|
|
|
896
923
|
public readonly lsn: string | null
|
|
897
924
|
) {}
|
|
898
925
|
|
|
899
|
-
getParameterSets(lookups: sync_rules.ScopedParameterLookup[]): Promise<sync_rules.SqliteJsonRow[]> {
|
|
900
|
-
return this.storage.getParameterSets(this, lookups);
|
|
926
|
+
getParameterSets(lookups: sync_rules.ScopedParameterLookup[], limit: number): Promise<sync_rules.SqliteJsonRow[]> {
|
|
927
|
+
return this.storage.getParameterSets(this, lookups, limit);
|
|
901
928
|
}
|
|
902
929
|
}
|
|
@@ -20,16 +20,16 @@ import {
|
|
|
20
20
|
import * as sync_rules from '@powersync/service-sync-rules';
|
|
21
21
|
import * as timers from 'timers/promises';
|
|
22
22
|
import * as t from 'ts-codec';
|
|
23
|
+
import { bigint } from '../../types/codecs.js';
|
|
23
24
|
import { CurrentBucket, V3CurrentDataDecoded } from '../../types/models/CurrentData.js';
|
|
24
25
|
import { models, RequiredOperationBatchLimits } from '../../types/types.js';
|
|
25
26
|
import { NOTIFICATION_CHANNEL } from '../../utils/db.js';
|
|
26
27
|
import { pick } from '../../utils/ts-codec.js';
|
|
27
28
|
import { batchCreateCustomWriteCheckpoints } from '../checkpoints/PostgresWriteCheckpointAPI.js';
|
|
28
|
-
import { cacheKey, encodedCacheKey, OperationBatch, RecordOperation } from './OperationBatch.js';
|
|
29
|
-
import { PostgresPersistedBatch } from './PostgresPersistedBatch.js';
|
|
30
|
-
import { bigint } from '../../types/codecs.js';
|
|
31
29
|
import { PostgresCurrentDataStore } from '../current-data-store.js';
|
|
32
30
|
import { postgresTableId } from '../table-id.js';
|
|
31
|
+
import { cacheKey, encodedCacheKey, OperationBatch, RecordOperation } from './OperationBatch.js';
|
|
32
|
+
import { PostgresPersistedBatch } from './PostgresPersistedBatch.js';
|
|
33
33
|
|
|
34
34
|
export interface PostgresBucketBatchOptions {
|
|
35
35
|
logger: Logger;
|
|
@@ -52,7 +52,7 @@ export interface PostgresBucketBatchOptions {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
|
-
* Intermediate type which helps for only watching the active
|
|
55
|
+
* Intermediate type which helps for only watching the active replication stream
|
|
56
56
|
* via the Postgres NOTIFY protocol.
|
|
57
57
|
*/
|
|
58
58
|
const StatefulCheckpoint = models.ActiveCheckpoint.and(t.object({ state: t.Enum(storage.SyncRuleState) }));
|
|
@@ -1054,7 +1054,7 @@ export class PostgresBucketBatch
|
|
|
1054
1054
|
}
|
|
1055
1055
|
});
|
|
1056
1056
|
if (didActivate) {
|
|
1057
|
-
this.logger.info(`Activated new
|
|
1057
|
+
this.logger.info(`Activated new replication stream at ${lsn}`);
|
|
1058
1058
|
}
|
|
1059
1059
|
}
|
|
1060
1060
|
|