@powersync/service-core-tests 0.13.2 → 0.15.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 (35) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/dist/test-utils/general-utils.d.ts +9 -3
  3. package/dist/test-utils/general-utils.js +26 -26
  4. package/dist/test-utils/general-utils.js.map +1 -1
  5. package/dist/tests/register-compacting-tests.d.ts +1 -1
  6. package/dist/tests/register-compacting-tests.js +136 -93
  7. package/dist/tests/register-compacting-tests.js.map +1 -1
  8. package/dist/tests/register-data-storage-checkpoint-tests.d.ts +1 -1
  9. package/dist/tests/register-data-storage-checkpoint-tests.js +44 -27
  10. package/dist/tests/register-data-storage-checkpoint-tests.js.map +1 -1
  11. package/dist/tests/register-data-storage-data-tests.d.ts +2 -2
  12. package/dist/tests/register-data-storage-data-tests.js +715 -207
  13. package/dist/tests/register-data-storage-data-tests.js.map +1 -1
  14. package/dist/tests/register-data-storage-parameter-tests.d.ts +1 -1
  15. package/dist/tests/register-data-storage-parameter-tests.js +123 -58
  16. package/dist/tests/register-data-storage-parameter-tests.js.map +1 -1
  17. package/dist/tests/register-parameter-compacting-tests.d.ts +1 -1
  18. package/dist/tests/register-parameter-compacting-tests.js +13 -13
  19. package/dist/tests/register-parameter-compacting-tests.js.map +1 -1
  20. package/dist/tests/register-sync-tests.d.ts +4 -1
  21. package/dist/tests/register-sync-tests.js +63 -34
  22. package/dist/tests/register-sync-tests.js.map +1 -1
  23. package/dist/tests/util.d.ts +6 -1
  24. package/dist/tests/util.js +31 -2
  25. package/dist/tests/util.js.map +1 -1
  26. package/package.json +3 -3
  27. package/src/test-utils/general-utils.ts +42 -28
  28. package/src/tests/register-compacting-tests.ts +153 -103
  29. package/src/tests/register-data-storage-checkpoint-tests.ts +70 -22
  30. package/src/tests/register-data-storage-data-tests.ts +732 -110
  31. package/src/tests/register-data-storage-parameter-tests.ts +168 -59
  32. package/src/tests/register-parameter-compacting-tests.ts +18 -13
  33. package/src/tests/register-sync-tests.ts +71 -35
  34. package/src/tests/util.ts +52 -2
  35. package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,48 @@
1
1
  # @powersync/service-core-tests
2
2
 
3
+ ## 0.15.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 8c5bb3b: [Internal] Allow using multiple BucketStorageBatch instances concurrently.
8
+ - c15efc7: [Internal] Track and propagate source on buckets and parameter indexes to storage APIs.
9
+
10
+ ### Patch Changes
11
+
12
+ - 642cb11: [Postgres Storage] Fix concurrency issue in compacting, leading to "[PSYNC_S1101] Unexpected PUT operation".
13
+ - Updated dependencies [8c5bb3b]
14
+ - Updated dependencies [dcddcf1]
15
+ - Updated dependencies [c15efc7]
16
+ - Updated dependencies [e7152ce]
17
+ - Updated dependencies [e150c5c]
18
+ - Updated dependencies [b410924]
19
+ - @powersync/service-core@1.20.1
20
+ - @powersync/service-sync-rules@0.33.0
21
+
22
+ ## 0.14.0
23
+
24
+ ### Minor Changes
25
+
26
+ - 8a4c34e: Refactor `BucketStorageFactory` and `PersistedSyncRulesContent` to be abstract classes instead of interfaces.
27
+ - 8bd83e8: Introduce storage versions.
28
+
29
+ ### Patch Changes
30
+
31
+ - Updated dependencies [0998251]
32
+ - Updated dependencies [65f3c89]
33
+ - Updated dependencies [1c45667]
34
+ - Updated dependencies [8785a3f]
35
+ - Updated dependencies [8a4c34e]
36
+ - Updated dependencies [b440093]
37
+ - Updated dependencies [d7ff4ad]
38
+ - Updated dependencies [c683322]
39
+ - Updated dependencies [8bd83e8]
40
+ - Updated dependencies [83989b2]
41
+ - Updated dependencies [79a9729]
42
+ - Updated dependencies [5edd95f]
43
+ - @powersync/service-core@1.20.0
44
+ - @powersync/service-sync-rules@0.32.0
45
+
3
46
  ## 0.13.2
4
47
 
5
48
  ### Patch Changes
@@ -1,17 +1,23 @@
1
- import { storage, utils } from '@powersync/service-core';
1
+ import { BucketDataRequest, InternalOpId, storage, utils } from '@powersync/service-core';
2
2
  import { GetQuerierOptions, RequestParameters } from '@powersync/service-sync-rules';
3
3
  import * as bson from 'bson';
4
4
  export declare const ZERO_LSN = "0/0";
5
5
  export declare const PARSE_OPTIONS: storage.ParseSyncRulesOptions;
6
6
  export declare const BATCH_OPTIONS: storage.StartBatchOptions;
7
- export declare function testRules(content: string): storage.PersistedSyncRulesContent;
8
- export declare function makeTestTable(name: string, replicaIdColumns?: string[] | undefined): storage.SourceTable;
7
+ export declare function makeTestTable(name: string, replicaIdColumns?: string[] | undefined, options?: {
8
+ tableIdStrings: boolean;
9
+ }): storage.SourceTable;
9
10
  export declare function getBatchData(batch: utils.SyncBucketData[] | storage.SyncBucketDataChunk[] | storage.SyncBucketDataChunk): {
10
11
  op_id: string;
11
12
  op: "PUT" | "REMOVE" | "MOVE" | "CLEAR";
12
13
  object_id: string | undefined;
13
14
  checksum: number | bigint;
14
15
  }[];
16
+ /**
17
+ * Bucket names no longer purely depend on the sync rules.
18
+ * This converts a bucket name like "global[]" into the actual bucket name, for use in tests.
19
+ */
20
+ export declare function bucketRequest(syncRules: storage.PersistedSyncRulesContent | storage.PersistedSyncRules, bucket: string, start?: InternalOpId | string | number): BucketDataRequest;
15
21
  export declare function getBatchMeta(batch: utils.SyncBucketData[] | storage.SyncBucketDataChunk[] | storage.SyncBucketDataChunk): {
16
22
  has_more: boolean;
17
23
  after: string;
@@ -1,6 +1,4 @@
1
1
  import { storage, utils } from '@powersync/service-core';
2
- import { SqlSyncRules } from '@powersync/service-sync-rules';
3
- import { versionedHydrationState } from '@powersync/service-sync-rules/src/HydrationState.js';
4
2
  import * as bson from 'bson';
5
3
  export const ZERO_LSN = '0/0';
6
4
  export const PARSE_OPTIONS = {
@@ -11,31 +9,9 @@ export const BATCH_OPTIONS = {
11
9
  zeroLSN: ZERO_LSN,
12
10
  storeCurrentData: true
13
11
  };
14
- export function testRules(content) {
15
- return {
16
- id: 1,
17
- sync_rules_content: content,
18
- slot_name: 'test',
19
- active: true,
20
- last_checkpoint_lsn: '',
21
- parsed(options) {
22
- return {
23
- id: 1,
24
- sync_rules: SqlSyncRules.fromYaml(content, options),
25
- slot_name: 'test',
26
- hydratedSyncRules() {
27
- return this.sync_rules.config.hydrate({ hydrationState: versionedHydrationState(1) });
28
- }
29
- };
30
- },
31
- lock() {
32
- throw new Error('Not implemented');
33
- }
34
- };
35
- }
36
- export function makeTestTable(name, replicaIdColumns) {
12
+ export function makeTestTable(name, replicaIdColumns, options) {
37
13
  const relId = utils.hashData('table', name, (replicaIdColumns ?? ['id']).join(','));
38
- const id = new bson.ObjectId('6544e3899293153fa7b38331');
14
+ const id = options?.tableIdStrings == false ? new bson.ObjectId('6544e3899293153fa7b38331') : '6544e3899293153fa7b38331';
39
15
  return new storage.SourceTable({
40
16
  id: id,
41
17
  connectionTag: storage.SourceTable.DEFAULT_TAG,
@@ -60,6 +36,30 @@ export function getBatchData(batch) {
60
36
  };
61
37
  });
62
38
  }
39
+ function isParsedSyncRules(syncRules) {
40
+ return syncRules.sync_rules !== undefined;
41
+ }
42
+ /**
43
+ * Bucket names no longer purely depend on the sync rules.
44
+ * This converts a bucket name like "global[]" into the actual bucket name, for use in tests.
45
+ */
46
+ export function bucketRequest(syncRules, bucket, start) {
47
+ const parsed = isParsedSyncRules(syncRules) ? syncRules : syncRules.parsed(PARSE_OPTIONS);
48
+ const hydrationState = parsed.hydrationState;
49
+ const parameterStart = bucket.indexOf('[');
50
+ const definitionName = bucket.substring(0, parameterStart);
51
+ const parameters = bucket.substring(parameterStart);
52
+ const source = parsed.sync_rules.config.bucketDataSources.find((b) => b.uniqueName === definitionName);
53
+ if (source == null) {
54
+ throw new Error(`Failed to find global bucket ${bucket}`);
55
+ }
56
+ const bucketName = hydrationState.getBucketSourceScope(source).bucketPrefix + parameters;
57
+ return {
58
+ bucket: bucketName,
59
+ start: BigInt(start ?? 0n),
60
+ source: source
61
+ };
62
+ }
63
63
  export function getBatchMeta(batch) {
64
64
  const first = getFirst(batch);
65
65
  if (first == null) {
@@ -1 +1 @@
1
- {"version":3,"file":"general-utils.js","sourceRoot":"","sources":["../../src/test-utils/general-utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"general-utils.js","sourceRoot":"","sources":["../../src/test-utils/general-utils.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
1
  import { storage } from '@powersync/service-core';
2
- export declare function registerCompactTests(generateStorageFactory: storage.TestStorageFactory): void;
2
+ export declare function registerCompactTests(config: storage.TestStorageConfig): void;
@@ -50,24 +50,26 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
50
50
  var e = new Error(message);
51
51
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
52
  });
53
- import { storage } from '@powersync/service-core';
53
+ import { addChecksums, storage, updateSyncRulesFromYaml } from '@powersync/service-core';
54
54
  import { expect, test } from 'vitest';
55
55
  import * as test_utils from '../test-utils/test-utils-index.js';
56
- const TEST_TABLE = test_utils.makeTestTable('test', ['id']);
57
- export function registerCompactTests(generateStorageFactory) {
56
+ import { bucketRequest } from '../test-utils/test-utils-index.js';
57
+ import { bucketRequestMap, bucketRequests } from './util.js';
58
+ export function registerCompactTests(config) {
59
+ const generateStorageFactory = config.factory;
60
+ const TEST_TABLE = test_utils.makeTestTable('test', ['id'], config);
58
61
  test('compacting (1)', async () => {
59
62
  const env_1 = { stack: [], error: void 0, hasError: false };
60
63
  try {
61
64
  const factory = __addDisposableResource(env_1, await generateStorageFactory(), true);
62
- const syncRules = await factory.updateSyncRules({
63
- content: `
65
+ const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
64
66
  bucket_definitions:
65
67
  global:
66
68
  data: [select * from test]
67
- `
68
- });
69
+ `));
69
70
  const bucketStorage = factory.getInstance(syncRules);
70
71
  const result = await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
72
+ await batch.markAllSnapshotDone('1/1');
71
73
  await batch.save({
72
74
  sourceTable: TEST_TABLE,
73
75
  tag: storage.SaveOperationTag.INSERT,
@@ -95,24 +97,22 @@ bucket_definitions:
95
97
  await batch.commit('1/1');
96
98
  });
97
99
  const checkpoint = result.flushed_op;
98
- const batchBefore = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint, new Map([['global[]', 0n]])));
100
+ const request = bucketRequest(syncRules, 'global[]');
101
+ const batchBefore = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
99
102
  const dataBefore = batchBefore.chunkData.data;
100
- const checksumBefore = await bucketStorage.getChecksums(checkpoint, ['global[]']);
103
+ const checksumBefore = await bucketStorage.getChecksums(checkpoint, [request]);
101
104
  expect(dataBefore).toMatchObject([
102
105
  {
103
- checksum: 2634521662,
104
106
  object_id: 't1',
105
107
  op: 'PUT',
106
108
  op_id: '1'
107
109
  },
108
110
  {
109
- checksum: 4243212114,
110
111
  object_id: 't2',
111
112
  op: 'PUT',
112
113
  op_id: '2'
113
114
  },
114
115
  {
115
- checksum: 4243212114,
116
116
  object_id: 't2',
117
117
  op: 'PUT',
118
118
  op_id: '3'
@@ -126,33 +126,28 @@ bucket_definitions:
126
126
  minBucketChanges: 1,
127
127
  minChangeRatio: 0
128
128
  });
129
- const batchAfter = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint, new Map([['global[]', 0n]])));
129
+ const batchAfter = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
130
130
  const dataAfter = batchAfter.chunkData.data;
131
- const checksumAfter = await bucketStorage.getChecksums(checkpoint, ['global[]']);
131
+ const checksumAfter = await bucketStorage.getChecksums(checkpoint, [request]);
132
132
  bucketStorage.clearChecksumCache();
133
- const checksumAfter2 = await bucketStorage.getChecksums(checkpoint, ['global[]']);
133
+ const checksumAfter2 = await bucketStorage.getChecksums(checkpoint, [request]);
134
134
  expect(batchAfter.targetOp).toEqual(3n);
135
135
  expect(dataAfter).toMatchObject([
136
+ dataBefore[0],
136
137
  {
137
- checksum: 2634521662,
138
- object_id: 't1',
139
- op: 'PUT',
140
- op_id: '1'
141
- },
142
- {
143
- checksum: 4243212114,
138
+ checksum: dataBefore[1].checksum,
144
139
  op: 'MOVE',
145
140
  op_id: '2'
146
141
  },
147
142
  {
148
- checksum: 4243212114,
143
+ checksum: dataBefore[2].checksum,
149
144
  object_id: 't2',
150
145
  op: 'PUT',
151
146
  op_id: '3'
152
147
  }
153
148
  ]);
154
- expect(checksumAfter.get('global[]')).toEqual(checksumBefore.get('global[]'));
155
- expect(checksumAfter2.get('global[]')).toEqual(checksumBefore.get('global[]'));
149
+ expect(checksumAfter.get(request.bucket)).toEqual(checksumBefore.get(request.bucket));
150
+ expect(checksumAfter2.get(request.bucket)).toEqual(checksumBefore.get(request.bucket));
156
151
  test_utils.validateCompactedBucket(dataBefore, dataAfter);
157
152
  }
158
153
  catch (e_1) {
@@ -169,15 +164,14 @@ bucket_definitions:
169
164
  const env_2 = { stack: [], error: void 0, hasError: false };
170
165
  try {
171
166
  const factory = __addDisposableResource(env_2, await generateStorageFactory(), true);
172
- const syncRules = await factory.updateSyncRules({
173
- content: `
167
+ const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
174
168
  bucket_definitions:
175
169
  global:
176
170
  data: [select * from test]
177
- `
178
- });
171
+ `));
179
172
  const bucketStorage = factory.getInstance(syncRules);
180
173
  const result = await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
174
+ await batch.markAllSnapshotDone('1/1');
181
175
  await batch.save({
182
176
  sourceTable: TEST_TABLE,
183
177
  tag: storage.SaveOperationTag.INSERT,
@@ -213,33 +207,27 @@ bucket_definitions:
213
207
  await batch.commit('1/1');
214
208
  });
215
209
  const checkpoint = result.flushed_op;
216
- const batchBefore = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint, new Map([['global[]', 0n]])));
210
+ const request = bucketRequest(syncRules, 'global[]');
211
+ const batchBefore = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
217
212
  const dataBefore = batchBefore.chunkData.data;
218
- const checksumBefore = await bucketStorage.getChecksums(checkpoint, ['global[]']);
213
+ const checksumBefore = await bucketStorage.getChecksums(checkpoint, [request]);
214
+ // op_id sequence depends on the storage implementation
219
215
  expect(dataBefore).toMatchObject([
220
216
  {
221
- checksum: 2634521662,
222
217
  object_id: 't1',
223
- op: 'PUT',
224
- op_id: '1'
218
+ op: 'PUT'
225
219
  },
226
220
  {
227
- checksum: 4243212114,
228
221
  object_id: 't2',
229
- op: 'PUT',
230
- op_id: '2'
222
+ op: 'PUT'
231
223
  },
232
224
  {
233
- checksum: 4228978084,
234
225
  object_id: 't1',
235
- op: 'REMOVE',
236
- op_id: '3'
226
+ op: 'REMOVE'
237
227
  },
238
228
  {
239
- checksum: 4243212114,
240
229
  object_id: 't2',
241
- op: 'PUT',
242
- op_id: '4'
230
+ op: 'PUT'
243
231
  }
244
232
  ]);
245
233
  await bucketStorage.compact({
@@ -249,26 +237,24 @@ bucket_definitions:
249
237
  minBucketChanges: 1,
250
238
  minChangeRatio: 0
251
239
  });
252
- const batchAfter = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint, new Map([['global[]', 0n]])));
240
+ const batchAfter = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
253
241
  const dataAfter = batchAfter.chunkData.data;
254
242
  bucketStorage.clearChecksumCache();
255
- const checksumAfter = await bucketStorage.getChecksums(checkpoint, ['global[]']);
256
- expect(batchAfter.targetOp).toEqual(4n);
243
+ const checksumAfter = await bucketStorage.getChecksums(checkpoint, [request]);
244
+ expect(batchAfter.targetOp).toBeLessThanOrEqual(checkpoint);
257
245
  expect(dataAfter).toMatchObject([
258
246
  {
259
- checksum: -1778190028,
260
- op: 'CLEAR',
261
- op_id: '3'
247
+ checksum: addChecksums(addChecksums(dataBefore[0].checksum, dataBefore[1].checksum), dataBefore[2].checksum),
248
+ op: 'CLEAR'
262
249
  },
263
250
  {
264
- checksum: 4243212114,
251
+ checksum: dataBefore[3].checksum,
265
252
  object_id: 't2',
266
- op: 'PUT',
267
- op_id: '4'
253
+ op: 'PUT'
268
254
  }
269
255
  ]);
270
- expect(checksumAfter.get('global[]')).toEqual({
271
- ...checksumBefore.get('global[]'),
256
+ expect(checksumAfter.get(request.bucket)).toEqual({
257
+ ...checksumBefore.get(request.bucket),
272
258
  count: 2
273
259
  });
274
260
  test_utils.validateCompactedBucket(dataBefore, dataAfter);
@@ -287,15 +273,14 @@ bucket_definitions:
287
273
  const env_3 = { stack: [], error: void 0, hasError: false };
288
274
  try {
289
275
  const factory = __addDisposableResource(env_3, await generateStorageFactory(), true);
290
- const syncRules = await factory.updateSyncRules({
291
- content: `
276
+ const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
292
277
  bucket_definitions:
293
278
  global:
294
279
  data: [select * from test]
295
- `
296
- });
280
+ `));
297
281
  const bucketStorage = factory.getInstance(syncRules);
298
282
  const result = await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
283
+ await batch.markAllSnapshotDone('1/1');
299
284
  await batch.save({
300
285
  sourceTable: TEST_TABLE,
301
286
  tag: storage.SaveOperationTag.INSERT,
@@ -323,7 +308,8 @@ bucket_definitions:
323
308
  await batch.commit('1/1');
324
309
  });
325
310
  const checkpoint1 = result.flushed_op;
326
- const checksumBefore = await bucketStorage.getChecksums(checkpoint1, ['global[]']);
311
+ const request = bucketRequest(syncRules, 'global[]');
312
+ const checksumBefore = await bucketStorage.getChecksums(checkpoint1, [request]);
327
313
  const result2 = await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
328
314
  await batch.save({
329
315
  sourceTable: TEST_TABLE,
@@ -343,22 +329,19 @@ bucket_definitions:
343
329
  minBucketChanges: 1,
344
330
  minChangeRatio: 0
345
331
  });
346
- const batchAfter = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint2, new Map([['global[]', 0n]])));
332
+ const batchAfter = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint2, [request]));
347
333
  const dataAfter = batchAfter.chunkData.data;
348
334
  await bucketStorage.clearChecksumCache();
349
- const checksumAfter = await bucketStorage.getChecksums(checkpoint2, ['global[]']);
350
- expect(batchAfter.targetOp).toEqual(4n);
335
+ const checksumAfter = await bucketStorage.getChecksums(checkpoint2, [request]);
351
336
  expect(dataAfter).toMatchObject([
352
337
  {
353
- checksum: 1874612650,
354
- op: 'CLEAR',
355
- op_id: '4'
338
+ op: 'CLEAR'
356
339
  }
357
340
  ]);
358
- expect(checksumAfter.get('global[]')).toEqual({
359
- bucket: 'global[]',
341
+ expect(checksumAfter.get(request.bucket)).toEqual({
342
+ bucket: request.bucket,
360
343
  count: 1,
361
- checksum: 1874612650
344
+ checksum: dataAfter[0].checksum
362
345
  });
363
346
  }
364
347
  catch (e_3) {
@@ -375,18 +358,17 @@ bucket_definitions:
375
358
  const env_4 = { stack: [], error: void 0, hasError: false };
376
359
  try {
377
360
  const factory = __addDisposableResource(env_4, await generateStorageFactory(), true);
378
- const syncRules = await factory.updateSyncRules({
379
- /* yaml */ content: ` bucket_definitions:
361
+ const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(` bucket_definitions:
380
362
  grouped:
381
363
  # The parameter query here is not important
382
364
  # We specifically don't want to create bucket_parameter records here
383
365
  # since the op_ids for bucket_data could vary between storage implementations.
384
366
  parameters: select 'b' as b
385
367
  data:
386
- - select * from test where b = bucket.b`
387
- });
368
+ - select * from test where b = bucket.b`));
388
369
  const bucketStorage = factory.getInstance(syncRules);
389
370
  const result = await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
371
+ await batch.markAllSnapshotDone('1/1');
390
372
  /**
391
373
  * Repeatedly create operations which fall into different buckets.
392
374
  * The bucket operations are purposely interleaved as the op_id increases.
@@ -456,7 +438,7 @@ bucket_definitions:
456
438
  minBucketChanges: 1,
457
439
  minChangeRatio: 0
458
440
  });
459
- const batchAfter = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, new Map([
441
+ const batchAfter = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, bucketRequestMap(syncRules, [
460
442
  ['grouped["b1"]', 0n],
461
443
  ['grouped["b2"]', 0n]
462
444
  ])));
@@ -499,15 +481,14 @@ bucket_definitions:
499
481
  const env_5 = { stack: [], error: void 0, hasError: false };
500
482
  try {
501
483
  const factory = __addDisposableResource(env_5, await generateStorageFactory(), true);
502
- const syncRules = await factory.updateSyncRules({
503
- content: `
484
+ const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
504
485
  bucket_definitions:
505
486
  global:
506
487
  data: [select * from test]
507
- `
508
- });
488
+ `));
509
489
  const bucketStorage = factory.getInstance(syncRules);
510
- const result = await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
490
+ await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
491
+ await batch.markAllSnapshotDone('1/1');
511
492
  await batch.save({
512
493
  sourceTable: TEST_TABLE,
513
494
  tag: storage.SaveOperationTag.INSERT,
@@ -553,13 +534,16 @@ bucket_definitions:
553
534
  await batch.commit('2/1');
554
535
  });
555
536
  const checkpoint2 = result2.flushed_op;
537
+ const request = bucketRequest(syncRules, 'global[]');
556
538
  await bucketStorage.clearChecksumCache();
557
- const checksumAfter = await bucketStorage.getChecksums(checkpoint2, ['global[]']);
558
- expect(checksumAfter.get('global[]')).toEqual({
559
- bucket: 'global[]',
560
- count: 4,
561
- checksum: 1874612650
539
+ const checksumAfter = await bucketStorage.getChecksums(checkpoint2, [request]);
540
+ const globalChecksum = checksumAfter.get(request.bucket);
541
+ expect(globalChecksum).toMatchObject({
542
+ bucket: request.bucket,
543
+ count: 4
562
544
  });
545
+ // storage-specific checksum - just check that it does not change
546
+ expect(globalChecksum).toMatchSnapshot();
563
547
  }
564
548
  catch (e_5) {
565
549
  env_5.error = e_5;
@@ -575,15 +559,14 @@ bucket_definitions:
575
559
  const env_6 = { stack: [], error: void 0, hasError: false };
576
560
  try {
577
561
  const factory = __addDisposableResource(env_6, await generateStorageFactory(), true);
578
- const syncRules = await factory.updateSyncRules({
579
- content: `
562
+ const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
580
563
  bucket_definitions:
581
564
  global:
582
565
  data: [select * from test]
583
- `
584
- });
566
+ `));
585
567
  const bucketStorage = factory.getInstance(syncRules);
586
568
  const result = await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
569
+ await batch.markAllSnapshotDone('1/1');
587
570
  await batch.save({
588
571
  sourceTable: TEST_TABLE,
589
572
  tag: storage.SaveOperationTag.INSERT,
@@ -603,7 +586,7 @@ bucket_definitions:
603
586
  await batch.commit('1/1');
604
587
  });
605
588
  // Get checksums here just to populate the cache
606
- await bucketStorage.getChecksums(result.flushed_op, ['global[]']);
589
+ await bucketStorage.getChecksums(result.flushed_op, bucketRequests(syncRules, ['global[]']));
607
590
  const result2 = await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
608
591
  await batch.save({
609
592
  sourceTable: TEST_TABLE,
@@ -623,13 +606,16 @@ bucket_definitions:
623
606
  minChangeRatio: 0
624
607
  });
625
608
  const checkpoint2 = result2.flushed_op;
609
+ const request = bucketRequest(syncRules, 'global[]');
626
610
  // Check that the checksum was correctly updated with the clear operation after having a cached checksum
627
- const checksumAfter = await bucketStorage.getChecksums(checkpoint2, ['global[]']);
628
- expect(checksumAfter.get('global[]')).toMatchObject({
629
- bucket: 'global[]',
630
- count: 1,
631
- checksum: -1481659821
611
+ const checksumAfter = await bucketStorage.getChecksums(checkpoint2, [request]);
612
+ const globalChecksum = checksumAfter.get(request.bucket);
613
+ expect(globalChecksum).toMatchObject({
614
+ bucket: request.bucket,
615
+ count: 1
632
616
  });
617
+ // storage-specific checksum - just check that it does not change
618
+ expect(globalChecksum).toMatchSnapshot();
633
619
  }
634
620
  catch (e_6) {
635
621
  env_6.error = e_6;
@@ -641,5 +627,62 @@ bucket_definitions:
641
627
  await result_6;
642
628
  }
643
629
  });
630
+ test('defaults maxOpId to current checkpoint', async () => {
631
+ const env_7 = { stack: [], error: void 0, hasError: false };
632
+ try {
633
+ const factory = __addDisposableResource(env_7, await generateStorageFactory(), true);
634
+ const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
635
+ bucket_definitions:
636
+ global:
637
+ data: [select * from test]
638
+ `));
639
+ const bucketStorage = factory.getInstance(syncRules);
640
+ const result1 = await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
641
+ await batch.markAllSnapshotDone('1/1');
642
+ await batch.save({
643
+ sourceTable: TEST_TABLE,
644
+ tag: storage.SaveOperationTag.INSERT,
645
+ after: { id: 't1' },
646
+ afterReplicaId: test_utils.rid('t1')
647
+ });
648
+ await batch.commit('1/1');
649
+ });
650
+ const checkpoint1 = result1.flushed_op;
651
+ const result2 = await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
652
+ // This is flushed but not committed (does not advance the checkpoint)
653
+ await batch.save({
654
+ sourceTable: TEST_TABLE,
655
+ tag: storage.SaveOperationTag.UPDATE,
656
+ after: { id: 't1' },
657
+ afterReplicaId: test_utils.rid('t1')
658
+ });
659
+ });
660
+ const checkpoint2 = result2.flushed_op;
661
+ const checkpointBeforeCompact = await bucketStorage.getCheckpoint();
662
+ expect(checkpointBeforeCompact.checkpoint).toEqual(checkpoint1);
663
+ // With default options, Postgres compaction should use the active checkpoint.
664
+ await bucketStorage.compact({
665
+ moveBatchLimit: 1,
666
+ moveBatchQueryLimit: 1,
667
+ minBucketChanges: 1,
668
+ minChangeRatio: 0
669
+ });
670
+ const batchAfterDefaultCompact = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint2, bucketRequestMap(syncRules, [['global[]', 0n]])));
671
+ // Operation 1 should remain a PUT because op_id=2 is above the default maxOpId checkpoint.
672
+ expect(batchAfterDefaultCompact.chunkData.data).toMatchObject([
673
+ { op_id: '1', op: 'PUT', object_id: 't1' },
674
+ { op_id: '2', op: 'PUT', object_id: 't1' }
675
+ ]);
676
+ }
677
+ catch (e_7) {
678
+ env_7.error = e_7;
679
+ env_7.hasError = true;
680
+ }
681
+ finally {
682
+ const result_7 = __disposeResources(env_7);
683
+ if (result_7)
684
+ await result_7;
685
+ }
686
+ });
644
687
  }
645
688
  //# sourceMappingURL=register-compacting-tests.js.map