@powersync/service-module-postgres-storage 0.16.3 → 0.18.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/dist/migrations/scripts/1782950400000-checkpoint-requested-at.d.ts +3 -0
  3. package/dist/migrations/scripts/1782950400000-checkpoint-requested-at.js +42 -0
  4. package/dist/migrations/scripts/1782950400000-checkpoint-requested-at.js.map +1 -0
  5. package/dist/migrations/scripts/1784900000000-source-metadata.d.ts +3 -0
  6. package/dist/migrations/scripts/1784900000000-source-metadata.js +22 -0
  7. package/dist/migrations/scripts/1784900000000-source-metadata.js.map +1 -0
  8. package/dist/storage/PostgresBucketStorageFactory.js +0 -2
  9. package/dist/storage/PostgresBucketStorageFactory.js.map +1 -1
  10. package/dist/storage/PostgresCompactor.d.ts +2 -0
  11. package/dist/storage/PostgresCompactor.js +20 -0
  12. package/dist/storage/PostgresCompactor.js.map +1 -1
  13. package/dist/storage/PostgresSyncRulesStorage.d.ts +16 -1
  14. package/dist/storage/PostgresSyncRulesStorage.js +200 -131
  15. package/dist/storage/PostgresSyncRulesStorage.js.map +1 -1
  16. package/dist/storage/batch/PostgresBucketBatch.d.ts +2 -20
  17. package/dist/storage/batch/PostgresBucketBatch.js +217 -240
  18. package/dist/storage/batch/PostgresBucketBatch.js.map +1 -1
  19. package/dist/storage/checkpoints/PostgresWriteCheckpointAPI.d.ts +1 -1
  20. package/dist/storage/checkpoints/PostgresWriteCheckpointAPI.js +156 -36
  21. package/dist/storage/checkpoints/PostgresWriteCheckpointAPI.js.map +1 -1
  22. package/dist/storage/current-data-store.d.ts +8 -2
  23. package/dist/storage/current-data-store.js +66 -11
  24. package/dist/storage/current-data-store.js.map +1 -1
  25. package/dist/types/models/SourceTable.d.ts +7 -2
  26. package/dist/types/models/SourceTable.js +6 -2
  27. package/dist/types/models/SourceTable.js.map +1 -1
  28. package/dist/types/models/WriteCheckpoint.d.ts +2 -0
  29. package/dist/types/models/WriteCheckpoint.js +5 -2
  30. package/dist/types/models/WriteCheckpoint.js.map +1 -1
  31. package/dist/utils/checkpoints.d.ts +9 -0
  32. package/dist/utils/checkpoints.js +26 -0
  33. package/dist/utils/checkpoints.js.map +1 -0
  34. package/package.json +8 -8
  35. package/src/migrations/scripts/1782950400000-checkpoint-requested-at.ts +51 -0
  36. package/src/migrations/scripts/1784900000000-source-metadata.ts +31 -0
  37. package/src/storage/PostgresBucketStorageFactory.ts +0 -3
  38. package/src/storage/PostgresCompactor.ts +24 -0
  39. package/src/storage/PostgresSyncRulesStorage.ts +219 -137
  40. package/src/storage/batch/PostgresBucketBatch.ts +227 -246
  41. package/src/storage/checkpoints/PostgresWriteCheckpointAPI.ts +165 -37
  42. package/src/storage/current-data-store.ts +66 -11
  43. package/src/types/models/SourceTable.ts +7 -2
  44. package/src/types/models/WriteCheckpoint.ts +5 -2
  45. package/src/utils/checkpoints.ts +31 -0
  46. package/test/src/__snapshots__/storage_sync.test.ts.snap +0 -582
  47. package/test/src/checkpoint_notifications.test.ts +522 -0
  48. package/test/src/storage.test.ts +214 -5
  49. package/test/src/storage_compacting.test.ts +3 -3
  50. package/test/src/storage_sync.test.ts +48 -4
  51. package/test/tsconfig.json +1 -1
  52. package/tsconfig.tsbuildinfo +1 -1
@@ -1,13 +1,16 @@
1
+ import { framework } from '@powersync/service-core';
1
2
  import * as t from 'ts-codec';
2
3
  import { bigint, jsonb } from '../codecs.js';
3
4
  export const WriteCheckpoint = t.object({
4
5
  user_id: t.string,
5
6
  lsns: jsonb(t.record(t.string)),
6
- write_checkpoint: bigint
7
+ write_checkpoint: bigint,
8
+ checkpoint_requested_at: t.Null.or(framework.codecs.date)
7
9
  });
8
10
  export const CustomWriteCheckpoint = t.object({
9
11
  user_id: t.string,
10
12
  write_checkpoint: bigint,
11
- sync_rules_id: bigint
13
+ sync_rules_id: bigint,
14
+ checkpoint_requested_at: t.Null.or(framework.codecs.date)
12
15
  });
13
16
  //# sourceMappingURL=WriteCheckpoint.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"WriteCheckpoint.js","sourceRoot":"","sources":["../../../src/types/models/WriteCheckpoint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,OAAO,EAAE,CAAC,CAAC,MAAM;IACjB,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC/B,gBAAgB,EAAE,MAAM;CACzB,CAAC,CAAC;AAKH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,OAAO,EAAE,CAAC,CAAC,MAAM;IACjB,gBAAgB,EAAE,MAAM;IACxB,aAAa,EAAE,MAAM;CACtB,CAAC,CAAC"}
1
+ {"version":3,"file":"WriteCheckpoint.js","sourceRoot":"","sources":["../../../src/types/models/WriteCheckpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,OAAO,EAAE,CAAC,CAAC,MAAM;IACjB,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC/B,gBAAgB,EAAE,MAAM;IACxB,uBAAuB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;CAC1D,CAAC,CAAC;AAKH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,OAAO,EAAE,CAAC,CAAC,MAAM;IACjB,gBAAgB,EAAE,MAAM;IACxB,aAAa,EAAE,MAAM;IACrB,uBAAuB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;CAC1D,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ import * as lib_postgres from '@powersync/lib-service-postgres';
2
+ import { models } from '../types/types.js';
3
+ /**
4
+ * Gets the latest active checkpoint document.
5
+ * This is mainly exported for mocking in tests.
6
+ */
7
+ export declare function getActiveCheckpointDocument({ db }: {
8
+ db: lib_postgres.DatabaseClient;
9
+ }): Promise<models.ActiveCheckpointDecoded | null>;
@@ -0,0 +1,26 @@
1
+ import { storage } from '@powersync/service-core';
2
+ import { models } from '../types/types.js';
3
+ /**
4
+ * Gets the latest active checkpoint document.
5
+ * This is mainly exported for mocking in tests.
6
+ */
7
+ export async function getActiveCheckpointDocument({ db }) {
8
+ return db.sql `
9
+ SELECT
10
+ id,
11
+ last_checkpoint,
12
+ last_checkpoint_lsn
13
+ FROM
14
+ sync_rules
15
+ WHERE
16
+ state = ${{ value: storage.SyncRuleState.ACTIVE, type: 'varchar' }}
17
+ OR state = ${{ value: storage.SyncRuleState.ERRORED, type: 'varchar' }}
18
+ ORDER BY
19
+ id DESC
20
+ LIMIT
21
+ 1
22
+ `
23
+ .decoded(models.ActiveCheckpoint)
24
+ .first();
25
+ }
26
+ //# sourceMappingURL=checkpoints.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkpoints.js","sourceRoot":"","sources":["../../src/utils/checkpoints.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,EAChD,EAAE,EAGH;IACC,OAAO,EAAE,CAAC,GAAG,CAAA;;;;;;;;gBAQC,EAAE,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE;mBACrD,EAAE,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE;;;;;GAKzE;SACE,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC;SAChC,KAAK,EAAE,CAAC;AACb,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@powersync/service-module-postgres-storage",
3
3
  "repository": "https://github.com/powersync-ja/powersync-service",
4
- "version": "0.16.3",
4
+ "version": "0.18.0",
5
5
  "license": "FSL-1.1-ALv2",
6
6
  "type": "module",
7
7
  "publishConfig": {
@@ -16,17 +16,17 @@
16
16
  "lru-cache": "^10.2.2",
17
17
  "ts-codec": "^1.3.0",
18
18
  "uuid": "^14.0.0",
19
- "@powersync/lib-service-postgres": "0.5.2",
20
- "@powersync/lib-services-framework": "0.9.8",
21
- "@powersync/service-core": "1.23.3",
22
- "@powersync/service-types": "0.16.1",
23
- "@powersync/service-jpgwire": "0.21.21",
19
+ "@powersync/lib-service-postgres": "0.5.3",
20
+ "@powersync/lib-services-framework": "0.10.0",
21
+ "@powersync/service-core": "1.25.0",
22
+ "@powersync/service-types": "0.17.0",
23
+ "@powersync/service-jpgwire": "0.21.22",
24
24
  "@powersync/service-jsonbig": "0.17.13",
25
- "@powersync/service-sync-rules": "0.39.0"
25
+ "@powersync/service-sync-rules": "0.40.0"
26
26
  },
27
27
  "devDependencies": {
28
28
  "typescript": "~6.0.3",
29
- "@powersync/service-core-tests": "0.17.2"
29
+ "@powersync/service-core-tests": "0.18.0"
30
30
  },
31
31
  "scripts": {
32
32
  "build": "tsc -b",
@@ -0,0 +1,51 @@
1
+ import { migrations } from '@powersync/service-core';
2
+
3
+ import { openMigrationDB } from '../migration-utils.js';
4
+
5
+ export const up: migrations.PowerSyncMigrationFunction = async (context) => {
6
+ const {
7
+ service_context: { configuration }
8
+ } = context;
9
+ await using client = openMigrationDB(configuration.storage);
10
+
11
+ await client.transaction(async (db) => {
12
+ await db.sql`
13
+ ALTER TABLE write_checkpoints
14
+ ADD COLUMN checkpoint_requested_at TIMESTAMP WITH TIME ZONE
15
+ `.execute();
16
+ await db.sql`
17
+ ALTER TABLE custom_write_checkpoints
18
+ ADD COLUMN checkpoint_requested_at TIMESTAMP WITH TIME ZONE
19
+ `.execute();
20
+ await db.sql`
21
+ CREATE INDEX write_checkpoints_checkpoint_requested_at ON write_checkpoints (checkpoint_requested_at)
22
+ WHERE
23
+ checkpoint_requested_at IS NOT NULL
24
+ `.execute();
25
+ await db.sql`
26
+ CREATE INDEX custom_write_checkpoints_checkpoint_requested_at ON custom_write_checkpoints (checkpoint_requested_at)
27
+ WHERE
28
+ checkpoint_requested_at IS NOT NULL
29
+ `.execute();
30
+ });
31
+ };
32
+
33
+ export const down: migrations.PowerSyncMigrationFunction = async (context) => {
34
+ const {
35
+ service_context: { configuration }
36
+ } = context;
37
+ await using client = openMigrationDB(configuration.storage);
38
+
39
+ await client.transaction(async (db) => {
40
+ // Also drops the write_checkpoints_checkpoint_requested_at index.
41
+ await db.sql`
42
+ ALTER TABLE write_checkpoints
43
+ DROP COLUMN checkpoint_requested_at
44
+ `.execute();
45
+ // Also drops the custom_write_checkpoints_checkpoint_requested_at index.
46
+ await db.sql`
47
+ ALTER TABLE custom_write_checkpoints
48
+ DROP COLUMN checkpoint_requested_at
49
+ `.execute();
50
+ });
51
+ };
@@ -0,0 +1,31 @@
1
+ import { migrations } from '@powersync/service-core';
2
+
3
+ import { openMigrationDB } from '../migration-utils.js';
4
+
5
+ export const up: migrations.PowerSyncMigrationFunction = async (context) => {
6
+ const {
7
+ service_context: { configuration }
8
+ } = context;
9
+ await using client = openMigrationDB(configuration.storage);
10
+
11
+ await client.transaction(async (db) => {
12
+ await db.sql`
13
+ ALTER TABLE source_tables
14
+ ADD COLUMN source_metadata JSONB
15
+ `.execute();
16
+ });
17
+ };
18
+
19
+ export const down: migrations.PowerSyncMigrationFunction = async (context) => {
20
+ const {
21
+ service_context: { configuration }
22
+ } = context;
23
+ await using client = openMigrationDB(configuration.storage);
24
+
25
+ await client.transaction(async (db) => {
26
+ await db.sql`
27
+ ALTER TABLE source_tables
28
+ DROP COLUMN source_metadata
29
+ `.execute();
30
+ });
31
+ };
@@ -8,7 +8,6 @@ import { models, NormalizedPostgresStorageConfig } from '../types/types.js';
8
8
 
9
9
  import { getStorageApplicationName } from '../utils/application-name.js';
10
10
  import { NOTIFICATION_CHANNEL, STORAGE_SCHEMA_NAME } from '../utils/db.js';
11
- import { notifySyncRulesUpdate } from './batch/PostgresBucketBatch.js';
12
11
  import { PostgresSyncRulesStorage } from './PostgresSyncRulesStorage.js';
13
12
  import { PostgresPersistedReplicationStream } from './sync-rules/PostgresPersistedSyncConfigContent.js';
14
13
 
@@ -220,8 +219,6 @@ export class PostgresBucketStorageFactory extends storage.BucketStorageFactory {
220
219
  .decoded(models.SyncRules)
221
220
  .first();
222
221
 
223
- await notifySyncRulesUpdate(this.db, newSyncRulesRow!);
224
-
225
222
  return new PostgresPersistedReplicationStream(this.db, newSyncRulesRow!);
226
223
  });
227
224
  }
@@ -53,6 +53,7 @@ export class PostgresCompactor {
53
53
  private clearBatchLimit: number;
54
54
  private maxOpId: InternalOpId;
55
55
  private buckets: string[] | undefined;
56
+ private deleteCheckpointRequestsBefore: Date | undefined;
56
57
 
57
58
  constructor(
58
59
  private db: lib_postgres.DatabaseClient,
@@ -65,6 +66,7 @@ export class PostgresCompactor {
65
66
  this.clearBatchLimit = options.clearBatchLimit ?? DEFAULT_CLEAR_BATCH_LIMIT;
66
67
  this.maxOpId = options.maxOpId ?? 0n;
67
68
  this.buckets = options.compactBuckets;
69
+ this.deleteCheckpointRequestsBefore = options.deleteCheckpointRequestsBefore;
68
70
  }
69
71
 
70
72
  /**
@@ -73,6 +75,8 @@ export class PostgresCompactor {
73
75
  * See /docs/storage/compacting-operations.md for details.
74
76
  */
75
77
  async compact() {
78
+ await this.deleteOldCheckpointRequests();
79
+
76
80
  if (this.buckets) {
77
81
  for (let bucket of this.buckets) {
78
82
  await this.compactSingleBucket(bucket);
@@ -82,6 +86,26 @@ export class PostgresCompactor {
82
86
  }
83
87
  }
84
88
 
89
+ private async deleteOldCheckpointRequests() {
90
+ if (this.deleteCheckpointRequestsBefore == null) {
91
+ return;
92
+ }
93
+
94
+ await this.db.sql`
95
+ DELETE FROM write_checkpoints
96
+ WHERE
97
+ checkpoint_requested_at IS NOT NULL
98
+ AND checkpoint_requested_at < ${{ type: 1184, value: this.deleteCheckpointRequestsBefore.toISOString() }}
99
+ `.execute();
100
+
101
+ await this.db.sql`
102
+ DELETE FROM custom_write_checkpoints
103
+ WHERE
104
+ checkpoint_requested_at IS NOT NULL
105
+ AND checkpoint_requested_at < ${{ type: 1184, value: this.deleteCheckpointRequestsBefore.toISOString() }}
106
+ `.execute();
107
+ }
108
+
85
109
  private async compactAllBuckets() {
86
110
  const DISCOVERY_BATCH_SIZE = 200;
87
111
  let lastBucket = '';