fix: clean up
This commit is contained in:
parent
2a628e89af
commit
d7ccd914d4
@ -1,3 +1,2 @@
|
|||||||
export * from './decorator'
|
export * from './decorator'
|
||||||
export * from './paginate'
|
export * from './paginate'
|
||||||
export { FilterOperator, FilterComparator } from './operator'
|
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
import { values } from 'lodash'
|
|
||||||
import {
|
|
||||||
Equal,
|
|
||||||
FindOperator,
|
|
||||||
In,
|
|
||||||
MoreThan,
|
|
||||||
MoreThanOrEqual,
|
|
||||||
IsNull,
|
|
||||||
LessThan,
|
|
||||||
LessThanOrEqual,
|
|
||||||
Between,
|
|
||||||
ILike,
|
|
||||||
Not,
|
|
||||||
} from 'typeorm'
|
|
||||||
|
|
||||||
export enum FilterOperator {
|
|
||||||
EQ = '$eq',
|
|
||||||
GT = '$gt',
|
|
||||||
GTE = '$gte',
|
|
||||||
IN = '$in',
|
|
||||||
NULL = '$null',
|
|
||||||
LT = '$lt',
|
|
||||||
LTE = '$lte',
|
|
||||||
BTW = '$btw',
|
|
||||||
ILIKE = '$ilike',
|
|
||||||
SW = '$sw',
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isOperator(value: unknown): value is FilterOperator {
|
|
||||||
return values(FilterOperator).includes(value as any)
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum FilterSuffix {
|
|
||||||
NOT = '$not',
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isSuffix(value: unknown): value is FilterSuffix {
|
|
||||||
return values(FilterSuffix).includes(value as any)
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum FilterComparator {
|
|
||||||
AND = '$and',
|
|
||||||
OR = '$or',
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isComparator(value: unknown): value is FilterComparator {
|
|
||||||
return values(FilterComparator).includes(value as any)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const OperatorSymbolToFunction = new Map<
|
|
||||||
FilterOperator | FilterSuffix,
|
|
||||||
(...args: any[]) => FindOperator<string>
|
|
||||||
>([
|
|
||||||
[FilterOperator.EQ, Equal],
|
|
||||||
[FilterOperator.GT, MoreThan],
|
|
||||||
[FilterOperator.GTE, MoreThanOrEqual],
|
|
||||||
[FilterOperator.IN, In],
|
|
||||||
[FilterOperator.NULL, IsNull],
|
|
||||||
[FilterOperator.LT, LessThan],
|
|
||||||
[FilterOperator.LTE, LessThanOrEqual],
|
|
||||||
[FilterOperator.BTW, Between],
|
|
||||||
[FilterOperator.ILIKE, ILike],
|
|
||||||
[FilterSuffix.NOT, Not],
|
|
||||||
[FilterOperator.SW, ILike],
|
|
||||||
])
|
|
@ -1,6 +1,21 @@
|
|||||||
import { Brackets, FindOperator, SelectQueryBuilder } from 'typeorm'
|
import { values } from 'lodash'
|
||||||
|
import {
|
||||||
|
Brackets,
|
||||||
|
Equal,
|
||||||
|
FindOperator,
|
||||||
|
In,
|
||||||
|
MoreThan,
|
||||||
|
MoreThanOrEqual,
|
||||||
|
IsNull,
|
||||||
|
LessThan,
|
||||||
|
LessThanOrEqual,
|
||||||
|
Between,
|
||||||
|
ILike,
|
||||||
|
Not,
|
||||||
|
SelectQueryBuilder,
|
||||||
|
} from 'typeorm'
|
||||||
import { WherePredicateOperator } from 'typeorm/query-builder/WhereClause'
|
import { WherePredicateOperator } from 'typeorm/query-builder/WhereClause'
|
||||||
import { PaginateQuery } from './decorator'
|
import { PaginateQuery } from '../decorator'
|
||||||
import {
|
import {
|
||||||
checkIsEmbedded,
|
checkIsEmbedded,
|
||||||
checkIsRelation,
|
checkIsRelation,
|
||||||
@ -8,16 +23,57 @@ import {
|
|||||||
fixColumnAlias,
|
fixColumnAlias,
|
||||||
getPropertiesByColumnName,
|
getPropertiesByColumnName,
|
||||||
} from './helper'
|
} from './helper'
|
||||||
import {
|
|
||||||
FilterComparator,
|
export enum FilterOperator {
|
||||||
FilterOperator,
|
EQ = '$eq',
|
||||||
FilterSuffix,
|
GT = '$gt',
|
||||||
isComparator,
|
GTE = '$gte',
|
||||||
isOperator,
|
IN = '$in',
|
||||||
isSuffix,
|
NULL = '$null',
|
||||||
OperatorSymbolToFunction,
|
LT = '$lt',
|
||||||
} from './operator'
|
LTE = '$lte',
|
||||||
import { PaginateConfig } from './paginate'
|
BTW = '$btw',
|
||||||
|
ILIKE = '$ilike',
|
||||||
|
SW = '$sw',
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isOperator(value: unknown): value is FilterOperator {
|
||||||
|
return values(FilterOperator).includes(value as any)
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum FilterSuffix {
|
||||||
|
NOT = '$not',
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isSuffix(value: unknown): value is FilterSuffix {
|
||||||
|
return values(FilterSuffix).includes(value as any)
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum FilterComparator {
|
||||||
|
AND = '$and',
|
||||||
|
OR = '$or',
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isComparator(value: unknown): value is FilterComparator {
|
||||||
|
return values(FilterComparator).includes(value as any)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const OperatorSymbolToFunction = new Map<
|
||||||
|
FilterOperator | FilterSuffix,
|
||||||
|
(...args: any[]) => FindOperator<string>
|
||||||
|
>([
|
||||||
|
[FilterOperator.EQ, Equal],
|
||||||
|
[FilterOperator.GT, MoreThan],
|
||||||
|
[FilterOperator.GTE, MoreThanOrEqual],
|
||||||
|
[FilterOperator.IN, In],
|
||||||
|
[FilterOperator.NULL, IsNull],
|
||||||
|
[FilterOperator.LT, LessThan],
|
||||||
|
[FilterOperator.LTE, LessThanOrEqual],
|
||||||
|
[FilterOperator.BTW, Between],
|
||||||
|
[FilterOperator.ILIKE, ILike],
|
||||||
|
[FilterSuffix.NOT, Not],
|
||||||
|
[FilterOperator.SW, ILike],
|
||||||
|
])
|
||||||
|
|
||||||
type Filter = { comparator: FilterComparator; findOperator: FindOperator<string> }
|
type Filter = { comparator: FilterComparator; findOperator: FindOperator<string> }
|
||||||
type ColumnsFilters = { [columnName: string]: Filter[] }
|
type ColumnsFilters = { [columnName: string]: Filter[] }
|
||||||
@ -168,7 +224,7 @@ export function getFilterTokens(raw?: string): FilterToken | null {
|
|||||||
|
|
||||||
export function parseFilter<T>(
|
export function parseFilter<T>(
|
||||||
query: PaginateQuery,
|
query: PaginateQuery,
|
||||||
filterableColumns?: PaginateConfig<T>['filterableColumns']
|
filterableColumns?: { [column: string]: (FilterOperator | FilterSuffix)[] }
|
||||||
): ColumnsFilters {
|
): ColumnsFilters {
|
||||||
const filter: ColumnsFilters = {}
|
const filter: ColumnsFilters = {}
|
||||||
if (!filterableColumns || !query.filter) {
|
if (!filterableColumns || !query.filter) {
|
||||||
@ -237,7 +293,7 @@ export function parseFilter<T>(
|
|||||||
export function addFilter<T>(
|
export function addFilter<T>(
|
||||||
qb: SelectQueryBuilder<T>,
|
qb: SelectQueryBuilder<T>,
|
||||||
query: PaginateQuery,
|
query: PaginateQuery,
|
||||||
filterableColumns?: PaginateConfig<T>['filterableColumns']
|
filterableColumns?: { [column: string]: (FilterOperator | FilterSuffix)[] }
|
||||||
): SelectQueryBuilder<T> {
|
): SelectQueryBuilder<T> {
|
||||||
const filter = parseFilter(query, filterableColumns)
|
const filter = parseFilter(query, filterableColumns)
|
||||||
return qb.andWhere(
|
return qb.andWhere(
|
@ -34,6 +34,10 @@ export type RelationColumn<T> = Extract<
|
|||||||
export type Order<T> = [Column<T>, 'ASC' | 'DESC']
|
export type Order<T> = [Column<T>, 'ASC' | 'DESC']
|
||||||
export type SortBy<T> = Order<T>[]
|
export type SortBy<T> = Order<T>[]
|
||||||
|
|
||||||
|
export function isEntityKey<T>(entityColumns: Column<T>[], column: string): column is Column<T> {
|
||||||
|
return !!entityColumns.find((c) => c === column)
|
||||||
|
}
|
||||||
|
|
||||||
export const positiveNumberOrDefault = (value: number | undefined, defaultValue: number, minValue: 0 | 1 = 0) =>
|
export const positiveNumberOrDefault = (value: number | undefined, defaultValue: number, minValue: 0 | 1 = 0) =>
|
||||||
value === undefined || value < minValue ? defaultValue : value
|
value === undefined || value < minValue ? defaultValue : value
|
||||||
|
|
@ -1,21 +1,21 @@
|
|||||||
import { Repository, In, DataSource, TypeORMError } from 'typeorm'
|
import { Repository, In, DataSource, TypeORMError } from 'typeorm'
|
||||||
import { Paginated, paginate, PaginateConfig, NO_PAGINATION } from './paginate'
|
import { Paginated, paginate, PaginateConfig, NO_PAGINATION } from '.'
|
||||||
import { PaginateQuery } from './decorator'
|
import { PaginateQuery } from '../decorator'
|
||||||
import { HttpException } from '@nestjs/common'
|
import { HttpException } from '@nestjs/common'
|
||||||
import { CatEntity } from './__tests__/cat.entity'
|
import { CatEntity } from '../__tests__/cat.entity'
|
||||||
import { CatToyEntity } from './__tests__/cat-toy.entity'
|
import { CatToyEntity } from '../__tests__/cat-toy.entity'
|
||||||
import { CatHomeEntity } from './__tests__/cat-home.entity'
|
import { CatHomeEntity } from '../__tests__/cat-home.entity'
|
||||||
import { CatHomePillowEntity } from './__tests__/cat-home-pillow.entity'
|
import { CatHomePillowEntity } from '../__tests__/cat-home-pillow.entity'
|
||||||
import { clone } from 'lodash'
|
import { clone } from 'lodash'
|
||||||
import {
|
import {
|
||||||
|
getFilterTokens,
|
||||||
FilterComparator,
|
FilterComparator,
|
||||||
FilterOperator,
|
FilterOperator,
|
||||||
FilterSuffix,
|
FilterSuffix,
|
||||||
isOperator,
|
isOperator,
|
||||||
isSuffix,
|
isSuffix,
|
||||||
OperatorSymbolToFunction,
|
OperatorSymbolToFunction,
|
||||||
} from './operator'
|
} from './filter'
|
||||||
import { getFilterTokens } from './filter'
|
|
||||||
|
|
||||||
describe('paginate', () => {
|
describe('paginate', () => {
|
||||||
let dataSource: DataSource
|
let dataSource: DataSource
|
@ -7,7 +7,7 @@ import {
|
|||||||
ObjectLiteral,
|
ObjectLiteral,
|
||||||
FindOptionsUtils,
|
FindOptionsUtils,
|
||||||
} from 'typeorm'
|
} from 'typeorm'
|
||||||
import { PaginateQuery } from './decorator'
|
import { PaginateQuery } from '../decorator'
|
||||||
import { ServiceUnavailableException, Logger } from '@nestjs/common'
|
import { ServiceUnavailableException, Logger } from '@nestjs/common'
|
||||||
import { mapKeys } from 'lodash'
|
import { mapKeys } from 'lodash'
|
||||||
import { stringify } from 'querystring'
|
import { stringify } from 'querystring'
|
||||||
@ -25,12 +25,14 @@ import {
|
|||||||
SortBy,
|
SortBy,
|
||||||
hasColumnWithPropertyPath,
|
hasColumnWithPropertyPath,
|
||||||
includesAllPrimaryKeyColumns,
|
includesAllPrimaryKeyColumns,
|
||||||
|
isEntityKey,
|
||||||
} from './helper'
|
} from './helper'
|
||||||
import { FilterOperator, FilterSuffix } from './operator'
|
import { addFilter, FilterOperator, FilterSuffix } from './filter'
|
||||||
import { addFilter } from './filter'
|
|
||||||
|
|
||||||
const logger: Logger = new Logger('nestjs-paginate')
|
const logger: Logger = new Logger('nestjs-paginate')
|
||||||
|
|
||||||
|
export { FilterOperator, FilterSuffix }
|
||||||
|
|
||||||
export class Paginated<T> {
|
export class Paginated<T> {
|
||||||
data: T[]
|
data: T[]
|
||||||
meta: {
|
meta: {
|
||||||
@ -121,10 +123,6 @@ export async function paginate<T extends ObjectLiteral>(
|
|||||||
path = queryOrigin + queryPath
|
path = queryOrigin + queryPath
|
||||||
}
|
}
|
||||||
|
|
||||||
function isEntityKey(entityColumns: Column<T>[], column: string): column is Column<T> {
|
|
||||||
return !!entityColumns.find((c) => c === column)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.sortableColumns.length < 1) {
|
if (config.sortableColumns.length < 1) {
|
||||||
logger.debug("Missing required 'sortableColumns' config.")
|
logger.debug("Missing required 'sortableColumns' config.")
|
||||||
throw new ServiceUnavailableException()
|
throw new ServiceUnavailableException()
|
||||||
@ -142,18 +140,6 @@ export async function paginate<T extends ObjectLiteral>(
|
|||||||
sortBy.push(...(config.defaultSortBy || [[config.sortableColumns[0], 'ASC']]))
|
sortBy.push(...(config.defaultSortBy || [[config.sortableColumns[0], 'ASC']]))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.searchableColumns) {
|
|
||||||
if (query.searchBy) {
|
|
||||||
for (const column of query.searchBy) {
|
|
||||||
if (isEntityKey(config.searchableColumns, column)) {
|
|
||||||
searchBy.push(column)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
searchBy.push(...config.searchableColumns)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let [items, totalItems]: [T[], number] = [[], 0]
|
let [items, totalItems]: [T[], number] = [[], 0]
|
||||||
|
|
||||||
const queryBuilder = repo instanceof Repository ? repo.createQueryBuilder('__root') : repo
|
const queryBuilder = repo instanceof Repository ? repo.createQueryBuilder('__root') : repo
|
||||||
@ -165,10 +151,12 @@ export async function paginate<T extends ObjectLiteral>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isPaginated) {
|
if (isPaginated) {
|
||||||
// Switch from take and skip to limit and offset
|
// Allow user to choose between limit/offset and take/skip.
|
||||||
// due to this problem https://github.com/typeorm/typeorm/issues/5670
|
// However, using limit/offset can return unexpected results.
|
||||||
// (anyway this creates more clean query without double distinct)
|
// For more information see:
|
||||||
// queryBuilder.limit(limit).offset((page - 1) * limit)
|
// [#477](https://github.com/ppetzold/nestjs-paginate/issues/477)
|
||||||
|
// [#4742](https://github.com/typeorm/typeorm/issues/4742)
|
||||||
|
// [#5670](https://github.com/typeorm/typeorm/issues/5670)
|
||||||
if (paginationType === PaginationType.LIMIT_AND_OFFSET) {
|
if (paginationType === PaginationType.LIMIT_AND_OFFSET) {
|
||||||
queryBuilder.limit(limit).offset((page - 1) * limit)
|
queryBuilder.limit(limit).offset((page - 1) * limit)
|
||||||
} else {
|
} else {
|
||||||
@ -248,6 +236,18 @@ export async function paginate<T extends ObjectLiteral>(
|
|||||||
queryBuilder.withDeleted()
|
queryBuilder.withDeleted()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.searchableColumns) {
|
||||||
|
if (query.searchBy) {
|
||||||
|
for (const column of query.searchBy) {
|
||||||
|
if (isEntityKey(config.searchableColumns, column)) {
|
||||||
|
searchBy.push(column)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
searchBy.push(...config.searchableColumns)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (query.search && searchBy.length) {
|
if (query.search && searchBy.length) {
|
||||||
queryBuilder.andWhere(
|
queryBuilder.andWhere(
|
||||||
new Brackets((qb: SelectQueryBuilder<T>) => {
|
new Brackets((qb: SelectQueryBuilder<T>) => {
|
Loading…
Reference in New Issue
Block a user