big fix
This commit is contained in:
67
src/requests/data-result.ts
Normal file
67
src/requests/data-result.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import type { TPagination } from './pagination'
|
||||
import type { TNotificationItem } from '../notification'
|
||||
|
||||
import { Pagination } from './pagination'
|
||||
|
||||
export type TInfoDataResult = {
|
||||
type: 'object' | 'array' | 'undefined'
|
||||
length: number
|
||||
pagination?: TPagination
|
||||
}
|
||||
|
||||
export interface IDataResult<T> {
|
||||
status: number
|
||||
message: string
|
||||
data: T
|
||||
info: TInfoDataResult
|
||||
errors: TNotificationItem[]
|
||||
setData(data: T, pagination?: TPagination): void
|
||||
}
|
||||
|
||||
export class DataResultEntity<T> implements IDataResult<T> {
|
||||
status: number = 200
|
||||
message: string = 'Ok'
|
||||
data: T
|
||||
info: TInfoDataResult = { type: 'undefined', length: 0 }
|
||||
errors: TNotificationItem[] = []
|
||||
|
||||
constructor(data: any = {}) {
|
||||
this.data = data
|
||||
this.setData()
|
||||
}
|
||||
|
||||
setData(data: T = null, pagination?: TPagination): void {
|
||||
if (data !== null) {
|
||||
this.data = data
|
||||
}
|
||||
|
||||
// Если данные есть.
|
||||
if (this.data) {
|
||||
// Если данные это массив.
|
||||
if (Array.isArray(this.data)) {
|
||||
this.info.type = 'array'
|
||||
this.info.length = [...this.data].length
|
||||
|
||||
if (pagination) {
|
||||
this.info.pagination = pagination
|
||||
} else {
|
||||
const pagination = new Pagination(
|
||||
{ page: 1, limit: this.info.length, total: this.info.length },
|
||||
this.info.length
|
||||
)
|
||||
this.info.pagination = pagination.toObject()
|
||||
}
|
||||
|
||||
// Если общее кол-во меньше чем размер массива.
|
||||
// Это обычно значение по умолчанию "0" при инициализации объекта пагинации.
|
||||
if (this.info.pagination.total < this.info.length) {
|
||||
this.info.pagination.total = this.info.length
|
||||
}
|
||||
} else {
|
||||
// Данные это объект.
|
||||
this.info.type = 'object'
|
||||
this.info.length = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
79
src/requests/find-filter.ts
Normal file
79
src/requests/find-filter.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import type { TPagination } from './pagination'
|
||||
|
||||
import { z } from 'zod'
|
||||
import { isEqual } from '../utils'
|
||||
import { Pagination, paginationQuerySchema } from './pagination'
|
||||
import { bFieldsSchema, cFieldsSchema, fieldSchema } from '../forms'
|
||||
|
||||
|
||||
export const querySchema = cFieldsSchema
|
||||
.pick({ q: true })
|
||||
.extend(paginationQuerySchema.shape)
|
||||
.extend({
|
||||
sort: fieldSchema(bFieldsSchema.string.min(1).max(64), {
|
||||
label: 'Сортировка'
|
||||
})
|
||||
})
|
||||
|
||||
export type TQuery = z.infer<typeof querySchema>
|
||||
|
||||
/**
|
||||
* Объект для преобразования фильтра в URL.
|
||||
*/
|
||||
export type TFindFilter<T extends TQuery> = {
|
||||
obj?: Omit<T, 'page' | 'limit' | 'sort'>
|
||||
pagination?: TPagination
|
||||
sort?: string
|
||||
}
|
||||
|
||||
export class FindFilter<T extends TQuery> implements TFindFilter<T> {
|
||||
obj?: Omit<T, 'page' | 'limit' | 'sort'>
|
||||
pagination?: TPagination
|
||||
sort?: string
|
||||
|
||||
constructor(query?: T) {
|
||||
let queryCopy = Object.assign({}, query)
|
||||
|
||||
// Pagination.
|
||||
this.setPagination(queryCopy)
|
||||
for (const key of Object.keys(this.pagination)) {
|
||||
if (queryCopy[key]) delete queryCopy[key]
|
||||
}
|
||||
|
||||
// Sort.
|
||||
if (queryCopy.sort) {
|
||||
this.sort = queryCopy.sort
|
||||
delete queryCopy.sort
|
||||
}
|
||||
|
||||
// Obj.
|
||||
this.obj = queryCopy
|
||||
}
|
||||
|
||||
setPagination(pagination?: TPagination) {
|
||||
this.pagination = new Pagination(pagination).toObject()
|
||||
}
|
||||
|
||||
static getQuery <T extends TQuery = {}>(filter: TFindFilter<T>): T {
|
||||
let query: any = {}
|
||||
for(const key of Object.keys(filter.obj)) {
|
||||
query[key] = filter.obj[key]
|
||||
}
|
||||
if (filter.pagination?.page) query.page = filter.pagination.page
|
||||
if (filter.pagination?.limit) query.limit = filter.pagination.limit
|
||||
if (filter.sort) query.sort = filter.sort
|
||||
return query
|
||||
}
|
||||
|
||||
toObject(): TFindFilter<T> {
|
||||
return {
|
||||
obj: this.obj,
|
||||
pagination: this.pagination,
|
||||
sort: this.sort
|
||||
}
|
||||
}
|
||||
|
||||
isEqual(filters: TFindFilter<T>[]) {
|
||||
return isEqual([this, ...filters])
|
||||
}
|
||||
}
|
||||
3
src/requests/index.ts
Normal file
3
src/requests/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from './pagination'
|
||||
export * from './data-result'
|
||||
export * from './find-filter'
|
||||
121
src/requests/pagination.ts
Normal file
121
src/requests/pagination.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import { z } from 'zod'
|
||||
import { cFieldsSchema, fieldSchema } from '../forms'
|
||||
|
||||
export const paginationSchema = cFieldsSchema
|
||||
.pick({
|
||||
page: true,
|
||||
limit: true
|
||||
})
|
||||
.extend({
|
||||
total: fieldSchema(cFieldsSchema.shape.number, {
|
||||
label: 'Общее кол-во'
|
||||
}),
|
||||
skip: fieldSchema(cFieldsSchema.shape.number, {
|
||||
label: 'Пропустить'
|
||||
}),
|
||||
pages: fieldSchema(cFieldsSchema.shape.number, {
|
||||
label: 'Кол-во всех страниц'
|
||||
})
|
||||
})
|
||||
.describe('Пагинация')
|
||||
|
||||
export type TPagination = z.infer<typeof paginationSchema>
|
||||
|
||||
export const paginationQuerySchema = paginationSchema.pick({
|
||||
page: true, limit: true
|
||||
})
|
||||
|
||||
export type TPaginationQuery = z.infer<typeof paginationQuerySchema>
|
||||
|
||||
// Константы.
|
||||
const DEFAULTS = { page: 1, limit: 10, maxLimit: 100 }
|
||||
|
||||
export type TPaginationParseArg = number | string | undefined
|
||||
|
||||
export type TPaginationArguments = {
|
||||
page?: TPaginationParseArg
|
||||
limit?: TPaginationParseArg
|
||||
total?: number
|
||||
}
|
||||
|
||||
export class Pagination implements TPagination {
|
||||
/**
|
||||
* Максимальный лимит элементов.
|
||||
*/
|
||||
#maxLimit: number
|
||||
|
||||
page: number = DEFAULTS.page
|
||||
limit: number = DEFAULTS.limit
|
||||
|
||||
skip: number = 0
|
||||
total: number = 0
|
||||
pages: number = 0
|
||||
|
||||
static parseArg(
|
||||
arg: TPaginationParseArg,
|
||||
defaultReturnValue: number
|
||||
): number {
|
||||
return Math.abs(
|
||||
typeof arg === 'string'
|
||||
? Number.parseInt(arg) || defaultReturnValue
|
||||
: arg || defaultReturnValue
|
||||
)
|
||||
}
|
||||
|
||||
constructor(args: TPaginationArguments = {}, maxLimit?: number) {
|
||||
this.#maxLimit = this.parseArg(maxLimit, DEFAULTS.maxLimit)
|
||||
this.set(args)
|
||||
}
|
||||
|
||||
parseArg(arg: TPaginationParseArg, defaultReturnValue: number): number {
|
||||
return Pagination.parseArg(arg, defaultReturnValue)
|
||||
}
|
||||
|
||||
set(args: TPaginationArguments = {}): this {
|
||||
let isCalcSkip: boolean = false
|
||||
|
||||
// Страница.
|
||||
if (args.page && args.page !== this.page) {
|
||||
// Инициализипуем страницу.
|
||||
this.page = this.parseArg(args.page, DEFAULTS.page)
|
||||
isCalcSkip = true
|
||||
}
|
||||
|
||||
// Лимит.
|
||||
if (args.limit && args.limit !== this.limit) {
|
||||
this.limit = this.parseArg(args.limit, this.limit)
|
||||
isCalcSkip = true
|
||||
}
|
||||
|
||||
// Проверка лимита.
|
||||
if (this.limit > this.#maxLimit) this.limit = this.#maxLimit
|
||||
|
||||
// Общее кол-во.
|
||||
if (args.total && args.total !== this.total) {
|
||||
this.total = Math.abs(args.total)
|
||||
this.pages = Math.ceil(this.total / this.limit)
|
||||
}
|
||||
|
||||
// Перерасчёт пропускаемых элементов.
|
||||
if (isCalcSkip) {
|
||||
let skip = 0
|
||||
try {
|
||||
skip = (this.page - 1) * this.limit
|
||||
} catch (ex: any) {}
|
||||
this.skip = skip > 0 ? skip : 0
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
toObject(): TPagination {
|
||||
return {
|
||||
page: this.page,
|
||||
limit: this.limit,
|
||||
total: this.total,
|
||||
|
||||
skip: this.skip,
|
||||
pages: this.pages
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user