Skip to content

Commit

Permalink
feat: wip
Browse files Browse the repository at this point in the history
  • Loading branch information
andresgutgon committed Sep 27, 2024
1 parent df143a2 commit 5d61174
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 100 deletions.
19 changes: 19 additions & 0 deletions packages/core/src/lib/pagination/buildPaginatedUrl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export type QueryParams = { [key: string]: string | string[] | undefined }
export function buildPaginatedUrl({
baseUrl,
page,
limit,
queryParams,
}: {
baseUrl: string
page: number
limit: number
queryParams?: QueryParams
}) {
const queryString = new URLSearchParams({
page: String(page),
limit: String(limit),
...queryParams,
}).toString()
return `${baseUrl}?${queryString}`
}
113 changes: 44 additions & 69 deletions packages/core/src/lib/pagination/buildPagination.ts
Original file line number Diff line number Diff line change
@@ -1,110 +1,85 @@
import { isNumber } from 'lodash-es'
import { buildPaginatedUrl, QueryParams } from './buildPaginatedUrl'

type ItemType = 'page' | 'ellipsis'
type PageItem<T extends ItemType> = T extends 'page'
? { type: T; value: number; url: string }
: { type: T; value: '...' }

export type PaginationArgs = {
page?: number
pageSize?: number
}

export type IPagination = {
count: number
totalPages: number
currentPage: number
prevPage?: PageItem<'page'>
pageItems: (PageItem<'page'> | PageItem<'ellipsis'>)[]
nextPage?: PageItem<'page'>
prevPage?: PageItem<'page'>
}

function buildUrl({
baseUrl,
page,
limit,
function parsePage(page: string | string[] | number | undefined): number {
return typeof page === 'string' ? Number(page) : 1
}

export function getPaginationParamsWithDefaults({
defaultPaginate,
searchParams,
}: {
baseUrl: string
page: number
limit: number
defaultPaginate?: Exclude<PaginationArgs, 'page'>
searchParams?: QueryParams
}) {
return `${baseUrl}?page=${page}&limit=${limit}`
return {
page: parsePage(searchParams?.page),
pageSize: searchParams?.pageSize
? Number(searchParams.pageSize)
: (defaultPaginate?.pageSize ?? 25),
}
}

export function buildPagination({
baseUrl,
count,
queryParams,
page,
pageSize,
pageItemsCount = 10,
}: {
baseUrl: string
count: number
queryParams?: QueryParams
page: number
pageSize: number
pageItemsCount?: number
}) {
const totalPages = Math.ceil(count / pageSize)
const pagination: IPagination = {
return {
count,
totalPages,
currentPage: page,
prevPage:
page > 1
? {
type: 'page',
value: page - 1,
url: buildUrl({ baseUrl, page: page - 1, limit: pageSize }),
}
type: 'page',
value: page - 1,
url: buildPaginatedUrl({
baseUrl,
page: page - 1,
limit: pageSize,
queryParams,
}),
}
: undefined,
pageItems: [],
nextPage:
page < totalPages
? {
type: 'page',
value: page + 1,
url: buildUrl({ baseUrl, page: page + 1, limit: pageSize }),
}
type: 'page',
value: page + 1,
url: buildPaginatedUrl({
baseUrl,
page: page + 1,
limit: pageSize,
queryParams,
}),
}
: undefined,
}

for (let i = page - 1; i >= 1 && pagination.pageItems.length < 2; i--) {
pagination.pageItems.unshift({
type: 'page',
url: buildUrl({ baseUrl, page: i, limit: pageSize }),
value: i,
})
}

const prevItem = pagination.pageItems[0]
const prevPage = isNumber(prevItem?.value) ? prevItem.value : undefined
if (pagination.pageItems.length > 0 && prevPage && prevPage < page - 2) {
pagination.pageItems.push({ type: 'ellipsis', value: '...' })
}

pagination.pageItems.push({
type: 'page',
value: page,
url: buildUrl({ baseUrl, page, limit: pageSize }),
})

for (
let i = page + 1;
i <= totalPages && pagination.pageItems.length < pageItemsCount;
i++
) {
pagination.pageItems.push({
type: 'page',
value: i,
url: buildUrl({ baseUrl, page: i, limit: pageSize }),
})
}

const nextItem = pagination.pageItems[pagination.pageItems.length - 1]
const nextPage = isNumber(nextItem?.value) ? nextItem.value : undefined
if (pagination.pageItems.length > 0 && nextPage && nextPage > page + 1) {
pagination.pageItems.push({ type: 'ellipsis', value: '...' })
}

return pagination
}

export function parsePage(
page: string | string[] | number | undefined,
): number {
return typeof page === 'string' ? Number(page) : 1
}
57 changes: 26 additions & 31 deletions packages/core/src/lib/pagination/paginate.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,12 @@
import { sql, type ColumnsSelection } from 'drizzle-orm'
import type { PgSelect, PgSelectBase } from 'drizzle-orm/pg-core'
import { SelectMode } from 'drizzle-orm/query-builders/select.types'
import { sql } from 'drizzle-orm'
import type { PgSelect } from 'drizzle-orm/pg-core'

import { buildPagination, parsePage } from './buildPagination'

type ISearchParamsObject = { [key: string]: string | string[] | undefined }
type PaginationArgs = {
page?: number
pageSize?: number
pageItemsCount?: number
}

function queryParamsWithDefaults({
defaultPaginate,
searchParams,
}: {
defaultPaginate?: Exclude<PaginationArgs, 'page'>
searchParams?: ISearchParamsObject | undefined
}) {
return {
page: parsePage(searchParams?.page),
pageSize: searchParams?.pageSize
? Number(searchParams.pageSize)
: (defaultPaginate?.pageSize ?? 25),
pageItemsCount: defaultPaginate?.pageItemsCount ?? 10,
}
}
import { QueryParams } from './buildPaginatedUrl'
import {
buildPagination,
getPaginationParamsWithDefaults,
PaginationArgs,
} from './buildPagination'

/**
* This use $dynamic() query
Expand Down Expand Up @@ -58,17 +39,31 @@ export async function paginateQuery<T extends PgSelect>({
searchParams,
defaultPaginate,
}: {
/**
* IMPORTANT:
* You need to use $dynamic() in your query
* Example: `yourQuery.$dynamic()`
*/
dynamicQuery: T
pageUrl?: { base?: string; queryParams?: Record<string, unknown> }
searchParams?: ISearchParamsObject
searchParams?: QueryParams
defaultPaginate?: Exclude<PaginationArgs, 'page'>
}) {
const params = queryParamsWithDefaults({ searchParams, defaultPaginate })
const { rows, count } = await paginateQuerySql({ dynamicQuery, ...params })
const { page, pageSize } = getPaginationParamsWithDefaults({
defaultPaginate,
searchParams,
})
const { rows, count } = await paginateQuerySql({
dynamicQuery,
page,
pageSize,
})
const pagination = buildPagination({
baseUrl: pageUrl?.base ?? '',
count,
...params,
queryParams: searchParams,
page,
pageSize,
})

return { rows, pagination }
Expand Down

0 comments on commit 5d61174

Please sign in to comment.