Compare commits
No commits in common. "58770bf89f0926b684c34ec019e8583c1673a433" and "1da2dc9c26a977a88685e25de01720fc04dd72a5" have entirely different histories.
58770bf89f
...
1da2dc9c26
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "axp-ts",
|
||||
"version": "1.9.7",
|
||||
"version": "1.9.6",
|
||||
"description": "TypeScript helper library",
|
||||
"author": "AntoXa PRO <info@antoxa.pro>",
|
||||
"homepage": "https://antoxahub.ru/antoxa/axp-ts",
|
||||
@ -18,7 +18,7 @@
|
||||
"prepare": "npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"zod": "^3.22.1"
|
||||
"zod": "^3.21.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^2.8.8",
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { TPagination } from './pagination'
|
||||
import type { TNotificationItem } from '../notification'
|
||||
import type { TNotificationItem } from './notification'
|
||||
|
||||
import { Pagination } from './pagination'
|
||||
|
@ -36,6 +36,8 @@ export const bFieldsSchema = {
|
||||
string: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(2)
|
||||
.max(64)
|
||||
.describe(
|
||||
FormSchemaCtrl.toString({
|
||||
label: 'Строка',
|
||||
@ -77,6 +79,16 @@ export const cFieldsSchema = z.object({
|
||||
dateUpdate: fieldSchema(bFieldsSchema.date, {
|
||||
label: 'Дата изменения'
|
||||
}),
|
||||
q: fieldSchema(
|
||||
z.preprocess(
|
||||
val => String(val).replace(regexSearch, ''),
|
||||
bFieldsSchema.string
|
||||
),
|
||||
{
|
||||
label: 'Поиск',
|
||||
component: 'ui-field-search'
|
||||
}
|
||||
),
|
||||
name: fieldSchema(bFieldsSchema.string, {
|
||||
label: 'Название'
|
||||
}),
|
||||
@ -175,23 +187,5 @@ export const cFieldsSchema = z.object({
|
||||
days: fieldSchema(bFieldsSchema.number.array(), {
|
||||
label: 'Дни недели',
|
||||
component: 'ui-picker-days'
|
||||
}),
|
||||
q: fieldSchema(
|
||||
z.preprocess(
|
||||
val => String(val).replace(regexSearch, ''),
|
||||
bFieldsSchema.string
|
||||
),
|
||||
{
|
||||
label: 'Поиск',
|
||||
component: 'ui-field-search'
|
||||
}
|
||||
),
|
||||
page: fieldSchema(
|
||||
z.preprocess(val => Math.abs(Number(val)), bFieldsSchema.number),
|
||||
{ label: 'Страница' }
|
||||
),
|
||||
limit: fieldSchema(
|
||||
z.preprocess(val => Math.abs(Number(val)), bFieldsSchema.number),
|
||||
{ label: 'Лимит' }
|
||||
)
|
||||
})
|
||||
})
|
@ -27,7 +27,7 @@ export interface IFormModel<T> {
|
||||
/**
|
||||
* Базовая модель для валидирования форм.
|
||||
*/
|
||||
export class BaseFormModel<T extends object = {}> implements IFormModel<T> {
|
||||
export class BaseFormModel<T extends Object = {}> implements IFormModel<T> {
|
||||
_id: string
|
||||
|
||||
dateCreate?: Date
|
@ -1,5 +1,5 @@
|
||||
export * from './utils'
|
||||
export * from './notification'
|
||||
export * from './entities'
|
||||
export * from './requests'
|
||||
export * from './forms'
|
||||
export * from './form'
|
||||
export * from './notification'
|
||||
export * from './pagination'
|
||||
export * from './data-result'
|
||||
|
@ -7,7 +7,7 @@ export class NotificationItem implements TNotificationItem {
|
||||
code: string
|
||||
text: string
|
||||
|
||||
constructor(args: { code: string; text: string }) {
|
||||
constructor(args: {code: string, text: string }) {
|
||||
this.code = args.code
|
||||
this.text = args.text
|
||||
}
|
||||
|
@ -1,12 +1,13 @@
|
||||
import { z } from 'zod'
|
||||
import { cFieldsSchema, fieldSchema } from '../forms'
|
||||
import { cFieldsSchema, fieldSchema } from './form'
|
||||
|
||||
export const paginationSchema = cFieldsSchema
|
||||
.pick({
|
||||
page: true,
|
||||
limit: true
|
||||
})
|
||||
.extend({
|
||||
export const paginationSchema = z.object({
|
||||
page: fieldSchema(cFieldsSchema.shape.number, {
|
||||
label: 'Номер страницы'
|
||||
}),
|
||||
limit: fieldSchema(cFieldsSchema.shape.number, {
|
||||
label: 'Лимит на странице'
|
||||
}),
|
||||
total: fieldSchema(cFieldsSchema.shape.number, {
|
||||
label: 'Общее кол-во'
|
||||
}),
|
||||
@ -17,16 +18,9 @@ export const paginationSchema = cFieldsSchema
|
||||
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 }
|
||||
|
||||
@ -38,11 +32,43 @@ export type TPaginationArguments = {
|
||||
total?: number
|
||||
}
|
||||
|
||||
export class Pagination implements TPagination {
|
||||
export interface IPagination extends TPagination {
|
||||
/**
|
||||
* Максимальный лимит элементов.
|
||||
*/
|
||||
#maxLimit: number
|
||||
get maxLimit(): number
|
||||
|
||||
/**
|
||||
* Парсинг аргументов.
|
||||
* @param arg - Значение аргумента для парсинга.
|
||||
* @param defaultReturnValue - Возвращаемое значение по умолчанию.
|
||||
* @returns Возвращает абсолютное значение числа аргумента.
|
||||
*/
|
||||
parseArg(
|
||||
arg: number | string | undefined,
|
||||
defaultReturnValue: number
|
||||
): number
|
||||
|
||||
/**
|
||||
* Присваивает значения для основных свойств класса и считает кол-во
|
||||
* пропускаемых элементов в зависимости от полученных аргументов.
|
||||
* @param args - Аргументы пагинации.
|
||||
* @returns Возвращает текущий экземпляр класса.
|
||||
*/
|
||||
set(args: TPaginationArguments): this
|
||||
|
||||
/**
|
||||
* Возвращает простой объект пагинации.
|
||||
* @returns Объект пагинации.
|
||||
*/
|
||||
toObject(): TPagination
|
||||
}
|
||||
|
||||
export class Pagination implements IPagination {
|
||||
/**
|
||||
* Максимальный лимит элементов.
|
||||
*/
|
||||
private _maxLimit: number
|
||||
|
||||
page: number = DEFAULTS.page
|
||||
limit: number = DEFAULTS.limit
|
||||
@ -63,10 +89,14 @@ export class Pagination implements TPagination {
|
||||
}
|
||||
|
||||
constructor(args: TPaginationArguments = {}, maxLimit?: number) {
|
||||
this.#maxLimit = this.parseArg(maxLimit, DEFAULTS.maxLimit)
|
||||
this._maxLimit = this.parseArg(maxLimit, DEFAULTS.maxLimit)
|
||||
this.set(args)
|
||||
}
|
||||
|
||||
get maxLimit() {
|
||||
return this._maxLimit
|
||||
}
|
||||
|
||||
parseArg(arg: TPaginationParseArg, defaultReturnValue: number): number {
|
||||
return Pagination.parseArg(arg, defaultReturnValue)
|
||||
}
|
||||
@ -88,7 +118,7 @@ export class Pagination implements TPagination {
|
||||
}
|
||||
|
||||
// Проверка лимита.
|
||||
if (this.limit > this.#maxLimit) this.limit = this.#maxLimit
|
||||
if (this.limit > this.maxLimit) this.limit = this.maxLimit
|
||||
|
||||
// Общее кол-во.
|
||||
if (args.total && args.total !== this.total) {
|
@ -1,79 +0,0 @@
|
||||
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])
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
export * from './pagination'
|
||||
export * from './data-result'
|
||||
export * from './find-filter'
|
@ -1 +0,0 @@
|
||||
export * from './objects'
|
@ -1,28 +0,0 @@
|
||||
export const isEqual = <T extends object>(objects: T[]) => {
|
||||
for (let i = 0; i < objects.length; i++) {
|
||||
const obj1 = objects[i]
|
||||
const obj2 = objects[i + 1]
|
||||
if (obj2) {
|
||||
const keys1 = Object.keys(obj1)
|
||||
const keys2 = Object.keys(obj2)
|
||||
|
||||
if (keys1.length !== keys2.length) {
|
||||
return false
|
||||
}
|
||||
|
||||
for(const key of keys1) {
|
||||
if (typeof obj1[key] !== 'object') {
|
||||
if (obj1[key] !== obj2[key]) {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
if (!isEqual([obj1[key], obj2[key]])) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
Loading…
Reference in New Issue
Block a user