Skip to content

Commit ae08fd3

Browse files
committed
Remove BucketIdTransformer.
1 parent 1eecae9 commit ae08fd3

File tree

20 files changed

+123
-163
lines changed

20 files changed

+123
-163
lines changed

modules/module-mongodb-storage/src/storage/implementation/MongoPersistedSyncRules.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { SqlSyncRules, HydratedSyncRules } from '@powersync/service-sync-rules';
22

33
import { storage } from '@powersync/service-core';
4+
import { versionedHydrationState } from '@powersync/service-sync-rules/src/HydrationState.js';
45

56
export class MongoPersistedSyncRules implements storage.PersistedSyncRules {
67
public readonly slot_name: string;
@@ -15,6 +16,6 @@ export class MongoPersistedSyncRules implements storage.PersistedSyncRules {
1516
}
1617

1718
hydratedSyncRules(): HydratedSyncRules {
18-
return this.sync_rules.hydrate({ bucketIdTransformer: SqlSyncRules.versionedBucketIdTransformer(`${this.id}`) });
19+
return this.sync_rules.hydrate({ hydrationState: versionedHydrationState(this.id) });
1920
}
2021
}

modules/module-postgres-storage/src/storage/sync-rules/PostgresPersistedSyncRulesContent.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { storage } from '@powersync/service-core';
44
import { SqlSyncRules } from '@powersync/service-sync-rules';
55

66
import { models } from '../../types/types.js';
7+
import { versionedHydrationState } from '@powersync/service-sync-rules/src/HydrationState.js';
78

89
export class PostgresPersistedSyncRulesContent implements storage.PersistedSyncRulesContent {
910
public readonly slot_name: string;
@@ -38,7 +39,7 @@ export class PostgresPersistedSyncRulesContent implements storage.PersistedSyncR
3839
sync_rules: SqlSyncRules.fromYaml(this.sync_rules_content, options),
3940
hydratedSyncRules() {
4041
return this.sync_rules.hydrate({
41-
bucketIdTransformer: SqlSyncRules.versionedBucketIdTransformer(`${this.id}`)
42+
hydrationState: versionedHydrationState(this.id)
4243
});
4344
}
4445
};

packages/service-core-tests/src/test-utils/general-utils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { storage, utils } from '@powersync/service-core';
22
import { GetQuerierOptions, RequestParameters, SqlSyncRules } from '@powersync/service-sync-rules';
3+
import { versionedHydrationState } from '@powersync/service-sync-rules/src/HydrationState.js';
34
import * as bson from 'bson';
45

56
export const ZERO_LSN = '0/0';
@@ -27,7 +28,7 @@ export function testRules(content: string): storage.PersistedSyncRulesContent {
2728
sync_rules: SqlSyncRules.fromYaml(content, options),
2829
slot_name: 'test',
2930
hydratedSyncRules() {
30-
return this.sync_rules.hydrate({ bucketIdTransformer: SqlSyncRules.versionedBucketIdTransformer('1') });
31+
return this.sync_rules.hydrate({ hydrationState: versionedHydrationState(1) });
3132
}
3233
};
3334
},

packages/service-core/test/src/sync/BucketChecksumState.test.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ import {
1212
WatchFilterEvent
1313
} from '@/index.js';
1414
import { JSONBig } from '@powersync/service-jsonbig';
15-
import { SqliteJsonRow, ParameterLookup, SqlSyncRules, RequestJwtPayload } from '@powersync/service-sync-rules';
16-
import { describe, expect, test, beforeEach } from 'vitest';
15+
import { ParameterLookup, RequestJwtPayload, SqliteJsonRow, SqlSyncRules } from '@powersync/service-sync-rules';
16+
import { versionedHydrationState } from '@powersync/service-sync-rules/src/HydrationState.js';
17+
import { beforeEach, describe, expect, test } from 'vitest';
1718

1819
describe('BucketChecksumState', () => {
1920
// Single global[] bucket.
@@ -25,7 +26,7 @@ bucket_definitions:
2526
data: []
2627
`,
2728
{ defaultSchema: 'public' }
28-
).hydrate({ bucketIdTransformer: SqlSyncRules.versionedBucketIdTransformer('1') });
29+
).hydrate({ hydrationState: versionedHydrationState(1) });
2930

3031
// global[1] and global[2]
3132
const SYNC_RULES_GLOBAL_TWO = SqlSyncRules.fromYaml(
@@ -38,7 +39,7 @@ bucket_definitions:
3839
data: []
3940
`,
4041
{ defaultSchema: 'public' }
41-
).hydrate({ bucketIdTransformer: SqlSyncRules.versionedBucketIdTransformer('2') });
42+
).hydrate({ hydrationState: versionedHydrationState(2) });
4243

4344
// by_project[n]
4445
const SYNC_RULES_DYNAMIC = SqlSyncRules.fromYaml(
@@ -49,7 +50,7 @@ bucket_definitions:
4950
data: []
5051
`,
5152
{ defaultSchema: 'public' }
52-
).hydrate({ bucketIdTransformer: SqlSyncRules.versionedBucketIdTransformer('3') });
53+
).hydrate({ hydrationState: versionedHydrationState(3) });
5354

5455
const syncContext = new SyncContext({
5556
maxBuckets: 100,
@@ -614,7 +615,7 @@ config:
614615

615616
const rules = SqlSyncRules.fromYaml(source, {
616617
defaultSchema: 'public'
617-
}).hydrate({ bucketIdTransformer: SqlSyncRules.versionedBucketIdTransformer('1') });
618+
}).hydrate({ hydrationState: versionedHydrationState(1) });
618619

619620
return new BucketChecksumState({
620621
syncContext,

packages/sync-rules/src/BucketSource.ts

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,13 @@
11
import { BucketParameterQuerier, ParameterLookup, PendingQueriers } from './BucketParameterQuerier.js';
22
import { ColumnDefinition } from './ExpressionType.js';
3-
import { HydrationState, ParameterLookupScope } from './HydrationState.js';
3+
import { DEFAULT_HYDRATION_STATE, HydrationState, ParameterLookupScope } from './HydrationState.js';
44
import { SourceTableInterface } from './SourceTableInterface.js';
55
import { GetQuerierOptions } from './SqlSyncRules.js';
66
import { TablePattern } from './TablePattern.js';
7-
import {
8-
BucketIdTransformer,
9-
EvaluatedParametersResult,
10-
EvaluateRowOptions,
11-
EvaluationResult,
12-
SourceSchema,
13-
SqliteRow
14-
} from './types.js';
7+
import { EvaluatedParametersResult, EvaluateRowOptions, EvaluationResult, SourceSchema, SqliteRow } from './types.js';
158

169
export interface CreateSourceParams {
17-
hydrationState?: HydrationState;
18-
/**
19-
* @deprecated Use hydrationState instead.
20-
*/
21-
bucketIdTransformer?: BucketIdTransformer;
10+
hydrationState: HydrationState;
2211
}
2312

2413
/**
@@ -227,7 +216,8 @@ export function mergeParameterQuerierSources(sources: BucketParameterQuerierSour
227216
* it is useful to have a single merged source that can evaluate everything.
228217
*/
229218
export function debugHydratedMergedSource(bucketSource: BucketSource, params?: CreateSourceParams): DebugMergedSource {
230-
const resolvedParams = params ?? { bucketIdTransformer: (id: string) => id };
219+
const hydrationState = params?.hydrationState ?? DEFAULT_HYDRATION_STATE;
220+
const resolvedParams = { hydrationState };
231221
const dataSource = mergeDataSources(
232222
bucketSource.dataSources.map((source) => source.createDataSource(resolvedParams))
233223
);

packages/sync-rules/src/HydrationState.ts

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { BucketDataSourceDefinition, BucketParameterLookupSourceDefinition } from './BucketSource.js';
2-
import { BucketIdTransformer, CreateSourceParams } from './index.js';
32

43
export interface BucketSourceState {
54
/** The prefix is the bucket name before the parameters. */
@@ -49,33 +48,29 @@ export const DEFAULT_HYDRATION_STATE: HydrationState = {
4948
}
5049
};
5150

52-
export function versionedHydrationState(version: number) {
53-
return new BucketIdTransformerHydrationState((bucketId: string) => {
54-
return `${version}#${bucketId}`;
55-
});
56-
}
57-
58-
export class BucketIdTransformerHydrationState implements HydrationState {
59-
constructor(private transformer: BucketIdTransformer) {}
60-
61-
getBucketSourceState(source: BucketDataSourceDefinition): BucketSourceState {
62-
return {
63-
bucketPrefix: this.transformer(source.defaultBucketPrefix)
64-
};
65-
}
66-
67-
getParameterLookupScope(source: BucketParameterLookupSourceDefinition): ParameterLookupScope {
68-
// No transformations applied here
69-
return source.defaultLookupScope;
70-
}
71-
}
51+
/**
52+
* Transforms bucket ids generated when evaluating the row by e.g. encoding version information.
53+
*
54+
* Because buckets are recreated on a sync rule redeploy, it makes sense to use different bucket ids (otherwise, clients
55+
* may run into checksum errors causing a sync to take longer than necessary or breaking progress).
56+
*
57+
* So, this transformer receives the original bucket id as generated by defined sync rules, and can prepend a version
58+
* identifier.
59+
*
60+
* Note that this transformation has not been present in older versions of the sync service. To preserve backwards
61+
* compatibility, sync rules will not use this without an opt-in.
62+
*/
63+
export function versionedHydrationState(version: number): HydrationState {
64+
return {
65+
getBucketSourceState(source: BucketDataSourceDefinition): BucketSourceState {
66+
return {
67+
bucketPrefix: `${version}#${source.defaultBucketPrefix}`
68+
};
69+
},
7270

73-
export function resolveHydrationState(params: CreateSourceParams): HydrationState {
74-
if (params.hydrationState) {
75-
return params.hydrationState;
76-
} else if (params.bucketIdTransformer) {
77-
return new BucketIdTransformerHydrationState(params.bucketIdTransformer);
78-
} else {
79-
return DEFAULT_HYDRATION_STATE;
80-
}
71+
getParameterLookupScope(source: BucketParameterLookupSourceDefinition): ParameterLookupScope {
72+
// No transformations applied here
73+
return source.defaultLookupScope;
74+
}
75+
};
8176
}

packages/sync-rules/src/SqlBucketDescriptor.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
CreateSourceParams
77
} from './BucketSource.js';
88
import { ColumnDefinition } from './ExpressionType.js';
9-
import { resolveHydrationState } from './HydrationState.js';
109
import { IdSequence } from './IdSequence.js';
1110
import { SourceTableInterface } from './SourceTableInterface.js';
1211
import { SqlDataQuery } from './SqlDataQuery.js';
@@ -158,7 +157,7 @@ export class BucketDefinitionDataSource implements BucketDataSourceDefinition {
158157
}
159158

160159
createDataSource(params: CreateSourceParams): BucketDataSource {
161-
const hydrationState = resolveHydrationState(params);
160+
const hydrationState = params.hydrationState;
162161
const bucketPrefix = hydrationState.getBucketSourceState(this).bucketPrefix;
163162
return {
164163
evaluateRow: (options) => {

packages/sync-rules/src/SqlParameterQuery.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
CreateSourceParams
2020
} from './BucketSource.js';
2121
import { SqlRuleError } from './errors.js';
22-
import { ParameterLookupScope, resolveHydrationState } from './HydrationState.js';
22+
import { ParameterLookupScope } from './HydrationState.js';
2323
import { BucketDataSourceDefinition, GetQuerierOptions } from './index.js';
2424
import { SourceTableInterface } from './SourceTableInterface.js';
2525
import { AvailableTable, SqlTools } from './sql_filters.js';
@@ -346,7 +346,7 @@ export class SqlParameterQuery
346346
}
347347

348348
createParameterQuerierSource(params: CreateSourceParams): BucketParameterQuerierSource {
349-
const hydrationState = resolveHydrationState(params);
349+
const hydrationState = params.hydrationState;
350350
const bucketPrefix = hydrationState.getBucketSourceState(this.querierDataSource).bucketPrefix;
351351
const lookupState = hydrationState.getParameterLookupScope(this);
352352

@@ -359,7 +359,7 @@ export class SqlParameterQuery
359359
}
360360

361361
createParameterLookupSource(params: CreateSourceParams): BucketParameterLookupSource {
362-
const hydrationState = resolveHydrationState(params);
362+
const hydrationState = params.hydrationState;
363363
const lookupState = hydrationState.getParameterLookupScope(this);
364364
return {
365365
evaluateParameterRow: (sourceTable: SourceTableInterface, row: SqliteRow): EvaluatedParametersResult[] => {

packages/sync-rules/src/SqlSyncRules.ts

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,20 @@ import {
55
BucketDataSourceDefinition,
66
BucketParameterLookupSourceDefinition,
77
BucketParameterQuerierSourceDefinition,
8-
BucketSource
8+
BucketSource,
9+
CreateSourceParams
910
} from './BucketSource.js';
1011
import { CompatibilityContext, CompatibilityEdition, CompatibilityOption } from './compatibility.js';
1112
import { SqlRuleError, SyncRulesErrors, YamlError } from './errors.js';
1213
import { SqlEventDescriptor } from './events/SqlEventDescriptor.js';
14+
import { DEFAULT_HYDRATION_STATE } from './HydrationState.js';
1315
import { validateSyncRulesSchema } from './json_schema.js';
1416
import { SourceTableInterface } from './SourceTableInterface.js';
1517
import { QueryParseResult, SqlBucketDescriptor } from './SqlBucketDescriptor.js';
1618
import { syncStreamFromSql } from './streams/from_sql.js';
1719
import { HydratedSyncRules } from './SyncRules.js';
1820
import { TablePattern } from './TablePattern.js';
1921
import {
20-
BucketIdTransformer,
2122
QueryParseOptions,
2223
RequestParameters,
2324
SourceSchema,
@@ -388,21 +389,20 @@ export class SqlSyncRules {
388389
/**
389390
* Hydrate the sync rule definitions with persisted state into runnable sync rules.
390391
*
391-
* Right now this is just the bucketIdTransformer, but this is expected to expand in the future to support
392-
* incremental sync rule reprocessing.
393-
*
394-
* @param params.bucketIdTransformer A function that transforms bucket ids based on persisted state. May omit for tests.
392+
* @param params.hydrationState Transforms bucket ids based on persisted state. May omit for tests.
395393
*/
396-
hydrate(params?: { bucketIdTransformer?: BucketIdTransformer }): HydratedSyncRules {
397-
const bucketIdTransformer = this.compatibility.isEnabled(CompatibilityOption.versionedBucketIds)
398-
? (params?.bucketIdTransformer ?? ((id: string) => id))
399-
: (id: string) => id;
394+
hydrate(params?: CreateSourceParams): HydratedSyncRules {
395+
let hydrationState = params?.hydrationState;
396+
if (hydrationState == null || !this.compatibility.isEnabled(CompatibilityOption.versionedBucketIds)) {
397+
hydrationState = DEFAULT_HYDRATION_STATE;
398+
}
399+
const resolvedParams = { hydrationState };
400400
return new HydratedSyncRules({
401401
definition: this,
402-
createParams: { bucketIdTransformer },
403-
bucketDataSources: this.bucketDataSources.map((d) => d.createDataSource({ bucketIdTransformer })),
402+
createParams: resolvedParams,
403+
bucketDataSources: this.bucketDataSources.map((d) => d.createDataSource(resolvedParams)),
404404
bucketParameterLookupSources: this.bucketParameterLookupSources.map((d) =>
405-
d.createParameterLookupSource({ bucketIdTransformer })
405+
d.createParameterLookupSource(resolvedParams)
406406
),
407407
eventDescriptors: this.eventDescriptors,
408408
compatibility: this.compatibility
@@ -488,8 +488,4 @@ export class SqlSyncRules {
488488
}
489489
}
490490
}
491-
492-
static versionedBucketIdTransformer(version: string) {
493-
return (bucketId: string) => `${version}#${bucketId}`;
494-
}
495491
}

packages/sync-rules/src/StaticSqlParameterQuery.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
CreateSourceParams
88
} from './BucketSource.js';
99
import { SqlRuleError } from './errors.js';
10-
import { resolveHydrationState } from './HydrationState.js';
1110
import { BucketDataSourceDefinition, GetQuerierOptions } from './index.js';
1211
import { SourceTableInterface } from './SourceTableInterface.js';
1312
import { AvailableTable, SqlTools } from './sql_filters.js';
@@ -180,7 +179,7 @@ export class StaticSqlParameterQuery implements BucketParameterQuerierSourceDefi
180179
}
181180

182181
createParameterQuerierSource(params: CreateSourceParams): BucketParameterQuerierSource {
183-
const hydrationState = resolveHydrationState(params);
182+
const hydrationState = params.hydrationState;
184183
const bucketPrefix = hydrationState.getBucketSourceState(this.querierDataSource).bucketPrefix;
185184
return {
186185
pushBucketParameterQueriers: (result: PendingQueriers, options: GetQuerierOptions) => {

0 commit comments

Comments
 (0)