Skip to content

Commit

Permalink
Intial parameter lookup refactoring.
Browse files Browse the repository at this point in the history
  • Loading branch information
rkistner committed Jul 2, 2024
1 parent 474bac6 commit fc585a6
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 18 deletions.
101 changes: 83 additions & 18 deletions packages/sync-rules/src/SqlParameterQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { parse, SelectedColumn } from 'pgsql-ast-parser';
import {
EvaluatedParameters,
EvaluatedParametersResult,
FilterParameters,
ParameterMatchClause,
QueryBucketIdOptions,
QuerySchema,
Expand All @@ -21,6 +22,20 @@ import { SourceTableInterface } from './SourceTableInterface.js';
import { checkUnsupportedFeatures, isClauseError } from './sql_support.js';
import { TableQuerySchema } from './TableQuerySchema.js';

interface InputParameter {
expands: boolean;

/**
* Given FilterParameters from a data row, return the associated value.
*/
filteredRowToLookupValue(filterParameters: FilterParameters): SqliteJsonValue;

/**
* Given SyncParamters, return the associated value to lookup.
*/
parametersToLookupValue(parameters: SyncParameters): SqliteJsonValue;
}

/**
* Represents a parameter query, such as:
*
Expand Down Expand Up @@ -101,8 +116,37 @@ export class SqlParameterQuery {
rows.filter = filter;
rows.descriptor_name = descriptor_name;
rows.bucket_parameters = bucket_parameters;
rows.input_parameters = filter.bucketParameters!;
const expandedParams = rows.input_parameters.filter((param) => param.endsWith('[*]'));
rows.input_parameters = filter.bucketParameters!.map((parameterName) => {
if (!parameterName.endsWith('[*]')) {
const [table, column] = parameterName.split('.');

return {
filteredRowToLookupValue(filterParameters) {
return filterParameters[parameterName];
},
parametersToLookupValue(parameters) {
const pt: SqliteJsonRow | undefined = (parameters as any)[table];
return pt?.[column] ?? null;
},
expands: false
};
} else {
const shortName = parameterName.substring(0, parameterName.length - 3);
const [table, column] = shortName.split('.');

return {
filteredRowToLookupValue(filterParameters) {
return filterParameters[parameterName];
},
parametersToLookupValue(parameters) {
const pt: SqliteJsonRow | undefined = (parameters as any)[table];
return pt?.[column] ?? null;
},
expands: true
};
}
});
const expandedParams = rows.input_parameters!.filter((param) => param.expands);
if (expandedParams.length > 1) {
rows.errors.push(new SqlRuleError('Cannot have multiple array input parameters', sql));
}
Expand Down Expand Up @@ -152,17 +196,30 @@ export class SqlParameterQuery {
lookup_columns?: SelectedColumn[];
static_columns?: SelectedColumn[];

/**
* Example: SELECT *user.id* FROM users WHERE ...
*/
lookup_extractors: Record<string, StaticRowValueClause> = {};

/**
* Example: SELECT *token_parameters.user_id*
*/
static_extractors: Record<string, StaticRowValueClause> = {};

filter?: ParameterMatchClause;
descriptor_name?: string;

/** _Input_ token / user parameters */
input_parameters?: string[];
input_parameters?: InputParameter[];

expanded_input_parameter?: string;
/** If specified, an input parameter that expands to an array. */
expanded_input_parameter?: InputParameter;

/** _Output_ bucket parameters */
/**
* _Output_ bucket parameters.
*
* Each one of these will be present in either lookup_extractors or static_extractors.
*/
bucket_parameters?: string[];

id?: string;
Expand All @@ -188,7 +245,7 @@ export class SqlParameterQuery {
let lookup: SqliteJsonValue[] = [this.descriptor_name!, this.id!];
lookup.push(
...this.input_parameters!.map((param) => {
return filterParamSet[param];
return param.filteredRowToLookupValue(filterParamSet);
})
);

Expand Down Expand Up @@ -216,6 +273,9 @@ export class SqlParameterQuery {
return [result];
}

/**
* Given partial parameter rows, turn into bucket ids.
*/
resolveBucketIds(bucketParameters: SqliteJsonRow[], parameters: SyncParameters): string[] {
const tables = { token_parameters: parameters.token_parameters, user_parameters: parameters.user_parameters };

Expand Down Expand Up @@ -246,28 +306,25 @@ export class SqlParameterQuery {
.filter((lookup) => lookup != null) as string[];
}

lookupParam(param: string, parameters: SyncParameters) {
const [table, column] = param.split('.');
const pt: SqliteJsonRow | undefined = (parameters as any)[table];
return pt?.[column] ?? null;
}

/**
* Given sync parameters, get lookups we need to perform on the database.
*
* Each lookup is [bucket definition name, parameter query index, ...lookup values]
*/
getLookups(parameters: SyncParameters): SqliteJsonValue[][] {
if (!this.expanded_input_parameter) {
let lookup: SqliteJsonValue[] = [this.descriptor_name!, this.id!];

lookup.push(
...this.input_parameters!.map((param): SqliteJsonValue => {
// Scalar value
return this.lookupParam(param, parameters);
return param.parametersToLookupValue(parameters);
})
);
return [lookup];
} else {
const arrayString = this.lookupParam(
this.expanded_input_parameter.substring(0, this.expanded_input_parameter.length - 3),
parameters
);
const arrayString = this.expanded_input_parameter.parametersToLookupValue(parameters);

if (arrayString == null || typeof arrayString != 'string') {
return [];
}
Expand All @@ -291,7 +348,7 @@ export class SqlParameterQuery {
return expandedValue;
} else {
// Scalar value
return this.lookupParam(param, parameters);
return param.parametersToLookupValue(parameters);
}
})
);
Expand All @@ -301,6 +358,14 @@ export class SqlParameterQuery {
}
}

/**
* Given sync parameters (token and user parameters), return bucket ids.
*
* This is done in three steps:
* 1. Given the parameters, get lookups we need to perform on the database.
* 2. Perform the lookups, returning parameter sets (partial rows).
* 3. Given the parameter sets, resolve bucket ids.
*/
async queryBucketIds(options: QueryBucketIdOptions): Promise<string[]> {
let lookups = this.getLookups(options.parameters);
if (lookups.length == 0) {
Expand Down
4 changes: 4 additions & 0 deletions packages/sync-rules/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ export type QueryParameters = { [table: string]: SqliteRow };
* A single set of parameters that would make a WHERE filter true.
*
* Each parameter is prefixed with a table name, e.g. 'bucket.param'.
*
* Data queries: this is converted into a bucket id, given named bucket parameters.
*
* Parameter queries: this is converted into a lookup array.
*/
export type FilterParameters = { [parameter: string]: SqliteJsonValue };

Expand Down

0 comments on commit fc585a6

Please sign in to comment.