Skip to content

Commit fb6f76a

Browse files
committed
Refactor parameter lookups to make the names configurable.
1 parent 1075d04 commit fb6f76a

File tree

13 files changed

+378
-304
lines changed

13 files changed

+378
-304
lines changed

packages/service-core-tests/src/tests/register-data-storage-parameter-tests.ts

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { ParameterLookup, RequestParameters } from '@powersync/service-sync-rule
33
import { expect, test } from 'vitest';
44
import * as test_utils from '../test-utils/test-utils-index.js';
55
import { TEST_TABLE } from './util.js';
6+
import { ParameterLookupScope } from '@powersync/service-sync-rules/src/HydrationState.js';
67

78
/**
89
* @example
@@ -15,6 +16,8 @@ import { TEST_TABLE } from './util.js';
1516
* ```
1617
*/
1718
export function registerDataStorageParameterTests(generateStorageFactory: storage.TestStorageFactory) {
19+
const MYBUCKET_1: ParameterLookupScope = { lookupName: 'mybucket', queryId: '1' };
20+
1821
test('save and load parameters', async () => {
1922
await using factory = await generateStorageFactory();
2023
const syncRules = await factory.updateSyncRules({
@@ -57,7 +60,7 @@ bucket_definitions:
5760
});
5861

5962
const checkpoint = await bucketStorage.getCheckpoint();
60-
const parameters = await checkpoint.getParameterSets([ParameterLookup.normalized('mybucket', '1', ['user1'])]);
63+
const parameters = await checkpoint.getParameterSets([ParameterLookup.normalized(MYBUCKET_1, ['user1'])]);
6164
expect(parameters).toEqual([
6265
{
6366
group_id: 'group1a'
@@ -105,15 +108,15 @@ bucket_definitions:
105108
});
106109
const checkpoint2 = await bucketStorage.getCheckpoint();
107110

108-
const parameters = await checkpoint2.getParameterSets([ParameterLookup.normalized('mybucket', '1', ['user1'])]);
111+
const parameters = await checkpoint2.getParameterSets([ParameterLookup.normalized(MYBUCKET_1, ['user1'])]);
109112
expect(parameters).toEqual([
110113
{
111114
group_id: 'group2'
112115
}
113116
]);
114117

115118
// Use the checkpoint to get older data if relevant
116-
const parameters2 = await checkpoint1.getParameterSets([ParameterLookup.normalized('mybucket', '1', ['user1'])]);
119+
const parameters2 = await checkpoint1.getParameterSets([ParameterLookup.normalized(MYBUCKET_1, ['user1'])]);
117120
expect(parameters2).toEqual([
118121
{
119122
group_id: 'group1'
@@ -182,8 +185,8 @@ bucket_definitions:
182185
// association of `list1`::`todo2`
183186
const checkpoint = await bucketStorage.getCheckpoint();
184187
const parameters = await checkpoint.getParameterSets([
185-
ParameterLookup.normalized('mybucket', '1', ['list1']),
186-
ParameterLookup.normalized('mybucket', '1', ['list2'])
188+
ParameterLookup.normalized(MYBUCKET_1, ['list1']),
189+
ParameterLookup.normalized(MYBUCKET_1, ['list2'])
187190
]);
188191

189192
expect(parameters.sort((a, b) => (a.todo_id as string).localeCompare(b.todo_id as string))).toEqual([
@@ -230,17 +233,11 @@ bucket_definitions:
230233

231234
const checkpoint = await bucketStorage.getCheckpoint();
232235

233-
const parameters1 = await checkpoint.getParameterSets([
234-
ParameterLookup.normalized('mybucket', '1', [314n, 314, 3.14])
235-
]);
236+
const parameters1 = await checkpoint.getParameterSets([ParameterLookup.normalized(MYBUCKET_1, [314n, 314, 3.14])]);
236237
expect(parameters1).toEqual([TEST_PARAMS]);
237-
const parameters2 = await checkpoint.getParameterSets([
238-
ParameterLookup.normalized('mybucket', '1', [314, 314n, 3.14])
239-
]);
238+
const parameters2 = await checkpoint.getParameterSets([ParameterLookup.normalized(MYBUCKET_1, [314, 314n, 3.14])]);
240239
expect(parameters2).toEqual([TEST_PARAMS]);
241-
const parameters3 = await checkpoint.getParameterSets([
242-
ParameterLookup.normalized('mybucket', '1', [314n, 314, 3])
243-
]);
240+
const parameters3 = await checkpoint.getParameterSets([ParameterLookup.normalized(MYBUCKET_1, [314n, 314, 3])]);
244241
expect(parameters3).toEqual([]);
245242
});
246243

@@ -294,7 +291,7 @@ bucket_definitions:
294291
const checkpoint = await bucketStorage.getCheckpoint();
295292

296293
const parameters1 = await checkpoint.getParameterSets([
297-
ParameterLookup.normalized('mybucket', '1', [1152921504606846976n])
294+
ParameterLookup.normalized(MYBUCKET_1, [1152921504606846976n])
298295
]);
299296
expect(parameters1).toEqual([TEST_PARAMS]);
300297
});
@@ -335,7 +332,7 @@ bucket_definitions:
335332
const querier = sync_rules.getBucketParameterQuerier(test_utils.querierOptions(parameters)).querier;
336333

337334
const lookups = querier.parameterQueryLookups;
338-
expect(lookups).toEqual([ParameterLookup.normalized('by_workspace', '1', ['u1'])]);
335+
expect(lookups).toEqual([ParameterLookup.normalized({ lookupName: 'by_workspace', queryId: '1' }, ['u1'])]);
339336

340337
const parameter_sets = await checkpoint.getParameterSets(lookups);
341338
expect(parameter_sets).toEqual([{ workspace_id: 'workspace1' }]);
@@ -408,7 +405,7 @@ bucket_definitions:
408405
const querier = sync_rules.getBucketParameterQuerier(test_utils.querierOptions(parameters)).querier;
409406

410407
const lookups = querier.parameterQueryLookups;
411-
expect(lookups).toEqual([ParameterLookup.normalized('by_public_workspace', '1', [])]);
408+
expect(lookups).toEqual([ParameterLookup.normalized({ lookupName: 'by_public_workspace', queryId: '1' }, [])]);
412409

413410
const parameter_sets = await checkpoint.getParameterSets(lookups);
414411
parameter_sets.sort((a, b) => JSON.stringify(a).localeCompare(JSON.stringify(b)));
@@ -510,8 +507,8 @@ bucket_definitions:
510507

511508
const lookups = querier.parameterQueryLookups;
512509
expect(lookups).toEqual([
513-
ParameterLookup.normalized('by_workspace', '1', []),
514-
ParameterLookup.normalized('by_workspace', '2', ['u1'])
510+
ParameterLookup.normalized({ lookupName: 'by_workspace', queryId: '1' }, []),
511+
ParameterLookup.normalized({ lookupName: 'by_workspace', queryId: '2' }, ['u1'])
515512
]);
516513

517514
const parameter_sets = await checkpoint.getParameterSets(lookups);
@@ -561,7 +558,7 @@ bucket_definitions:
561558

562559
const checkpoint = await bucketStorage.getCheckpoint();
563560

564-
const parameters = await checkpoint.getParameterSets([ParameterLookup.normalized('mybucket', '1', ['user1'])]);
561+
const parameters = await checkpoint.getParameterSets([ParameterLookup.normalized(MYBUCKET_1, ['user1'])]);
565562
expect(parameters).toEqual([]);
566563
});
567564

packages/service-core-tests/src/tests/register-parameter-compacting-tests.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ bucket_definitions:
4040
await batch.commit('1/1');
4141
});
4242

43-
const lookup = ParameterLookup.normalized('test', '1', ['t1']);
43+
const lookup = ParameterLookup.normalized({ lookupName: 'test', queryId: '1' }, ['t1']);
4444

4545
const checkpoint1 = await bucketStorage.getCheckpoint();
4646
const parameters1 = await checkpoint1.getParameterSets([lookup]);
@@ -151,7 +151,7 @@ bucket_definitions:
151151
await batch.commit('3/1');
152152
});
153153

154-
const lookup = ParameterLookup.normalized('test', '1', ['u1']);
154+
const lookup = ParameterLookup.normalized({ lookupName: 'test', queryId: '1' }, ['u1']);
155155

156156
const checkpoint1 = await bucketStorage.getCheckpoint();
157157
const parameters1 = await checkpoint1.getParameterSets([lookup]);

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ bucket_definitions:
504504

505505
const line = (await state.buildNextCheckpointLine({
506506
base: storage.makeCheckpoint(1n, (lookups) => {
507-
expect(lookups).toEqual([ParameterLookup.normalized('by_project', '1', ['u1'])]);
507+
expect(lookups).toEqual([ParameterLookup.normalized({ lookupName: 'by_project', queryId: '1' }, ['u1'])]);
508508
return [{ id: 1 }, { id: 2 }];
509509
}),
510510
writeCheckpoint: null,
@@ -565,7 +565,7 @@ bucket_definitions:
565565
// Now we get a new line
566566
const line2 = (await state.buildNextCheckpointLine({
567567
base: storage.makeCheckpoint(2n, (lookups) => {
568-
expect(lookups).toEqual([ParameterLookup.normalized('by_project', '1', ['u1'])]);
568+
expect(lookups).toEqual([ParameterLookup.normalized({ lookupName: 'by_project', queryId: '1' }, ['u1'])]);
569569
return [{ id: 1 }, { id: 2 }, { id: 3 }];
570570
}),
571571
writeCheckpoint: null,

packages/sync-rules/src/BucketParameterQuerier.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ResolvedBucket } from './BucketDescription.js';
2+
import { ParameterLookupScope } from './HydrationState.js';
23
import { RequestedStream } from './SqlSyncRules.js';
34
import { RequestParameters, SqliteJsonRow, SqliteJsonValue } from './types.js';
45
import { normalizeParameterValue } from './utils.js';
@@ -92,15 +93,15 @@ export class ParameterLookup {
9293
// bucket definition name, parameter query index, ...lookup values
9394
readonly values: SqliteJsonValue[];
9495

95-
static normalized(bucketDefinitionName: string, queryIndex: string, values: SqliteJsonValue[]): ParameterLookup {
96-
return new ParameterLookup([bucketDefinitionName, queryIndex, ...values.map(normalizeParameterValue)]);
96+
static normalized(scope: ParameterLookupScope, values: SqliteJsonValue[]): ParameterLookup {
97+
return new ParameterLookup([scope.lookupName, scope.queryId, ...values.map(normalizeParameterValue)]);
9798
}
9899

99100
/**
100101
*
101102
* @param values must be pre-normalized (any integer converted into bigint)
102103
*/
103-
constructor(values: SqliteJsonValue[]) {
104+
private constructor(values: SqliteJsonValue[]) {
104105
this.values = values;
105106
}
106107
}

packages/sync-rules/src/HydrationState.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export interface BucketSourceState {
66
bucketPrefix: string;
77
}
88

9-
export interface BucketParameterLookupSourceState {
9+
export interface ParameterLookupScope {
1010
/** The lookup name + queryid is used to reference the parameter lookup record. */
1111
lookupName: string;
1212
queryId: string;
@@ -20,7 +20,7 @@ export interface BucketParameterLookupSourceState {
2020
*/
2121
export interface HydrationState<
2222
T extends BucketSourceState = BucketSourceState,
23-
U extends BucketParameterLookupSourceState = BucketParameterLookupSourceState
23+
U extends ParameterLookupScope = ParameterLookupScope
2424
> {
2525
/**
2626
* Given a bucket data source definition, get the bucket prefix to use for it.
@@ -30,7 +30,7 @@ export interface HydrationState<
3030
/**
3131
* Given a bucket parameter lookup definition, get the persistence name to use.
3232
*/
33-
getParameterLookupState(source: BucketParameterLookupSourceDefinition): U;
33+
getParameterLookupScope(source: BucketParameterLookupSourceDefinition): U;
3434
}
3535

3636
/**
@@ -44,7 +44,7 @@ export const DEFAULT_HYDRATION_STATE: HydrationState = {
4444
bucketPrefix: source.defaultBucketPrefix
4545
};
4646
},
47-
getParameterLookupState(source) {
47+
getParameterLookupScope(source) {
4848
return {
4949
lookupName: source.defaultLookupName,
5050
queryId: source.defaultQueryId
@@ -67,7 +67,7 @@ export class VersionedHydrationState implements HydrationState {
6767
};
6868
}
6969

70-
getParameterLookupState(source: BucketParameterLookupSourceDefinition): BucketParameterLookupSourceState {
70+
getParameterLookupScope(source: BucketParameterLookupSourceDefinition): ParameterLookupScope {
7171
// No transformations applied here
7272
return {
7373
lookupName: source.defaultLookupName,
@@ -85,7 +85,7 @@ export class BucketIdTransformerHydrationState implements HydrationState {
8585
};
8686
}
8787

88-
getParameterLookupState(source: BucketParameterLookupSourceDefinition): BucketParameterLookupSourceState {
88+
getParameterLookupScope(source: BucketParameterLookupSourceDefinition): ParameterLookupScope {
8989
// No transformations applied here
9090
return {
9191
lookupName: source.defaultLookupName,

packages/sync-rules/src/SqlParameterQuery.ts

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ import {
4444
} from './types.js';
4545
import { filterJsonRow, getBucketId, isJsonValue, isSelectStatement, normalizeParameterValue } from './utils.js';
4646
import { DetectRequestParameters } from './validators.js';
47-
import { HydrationState, resolveHydrationState } from './HydrationState.js';
47+
import { ParameterLookupScope, HydrationState, resolveHydrationState } from './HydrationState.js';
4848

4949
export interface SqlParameterQueryOptions {
5050
sourceTable: TablePattern;
@@ -350,20 +350,24 @@ export class SqlParameterQuery
350350
createParameterQuerierSource(params: CreateSourceParams): BucketParameterQuerierSource {
351351
const hydrationState = resolveHydrationState(params);
352352
const bucketPrefix = hydrationState.getBucketSourceState(this.querierDataSource).bucketPrefix;
353+
const lookupState = hydrationState.getParameterLookupScope(this);
354+
353355
return {
354356
pushBucketParameterQueriers: (result: PendingQueriers, options: GetQuerierOptions) => {
355-
const q = this.getBucketParameterQuerier(options.globalParameters, ['default'], bucketPrefix);
357+
const q = this.getBucketParameterQuerier(options.globalParameters, ['default'], bucketPrefix, lookupState);
356358
result.queriers.push(q);
357359
}
358360
};
359361
}
360362

361363
createParameterLookupSource(params: CreateSourceParams): BucketParameterLookupSource {
362364
// FIXME: Use HydrationState for lookups.
365+
const hydrationState = resolveHydrationState(params);
366+
const lookupState = hydrationState.getParameterLookupScope(this);
363367
return {
364368
evaluateParameterRow: (sourceTable: SourceTableInterface, row: SqliteRow): EvaluatedParametersResult[] => {
365369
if (this.tableSyncsParameters(sourceTable)) {
366-
return this.evaluateParameterRow(row);
370+
return this.evaluateParameterRow(lookupState, row);
367371
} else {
368372
return [];
369373
}
@@ -374,16 +378,16 @@ export class SqlParameterQuery
374378
/**
375379
* Given a replicated row, results an array of bucket parameter rows to persist.
376380
*/
377-
evaluateParameterRow(row: SqliteRow): EvaluatedParametersResult[] {
381+
evaluateParameterRow(scope: ParameterLookupScope, row: SqliteRow): EvaluatedParametersResult[] {
378382
const tables = {
379383
[this.table.nameInSchema]: row
380384
};
381385
try {
382386
const filterParameters = this.filter.filterRow(tables);
383387
let result: EvaluatedParametersResult[] = [];
384388
for (let filterParamSet of filterParameters) {
385-
let lookup: SqliteJsonValue[] = [this.descriptorName, this.queryId];
386-
lookup.push(
389+
let lookupValues: SqliteJsonValue[] = [];
390+
lookupValues.push(
387391
...this.inputParameters.map((param) => {
388392
return normalizeParameterValue(param.filteredRowToLookupValue(filterParamSet));
389393
})
@@ -393,7 +397,7 @@ export class SqlParameterQuery
393397

394398
const role: EvaluatedParameters = {
395399
bucketParameters: data.map((row) => filterJsonRow(row)),
396-
lookup: new ParameterLookup(lookup)
400+
lookup: ParameterLookup.normalized(scope, lookupValues)
397401
};
398402
result.push(role);
399403
}
@@ -458,12 +462,12 @@ export class SqlParameterQuery
458462
*
459463
* Each lookup is [bucket definition name, parameter query index, ...lookup values]
460464
*/
461-
getLookups(parameters: RequestParameters): ParameterLookup[] {
465+
getLookups(scope: ParameterLookupScope, parameters: RequestParameters): ParameterLookup[] {
462466
if (!this.expandedInputParameter) {
463-
let lookup: SqliteJsonValue[] = [this.descriptorName, this.queryId];
467+
let lookupValues: SqliteJsonValue[] = [];
464468

465469
let valid = true;
466-
lookup.push(
470+
lookupValues.push(
467471
...this.inputParameters.map((param): SqliteJsonValue => {
468472
// Scalar value
469473
const value = param.parametersToLookupValue(parameters);
@@ -479,7 +483,7 @@ export class SqlParameterQuery
479483
if (!valid) {
480484
return [];
481485
}
482-
return [new ParameterLookup(lookup)];
486+
return [ParameterLookup.normalized(scope, lookupValues)];
483487
} else {
484488
const arrayString = this.expandedInputParameter.parametersToLookupValue(parameters);
485489

@@ -498,10 +502,10 @@ export class SqlParameterQuery
498502

499503
return values
500504
.map((expandedValue) => {
501-
let lookup: SqliteJsonValue[] = [this.descriptorName, this.queryId];
505+
let lookupValues: SqliteJsonValue[] = [];
502506
let valid = true;
503507
const normalizedExpandedValue = normalizeParameterValue(expandedValue);
504-
lookup.push(
508+
lookupValues.push(
505509
...this.inputParameters.map((param): SqliteJsonValue => {
506510
if (param == this.expandedInputParameter) {
507511
// Expand array value
@@ -523,7 +527,7 @@ export class SqlParameterQuery
523527
return null;
524528
}
525529

526-
return new ParameterLookup(lookup);
530+
return ParameterLookup.normalized(scope, lookupValues);
527531
})
528532
.filter((lookup) => lookup != null) as ParameterLookup[];
529533
}
@@ -532,9 +536,10 @@ export class SqlParameterQuery
532536
getBucketParameterQuerier(
533537
requestParameters: RequestParameters,
534538
reasons: BucketInclusionReason[],
535-
bucketPrefix: string
539+
bucketPrefix: string,
540+
scope: ParameterLookupScope
536541
): BucketParameterQuerier {
537-
const lookups = this.getLookups(requestParameters);
542+
const lookups = this.getLookups(scope, requestParameters);
538543
if (lookups.length == 0) {
539544
// This typically happens when the query is pre-filtered using a where clause
540545
// on the parameters, and does not depend on the database state.

0 commit comments

Comments
 (0)