Skip to content

Commit 860c362

Browse files
Update hook results to be readonly
1 parent 937c1e2 commit 860c362

File tree

6 files changed

+22
-24
lines changed

6 files changed

+22
-24
lines changed

.changeset/tricky-bottles-greet.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@powersync/react': minor
3+
'@powersync/vue': minor
4+
---
5+
6+
[Potentially breaking change] The `useQuery` hook results are now explicitly defined as readonly. These values should not be mutated.

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

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,5 @@ export const useWatchedQuery = <RowType = unknown>(
4141
}
4242
}, [queryChanged]);
4343

44-
const result = useWatchedQuerySubscription(watchedQuery);
45-
return {
46-
...result,
47-
// The Watched Query API returns readonly arrays.
48-
// We need to keep the same reference also.
49-
// This allows compatibility with the hook API.
50-
data: result.data as RowType[]
51-
};
44+
return useWatchedQuerySubscription(watchedQuery);
5245
};

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@ export interface AdditionalOptions<RowType = unknown> extends HookWatchOptions<R
1010
}
1111

1212
export type QueryResult<RowType> = {
13-
data: RowType[];
13+
readonly data: ReadonlyArray<Readonly<RowType>>;
1414
/**
1515
* Indicates the initial loading state (hard loading). Loading becomes false once the first set of results from the watched query is available or an error occurs.
1616
*/
17-
isLoading: boolean;
17+
readonly isLoading: boolean;
1818
/**
1919
* Indicates whether the query is currently fetching data, is true during the initial load and any time when the query is re-evaluating (useful for large queries).
2020
*/
21-
isFetching: boolean;
22-
error: Error | undefined;
21+
readonly isFetching: boolean;
22+
readonly error: Error | undefined;
2323
/**
2424
* Function used to run the query again.
2525
*/

packages/vue/src/composables/useQuery.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@ import { AdditionalOptions, useSingleQuery } from './useSingleQuery';
44
import { useWatchedQuery } from './useWatchedQuery';
55

66
export type WatchedQueryResult<T> = {
7-
data: Ref<T[]>;
7+
readonly data: Ref<ReadonlyArray<Readonly<T>>>;
88
/**
99
* Indicates the initial loading state (hard loading). Loading becomes false once the first set of results from the watched query is available or an error occurs.
1010
*/
11-
isLoading: Ref<boolean>;
11+
readonly isLoading: Ref<boolean>;
1212
/**
1313
* Indicates whether the query is currently fetching data, is true during the initial load and any time when the query is re-evaluating (useful for large queries).
1414
*/
15-
isFetching: Ref<boolean>;
16-
error: Ref<Error | undefined>;
15+
readonly isFetching: Ref<boolean>;
16+
readonly error: Ref<Error | undefined>;
1717
/**
1818
* Function used to run the query again.
1919
*/

packages/vue/src/composables/useSingleQuery.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,16 @@ export interface AdditionalOptions<RowType = unknown> extends Omit<SQLOnChangeOp
1414
}
1515

1616
export type WatchedQueryResult<T> = {
17-
data: Ref<T[]>;
17+
readonly data: Ref<ReadonlyArray<Readonly<T>>>;
1818
/**
1919
* Indicates the initial loading state (hard loading). Loading becomes false once the first set of results from the watched query is available or an error occurs.
2020
*/
21-
isLoading: Ref<boolean>;
21+
readonly isLoading: Ref<boolean>;
2222
/**
2323
* Indicates whether the query is currently fetching data, is true during the initial load and any time when the query is re-evaluating (useful for large queries).
2424
*/
25-
isFetching: Ref<boolean>;
26-
error: Ref<Error | undefined>;
25+
readonly isFetching: Ref<boolean>;
26+
readonly error: Ref<Error | undefined>;
2727
/**
2828
* Function used to run the query again.
2929
*/
@@ -35,7 +35,7 @@ export const useSingleQuery = <T = any>(
3535
sqlParameters: MaybeRef<any[]> = [],
3636
options: AdditionalOptions<T> = {}
3737
): WatchedQueryResult<T> => {
38-
const data = ref<T[]>([]) as Ref<T[]>;
38+
const data = ref<ReadonlyArray<Readonly<T>>>([]) as Ref<ReadonlyArray<Readonly<T>>>;
3939
const error = ref<Error | undefined>(undefined);
4040
const isLoading = ref(true);
4141
const isFetching = ref(true);

packages/vue/src/composables/useWatchedQuery.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export const useWatchedQuery = <T = any>(
88
sqlParameters: MaybeRef<any[]> = [],
99
options: AdditionalOptions<T> = {}
1010
): WatchedQueryResult<T> => {
11-
const data = ref<T[]>([]) as Ref<T[]>;
11+
const data = ref<ReadonlyArray<Readonly<T>>>([]) as Ref<ReadonlyArray<Readonly<T>>>;
1212
const error = ref<Error | undefined>(undefined);
1313
const isLoading = ref(true);
1414
const isFetching = ref(true);
@@ -72,8 +72,7 @@ export const useWatchedQuery = <T = any>(
7272
onStateChange: (state) => {
7373
isLoading.value = state.isLoading;
7474
isFetching.value = state.isFetching;
75-
// The watched query state is readonly
76-
data.value = state.data as T[];
75+
data.value = state.data;
7776
if (state.error) {
7877
const wrappedError = new Error('PowerSync failed to fetch data: ' + state.error.message);
7978
wrappedError.cause = state.error;

0 commit comments

Comments
 (0)