-
Notifications
You must be signed in to change notification settings - Fork 98
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: allow unpaginated request #406
Changes from 6 commits
8b9bfd6
7166dd1
d5d624b
b5a8f3e
75678f3
bbaa922
cbd008e
a94d67a
f6216f3
50652c6
e918283
3da1b75
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,4 @@ lib/ | |
coverage/ | ||
.DS_Store | ||
npm-debug.log | ||
.history |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -171,16 +171,31 @@ function parseFilter<T>(query: PaginateQuery, config: PaginateConfig<T>) { | |
return filter | ||
} | ||
|
||
export const DEFAULT_MAX_LIMIT = 100 | ||
export const DEFAULT_LIMIT = 20 | ||
export const NO_PAGINATION = 0 | ||
|
||
const positiveNumberOrDefault = (value: number | undefined, defaultValue: number, minValue: 0 | 1 = 0) => | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. move to |
||
value === undefined || value < minValue ? defaultValue : value | ||
|
||
export async function paginate<T extends ObjectLiteral>( | ||
query: PaginateQuery, | ||
repo: Repository<T> | SelectQueryBuilder<T>, | ||
config: PaginateConfig<T> | ||
): Promise<Paginated<T>> { | ||
let page = query.page || 1 | ||
const limit = Math.min(query.limit || config.defaultLimit || 20, config.maxLimit || 100) | ||
const page = positiveNumberOrDefault(query.page, 1, 1) | ||
|
||
const defaultLimit = config.defaultLimit || DEFAULT_LIMIT | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
let's untangle this a bit and add const defaultLimit = config.defaultLimit || DEFAULT_LIMIT
const maxLimit = positiveNumberOrDefault(config.maxLimit, DEFAULT_MAX_LIMIT, 0)
const queryLimit = positiveNumberOrDefault(query.limit, defaultLimit, 0)
const isPaginated = !(queryLimit === NO_PAGINATION && maxLimit === NO_PAGINATION)
const limit = isPaginated ? Math.min(queryLimit, maxLimit || DEFAULT_MAX_LIMIT) : NO_PAGINATION |
||
const maxLimit = positiveNumberOrDefault(config.maxLimit, DEFAULT_MAX_LIMIT, 0) | ||
const qLimit = positiveNumberOrDefault(query.limit, defaultLimit, 0) | ||
const limit = | ||
qLimit == NO_PAGINATION && maxLimit == NO_PAGINATION | ||
? NO_PAGINATION | ||
: Math.min(qLimit || defaultLimit, maxLimit || DEFAULT_MAX_LIMIT) | ||
|
||
const sortBy = [] as SortBy<T> | ||
const searchBy: Column<T>[] = [] | ||
let path | ||
let path: string | ||
|
||
const r = new RegExp('^(?:[a-z+]+:)?//', 'i') | ||
let queryOrigin = '' | ||
|
@@ -234,19 +249,12 @@ export async function paginate<T extends ObjectLiteral>( | |
} | ||
} | ||
|
||
if (page < 1) page = 1 | ||
|
||
let [items, totalItems]: [T[], number] = [[], 0] | ||
|
||
let queryBuilder: SelectQueryBuilder<T> | ||
const queryBuilder = repo instanceof Repository ? repo.createQueryBuilder('e') : repo | ||
|
||
if (repo instanceof Repository) { | ||
queryBuilder = repo | ||
.createQueryBuilder('e') | ||
.take(limit) | ||
.skip((page - 1) * limit) | ||
} else { | ||
queryBuilder = repo.take(limit).skip((page - 1) * limit) | ||
if (limit) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use |
||
queryBuilder.take(limit).skip((page - 1) * limit) | ||
} | ||
|
||
if (config.relations?.length) { | ||
|
@@ -362,9 +370,6 @@ export async function paginate<T extends ObjectLiteral>( | |
|
||
;[items, totalItems] = await queryBuilder.getManyAndCount() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does this still execute 2 queries ? (1) count and (2) find? should be then just using |
||
|
||
let totalPages = totalItems / limit | ||
if (totalItems % limit) totalPages = Math.ceil(totalPages) | ||
|
||
const sortByQuery = sortBy.map((order) => `&sortBy=${order.join(':')}`).join('') | ||
const searchQuery = query.search ? `&search=${query.search}` : '' | ||
|
||
|
@@ -385,25 +390,53 @@ export async function paginate<T extends ObjectLiteral>( | |
|
||
const buildLink = (p: number): string => path + '?page=' + p + options | ||
|
||
const results: Paginated<T> = { | ||
data: items, | ||
meta: { | ||
itemsPerPage: limit, | ||
totalItems, | ||
currentPage: page, | ||
totalPages: totalPages, | ||
sortBy, | ||
search: query.search, | ||
searchBy: query.search ? searchBy : undefined, | ||
filter: query.filter, | ||
}, | ||
links: { | ||
first: page == 1 ? undefined : buildLink(1), | ||
previous: page - 1 < 1 ? undefined : buildLink(page - 1), | ||
current: buildLink(page), | ||
next: page + 1 > totalPages ? undefined : buildLink(page + 1), | ||
last: page == totalPages || !totalItems ? undefined : buildLink(totalPages), | ||
}, | ||
let results: Paginated<T> | ||
|
||
if (limit) { | ||
let totalPages = totalItems / limit | ||
if (totalItems % limit) totalPages = Math.ceil(totalPages) | ||
|
||
results = { | ||
data: items, | ||
meta: { | ||
itemsPerPage: limit, | ||
totalItems, | ||
currentPage: page, | ||
totalPages: totalPages, | ||
sortBy, | ||
search: query.search, | ||
searchBy: query.search ? searchBy : undefined, | ||
filter: query.filter, | ||
}, | ||
links: { | ||
first: page == 1 ? undefined : buildLink(1), | ||
previous: page - 1 < 1 ? undefined : buildLink(page - 1), | ||
current: buildLink(page), | ||
next: page + 1 > totalPages ? undefined : buildLink(page + 1), | ||
last: page == totalPages || !totalItems ? undefined : buildLink(totalPages), | ||
}, | ||
} | ||
} else { | ||
results = { | ||
data: items, | ||
meta: { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's just branch the calculation of the meta values which are computed differently now, instead of this larger code duplication |
||
itemsPerPage: items.length, | ||
totalItems, | ||
currentPage: page, | ||
totalPages: items.length, | ||
sortBy, | ||
search: query.search, | ||
searchBy: query.search ? searchBy : undefined, | ||
filter: query.filter, | ||
}, | ||
links: { | ||
first: undefined, | ||
previous: undefined, | ||
current: buildLink(page), | ||
next: undefined, | ||
last: undefined, | ||
}, | ||
} | ||
} | ||
|
||
return Object.assign(new Paginated<T>(), results) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
place addition in next line, as it's a code frame with horizontal slider