Skip to content

Commit 40b849c

Browse files
cleanup compatible queries
1 parent 4581a97 commit 40b849c

File tree

6 files changed

+60
-11
lines changed

6 files changed

+60
-11
lines changed

packages/common/src/client/watched/WatchedQuery.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { CompiledQuery } from '../../types/types.js';
12
import { BaseListener, BaseObserverInterface } from '../../utils/BaseObserver.js';
23

34
export interface WatchedQueryState<Data> {
@@ -25,10 +26,16 @@ export interface WatchedQueryState<Data> {
2526
data: Data;
2627
}
2728

29+
/**
30+
* Similar to {@link CompiledQuery}, but used for watched queries.
31+
* The parameters are not read-only, as they can be modified. This is useful for compatibility with
32+
* PowerSync queries.
33+
*/
2834
export interface WatchCompiledQuery {
2935
sql: string;
3036
parameters: any[];
3137
}
38+
3239
/**
3340
*
3441
* @internal
@@ -37,7 +44,7 @@ export interface WatchCompiledQuery {
3744
*/
3845
export interface WatchCompatibleQuery<ResultType> {
3946
execute(compiled: WatchCompiledQuery): Promise<ResultType>;
40-
compile(): WatchCompiledQuery;
47+
compile(): CompiledQuery;
4148
}
4249

4350
/**

packages/common/src/client/watched/processors/OnChangeQueryProcessor.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,12 @@ export class OnChangeQueryProcessor<Data> extends AbstractQueryProcessor<Data> {
8080
const partialStateUpdate: Partial<WatchedQueryState<Data>> = {};
8181

8282
// Always run the query if an underlaying table has changed
83-
const result = await watchOptions.query.execute(compiledQuery);
83+
const result = await watchOptions.query.execute({
84+
sql: compiledQuery.sql,
85+
// Allows casting from ReadOnlyArray[unknown] to Array<unknown>
86+
// This allows simpler compatibility with PowerSync queries
87+
parameters: [...compiledQuery.parameters]
88+
});
8489

8590
if (this.reportFetching) {
8691
partialStateUpdate.isFetching = false;

packages/kysely-driver/tests/sqlite/watch.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,4 +261,38 @@ describe('Watch Tests', () => {
261261
expect(receivedWithManagedOverflowCount).greaterThan(2);
262262
expect(receivedWithManagedOverflowCount).toBeLessThanOrEqual(4);
263263
});
264+
265+
it('incremental watch should accept queries', async () => {
266+
const query = db.selectFrom('assets').select(db.fn.count('assets.id').as('count'));
267+
268+
const watch = powerSyncDb.incrementalWatch({
269+
watch: {
270+
query,
271+
placeholderData: []
272+
}
273+
});
274+
275+
const latestDataPromise = new Promise<Awaited<ReturnType<typeof query.execute>>>((resolve) => {
276+
const dispose = watch.subscribe({
277+
onData: (data) => {
278+
if (data.length > 0) {
279+
resolve(data);
280+
dispose();
281+
}
282+
}
283+
});
284+
});
285+
286+
await db
287+
.insertInto('assets')
288+
.values({
289+
id: sql`uuid()`,
290+
make: 'test',
291+
customer_id: sql`uuid()`
292+
})
293+
.execute();
294+
295+
const data = await latestDataPromise;
296+
expect(data.length).equals(1);
297+
});
264298
});

packages/react/src/hooks/suspense/useSingleSuspenseQuery.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,11 @@ export const useSingleSuspenseQuery = <T = any>(
6464
refresh: async (signal) => {
6565
try {
6666
console.log('calling refresh for single query', key);
67-
const result = await parsedQuery.execute(parsedQuery.compile());
67+
const compiledQuery = parsedQuery.compile();
68+
const result = await parsedQuery.execute({
69+
sql: compiledQuery.sql,
70+
parameters: [...compiledQuery.parameters]
71+
});
6872
if (signal.aborted) {
6973
return; // Abort if the signal is already aborted
7074
}

packages/react/src/hooks/watched/useSingleQuery.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ export const useSingleQuery = <RowType = any>(options: InternalHookOptions<RowTy
1616
async (signal?: AbortSignal) => {
1717
setOutputState((prev) => ({ ...prev, isLoading: true, isFetching: true, error: undefined }));
1818
try {
19-
const result = await query.execute(query.compile());
19+
const compiledQuery = query.compile();
20+
const result = await query.execute({
21+
sql: compiledQuery.sql,
22+
parameters: [...compiledQuery.parameters]
23+
});
2024
if (signal.aborted) {
2125
return;
2226
}

packages/react/src/hooks/watched/watch-utils.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
import {
2-
AbstractPowerSyncDatabase,
3-
CompilableQuery,
4-
WatchCompatibleQuery,
5-
WatchCompiledQuery
6-
} from '@powersync/common';
1+
import { AbstractPowerSyncDatabase, CompilableQuery, CompiledQuery, WatchCompatibleQuery } from '@powersync/common';
72
import React from 'react';
83
import { usePowerSync } from '../PowerSyncContext';
94
import { AdditionalOptions } from './watch-types';
@@ -15,7 +10,7 @@ export type InternalHookOptions<DataType> = {
1510
};
1611

1712
export const checkQueryChanged = <T>(query: WatchCompatibleQuery<T>, options: AdditionalOptions) => {
18-
let _compiled: WatchCompiledQuery;
13+
let _compiled: CompiledQuery;
1914
try {
2015
_compiled = query.compile();
2116
} catch (error) {

0 commit comments

Comments
 (0)