Skip to content

Commit 1bb8562

Browse files
committed
Start with raw tables API
1 parent 71db1e7 commit 1bb8562

File tree

5 files changed

+103
-10
lines changed

5 files changed

+103
-10
lines changed

packages/common/src/client/AbstractPowerSyncDatabase.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,10 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
469469
* Connects to stream of events from the PowerSync instance.
470470
*/
471471
async connect(connector: PowerSyncBackendConnector, options?: PowerSyncConnectionOptions) {
472-
return this.connectionManager.connect(connector, options);
472+
const resolvedOptions = options ?? {};
473+
resolvedOptions.serializedSchema = this.schema.toJSON();
474+
475+
return this.connectionManager.connect(connector, resolvedOptions);
473476
}
474477

475478
/**

packages/common/src/client/ConnectionManager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ export class ConnectionManager extends BaseObserver<ConnectionManagerListener> {
9595
await this.syncDisposer?.();
9696
}
9797

98-
async connect(connector: PowerSyncBackendConnector, options?: PowerSyncConnectionOptions) {
98+
async connect(connector: PowerSyncBackendConnector, options: PowerSyncConnectionOptions) {
9999
// Keep track if there were pending operations before this call
100100
const hadPendingOptions = !!this.pendingConnectionOptions;
101101

packages/common/src/client/sync/stream/AbstractStreamingSyncImplementation.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ export interface BaseConnectionOptions {
150150
* These parameters are passed to the sync rules, and will be available under the`user_parameters` object.
151151
*/
152152
params?: Record<string, StreamingSyncRequestParameterType>;
153+
154+
/**
155+
* The serialized schema - mainly used to forward information about raw tables to the sync client.
156+
*/
157+
serializedSchema?: any;
153158
}
154159

155160
/** @internal */
@@ -206,7 +211,8 @@ export const DEFAULT_STREAM_CONNECTION_OPTIONS: RequiredPowerSyncConnectionOptio
206211
connectionMethod: SyncStreamConnectionMethod.WEB_SOCKET,
207212
clientImplementation: DEFAULT_SYNC_CLIENT_IMPLEMENTATION,
208213
fetchStrategy: FetchStrategy.Buffered,
209-
params: {}
214+
params: {},
215+
serializedSchema: undefined
210216
};
211217

212218
// The priority we assume when we receive checkpoint lines where no priority is set.
@@ -999,12 +1005,12 @@ The next upload iteration will be delayed.`);
9991005
}
10001006

10011007
try {
1002-
await control(
1003-
PowerSyncControlCommand.START,
1004-
JSON.stringify({
1005-
parameters: resolvedOptions.params
1006-
})
1007-
);
1008+
const options: any = { parameters: resolvedOptions.params };
1009+
if (resolvedOptions.serializedSchema) {
1010+
options.schema = resolvedOptions.serializedSchema;
1011+
}
1012+
1013+
await control(PowerSyncControlCommand.START, JSON.stringify(options));
10081014

10091015
this.notifyCompletedUploads = () => {
10101016
controlInvocations?.enqueueData({ command: PowerSyncControlCommand.NOTIFY_CRUD_UPLOAD_COMPLETED });
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/**
2+
* A pending variant of a {@link RawTable} that doesn't have a name (because it would be inferred when creating the
3+
* schema).
4+
*/
5+
export type RawTableType = {
6+
/**
7+
* The statement to run when PowerSync detects that a row needs to be inserted or updated.
8+
*/
9+
put: PendingStatement;
10+
/**
11+
* The statement to run when PowerSync detects that a row needs to be deleted.
12+
*/
13+
delete: PendingStatement;
14+
};
15+
16+
/**
17+
* A parameter to use as part of {@link PendingStatement}.
18+
*
19+
* For delete statements, only the `"Id"` value is supported - the sync client will replace it with the id of the row to
20+
* be synced.
21+
*
22+
* For insert and replace operations, the values of columns in the table are available as parameters through
23+
* `{Column: 'name'}`.
24+
*/
25+
export type PendingStatementParameter = 'Id' | { Column: string };
26+
27+
/**
28+
* A statement that the PowerSync client should use to insert or delete data into a table managed by the user.
29+
*/
30+
export type PendingStatement = {
31+
sql: string;
32+
params: PendingStatementParameter[];
33+
};
34+
35+
/**
36+
* Instructs PowerSync to sync data into a "raw" table.
37+
*
38+
* Since raw tables are not backed by JSON, running complex queries on them may be more efficient. Further, they allow
39+
* using client-side table and column constraints.
40+
*
41+
* Note that raw tables are only supported when using the new `SyncClientImplementation.rust` sync client.
42+
*
43+
* @experimental Please note that this feature is experimental at the moment, and not covered by PowerSync semver or
44+
* stability guarantees.
45+
*/
46+
export class RawTable implements RawTableType {
47+
/**
48+
* The name of the table.
49+
*
50+
* This does not have to match the actual table name in the schema - {@link put} and {@link delete} are free to use
51+
* another table. Instead, this name is used by the sync client to recognize that operations on this table (as it
52+
* appears in the source / backend database) are to be handled specially.
53+
*/
54+
name: string;
55+
put: PendingStatement;
56+
delete: PendingStatement;
57+
58+
constructor(name: string, type: RawTableType) {
59+
this.name = name;
60+
this.put = type.put;
61+
this.delete = type.delete;
62+
}
63+
}

packages/common/src/db/schema/Schema.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { RawTable, RawTableType } from './RawTable.js';
12
import { RowType, Table } from './Table.js';
23

34
type SchemaType = Record<string, Table<any>>;
@@ -16,6 +17,7 @@ export class Schema<S extends SchemaType = SchemaType> {
1617
readonly types: SchemaTableType<S>;
1718
readonly props: S;
1819
readonly tables: Table[];
20+
readonly rawTables: RawTable[];
1921

2022
constructor(tables: Table[] | S) {
2123
if (Array.isArray(tables)) {
@@ -36,6 +38,24 @@ export class Schema<S extends SchemaType = SchemaType> {
3638
this.props = tables as S;
3739
this.tables = this.convertToClassicTables(this.props);
3840
}
41+
42+
this.rawTables = [];
43+
}
44+
45+
/**
46+
* Adds raw tables to this schema. Raw tables are identified by their name, but entirely managed by the application
47+
* developer instead of automatically by PowerSync.
48+
* Since raw tables are not backed by JSON, running complex queries on them may be more efficient. Further, they allow
49+
* using client-side table and column constraints.
50+
* Note that raw tables are only supported when using the new `SyncClientImplementation.rust` sync client.
51+
*
52+
* @param tables An object of (table name, raw table definition) entries.
53+
* @experimental Note that the raw tables API is still experimental and may change in the future.
54+
*/
55+
withRawTables(tables: Record<string, RawTableType>) {
56+
for (const [name, rawTableDefinition] of Object.entries(tables)) {
57+
this.rawTables.push(new RawTable(name, rawTableDefinition));
58+
}
3959
}
4060

4161
validate() {
@@ -47,7 +67,8 @@ export class Schema<S extends SchemaType = SchemaType> {
4767
toJSON() {
4868
return {
4969
// This is required because "name" field is not present in TableV2
50-
tables: this.tables.map((t) => t.toJSON())
70+
tables: this.tables.map((t) => t.toJSON()),
71+
raw_tables: this.rawTables
5172
};
5273
}
5374

0 commit comments

Comments
 (0)