Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/orange-points-speak.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@powersync/react': patch
'@powersync/vue': patch
---

React and Vue helpers should execute queries from capatible query executor methods. This should allow Kysely queries with plugins to function correctly.
5 changes: 3 additions & 2 deletions packages/react/src/hooks/useQuery.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type SQLWatchOptions, parseQuery, type CompilableQuery, type ParsedQuery } from '@powersync/common';
import { parseQuery, type CompilableQuery, type ParsedQuery, type SQLWatchOptions } from '@powersync/common';
import React from 'react';
import { usePowerSync } from './PowerSyncContext';

Expand Down Expand Up @@ -85,7 +85,8 @@ export const useQuery = <T = any>(
const fetchData = async () => {
setIsFetching(true);
try {
const result = await powerSync.getAll<T>(sqlStatement, queryParameters);
const result =
typeof query == 'string' ? await powerSync.getAll<T>(sqlStatement, queryParameters) : await query.execute();
handleResult(result);
} catch (e) {
console.error('Failed to fetch data:', e);
Expand Down
25 changes: 21 additions & 4 deletions packages/react/tests/useQuery.test.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from 'react';
import * as commonSdk from '@powersync/common';
import { renderHook, waitFor } from '@testing-library/react';
import { vi, describe, expect, it, afterEach } from 'vitest';
import { useQuery } from '../src/hooks/useQuery';
import React from 'react';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { PowerSyncContext } from '../src/hooks/PowerSyncContext';
import * as commonSdk from '@powersync/common';
import { useQuery } from '../src/hooks/useQuery';

const mockPowerSync = {
currentStatus: { status: 'initial' },
Expand Down Expand Up @@ -156,6 +156,23 @@ describe('useQuery', () => {
expect(currentResult.isLoading).toEqual(true);
});

it('should execute compatible queries', async () => {
const wrapper = ({ children }) => (
<PowerSyncContext.Provider value={mockPowerSync as any}>{children}</PowerSyncContext.Provider>
);

const query = () =>
useQuery({
execute: () => [{ test: 'custom' }] as any,
compile: () => ({ sql: 'SELECT * from lists', parameters: [] })
});
const { result } = renderHook(query, { wrapper });

await vi.waitFor(() => {
expect(result.current.data[0]?.test).toEqual('custom');
});
});

// The test returns unhandled errors when run with all the others.
// TODO: Fix the test so that there are no unhandled errors (this may be a vitest or @testing-library/react issue)
it.skip('should show an error if parsing the query results in an error', async () => {
Expand Down
13 changes: 8 additions & 5 deletions packages/vue/src/composables/useQuery.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type SQLWatchOptions, parseQuery, type CompilableQuery, ParsedQuery } from '@powersync/common';
import { type CompilableQuery, ParsedQuery, type SQLWatchOptions, parseQuery } from '@powersync/common';
import { type MaybeRef, type Ref, ref, toValue, watchEffect } from 'vue';
import { usePowerSync } from './powerSync';

Expand Down Expand Up @@ -87,10 +87,10 @@ export const useQuery = <T = any>(
error.value = wrappedError;
};

const _fetchData = async (sql: string, parameters: any[]) => {
const _fetchData = async (executor: () => Promise<T[]>) => {
isFetching.value = true;
try {
const result = await powerSync.value.getAll<T>(sql, parameters);
const result = await executor();
handleResult(result);
} catch (e) {
console.error('Failed to fetch data:', e);
Expand All @@ -104,8 +104,9 @@ export const useQuery = <T = any>(
onCleanup(() => abortController.abort());

let parsedQuery: ParsedQuery;
const queryValue = toValue(query);
try {
parsedQuery = parseQuery(toValue(query), toValue(sqlParameters).map(toValue));
parsedQuery = parseQuery(queryValue, toValue(sqlParameters).map(toValue));
} catch (e) {
console.error('Failed to parse query:', e);
handleError(e);
Expand All @@ -123,7 +124,9 @@ export const useQuery = <T = any>(
return;
}
// Fetch initial data
fetchData = () => _fetchData(sql, parameters);
const executor =
typeof queryValue == 'string' ? () => powerSync.value.getAll<T>(sql, parameters) : () => queryValue.execute();
fetchData = () => _fetchData(executor);
await fetchData();

if (options.runQueryOnce) {
Expand Down
16 changes: 16 additions & 0 deletions packages/vue/tests/useQuery.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,22 @@ describe('useQuery', () => {
expect(isLoading.value).toEqual(false);
});

it('should execute compilable queries', async () => {
vi.spyOn(PowerSync, 'usePowerSync').mockReturnValue(ref(mockPowerSync) as any);

const [{ isLoading, data }] = withSetup(() =>
useQuery({
execute: () => [{ test: 'custom' }] as any,
compile: () => ({ sql: 'SELECT * from lists', parameters: [] })
})
);

expect(isLoading.value).toEqual(true);
await flushPromises();
expect(isLoading.value).toEqual(false);
expect(data.value[0].test).toEqual('custom');
});

it('should set error for compilable query on useQuery parameters', async () => {
vi.spyOn(PowerSync, 'usePowerSync').mockReturnValue(ref(mockPowerSync) as any);

Expand Down
Loading