@powersync/service-sync-rules 0.28.0 → 0.29.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.
- package/LICENSE +3 -3
- package/dist/BaseSqlDataQuery.d.ts +9 -1
- package/dist/BaseSqlDataQuery.js +42 -0
- package/dist/BaseSqlDataQuery.js.map +1 -1
- package/dist/BucketDescription.d.ts +16 -0
- package/dist/BucketParameterQuerier.d.ts +19 -3
- package/dist/BucketParameterQuerier.js.map +1 -1
- package/dist/BucketSource.d.ts +72 -0
- package/dist/BucketSource.js +6 -0
- package/dist/BucketSource.js.map +1 -0
- package/dist/ExpressionType.d.ts +1 -0
- package/dist/ExpressionType.js.map +1 -1
- package/dist/SqlBucketDescriptor.d.ts +40 -8
- package/dist/SqlBucketDescriptor.js +78 -10
- package/dist/SqlBucketDescriptor.js.map +1 -1
- package/dist/SqlDataQuery.d.ts +4 -3
- package/dist/SqlDataQuery.js +10 -30
- package/dist/SqlDataQuery.js.map +1 -1
- package/dist/SqlParameterQuery.d.ts +4 -4
- package/dist/SqlParameterQuery.js +9 -4
- package/dist/SqlParameterQuery.js.map +1 -1
- package/dist/SqlSyncRules.d.ts +55 -7
- package/dist/SqlSyncRules.js +126 -47
- package/dist/SqlSyncRules.js.map +1 -1
- package/dist/StaticSqlParameterQuery.d.ts +2 -2
- package/dist/StaticSqlParameterQuery.js +3 -2
- package/dist/StaticSqlParameterQuery.js.map +1 -1
- package/dist/TableValuedFunctionSqlParameterQuery.d.ts +2 -2
- package/dist/TableValuedFunctionSqlParameterQuery.js +11 -10
- package/dist/TableValuedFunctionSqlParameterQuery.js.map +1 -1
- package/dist/TableValuedFunctions.d.ts +2 -2
- package/dist/TableValuedFunctions.js +38 -35
- package/dist/TableValuedFunctions.js.map +1 -1
- package/dist/compatibility.d.ts +39 -0
- package/dist/compatibility.js +54 -0
- package/dist/compatibility.js.map +1 -0
- package/dist/events/SqlEventDescriptor.d.ts +3 -1
- package/dist/events/SqlEventDescriptor.js +4 -2
- package/dist/events/SqlEventDescriptor.js.map +1 -1
- package/dist/events/SqlEventSourceQuery.d.ts +2 -1
- package/dist/events/SqlEventSourceQuery.js +3 -2
- package/dist/events/SqlEventSourceQuery.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/json_schema.js +54 -1
- package/dist/json_schema.js.map +1 -1
- package/dist/request_functions.d.ts +24 -4
- package/dist/request_functions.js +68 -17
- package/dist/request_functions.js.map +1 -1
- package/dist/schema-generators/SchemaGenerator.js +2 -12
- package/dist/schema-generators/SchemaGenerator.js.map +1 -1
- package/dist/sql_filters.d.ts +25 -2
- package/dist/sql_filters.js +223 -119
- package/dist/sql_filters.js.map +1 -1
- package/dist/sql_functions.d.ts +13 -31
- package/dist/sql_functions.js +191 -114
- package/dist/sql_functions.js.map +1 -1
- package/dist/sql_support.d.ts +20 -0
- package/dist/sql_support.js +67 -14
- package/dist/sql_support.js.map +1 -1
- package/dist/streams/filter.d.ts +148 -0
- package/dist/streams/filter.js +426 -0
- package/dist/streams/filter.js.map +1 -0
- package/dist/streams/from_sql.d.ts +4 -0
- package/dist/streams/from_sql.js +375 -0
- package/dist/streams/from_sql.js.map +1 -0
- package/dist/streams/functions.d.ts +2 -0
- package/dist/streams/functions.js +38 -0
- package/dist/streams/functions.js.map +1 -0
- package/dist/streams/parameter.d.ts +67 -0
- package/dist/streams/parameter.js +2 -0
- package/dist/streams/parameter.js.map +1 -0
- package/dist/streams/stream.d.ts +40 -0
- package/dist/streams/stream.js +139 -0
- package/dist/streams/stream.js.map +1 -0
- package/dist/streams/utils.d.ts +1 -0
- package/dist/streams/utils.js +13 -0
- package/dist/streams/utils.js.map +1 -0
- package/dist/streams/variant.d.ts +122 -0
- package/dist/streams/variant.js +266 -0
- package/dist/streams/variant.js.map +1 -0
- package/dist/types/custom_sqlite_value.d.ts +38 -0
- package/dist/types/custom_sqlite_value.js +50 -0
- package/dist/types/custom_sqlite_value.js.map +1 -0
- package/dist/types/time.d.ts +33 -0
- package/dist/types/time.js +67 -0
- package/dist/types/time.js.map +1 -0
- package/dist/types.d.ts +52 -9
- package/dist/types.js +28 -2
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +9 -6
- package/dist/utils.js +42 -17
- package/dist/utils.js.map +1 -1
- package/package.json +3 -3
- package/schema/sync_rules.json +80 -2
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { DEFAULT_BUCKET_PRIORITY } from '../BucketDescription.js';
|
|
2
|
+
import { BucketSourceType } from '../BucketSource.js';
|
|
3
|
+
export class SyncStream {
|
|
4
|
+
name;
|
|
5
|
+
subscribedToByDefault;
|
|
6
|
+
priority;
|
|
7
|
+
variants;
|
|
8
|
+
data;
|
|
9
|
+
constructor(name, data) {
|
|
10
|
+
this.name = name;
|
|
11
|
+
this.subscribedToByDefault = false;
|
|
12
|
+
this.priority = DEFAULT_BUCKET_PRIORITY;
|
|
13
|
+
this.variants = [];
|
|
14
|
+
this.data = data;
|
|
15
|
+
}
|
|
16
|
+
get type() {
|
|
17
|
+
return BucketSourceType.SYNC_STREAM;
|
|
18
|
+
}
|
|
19
|
+
pushBucketParameterQueriers(result, options) {
|
|
20
|
+
const subscriptions = options.streams[this.name] ?? [];
|
|
21
|
+
if (!this.subscribedToByDefault && !subscriptions.length) {
|
|
22
|
+
// The client is not subscribing to this stream, so don't query buckets related to it.
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
let hasExplicitDefaultSubscription = false;
|
|
26
|
+
for (const subscription of subscriptions) {
|
|
27
|
+
let subscriptionParams = options.globalParameters;
|
|
28
|
+
if (subscription.parameters != null) {
|
|
29
|
+
subscriptionParams = subscriptionParams.withAddedStreamParameters(subscription.parameters);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
hasExplicitDefaultSubscription = true;
|
|
33
|
+
}
|
|
34
|
+
this.queriersForSubscription(result, subscription, subscriptionParams, options.bucketIdTransformer);
|
|
35
|
+
}
|
|
36
|
+
// If the stream is subscribed to by default and there is no explicit subscription that would match the default
|
|
37
|
+
// subscription, also include the default querier.
|
|
38
|
+
if (this.subscribedToByDefault && !hasExplicitDefaultSubscription) {
|
|
39
|
+
this.queriersForSubscription(result, null, options.globalParameters, options.bucketIdTransformer);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
queriersForSubscription(result, subscription, params, bucketIdTransformer) {
|
|
43
|
+
const reason = subscription != null ? { subscription: subscription.opaque_id } : 'default';
|
|
44
|
+
const queriers = [];
|
|
45
|
+
try {
|
|
46
|
+
for (const variant of this.variants) {
|
|
47
|
+
const querier = variant.querier(this, reason, params, bucketIdTransformer);
|
|
48
|
+
if (querier) {
|
|
49
|
+
queriers.push(querier);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
result.queriers.push(...queriers);
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
result.errors.push({
|
|
56
|
+
descriptor: this.name,
|
|
57
|
+
message: `Error evaluating bucket ids: ${e.message}`,
|
|
58
|
+
subscription: subscription ?? undefined
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
hasDynamicBucketQueries() {
|
|
63
|
+
return this.variants.some((v) => v.hasDynamicBucketQueries);
|
|
64
|
+
}
|
|
65
|
+
tableSyncsData(table) {
|
|
66
|
+
return this.data.applies(table);
|
|
67
|
+
}
|
|
68
|
+
tableSyncsParameters(table) {
|
|
69
|
+
for (const variant of this.variants) {
|
|
70
|
+
for (const subquery of variant.subqueries) {
|
|
71
|
+
if (subquery.parameterTable.matches(table)) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
getSourceTables() {
|
|
79
|
+
let result = new Set();
|
|
80
|
+
result.add(this.data.sourceTable);
|
|
81
|
+
for (let variant of this.variants) {
|
|
82
|
+
for (const subquery of variant.subqueries) {
|
|
83
|
+
result.add(subquery.parameterTable);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Note: No physical tables for global_parameter_queries
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
resolveResultSets(schema, tables) {
|
|
90
|
+
this.data.resolveResultSets(schema, tables);
|
|
91
|
+
}
|
|
92
|
+
debugRepresentation() {
|
|
93
|
+
return {
|
|
94
|
+
name: this.name,
|
|
95
|
+
type: BucketSourceType[this.type],
|
|
96
|
+
variants: this.variants.map((v) => v.debugRepresentation()),
|
|
97
|
+
data: {
|
|
98
|
+
table: this.data.sourceTable,
|
|
99
|
+
columns: this.data.columnOutputNames()
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
debugWriteOutputTables(result) {
|
|
104
|
+
result[this.data.table] ??= [];
|
|
105
|
+
const r = {
|
|
106
|
+
query: this.data.sql
|
|
107
|
+
};
|
|
108
|
+
result[this.data.table].push(r);
|
|
109
|
+
}
|
|
110
|
+
evaluateParameterRow(sourceTable, row) {
|
|
111
|
+
const result = [];
|
|
112
|
+
for (const variant of this.variants) {
|
|
113
|
+
variant.pushParameterRowEvaluation(result, sourceTable, row);
|
|
114
|
+
}
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
evaluateRow(options) {
|
|
118
|
+
if (!this.data.applies(options.sourceTable)) {
|
|
119
|
+
return [];
|
|
120
|
+
}
|
|
121
|
+
const stream = this;
|
|
122
|
+
const row = {
|
|
123
|
+
sourceTable: options.sourceTable,
|
|
124
|
+
record: options.record
|
|
125
|
+
};
|
|
126
|
+
return this.data.evaluateRowWithOptions({
|
|
127
|
+
table: options.sourceTable,
|
|
128
|
+
row: options.record,
|
|
129
|
+
bucketIds() {
|
|
130
|
+
const bucketIds = [];
|
|
131
|
+
for (const variant of stream.variants) {
|
|
132
|
+
bucketIds.push(...variant.bucketIdsForRow(stream.name, row, options.bucketIdTransformer));
|
|
133
|
+
}
|
|
134
|
+
return bucketIds;
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/streams/stream.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function cartesianProduct<T>(...sets: T[][]): Generator<T[]>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function* cartesianProduct(...sets) {
|
|
2
|
+
if (sets.length == 0) {
|
|
3
|
+
yield [];
|
|
4
|
+
return;
|
|
5
|
+
}
|
|
6
|
+
const [head, ...tail] = sets;
|
|
7
|
+
for (let h of head) {
|
|
8
|
+
const remainder = cartesianProduct(...tail);
|
|
9
|
+
for (let r of remainder)
|
|
10
|
+
yield [h, ...r];
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/streams/utils.ts"],"names":[],"mappings":"AAAA,MAAM,SAAS,CAAC,CAAC,gBAAgB,CAAI,GAAG,IAAW;IACjD,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QACrB,MAAM,EAAE,CAAC;QACT,OAAO;IACT,CAAC;IAED,MAAM,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAC7B,KAAK,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;QACnB,MAAM,SAAS,GAAG,gBAAgB,CAAC,GAAG,IAAI,CAAC,CAAC;QAC5C,KAAK,IAAI,CAAC,IAAI,SAAS;YAAE,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAC3C,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { BucketInclusionReason } from '../BucketDescription.js';
|
|
2
|
+
import { BucketParameterQuerier } from '../BucketParameterQuerier.js';
|
|
3
|
+
import { SourceTableInterface } from '../SourceTableInterface.js';
|
|
4
|
+
import { BucketIdTransformer, EvaluatedParametersResult, RequestParameters, SqliteJsonValue, SqliteRow, TableRow } from '../types.js';
|
|
5
|
+
import { BucketParameter, SubqueryEvaluator } from './parameter.js';
|
|
6
|
+
import { SyncStream } from './stream.js';
|
|
7
|
+
/**
|
|
8
|
+
* A variant of a stream.
|
|
9
|
+
*
|
|
10
|
+
* Variants are introduced on {@link Or} filters, since different sub-filters (with potentially different) bucket
|
|
11
|
+
* parameters can both cause a row to be matched.
|
|
12
|
+
*
|
|
13
|
+
* Consider the query `SELECT * FROM comments WHERE issue_id IN (SELECT id FROM issue WHERE owner_id = request.user()) OR request.is_admin()`.
|
|
14
|
+
* Here, the filter is an or clause matching rows where:
|
|
15
|
+
*
|
|
16
|
+
* - An {@link InOperator} associatates comments in issues owned by the requesting user. This gets implemented with a
|
|
17
|
+
* parameter lookup index mapping `issue.owner_id => issue.id`. `comments.issue_id` is a bucket parameter resolved
|
|
18
|
+
* dynamically.
|
|
19
|
+
* - Or, the user is an admin, in which case all comments are matched. There are no bucket parameters for this
|
|
20
|
+
* variant.
|
|
21
|
+
*
|
|
22
|
+
* The introduction of stream variants allows the `evaluateParameterRow` and `queriersForSubscription` implementations
|
|
23
|
+
* to operate independently.
|
|
24
|
+
*
|
|
25
|
+
* Multiple variants may cause the same row to get synced via different buckets. Depending on the request, users may
|
|
26
|
+
* also receive multiple buckets with the same data. This is not an issue! Clients deduplicate rows received across
|
|
27
|
+
* buckets, so we don't have to filter for this case in the sync service.
|
|
28
|
+
*/
|
|
29
|
+
export declare class StreamVariant {
|
|
30
|
+
id: number;
|
|
31
|
+
parameters: BucketParameter[];
|
|
32
|
+
subqueries: SubqueryEvaluator[];
|
|
33
|
+
/**
|
|
34
|
+
* Additional filters that don't introduce bucket parameters, but can exclude rows.
|
|
35
|
+
*
|
|
36
|
+
* This is introduced for streams like `SELECT * FROM assets WHERE LENGTH(assets.name < 10)`.
|
|
37
|
+
*/
|
|
38
|
+
additionalRowFilters: ((row: TableRow) => boolean)[];
|
|
39
|
+
/**
|
|
40
|
+
* Additional filters that are evaluated against the request of the stream subscription.
|
|
41
|
+
*
|
|
42
|
+
* These filters can either only depend on values in the request alone (e.g. `WHERE token_parameters.is_admin`), or
|
|
43
|
+
* on results from a subquery (e.g. `WHERE request.user_id() IN (SELECT id FROM user WHERE is_admin)`).
|
|
44
|
+
*/
|
|
45
|
+
requestFilters: RequestFilter[];
|
|
46
|
+
constructor(id: number);
|
|
47
|
+
/**
|
|
48
|
+
* Given a row in the table this stream selects from, returns all ids of buckets to which that row belongs to.
|
|
49
|
+
*/
|
|
50
|
+
bucketIdsForRow(streamName: string, options: TableRow, transformer: BucketIdTransformer): string[];
|
|
51
|
+
/**
|
|
52
|
+
* Given a row to evaluate, returns all instantiations of parameters that satisfy conditions.
|
|
53
|
+
*
|
|
54
|
+
* The inner arrays will have a length equal to the amount of parameters in this variant.
|
|
55
|
+
*/
|
|
56
|
+
instantiationsForRow(options: TableRow): SqliteJsonValue[][];
|
|
57
|
+
/**
|
|
58
|
+
* Turns an array of values for each parameter into an array of all instantiations by effectively building the
|
|
59
|
+
* cartesian product of the parameter sets.
|
|
60
|
+
*
|
|
61
|
+
* @param instantiations An array containing values for each parameter.
|
|
62
|
+
* @returns Each instantiation, with each sub-array having a value for a parameter.
|
|
63
|
+
*/
|
|
64
|
+
private cartesianProductOfParameterInstantiations;
|
|
65
|
+
get hasDynamicBucketQueries(): boolean;
|
|
66
|
+
querier(stream: SyncStream, reason: BucketInclusionReason, params: RequestParameters, bucketIdTransformer: BucketIdTransformer): BucketParameterQuerier | null;
|
|
67
|
+
findStaticInstantiations(params: RequestParameters): SqliteJsonValue[][];
|
|
68
|
+
/**
|
|
69
|
+
* Creates lookup indices for dynamically-resolved parameters.
|
|
70
|
+
*
|
|
71
|
+
* Resolving dynamic parameters is a two-step process: First, for tables referenced in subqueries, we create an index
|
|
72
|
+
* to resolve which request parameters would match rows in subqueries. Then, when resolving bucket ids for a request,
|
|
73
|
+
* we compute subquery results by looking up results in that index.
|
|
74
|
+
*
|
|
75
|
+
* This implements the first step of that process.
|
|
76
|
+
*
|
|
77
|
+
* @param result The array into which evaluation results should be written to.
|
|
78
|
+
* @param sourceTable A table we depend on in a subquery.
|
|
79
|
+
* @param row Row data to index.
|
|
80
|
+
*/
|
|
81
|
+
pushParameterRowEvaluation(result: EvaluatedParametersResult[], sourceTable: SourceTableInterface, row: SqliteRow): void;
|
|
82
|
+
debugRepresentation(): any;
|
|
83
|
+
/**
|
|
84
|
+
* Replaces {@link StreamVariant.parameters} with static values looked up in request parameters.
|
|
85
|
+
*
|
|
86
|
+
* Dynamic parameters that depend on subquery results are not replaced.
|
|
87
|
+
* This returns null if there's a {@link StaticRequestFilter} that doesn't match the request.
|
|
88
|
+
*/
|
|
89
|
+
private partiallyEvaluateParameters;
|
|
90
|
+
/**
|
|
91
|
+
* Builds a bucket id for an instantiation, like `stream|0[1,2,"foo"]`.
|
|
92
|
+
*
|
|
93
|
+
* @param streamName The name of the stream, included in the bucket id
|
|
94
|
+
* @param instantiation An instantiation for all parameters in this variant.
|
|
95
|
+
* @param transformer A transformer adding version information to the inner id.
|
|
96
|
+
* @returns The generated bucket id
|
|
97
|
+
*/
|
|
98
|
+
private buildBucketId;
|
|
99
|
+
private resolveBucket;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* A stateless filter condition that only depends on the request itself, e.g. `WHERE token_parameters.is_admin`.
|
|
103
|
+
*/
|
|
104
|
+
export interface StaticRequestFilter {
|
|
105
|
+
type: 'static';
|
|
106
|
+
matches(params: RequestParameters): boolean;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* A filter condition that depends on parameters and an evaluated subquery, e.g.
|
|
110
|
+
* `WHERE request.user_id() IN (SELECT id FROM users WHERE ...)`.
|
|
111
|
+
*/
|
|
112
|
+
export interface SubqueryRequestFilter {
|
|
113
|
+
type: 'dynamic';
|
|
114
|
+
subquery: SubqueryEvaluator;
|
|
115
|
+
/**
|
|
116
|
+
* Checks whether the parameter matches values from the subquery.
|
|
117
|
+
*
|
|
118
|
+
* @param results The values that the subquery evaluates to.
|
|
119
|
+
*/
|
|
120
|
+
matches(params: RequestParameters, results: SqliteJsonValue[]): boolean;
|
|
121
|
+
}
|
|
122
|
+
export type RequestFilter = StaticRequestFilter | SubqueryRequestFilter;
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { isJsonValue, JSONBucketNameSerialize } from '../utils.js';
|
|
2
|
+
import { cartesianProduct } from './utils.js';
|
|
3
|
+
/**
|
|
4
|
+
* A variant of a stream.
|
|
5
|
+
*
|
|
6
|
+
* Variants are introduced on {@link Or} filters, since different sub-filters (with potentially different) bucket
|
|
7
|
+
* parameters can both cause a row to be matched.
|
|
8
|
+
*
|
|
9
|
+
* Consider the query `SELECT * FROM comments WHERE issue_id IN (SELECT id FROM issue WHERE owner_id = request.user()) OR request.is_admin()`.
|
|
10
|
+
* Here, the filter is an or clause matching rows where:
|
|
11
|
+
*
|
|
12
|
+
* - An {@link InOperator} associatates comments in issues owned by the requesting user. This gets implemented with a
|
|
13
|
+
* parameter lookup index mapping `issue.owner_id => issue.id`. `comments.issue_id` is a bucket parameter resolved
|
|
14
|
+
* dynamically.
|
|
15
|
+
* - Or, the user is an admin, in which case all comments are matched. There are no bucket parameters for this
|
|
16
|
+
* variant.
|
|
17
|
+
*
|
|
18
|
+
* The introduction of stream variants allows the `evaluateParameterRow` and `queriersForSubscription` implementations
|
|
19
|
+
* to operate independently.
|
|
20
|
+
*
|
|
21
|
+
* Multiple variants may cause the same row to get synced via different buckets. Depending on the request, users may
|
|
22
|
+
* also receive multiple buckets with the same data. This is not an issue! Clients deduplicate rows received across
|
|
23
|
+
* buckets, so we don't have to filter for this case in the sync service.
|
|
24
|
+
*/
|
|
25
|
+
export class StreamVariant {
|
|
26
|
+
id;
|
|
27
|
+
parameters;
|
|
28
|
+
subqueries;
|
|
29
|
+
/**
|
|
30
|
+
* Additional filters that don't introduce bucket parameters, but can exclude rows.
|
|
31
|
+
*
|
|
32
|
+
* This is introduced for streams like `SELECT * FROM assets WHERE LENGTH(assets.name < 10)`.
|
|
33
|
+
*/
|
|
34
|
+
additionalRowFilters;
|
|
35
|
+
/**
|
|
36
|
+
* Additional filters that are evaluated against the request of the stream subscription.
|
|
37
|
+
*
|
|
38
|
+
* These filters can either only depend on values in the request alone (e.g. `WHERE token_parameters.is_admin`), or
|
|
39
|
+
* on results from a subquery (e.g. `WHERE request.user_id() IN (SELECT id FROM user WHERE is_admin)`).
|
|
40
|
+
*/
|
|
41
|
+
requestFilters;
|
|
42
|
+
constructor(id) {
|
|
43
|
+
this.id = id;
|
|
44
|
+
this.parameters = [];
|
|
45
|
+
this.subqueries = [];
|
|
46
|
+
this.additionalRowFilters = [];
|
|
47
|
+
this.requestFilters = [];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Given a row in the table this stream selects from, returns all ids of buckets to which that row belongs to.
|
|
51
|
+
*/
|
|
52
|
+
bucketIdsForRow(streamName, options, transformer) {
|
|
53
|
+
return this.instantiationsForRow(options).map((values) => this.buildBucketId(streamName, values, transformer));
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Given a row to evaluate, returns all instantiations of parameters that satisfy conditions.
|
|
57
|
+
*
|
|
58
|
+
* The inner arrays will have a length equal to the amount of parameters in this variant.
|
|
59
|
+
*/
|
|
60
|
+
instantiationsForRow(options) {
|
|
61
|
+
for (const additional of this.additionalRowFilters) {
|
|
62
|
+
if (!additional(options)) {
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Contains an array of all values satisfying each parameter. So this array has the same length as the amount of
|
|
67
|
+
// parameters, and each nested array has a dynamic length.
|
|
68
|
+
const parameterInstantiations = [];
|
|
69
|
+
for (const parameter of this.parameters) {
|
|
70
|
+
const matching = parameter.filterRow(options);
|
|
71
|
+
if (matching.length == 0) {
|
|
72
|
+
// The final list of bucket ids is the cartesian product of all matching parameters. So if there's no parameter
|
|
73
|
+
// satisfying this value, we know the final list will be empty.
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
parameterInstantiations.push(matching);
|
|
77
|
+
}
|
|
78
|
+
// Combine the map of values like {param_1: [foo, bar], param_2: [baz]} into parameter arrays:
|
|
79
|
+
// [foo, baz], [bar, baz].
|
|
80
|
+
return this.cartesianProductOfParameterInstantiations(parameterInstantiations);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Turns an array of values for each parameter into an array of all instantiations by effectively building the
|
|
84
|
+
* cartesian product of the parameter sets.
|
|
85
|
+
*
|
|
86
|
+
* @param instantiations An array containing values for each parameter.
|
|
87
|
+
* @returns Each instantiation, with each sub-array having a value for a parameter.
|
|
88
|
+
*/
|
|
89
|
+
cartesianProductOfParameterInstantiations(instantiations) {
|
|
90
|
+
return [...cartesianProduct(...instantiations)];
|
|
91
|
+
}
|
|
92
|
+
get hasDynamicBucketQueries() {
|
|
93
|
+
return this.requestFilters.some((f) => f.type == 'dynamic');
|
|
94
|
+
}
|
|
95
|
+
querier(stream, reason, params, bucketIdTransformer) {
|
|
96
|
+
const instantiation = this.partiallyEvaluateParameters(params);
|
|
97
|
+
if (instantiation == null) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
const dynamicRequestFilters = this.requestFilters.filter((f) => f.type == 'dynamic');
|
|
101
|
+
const dynamicParameters = [];
|
|
102
|
+
const subqueryToLookups = new Map();
|
|
103
|
+
for (let i = 0; i < this.parameters.length; i++) {
|
|
104
|
+
const parameter = this.parameters[i];
|
|
105
|
+
const lookup = parameter.lookup;
|
|
106
|
+
if (lookup.type == 'in' || lookup.type == 'overlap') {
|
|
107
|
+
dynamicParameters.push({
|
|
108
|
+
index: i,
|
|
109
|
+
subquery: lookup.subquery
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
for (const subquery of this.subqueries) {
|
|
114
|
+
subqueryToLookups.set(subquery, subquery.lookupsForRequest(params));
|
|
115
|
+
}
|
|
116
|
+
const staticBuckets = [];
|
|
117
|
+
if (dynamicParameters.length == 0 && dynamicRequestFilters.length == 0) {
|
|
118
|
+
// When we have no dynamic parameters, the partial evaluation is a full instantiation.
|
|
119
|
+
const instantiations = this.cartesianProductOfParameterInstantiations(instantiation);
|
|
120
|
+
for (const instantiation of instantiations) {
|
|
121
|
+
staticBuckets.push(this.resolveBucket(stream, instantiation, reason, bucketIdTransformer));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const variant = this;
|
|
125
|
+
return {
|
|
126
|
+
staticBuckets: staticBuckets,
|
|
127
|
+
hasDynamicBuckets: this.subqueries.length != 0,
|
|
128
|
+
parameterQueryLookups: [...subqueryToLookups.values()].flatMap((f) => f),
|
|
129
|
+
async queryDynamicBucketDescriptions(source) {
|
|
130
|
+
// Evaluate subqueries
|
|
131
|
+
const subqueryResults = new Map();
|
|
132
|
+
for (const [subquery, lookups] of subqueryToLookups.entries()) {
|
|
133
|
+
const rows = await source.getParameterSets(lookups);
|
|
134
|
+
// The result column used in parameter sets is always named result, see pushParameterRowEvaluation
|
|
135
|
+
const values = rows.map((r) => r.result);
|
|
136
|
+
subqueryResults.set(subquery, values);
|
|
137
|
+
}
|
|
138
|
+
// Check if we have a subquery-based request filter rejecting the row.
|
|
139
|
+
for (const filter of dynamicRequestFilters) {
|
|
140
|
+
if (!filter.matches(params, subqueryResults.get(filter.subquery))) {
|
|
141
|
+
return [];
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const perParameterInstantiation = [];
|
|
145
|
+
for (const parameter of instantiation) {
|
|
146
|
+
if (Array.isArray(parameter)) {
|
|
147
|
+
// Statically-resolved values
|
|
148
|
+
perParameterInstantiation.push(parameter);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
// to be instantiated with dynamic lookup
|
|
152
|
+
perParameterInstantiation.push([parameter]);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
for (const lookup of dynamicParameters) {
|
|
156
|
+
perParameterInstantiation[lookup.index] = subqueryResults.get(lookup.subquery);
|
|
157
|
+
}
|
|
158
|
+
const product = variant.cartesianProductOfParameterInstantiations(perParameterInstantiation);
|
|
159
|
+
return Promise.resolve(product.map((e) => variant.resolveBucket(stream, e, reason, bucketIdTransformer)));
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
findStaticInstantiations(params) {
|
|
164
|
+
if (this.subqueries.length) {
|
|
165
|
+
return [];
|
|
166
|
+
}
|
|
167
|
+
// This will be an array of values (i.e. a total evaluation) because there are no dynamic parameters.
|
|
168
|
+
return this.partiallyEvaluateParameters(params);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Creates lookup indices for dynamically-resolved parameters.
|
|
172
|
+
*
|
|
173
|
+
* Resolving dynamic parameters is a two-step process: First, for tables referenced in subqueries, we create an index
|
|
174
|
+
* to resolve which request parameters would match rows in subqueries. Then, when resolving bucket ids for a request,
|
|
175
|
+
* we compute subquery results by looking up results in that index.
|
|
176
|
+
*
|
|
177
|
+
* This implements the first step of that process.
|
|
178
|
+
*
|
|
179
|
+
* @param result The array into which evaluation results should be written to.
|
|
180
|
+
* @param sourceTable A table we depend on in a subquery.
|
|
181
|
+
* @param row Row data to index.
|
|
182
|
+
*/
|
|
183
|
+
pushParameterRowEvaluation(result, sourceTable, row) {
|
|
184
|
+
for (const subquery of this.subqueries) {
|
|
185
|
+
if (subquery.parameterTable.matches(sourceTable)) {
|
|
186
|
+
const lookups = subquery.lookupsForParameterRow(sourceTable, row);
|
|
187
|
+
if (lookups == null) {
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
// The row of the subquery. Since we only support subqueries with a single column, we unconditionally name the
|
|
191
|
+
// column `result` for simplicity.
|
|
192
|
+
const resultRow = { result: lookups.value };
|
|
193
|
+
result.push(...lookups.lookups.map((l) => ({
|
|
194
|
+
lookup: l,
|
|
195
|
+
bucketParameters: [resultRow]
|
|
196
|
+
})));
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
debugRepresentation() {
|
|
201
|
+
return {
|
|
202
|
+
id: this.id,
|
|
203
|
+
parameters: this.parameters.map((p) => ({
|
|
204
|
+
type: p.lookup.type
|
|
205
|
+
})),
|
|
206
|
+
subqueries: this.subqueries.map((s) => ({
|
|
207
|
+
table: s.parameterTable
|
|
208
|
+
})),
|
|
209
|
+
additional_row_filters: this.additionalRowFilters.length,
|
|
210
|
+
request_filters: this.requestFilters.map((f) => f.type)
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Replaces {@link StreamVariant.parameters} with static values looked up in request parameters.
|
|
215
|
+
*
|
|
216
|
+
* Dynamic parameters that depend on subquery results are not replaced.
|
|
217
|
+
* This returns null if there's a {@link StaticRequestFilter} that doesn't match the request.
|
|
218
|
+
*/
|
|
219
|
+
partiallyEvaluateParameters(params) {
|
|
220
|
+
for (const filter of this.requestFilters) {
|
|
221
|
+
if (filter.type == 'static' && !filter.matches(params)) {
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
const instantiation = [];
|
|
226
|
+
for (const parameter of this.parameters) {
|
|
227
|
+
const lookup = parameter.lookup;
|
|
228
|
+
if (lookup.type == 'static') {
|
|
229
|
+
const values = lookup.fromRequest(params)?.filter(isJsonValue);
|
|
230
|
+
if (values.length == 0) {
|
|
231
|
+
// Parameter not instantiable for this request. Since parameters in a single variant form a conjunction, that
|
|
232
|
+
// means the whole request won't find anything here.
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
instantiation.push(values);
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
instantiation.push(parameter);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return instantiation;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Builds a bucket id for an instantiation, like `stream|0[1,2,"foo"]`.
|
|
245
|
+
*
|
|
246
|
+
* @param streamName The name of the stream, included in the bucket id
|
|
247
|
+
* @param instantiation An instantiation for all parameters in this variant.
|
|
248
|
+
* @param transformer A transformer adding version information to the inner id.
|
|
249
|
+
* @returns The generated bucket id
|
|
250
|
+
*/
|
|
251
|
+
buildBucketId(streamName, instantiation, transformer) {
|
|
252
|
+
if (instantiation.length != this.parameters.length) {
|
|
253
|
+
throw Error('Internal error, instantiation length mismatch');
|
|
254
|
+
}
|
|
255
|
+
return transformer(`${streamName}|${this.id}${JSONBucketNameSerialize.stringify(instantiation)}`);
|
|
256
|
+
}
|
|
257
|
+
resolveBucket(stream, instantiation, reason, bucketIdTransformer) {
|
|
258
|
+
return {
|
|
259
|
+
definition: stream.name,
|
|
260
|
+
inclusion_reasons: [reason],
|
|
261
|
+
bucket: this.buildBucketId(stream.name, instantiation, bucketIdTransformer),
|
|
262
|
+
priority: stream.priority
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=variant.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"variant.js","sourceRoot":"","sources":["../../src/streams/variant.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { CompatibilityContext } from '../compatibility.js';
|
|
2
|
+
import { SqliteValue } from '../types.js';
|
|
3
|
+
import { SqliteValueType } from '../ExpressionType.js';
|
|
4
|
+
/**
|
|
5
|
+
* A value that decays into a {@link SqliteValue} in a context-specific way.
|
|
6
|
+
*
|
|
7
|
+
* This is used to conditionally render some values in different formats depending on compatibility options. For
|
|
8
|
+
* instance, old versions of the sync service used to [encode timestamp values incorrectly](https://github.com/powersync-ja/powersync-service/issues/286).
|
|
9
|
+
* To fix this without breaking backwards-compatibility, we now represent timestamp values as a {@link CustomSqliteValue}
|
|
10
|
+
* subtype where `toSqliteValue` returns the old or the new format depending on options.
|
|
11
|
+
*
|
|
12
|
+
* Instances of {@link CustomSqliteValue} are always temporary structures that aren't persisted. They are created by the
|
|
13
|
+
* replicator implementations, the sync rule implementation will invoke {@link toSqliteValue} to ensure that an
|
|
14
|
+
* {@link EvaluatedRow} only consists of proper SQLite values.
|
|
15
|
+
*/
|
|
16
|
+
export declare abstract class CustomSqliteValue {
|
|
17
|
+
/**
|
|
18
|
+
* Renders this custom value into a {@link SqliteValue}.
|
|
19
|
+
*
|
|
20
|
+
* @param context The current compatibility options.
|
|
21
|
+
*/
|
|
22
|
+
abstract toSqliteValue(context: CompatibilityContext): SqliteValue;
|
|
23
|
+
abstract get sqliteType(): SqliteValueType;
|
|
24
|
+
}
|
|
25
|
+
export declare class CustomArray extends CustomSqliteValue {
|
|
26
|
+
private readonly elements;
|
|
27
|
+
private readonly map;
|
|
28
|
+
constructor(elements: any[], map: (element: any, context: CompatibilityContext) => void);
|
|
29
|
+
get sqliteType(): SqliteValueType;
|
|
30
|
+
toSqliteValue(context: CompatibilityContext): SqliteValue;
|
|
31
|
+
}
|
|
32
|
+
export declare class CustomObject extends CustomSqliteValue {
|
|
33
|
+
private readonly source;
|
|
34
|
+
private readonly map;
|
|
35
|
+
constructor(source: Record<string, any>, map: (element: any, context: CompatibilityContext) => void);
|
|
36
|
+
get sqliteType(): SqliteValueType;
|
|
37
|
+
toSqliteValue(context: CompatibilityContext): SqliteValue;
|
|
38
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { JSONBig } from '@powersync/service-jsonbig';
|
|
2
|
+
/**
|
|
3
|
+
* A value that decays into a {@link SqliteValue} in a context-specific way.
|
|
4
|
+
*
|
|
5
|
+
* This is used to conditionally render some values in different formats depending on compatibility options. For
|
|
6
|
+
* instance, old versions of the sync service used to [encode timestamp values incorrectly](https://github.com/powersync-ja/powersync-service/issues/286).
|
|
7
|
+
* To fix this without breaking backwards-compatibility, we now represent timestamp values as a {@link CustomSqliteValue}
|
|
8
|
+
* subtype where `toSqliteValue` returns the old or the new format depending on options.
|
|
9
|
+
*
|
|
10
|
+
* Instances of {@link CustomSqliteValue} are always temporary structures that aren't persisted. They are created by the
|
|
11
|
+
* replicator implementations, the sync rule implementation will invoke {@link toSqliteValue} to ensure that an
|
|
12
|
+
* {@link EvaluatedRow} only consists of proper SQLite values.
|
|
13
|
+
*/
|
|
14
|
+
export class CustomSqliteValue {
|
|
15
|
+
}
|
|
16
|
+
export class CustomArray extends CustomSqliteValue {
|
|
17
|
+
elements;
|
|
18
|
+
map;
|
|
19
|
+
constructor(elements, map) {
|
|
20
|
+
super();
|
|
21
|
+
this.elements = elements;
|
|
22
|
+
this.map = map;
|
|
23
|
+
}
|
|
24
|
+
get sqliteType() {
|
|
25
|
+
return 'text';
|
|
26
|
+
}
|
|
27
|
+
toSqliteValue(context) {
|
|
28
|
+
return JSONBig.stringify(this.elements.map((element) => this.map(element, context)));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export class CustomObject extends CustomSqliteValue {
|
|
32
|
+
source;
|
|
33
|
+
map;
|
|
34
|
+
constructor(source, map) {
|
|
35
|
+
super();
|
|
36
|
+
this.source = source;
|
|
37
|
+
this.map = map;
|
|
38
|
+
}
|
|
39
|
+
get sqliteType() {
|
|
40
|
+
return 'text';
|
|
41
|
+
}
|
|
42
|
+
toSqliteValue(context) {
|
|
43
|
+
let record = {};
|
|
44
|
+
for (let key of Object.keys(this.source)) {
|
|
45
|
+
record[key] = this.map(this.source[key], context);
|
|
46
|
+
}
|
|
47
|
+
return JSONBig.stringify(record);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=custom_sqlite_value.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom_sqlite_value.js","sourceRoot":"","sources":["../../src/types/custom_sqlite_value.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAKrD;;;;;;;;;;;GAWG;AACH,MAAM,OAAgB,iBAAiB;CAStC;AAED,MAAM,OAAO,WAAY,SAAQ,iBAAiB;IAE7B;IACA;IAFnB,YACmB,QAAe,EACf,GAA0D;QAE3E,KAAK,EAAE,CAAC;QAHS,aAAQ,GAAR,QAAQ,CAAO;QACf,QAAG,GAAH,GAAG,CAAuD;IAG7E,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,aAAa,CAAC,OAA6B;QACzC,OAAO,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACvF,CAAC;CACF;AAED,MAAM,OAAO,YAAa,SAAQ,iBAAiB;IAE9B;IACA;IAFnB,YACmB,MAA2B,EAC3B,GAA0D;QAE3E,KAAK,EAAE,CAAC;QAHS,WAAM,GAAN,MAAM,CAAqB;QAC3B,QAAG,GAAH,GAAG,CAAuD;IAG7E,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,aAAa,CAAC,OAA6B;QACzC,IAAI,MAAM,GAAwB,EAAE,CAAC;QACrC,KAAK,IAAI,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACzC,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC;CACF"}
|