Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
25 changes: 25 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,31 @@ export function UserList() {
}
```

### Example usage with Next.js, zod and no default query

Notice that we let zod take a string and then coerce it to a number. If the coercion fails, we do not stop the whole parsing, but default the property to `undefined`.
This allows us to still use `departmentId` if it is defined while `userId` is not and vice versa.

```tsx
import { useQueryAndPagination } from '@aboutbits/react-pagination/dist/zod/routers/nextRouter'
import { z } from 'zod'

export function Component() {
const { page, size, query, setQuery, setPage, resetQuery } =
useQueryAndPagination(
z.object({
departmentId: z
.string()
.pipe(z.coerce.number().optional())
.catch(undefined),
userId: z.string().pipe(z.coerce.number().optional()).catch(undefined),
}),
)

// ... do something
}
```

### Example usage with React Router and zod

```tsx
Expand Down
2 changes: 1 addition & 1 deletion src/engine/pagination.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const useAbstractQueryAndPagination = <
>(
router: Router,
parseQuery: ParseQuery<TQuery>,
defaultQuery: TDefaultQuery,
defaultQuery: TDefaultQuery = {} as TDefaultQuery,
defaultPagination?: Partial<PaginationQuery>,
options?: Partial<AbstractQueryOptions>,
) => {
Expand Down
8 changes: 4 additions & 4 deletions src/engine/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ export type Router = {
}

export type RouterSSR = Router & {
isReady: boolean
isQueryReady: boolean
}

export const useQuery = <T extends Query>(router: Router, defaultQuery: T) => {
export const useQuery = (router: Router, defaultQuery: Query) => {
const resetQuery = useCallback(() => {
router.setQuery(defaultQuery, defaultQuery)
}, [router, defaultQuery])
Expand All @@ -47,7 +47,7 @@ export const useQuery = <T extends Query>(router: Router, defaultQuery: T) => {

return {
query,
setQuery: (query: Partial<T>) => {
setQuery: (query: Query) => {
router.setQuery(query, defaultQuery)
},
resetQuery,
Expand Down Expand Up @@ -81,7 +81,7 @@ export const useAbstractQuery = <
>(
router: Router,
parseQuery: ParseQuery<TQuery>,
defaultQuery: TDefaultQuery,
defaultQuery: TDefaultQuery = {} as TDefaultQuery,
options?: Partial<AbstractQueryOptions>,
) => {
const mergedOptions = useMemo(
Expand Down
63 changes: 62 additions & 1 deletion src/routers/__test__/nextRouter.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { act, renderHook } from '@testing-library/react'
import router from 'next/router'
import { z } from 'zod'
import { vi } from 'vitest'
import { expectTypeOf, vi } from 'vitest'
import { useQuery, useQueryAndPagination } from '../../zod/routers/nextRouter'
import { usePagination } from '../nextRouter'

Expand Down Expand Up @@ -82,11 +82,68 @@ describe('NextRouter', () => {
})

expect(result.current.query.search).toBe(search)
expectTypeOf(result.current.query.search).toEqualTypeOf<string>()
expect(router.query.search).toBe(search)
expect(result.current.page).toBe(0)
expect(router.query.page).toBeUndefined()
})

test('passing no default query should return query values that are possibly undefined', () => {
const { result: resultQueryAndPagination } = renderHook(() =>
useQueryAndPagination(searchSchema),
)
expectTypeOf(resultQueryAndPagination.current.query.search).toEqualTypeOf<
string | undefined
>()

const { result: resultQuery } = renderHook(() => useQuery(searchSchema))
expectTypeOf(resultQuery.current.query.search).toEqualTypeOf<
string | undefined
>()
})

test('passing a default query should return query values that are not undefined', () => {
const { result: resultQueryAndPagination } = renderHook(() =>
useQueryAndPagination(searchSchema, { search: '' }),
)
expectTypeOf(
resultQueryAndPagination.current.query.search,
).toEqualTypeOf<string>()

const { result: resultQuery } = renderHook(() =>
useQuery(searchSchema, { search: '' }),
)
expectTypeOf(resultQuery.current.query.search).toEqualTypeOf<string>()

const { result: resultPagination } = renderHook(() => usePagination())
expectTypeOf(resultPagination.current.page).toEqualTypeOf<number>()
})

test('passing a partial default query should return the default query values as not undefined and the remaining query values as possibly undefined', () => {
const querySchema = z.object({
role: z.string(),
name: z.string(),
})

const { result: resultQueryAndPagination } = renderHook(() =>
useQueryAndPagination(querySchema, { role: '' }),
)
expectTypeOf(
resultQueryAndPagination.current.query.role,
).toEqualTypeOf<string>()
expectTypeOf(resultQueryAndPagination.current.query.name).toEqualTypeOf<
string | undefined
>()

const { result: resultQuery } = renderHook(() =>
useQuery(querySchema, { name: '' }),
)
expectTypeOf(resultQuery.current.query.role).toEqualTypeOf<
string | undefined
>()
expectTypeOf(resultQuery.current.query.name).toEqualTypeOf<string>()
})

test('change default parameters', () => {
const page = 1
const size = 10
Expand Down Expand Up @@ -261,6 +318,7 @@ describe('NextRouter', () => {
})

expect(result.current.query.search).toBe(search)
expectTypeOf(result.current.query.search).toEqualTypeOf<string>()
expect(router.query.search).toBe(search)
})

Expand All @@ -270,6 +328,9 @@ describe('NextRouter', () => {
)

expect(result.current.query.department).toBeUndefined()
expectTypeOf(result.current.query.department).toEqualTypeOf<
string | undefined
>()
})

test('the query should be a merge of the default query and the current query', () => {
Expand Down
14 changes: 10 additions & 4 deletions src/routers/inMemory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,24 @@ const useInMemoryRouter = (): Router => {
}
}

export const useQuery = <TQuery extends AbstractQuery>(
export const useQuery = <
TQuery extends AbstractQuery,
TDefaultQuery extends Partial<TQuery>,
>(
parseQuery: ParseQuery<TQuery>,
defaultQuery: Partial<TQuery> = {},
defaultQuery?: TDefaultQuery,
options?: Partial<AbstractQueryOptions>,
) => {
const router = useInMemoryRouter()
return useAbstractQuery(router, parseQuery, defaultQuery, options)
}

export const useQueryAndPagination = <TQuery extends AbstractQuery>(
export const useQueryAndPagination = <
TQuery extends AbstractQuery,
TDefaultQuery extends Partial<TQuery>,
>(
parseQuery: ParseQuery<TQuery>,
defaultQuery: Partial<TQuery> = {},
defaultQuery?: TDefaultQuery,
defaultPagination?: Partial<PaginationQuery>,
options?: Partial<AbstractQueryOptions>,
) => {
Expand Down
24 changes: 15 additions & 9 deletions src/routers/nextRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,23 +55,29 @@ const useNextRouter = (
})
}
},
isReady: nextRouter.isReady,
isQueryReady: nextRouter.isReady,
}
}

export const useQuery = <TQuery extends AbstractQuery>(
export const useQuery = <
TQuery extends AbstractQuery,
TDefaultQuery extends Partial<TQuery>,
>(
parseQuery: ParseQuery<TQuery>,
defaultQuery: Partial<TQuery> = {},
defaultQuery?: TDefaultQuery,
options?: Partial<AbstractQueryOptions & RouterWithHistoryOptions>,
) => {
const router = useNextRouter(options)
const result = useAbstractQuery(router, parseQuery, defaultQuery, options)
return { ...result, queryIsReady: router.isReady }
return { ...result, isQueryReady: router.isQueryReady }
}

export const useQueryAndPagination = <TQuery extends AbstractQuery>(
export const useQueryAndPagination = <
TQuery extends AbstractQuery,
TDefaultQuery extends Partial<TQuery>,
>(
parseQuery: ParseQuery<TQuery>,
defaultQuery: Partial<TQuery> = {},
defaultQuery?: TDefaultQuery,
defaultPagination?: Partial<PaginationQuery>,
options?: Partial<AbstractQueryOptions & RouterWithHistoryOptions>,
) => {
Expand All @@ -83,7 +89,7 @@ export const useQueryAndPagination = <TQuery extends AbstractQuery>(
defaultPagination,
options,
)
return { ...result, queryIsReady: router.isReady }
return { ...result, isQueryReady: router.isQueryReady }
}

export const usePagination = (
Expand All @@ -97,7 +103,7 @@ export const usePagination = (
setSize,
setPagination,
resetPagination,
queryIsReady,
isQueryReady,
} = useQueryAndPagination(() => ({}), {}, defaultPagination, options)
return {
page,
Expand All @@ -106,6 +112,6 @@ export const usePagination = (
setSize,
setPagination,
resetPagination,
queryIsReady,
isQueryReady,
}
}
14 changes: 10 additions & 4 deletions src/routers/reactRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,24 @@ const useReactRouter = (
}
}

export const useQuery = <TQuery extends AbstractQuery>(
export const useQuery = <
TQuery extends AbstractQuery,
TDefaultQuery extends Partial<TQuery>,
>(
parseQuery: ParseQuery<TQuery>,
defaultQuery: Partial<TQuery> = {},
defaultQuery?: TDefaultQuery,
options?: Partial<AbstractQueryOptions & RouterWithHistoryOptions>,
) => {
const router = useReactRouter(options)
return useAbstractQuery(router, parseQuery, defaultQuery, options)
}

export const useQueryAndPagination = <TQuery extends AbstractQuery>(
export const useQueryAndPagination = <
TQuery extends AbstractQuery,
TDefaultQuery extends Partial<TQuery>,
>(
parseQuery: ParseQuery<TQuery>,
defaultQuery: Partial<TQuery> = {},
defaultQuery?: TDefaultQuery,
defaultPagination?: Partial<PaginationQuery>,
options?: Partial<AbstractQueryOptions & RouterWithHistoryOptions>,
) => {
Expand Down
9 changes: 7 additions & 2 deletions src/zod/routers/inMemory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ export const useQuery = <
schemaQuery: TSchema,
defaultQuery: Partial<TQuery> = {},
options?: Partial<AbstractQueryOptions>,
) => useQueryVanilla(zodParser(schemaQuery), defaultQuery, options)
) =>
useQueryVanilla(
zodParser<TQuery, TSchema>(schemaQuery),
defaultQuery,
options,
)

export const useQueryAndPagination = <
TSchema extends z.ZodTypeAny,
Expand All @@ -25,7 +30,7 @@ export const useQueryAndPagination = <
options?: Partial<AbstractQueryOptions>,
) =>
useQueryAndPaginationVanilla(
zodParser(schemaQuery),
zodParser<TQuery, TSchema>(schemaQuery),
defaultQuery,
defaultPagination,
options,
Expand Down
15 changes: 11 additions & 4 deletions src/zod/routers/nextRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,30 @@ import { RouterWithHistoryOptions } from '../../routers/shared'
export const useQuery = <
TSchema extends z.ZodTypeAny,
TQuery extends z.output<TSchema>,
TDefaultQuery extends Partial<TQuery>,
>(
schemaQuery: TSchema,
defaultQuery: Partial<TQuery> = {},
defaultQuery?: TDefaultQuery,
options?: Partial<AbstractQueryOptions & RouterWithHistoryOptions>,
) => useQueryVanilla(zodParser(schemaQuery), defaultQuery, options)
) =>
useQueryVanilla(
zodParser<TQuery, TSchema>(schemaQuery),
defaultQuery,
options,
)

export const useQueryAndPagination = <
TSchema extends z.ZodTypeAny,
TQuery extends z.output<TSchema>,
TDefaultQuery extends Partial<TQuery>,
>(
schemaQuery: TSchema,
defaultQuery: Partial<TQuery> = {},
defaultQuery?: TDefaultQuery,
defaultPagination?: Partial<PaginationQuery>,
options?: Partial<AbstractQueryOptions & RouterWithHistoryOptions>,
) =>
useQueryAndPaginationVanilla(
zodParser(schemaQuery),
zodParser<TQuery, TSchema>(schemaQuery),
defaultQuery,
defaultPagination,
options,
Expand Down
9 changes: 7 additions & 2 deletions src/zod/routers/reactRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ export const useQuery = <
schemaQuery: TSchema,
defaultQuery: Partial<TQuery> = {},
options?: Partial<AbstractQueryOptions & RouterWithHistoryOptions>,
) => useQueryVanilla(zodParser(schemaQuery), defaultQuery, options)
) =>
useQueryVanilla(
zodParser<TQuery, TSchema>(schemaQuery),
defaultQuery,
options,
)

export const useQueryAndPagination = <
TSchema extends z.ZodTypeAny,
Expand All @@ -26,7 +31,7 @@ export const useQueryAndPagination = <
options?: Partial<AbstractQueryOptions & RouterWithHistoryOptions>,
) =>
useQueryAndPaginationVanilla(
zodParser(schemaQuery),
zodParser<TQuery, TSchema>(schemaQuery),
defaultQuery,
defaultPagination,
options,
Expand Down