Skip to content

Commit 466064f

Browse files
author
devgioele
committed
prototype 2
1 parent d7aaa7b commit 466064f

3 files changed

Lines changed: 79 additions & 43 deletions

File tree

src/useQuery.ts

Lines changed: 63 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { useCallback, useMemo } from 'react'
2+
import { queryValueToIntOrUndefined } from './utils'
23

34
export type Query = Record<string, string | string[]>
45

5-
export type AbstractQueryValue = string | number | boolean
6+
export type AbstractQueryValueElement = string | number | boolean
67

78
export type AbstractQuery = Record<
89
string,
9-
AbstractQueryValue | AbstractQueryValue[]
10+
AbstractQueryValueElement | AbstractQueryValueElement[]
1011
>
1112

1213
/**
@@ -28,11 +29,6 @@ export type Router = {
2829
* If the query is bound to the URL, the router navigates to the new URL.
2930
*/
3031
setQuery: (query: Partial<Query>) => void
31-
32-
/**
33-
* Completely clears the query.
34-
*/
35-
clearQuery: () => void
3632
}
3733

3834
export const useQuery = <T extends Query>(defaultQuery: T, router: Router) => {
@@ -41,90 +37,115 @@ export const useQuery = <T extends Query>(defaultQuery: T, router: Router) => {
4137
[router, defaultQuery]
4238
)
4339

44-
const clearQuery = useCallback(() => router.clearQuery(), [router])
45-
4640
const query = useMemo(() => router.getQuery(), [router])
4741

4842
return {
4943
query,
5044
setQuery: (query: Partial<T>) => router.setQuery(query),
5145
resetQuery,
52-
clearQuery,
5346
}
5447
}
5548

56-
const abstractQueryToQuery = <T extends Partial<AbstractQuery>>(
57-
abstractQuery: T
58-
) => {
59-
const query: Query = {}
60-
for (const [key, value] of Object.entries(abstractQuery)) {
61-
if (value !== undefined) {
62-
query[key] = value.toString()
49+
type AbstractQueryOptions = {
50+
convertToQuery: <T extends Partial<AbstractQuery>>(abstractQuery: T) => Query
51+
}
52+
53+
const DEFAULT_ABSTRACT_QUERY_OPTIONS: AbstractQueryOptions = {
54+
convertToQuery: (abstractQuery) => {
55+
const query: Query = {}
56+
for (const [key, value] of Object.entries(abstractQuery)) {
57+
if (value !== undefined) {
58+
query[key] = value.toString()
59+
}
6360
}
64-
}
65-
return query
61+
return query
62+
},
6663
}
6764

6865
export const useAbstractQuery = <T extends AbstractQuery>(
6966
defaultQuery: T,
67+
parseQuery: ParseQuery<T>,
7068
router: Router,
71-
parse: ParseQuery<T>
69+
options?: Partial<AbstractQueryOptions>
7270
) => {
71+
const mergedOptions = useMemo(
72+
() => ({ ...DEFAULT_ABSTRACT_QUERY_OPTIONS, ...options }),
73+
[options]
74+
)
75+
7376
const convertedDefaultQuery = useMemo(
74-
() => abstractQueryToQuery(defaultQuery),
75-
[defaultQuery]
77+
() => mergedOptions.convertToQuery(defaultQuery),
78+
[mergedOptions, defaultQuery]
7679
)
7780

78-
const { query, setQuery, resetQuery, clearQuery } = useQuery(
81+
const { query, setQuery, resetQuery } = useQuery(
7982
convertedDefaultQuery,
8083
router
8184
)
8285

83-
const parsedQuery = useMemo(() => {
86+
const parsedQuery: T = useMemo(() => {
8487
let parsed: Partial<T>
8588
try {
86-
parsed = parse(query)
89+
parsed = parseQuery(query)
8790
} catch (e) {
8891
parsed = {}
8992
}
9093
return {
9194
...defaultQuery,
9295
...parsed,
9396
}
94-
}, [defaultQuery, parse, query])
97+
}, [defaultQuery, parseQuery, query])
9598

9699
const setAbstractQuery = useCallback(
97-
(query: Partial<T>) => setQuery(abstractQueryToQuery(query)),
98-
[setQuery]
100+
(query: Partial<T>) => setQuery(mergedOptions.convertToQuery(query)),
101+
[setQuery, mergedOptions]
99102
)
100103

101104
return {
102105
query: parsedQuery,
103106
setQuery: setAbstractQuery,
104107
resetQuery,
105-
clearQuery,
106108
}
107109
}
108110

109111
export type PaginationQuery = { page: number; size: number }
110112

111-
export const usePagination = (
112-
defaultQuery: PaginationQuery,
113-
router: Router,
114-
parse: ParseQuery<PaginationQuery>
113+
const parsePagination = (query: Query): Partial<PaginationQuery> => {
114+
return {
115+
page: queryValueToIntOrUndefined(query.page),
116+
size: queryValueToIntOrUndefined(query.size),
117+
}
118+
}
119+
120+
export const useQueryAndPagination = <T extends AbstractQuery>(
121+
defaultQuery: T,
122+
parseQuery: ParseQuery<T>,
123+
defaultPagination: PaginationQuery,
124+
router: Router
115125
) => {
116-
const { query, setQuery, resetQuery, clearQuery } = useAbstractQuery(
126+
const { query, setQuery, resetQuery } = useAbstractQuery(
117127
defaultQuery,
118-
router,
119-
parse
128+
parseQuery,
129+
router
120130
)
121131

132+
const {
133+
query: pagination,
134+
setQuery: setPagination,
135+
resetQuery: resetPagination,
136+
} = useAbstractQuery(defaultPagination, parsePagination, router)
137+
122138
return {
123-
page: query.page,
124-
size: query.size,
125-
setSize: (size: PaginationQuery['size']) => setQuery({ size }),
126-
setPage: (page: PaginationQuery['page']) => setQuery({ page }),
127-
resetPagination: resetQuery,
128-
clearQuery,
139+
query,
140+
setQuery,
141+
resetQuery,
142+
page: pagination.page,
143+
size: pagination.size,
144+
setPage: (page: PaginationQuery['page']) => setPagination({ page }),
145+
setSize: (size: PaginationQuery['size']) => setPagination({ size }),
146+
setPagination,
147+
resetPagination,
148+
resetQueryAndPagination: () =>
149+
setQuery({ ...defaultQuery, ...defaultPagination }),
129150
}
130151
}

src/utils.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
1+
import { Query } from './useQuery'
2+
13
export type NonNullableRecord<
24
T extends Record<string | number | symbol, unknown>
35
> = {
4-
[Key in keyof T]-?: NonNullable<T[Key]>
6+
[Key in keyof T]-?: NonNullable<T[Key]>
7+
}
8+
9+
export const queryValueToIntOrUndefined = (
10+
value: Query[keyof Query] | undefined
11+
): number | undefined => {
12+
if (value === undefined || Array.isArray(value)) {
13+
return undefined
514
}
15+
const parsed = parseInt(value)
16+
if (isNaN(parsed)) {
17+
return undefined
18+
}
19+
return parsed
20+
}

0 commit comments

Comments
 (0)