Skip to content

Commit 0a09ee3

Browse files
committed
Added QueryStore tests.
1 parent b891d32 commit 0a09ee3

File tree

4 files changed

+107
-4
lines changed

4 files changed

+107
-4
lines changed

packages/react/src/QueryStore.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
1-
import { AbstractPowerSyncDatabase, CompilableQuery, SQLWatchOptions } from '@powersync/common';
1+
import { AbstractPowerSyncDatabase, SQLWatchOptions } from '@powersync/common';
22
import { Query, WatchedQuery } from './WatchedQuery';
33

4+
export function generateQueryKey(
5+
sqlStatement: string,
6+
parameters: any[],
7+
options: Omit<SQLWatchOptions, 'signal'>
8+
): string {
9+
return `${sqlStatement} -- ${JSON.stringify(parameters)} -- ${JSON.stringify(options)}`;
10+
}
11+
412
export class QueryStore {
513
cache = new Map<string, WatchedQuery>();
614

packages/react/src/hooks/useSuspenseQuery.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import { getQueryStore } from '../QueryStore';
2+
import { generateQueryKey, getQueryStore } from '../QueryStore';
33
import { usePowerSync } from './PowerSyncContext';
44
import { CompilableQuery, ParsedQuery, parseQuery, SQLWatchOptions } from '@powersync/common';
55
import { WatchedQuery } from '../WatchedQuery';
@@ -23,7 +23,7 @@ export const useSuspenseQuery = <T = any>(
2323
} catch (error) {
2424
throw new Error('Failed to parse query: ' + error.message);
2525
}
26-
const key = `${parsedQuery.sqlStatement} -- ${JSON.stringify(parsedQuery.parameters)} -- ${JSON.stringify(options)}`;
26+
const key = generateQueryKey(parsedQuery.sqlStatement, parsedQuery.parameters, options);
2727

2828
// When the component is suspended, all state is discarded. We don't get
2929
// any notification of that. So checkoutQuery reserves a temporary hold
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { beforeEach, describe, expect, it, vi } from 'vitest';
2+
import { generateQueryKey, getQueryStore, QueryStore } from '../src/QueryStore';
3+
import { AbstractPowerSyncDatabase, SQLWatchOptions } from '@powersync/common';
4+
5+
describe('QueryStore', () => {
6+
describe('generateQueryKey', () => {
7+
it('should generate the correct key for given inputs', () => {
8+
const sqlStatement = 'SELECT * FROM users WHERE id = ?';
9+
const parameters = [1];
10+
const options: SQLWatchOptions = { tables: ['users'] };
11+
12+
const key = generateQueryKey(sqlStatement, parameters, options);
13+
expect(key).toBe('SELECT * FROM users WHERE id = ? -- [1] -- {"tables":["users"]}');
14+
});
15+
16+
it('should generate different keys for different parameters', () => {
17+
const sqlStatement = 'SELECT * FROM users WHERE id = ?';
18+
const parameters1 = [1];
19+
const parameters2 = [2];
20+
const options = {};
21+
22+
const key1 = generateQueryKey(sqlStatement, parameters1, options);
23+
const key2 = generateQueryKey(sqlStatement, parameters2, options);
24+
25+
expect(key1).not.toBe(key2);
26+
});
27+
28+
it('should generate different keys for different options', () => {
29+
const sqlStatement = 'SELECT * FROM users WHERE id = ?';
30+
const parameters = [1];
31+
const options1: SQLWatchOptions = { tables: ['users'] };
32+
const options2: SQLWatchOptions = { tables: ['local_users'] };
33+
34+
const key1 = generateQueryKey(sqlStatement, parameters, options1);
35+
const key2 = generateQueryKey(sqlStatement, parameters, options2);
36+
37+
expect(key1).not.toBe(key2);
38+
});
39+
});
40+
});
41+
42+
describe('QueryStore', () => {
43+
let db: AbstractPowerSyncDatabase;
44+
let store: QueryStore;
45+
let query: any;
46+
let options: SQLWatchOptions;
47+
48+
beforeEach(() => {
49+
db = createMockDatabase();
50+
store = new QueryStore(db);
51+
query = {};
52+
options = {};
53+
});
54+
55+
it('should return cached query if available', () => {
56+
const key = 'test-key';
57+
const watchedQuery1 = store.getQuery(key, query, options);
58+
const watchedQuery2 = store.getQuery(key, query, options);
59+
60+
expect(watchedQuery1).toBe(watchedQuery2);
61+
});
62+
63+
it('should create new query if not cached', () => {
64+
const key1 = 'test-key-1';
65+
const key2 = 'test-key-2';
66+
67+
const watchedQuery1 = store.getQuery(key1, query, options);
68+
const watchedQuery2 = store.getQuery(key2, query, options);
69+
70+
expect(watchedQuery1).not.toBe(watchedQuery2);
71+
});
72+
});
73+
74+
describe('getQueryStore', () => {
75+
it('should return the same store for the same database', () => {
76+
const db = createMockDatabase();
77+
const store1 = getQueryStore(db);
78+
const store2 = getQueryStore(db);
79+
80+
expect(store1).toBe(store2);
81+
});
82+
83+
it('should return different stores for different databases', () => {
84+
const db1 = createMockDatabase();
85+
const db2 = createMockDatabase();
86+
const store1 = getQueryStore(db1);
87+
const store2 = getQueryStore(db2);
88+
89+
expect(store1).not.toBe(store2);
90+
});
91+
});
92+
93+
function createMockDatabase() {
94+
return {} as AbstractPowerSyncDatabase;
95+
}

packages/react/tests/useQuery.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as commonSdk from '@powersync/common';
22
import { cleanup, renderHook, waitFor } from '@testing-library/react';
33
import React from 'react';
4-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
4+
import { beforeEach, describe, expect, it, vi } from 'vitest';
55
import { PowerSyncContext } from '../src/hooks/PowerSyncContext';
66
import { useQuery } from '../src/hooks/useQuery';
77

0 commit comments

Comments
 (0)