Compare commits

..

2 Commits

Author SHA1 Message Date
58770bf89f big fix 2023-09-14 18:19:36 +03:00
4bc155683b update packages 2023-08-17 09:20:12 +03:00
14 changed files with 166 additions and 79 deletions

View File

@ -1,6 +1,6 @@
{
"name": "axp-ts",
"version": "1.9.6",
"version": "1.9.7",
"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.21.4"
"zod": "^3.22.1"
},
"devDependencies": {
"prettier": "^2.8.8",

View File

@ -36,8 +36,6 @@ export const bFieldsSchema = {
string: z
.string()
.trim()
.min(2)
.max(64)
.describe(
FormSchemaCtrl.toString({
label: 'Строка',
@ -79,16 +77,6 @@ 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: 'Название'
}),
@ -187,5 +175,23 @@ 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: 'Лимит' }
)
})

View File

@ -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

View File

@ -1,5 +1,5 @@
export * from './entities'
export * from './form'
export * from './utils'
export * from './notification'
export * from './pagination'
export * from './data-result'
export * from './entities'
export * from './requests'
export * from './forms'

View File

@ -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
}

View File

@ -1,5 +1,5 @@
import type { TPagination } from './pagination'
import type { TNotificationItem } from './notification'
import type { TNotificationItem } from '../notification'
import { Pagination } from './pagination'

View 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
View File

@ -0,0 +1,3 @@
export * from './pagination'
export * from './data-result'
export * from './find-filter'

View File

@ -1,13 +1,12 @@
import { z } from 'zod'
import { cFieldsSchema, fieldSchema } from './form'
import { cFieldsSchema, fieldSchema } from '../forms'
export const paginationSchema = z.object({
page: fieldSchema(cFieldsSchema.shape.number, {
label: 'Номер страницы'
}),
limit: fieldSchema(cFieldsSchema.shape.number, {
label: 'Лимит на странице'
}),
export const paginationSchema = cFieldsSchema
.pick({
page: true,
limit: true
})
.extend({
total: fieldSchema(cFieldsSchema.shape.number, {
label: 'Общее кол-во'
}),
@ -18,9 +17,16 @@ export const paginationSchema = z.object({
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 }
@ -32,43 +38,11 @@ export type TPaginationArguments = {
total?: number
}
export interface IPagination extends TPagination {
export class Pagination implements TPagination {
/**
* Максимальный лимит элементов.
*/
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
#maxLimit: number
page: number = DEFAULTS.page
limit: number = DEFAULTS.limit
@ -89,14 +63,10 @@ export class Pagination implements IPagination {
}
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)
}
@ -118,7 +88,7 @@ export class Pagination implements IPagination {
}
// Проверка лимита.
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
src/utils/index.ts Normal file
View File

@ -0,0 +1 @@
export * from './objects'

28
src/utils/objects.ts Normal file
View File

@ -0,0 +1,28 @@
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
}