Skip to content

Commit 7a1b457

Browse files
authored
Query class with generic types for query management @boonya.dev/frontend-utils/query (#15)
* Clean up * @boonya.dev/frontend-utils/query
1 parent 37a1b43 commit 7a1b457

File tree

4 files changed

+90
-30
lines changed

4 files changed

+90
-30
lines changed

eslint.config.mjs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as reactHooks from 'eslint-plugin-react-hooks';
22
import {defineConfig} from 'eslint/config';
33
import globals from 'globals';
4-
import importX from 'eslint-plugin-import-x';
4+
import {importX} from 'eslint-plugin-import-x';
55
import js from '@eslint/js';
66
import json from '@eslint/json';
77
import markdown from '@eslint/markdown';
@@ -43,9 +43,7 @@ const tsConfig = ts.config(
4343
);
4444

4545
const importXConfig = [
46-
// eslint-disable-next-line import-x/no-named-as-default-member
4746
importX.flatConfigs.recommended,
48-
// eslint-disable-next-line import-x/no-named-as-default-member
4947
importX.flatConfigs.typescript,
5048
{
5149
files: ['**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}'],
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import Query from './query';
2+
3+
const sumFn = async (...args: number[]) => args.reduce((a, b) => a + b, 0);
4+
5+
describe('constructor', () => {
6+
it('should instantiate valid query object.', () => {
7+
const queryInstance = new Query(sumFn, ['base']);
8+
9+
expect(queryInstance).toEqual({
10+
baseKey: ['base'],
11+
queryFn: sumFn,
12+
getKey: expect.any(Function),
13+
create: expect.any(Function),
14+
});
15+
});
16+
});
17+
18+
describe('getKey', () => {
19+
it('should return a combination of baseKey and arguments.', () => {
20+
const queryInstance = new Query(sumFn, ['sum']);
21+
22+
const actual = queryInstance.getKey(2, 3);
23+
expect(actual).toEqual(['sum', '2', '3']);
24+
});
25+
26+
it.each([
27+
{params: [], expected: ['base']},
28+
{params: [1], expected: ['base', '1']},
29+
{params: [1, 2], expected: ['base', '1', '2']},
30+
{params: [1, 2, 3], expected: ['base', '1', '2', '3']},
31+
])('should return $expected when called with $params', ({params, expected}) => {
32+
const queryInstance = new Query(jest.fn(), ['base']);
33+
const actual = queryInstance.getKey(...params);
34+
expect(actual).toEqual(expected);
35+
});
36+
});
37+
38+
describe('create', () => {
39+
it('should return a query object.', () => {
40+
const queryInstance = new Query(sumFn, ['sum']);
41+
42+
const query = queryInstance.create(2, 3);
43+
expect(query).toEqual({
44+
queryKey: ['sum', '2', '3'],
45+
queryFn: expect.any(Function),
46+
});
47+
});
48+
49+
it.each([
50+
{params: [], expected: 0},
51+
{params: [1], expected: 1},
52+
{params: [1, 2], expected: 3},
53+
{params: [1, 2, 3], expected: 6},
54+
{params: [1, 2, 3, 4], expected: 10},
55+
])('should return $expected when called with $params', ({params, expected}) => {
56+
const sum = new Query(sumFn, ['sum']);
57+
58+
const query = sum.create(...params).queryFn();
59+
expect(query).resolves.toBe(expected);
60+
});
61+
});
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
type QueryKey = [string, ...string[]];
2+
3+
export default class Query<
4+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
5+
QueryFn extends (...params: any[] | never) => any,
6+
Key extends QueryKey = QueryKey,
7+
Params extends unknown[] | never = Parameters<QueryFn>,
8+
Data = ReturnType<QueryFn>,
9+
> {
10+
public queryFn: QueryFn;
11+
public baseKey: Key;
12+
13+
constructor(queryFn: QueryFn, baseKey: Readonly<Key>) {
14+
this.baseKey = baseKey;
15+
this.queryFn = queryFn;
16+
}
17+
18+
public getKey = (...params: Params) => {
19+
return [...this.baseKey, ...params.map(String)] as const;
20+
};
21+
22+
public create = (...params: Params) => {
23+
return {
24+
queryKey: this.getKey(...params),
25+
queryFn: () => this.queryFn(...params) as Data,
26+
};
27+
};
28+
}

replace-scope.sh

Lines changed: 0 additions & 27 deletions
This file was deleted.

0 commit comments

Comments
 (0)