From 081177aebfe548cf0ad75a77aafe109aab62112a Mon Sep 17 00:00:00 2001 From: Elbarae Rguig Date: Sat, 20 Aug 2022 23:25:48 +0100 Subject: [PATCH] feat: add ability to specify whether null values should be put at the beginning or the end of the result set when sorting (#296) --- README.md | 8 ++++++++ src/paginate.spec.ts | 16 ++++++++++++++++ src/paginate.ts | 7 +++++-- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4053b8b..42ff434 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,7 @@ export class CatsService { public findAll(query: PaginateQuery): Promise> { return paginate(query, this.catsRepository, { sortableColumns: ['id', 'name', 'color', 'age'], + nullSort: 'last', searchableColumns: ['name', 'color', 'age'], defaultSortBy: [['id', 'DESC']], filterableColumns: { @@ -154,6 +155,13 @@ const paginateConfig: PaginateConfig { * Description: These are the columns that are valid to be sorted by. */ sortableColumns: ['id', 'name', 'color'], + /** + * Required: false + * Type: 'first' | 'last' + * Default: 'last' + * Description: Define whether to put null values at the beginning or end of the result set. + */ + nullSort: 'last, /** * Required: false diff --git a/src/paginate.spec.ts b/src/paginate.spec.ts index 4a30671..65cf44e 100644 --- a/src/paginate.spec.ts +++ b/src/paginate.spec.ts @@ -196,6 +196,22 @@ describe('paginate', () => { expect(result.data).toStrictEqual(cats.slice(0).reverse()) }) + it('should put null values last when sorting', async () => { + const config: PaginateConfig = { + sortableColumns: ['age', 'createdAt'], + nullSort: 'last', + defaultSortBy: [['age', 'DESC']], + } + const query: PaginateQuery = { + path: '', + } + + const result = await paginate(query, catRepo, config) + + expect(result.meta.sortBy).toStrictEqual([['age', 'DESC']]) + expect(result.data).toStrictEqual(cats) + }) + it('should sort result by multiple columns', async () => { const config: PaginateConfig = { sortableColumns: ['name', 'color'], diff --git a/src/paginate.ts b/src/paginate.ts index 4bcbf91..e15b16d 100644 --- a/src/paginate.ts +++ b/src/paginate.ts @@ -46,6 +46,7 @@ export class Paginated { export interface PaginateConfig { relations?: RelationColumn[] sortableColumns: Column[] + nullSort?: 'first' | 'last' searchableColumns?: Column[] select?: Column[] maxLimit?: number @@ -172,6 +173,8 @@ export async function paginate( if (config.sortableColumns.length < 1) throw new ServiceUnavailableException() + const NULL_SORT = config.nullSort === 'last' ? 'NULLS LAST' : 'NULLS FIRST' + if (query.sortBy) { for (const order of query.sortBy) { if (isEntityKey(config.sortableColumns, order[0]) && ['ASC', 'DESC'].includes(order[1])) { @@ -219,9 +222,9 @@ export async function paginate( for (const order of sortBy) { if (order[0].split('.').length > 1) { - queryBuilder.addOrderBy(`${queryBuilder.alias}_${order[0]}`, order[1]) + queryBuilder.addOrderBy(`${queryBuilder.alias}_${order[0]}`, order[1], NULL_SORT) } else { - queryBuilder.addOrderBy(`${queryBuilder.alias}.${order[0]}`, order[1]) + queryBuilder.addOrderBy(`${queryBuilder.alias}.${order[0]}`, order[1], NULL_SORT) } }