Uecko_ERP/packages/rdx-criteria/src/Pagination/OffsetPaging.ts
2025-05-19 13:59:13 +02:00

145 lines
3.8 KiB
TypeScript

import Joi from "joi";
import { ValueObject } from "@repo/rdx-ddd";
import { Result, RuleValidator } from "@repo/rdx-utils";
import {
INITIAL_PAGE_INDEX,
INITIAL_PAGE_SIZE,
MAX_PAGE_SIZE,
MIN_PAGE_INDEX,
MIN_PAGE_SIZE,
} from "./defaults";
export interface IOffsetPagingProps {
offset: number | string | undefined;
limit: number | string | undefined;
}
export interface IOffsetPaging {
offset: number;
limit: number;
}
export class OffsetPaging extends ValueObject<IOffsetPaging> {
public static readonly LIMIT_DEFAULT_VALUE: number = INITIAL_PAGE_SIZE;
public static readonly LIMIT_MINIMAL_VALUE: number = MIN_PAGE_SIZE;
public static readonly LIMIT_MAXIMAL_VALUE: number = MAX_PAGE_SIZE;
public static readonly OFFSET_DEFAULT_VALUE: number = INITIAL_PAGE_INDEX;
public static readonly OFFSET_MINIMAL_VALUE: number = MIN_PAGE_INDEX;
public static readonly OFFSET_MAXIMAL_VALUE: number = Number.MAX_SAFE_INTEGER;
public static createWithMaxLimit(): Result<OffsetPaging> {
return OffsetPaging.create({
offset: OffsetPaging.OFFSET_DEFAULT_VALUE,
limit: OffsetPaging.LIMIT_MAXIMAL_VALUE,
});
}
public static createWithDefaultValues(): Result<OffsetPaging> {
return OffsetPaging.create({
offset: OffsetPaging.OFFSET_DEFAULT_VALUE,
limit: OffsetPaging.LIMIT_DEFAULT_VALUE,
});
}
public static create(paginationProps: IOffsetPagingProps) {
const offset = paginationProps.offset || OffsetPaging.OFFSET_DEFAULT_VALUE;
const limit = paginationProps.limit || OffsetPaging.LIMIT_DEFAULT_VALUE;
const validatedProps = OffsetPaging.validate(offset, limit);
if (validatedProps.isFailure) {
return Result.fail(validatedProps.error);
}
const paging: IOffsetPaging = validatedProps.data as IOffsetPaging;
return Result.ok<OffsetPaging>(new OffsetPaging(paging));
}
private static validate(offset: string | number, limit: string | number) {
const numberOrError = RuleValidator.validate(RuleValidator.RULE_IS_TYPE_NUMBER, offset);
if (numberOrError.isFailure) {
return numberOrError;
}
const _offset = typeof offset === "string" ? Number.parseInt(offset, 10) : offset;
const offsetValidate = RuleValidator.validate(
Joi.number().min(OffsetPaging.OFFSET_MINIMAL_VALUE).max(OffsetPaging.OFFSET_MAXIMAL_VALUE),
offset
);
if (offsetValidate.isFailure) {
return Result.fail(
new Error(`Page need to be larger than or equal to ${OffsetPaging.OFFSET_MINIMAL_VALUE}.`)
);
}
// limit
const limitNumberOrError = RuleValidator.validate(RuleValidator.RULE_IS_TYPE_NUMBER, limit);
if (limitNumberOrError.isFailure) {
return limitNumberOrError;
}
const _limit = typeof limit === "string" ? Number.parseInt(limit, 10) : limit;
const limitValidate = RuleValidator.validate(
Joi.number().min(0).max(OffsetPaging.LIMIT_MAXIMAL_VALUE),
offset
);
if (limitValidate.isFailure) {
return Result.fail(
new Error(`Page size need to be smaller than ${OffsetPaging.LIMIT_MAXIMAL_VALUE}`)
);
}
return Result.ok({
offset: _offset,
limit: _limit,
});
}
private constructor(props: IOffsetPaging) {
super(props);
}
getValue() {
return this.props;
}
get offset(): number {
return this.props.offset;
}
get limit(): number {
return this.props.limit;
}
public next(): OffsetPaging {
return new OffsetPaging({
offset: this.props.offset + this.props.limit,
limit: this.props.limit,
});
}
public toJSON(): string {
return JSON.stringify(this.toObject());
}
public toPrimitive(): string {
throw new Error("NOT IMPLEMENT OffsetPaging.toPrimitive()");
}
public toObject(): Record<string, any> {
return {
limit: this.props.limit,
offset: this.props.offset,
};
}
}