@longzai-intelligence/pagination 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +3 -3
- package/.turbo/turbo-test$colon$coverage.log +6 -6
- package/.turbo/turbo-test.log +7 -7
- package/CHANGELOG.md +7 -0
- package/README.md +5 -1
- package/coverage/coverage-final.json +6 -2
- package/coverage/index.html +19 -4
- package/coverage/src/adapters/index.html +1 -16
- package/coverage/src/adapters/typeorm.adapter.ts.html +1 -1
- package/coverage/src/index.html +16 -1
- package/coverage/src/index.ts.html +38 -11
- package/coverage/src/schemas/index.html +161 -0
- package/coverage/src/{adapters → schemas}/index.ts.html +61 -10
- package/coverage/src/schemas/pagination.schemas.ts.html +343 -0
- package/coverage/src/schemas/result.schemas.ts.html +724 -0
- package/coverage/src/schemas/sort.schemas.ts.html +544 -0
- package/coverage/src/typeorm.ts.html +154 -0
- package/coverage/src/types/index.html +1 -1
- package/coverage/src/types/index.ts.html +69 -3
- package/coverage/src/types/pagination.types.ts.html +15 -138
- package/coverage/src/types/result.types.ts.html +11 -299
- package/coverage/src/types/sort.types.ts.html +16 -139
- package/coverage/src/types/typeorm.d.ts.html +1 -1
- package/coverage/src/utils/index.html +1 -1
- package/coverage/src/utils/index.ts.html +1 -1
- package/coverage/src/utils/pagination.util.ts.html +1 -1
- package/coverage/src/utils/validation.util.ts.html +1 -1
- package/dist/index-C8FaNzej.d.mts +145 -0
- package/dist/index-CMiyhlfm.d.cts +145 -0
- package/dist/index.cjs +33 -1
- package/dist/index.d.cts +2 -81
- package/dist/index.d.mts +2 -81
- package/dist/index.mjs +1 -1
- package/dist/typeorm.cjs +129 -0
- package/dist/typeorm.d.cts +26 -0
- package/dist/typeorm.d.mts +26 -0
- package/dist/typeorm.mjs +1 -0
- package/dist/utils-CV6Ovku6.mjs +1 -0
- package/dist/utils-D_qD2YAX.cjs +1 -0
- package/docs/specs/spec-20260413-typeorm-subpath-export/checklist.md +33 -0
- package/docs/specs/spec-20260413-typeorm-subpath-export/spec.md +104 -0
- package/docs/specs/spec-20260413-typeorm-subpath-export/tasks.md +48 -0
- package/package.json +15 -3
- package/src/__tests__/index.test.ts +9 -3
- package/src/__tests__/pagination.util.test.ts +0 -2
- package/src/__tests__/result.schemas.test.ts +142 -0
- package/src/__tests__/sort.schemas.test.ts +157 -0
- package/src/__tests__/typeorm.adapter.test.ts +1 -3
- package/src/__tests__/validation.util.test.ts +0 -2
- package/src/adapters/{typeorm.adapter.ts → typeorm/adapter.ts} +10 -92
- package/src/adapters/typeorm/index.ts +23 -0
- package/src/adapters/typeorm/types.ts +95 -0
- package/src/index.ts +18 -9
- package/src/schemas/index.ts +28 -0
- package/src/schemas/pagination.schemas.ts +86 -0
- package/src/schemas/result.schemas.ts +213 -0
- package/src/schemas/sort.schemas.ts +153 -0
- package/src/typeorm.ts +23 -0
- package/src/types/index.ts +23 -1
- package/src/types/pagination.types.ts +13 -54
- package/src/types/result.types.ts +9 -105
- package/src/types/sort.types.ts +14 -55
- package/tsconfig/.cache/app.tsbuildinfo +1 -1
- package/tsconfig/.cache/node.tsbuildinfo +1 -1
- package/tsconfig/.cache/test.tsbuildinfo +1 -1
- package/tsconfig/app.json +4 -1
- package/tsdown.config.ts +10 -3
- package/src/adapters/index.ts +0 -11
- package/tsconfig/.cache/build.tsbuildinfo +0 -1
- /package/src/{types → adapters/typeorm}/typeorm.d.ts +0 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { T as PaginationParams, m as PaginatedResult } from "./index-CMiyhlfm.cjs";
|
|
2
|
+
import { FindManyOptions, FindOptionsOrder, ObjectLiteral, Repository, SelectQueryBuilder } from "typeorm";
|
|
3
|
+
|
|
4
|
+
//#region src/adapters/typeorm/types.d.ts
|
|
5
|
+
type EntityMapper<TEntity, TDto> = (entity: TEntity) => TDto | Promise<TDto>;
|
|
6
|
+
type TypeOrmPaginateOptionsWithMapper<TEntity extends ObjectLiteral, TDto> = {
|
|
7
|
+
mapper: EntityMapper<TEntity, TDto>;
|
|
8
|
+
order?: FindOptionsOrder<TEntity>;
|
|
9
|
+
where?: FindManyOptions<TEntity>['where'];
|
|
10
|
+
relations?: FindManyOptions<TEntity>['relations'];
|
|
11
|
+
select?: FindManyOptions<TEntity>['select'];
|
|
12
|
+
};
|
|
13
|
+
type TypeOrmPaginateOptionsNoMapper<TEntity extends ObjectLiteral> = {
|
|
14
|
+
order?: FindOptionsOrder<TEntity>;
|
|
15
|
+
where?: FindManyOptions<TEntity>['where'];
|
|
16
|
+
relations?: FindManyOptions<TEntity>['relations'];
|
|
17
|
+
select?: FindManyOptions<TEntity>['select'];
|
|
18
|
+
};
|
|
19
|
+
type TypeOrmPaginateOptions<TEntity extends ObjectLiteral, TDto = TEntity> = TypeOrmPaginateOptionsWithMapper<TEntity, TDto> | TypeOrmPaginateOptionsNoMapper<TEntity>;
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/adapters/typeorm/adapter.d.ts
|
|
22
|
+
declare function paginateWithRepository<TEntity extends ObjectLiteral, TDto = TEntity>(repository: Repository<TEntity>, params: PaginationParams, options?: TypeOrmPaginateOptions<TEntity, TDto>): Promise<PaginatedResult<TEntity | TDto>>;
|
|
23
|
+
declare function paginateWithQueryBuilder<TEntity extends ObjectLiteral, TDto = TEntity>(queryBuilder: SelectQueryBuilder<TEntity>, params: PaginationParams, mapper?: EntityMapper<TEntity, TDto>): Promise<PaginatedResult<TEntity | TDto>>;
|
|
24
|
+
declare function createPaginationQueryBuilder<TEntity extends ObjectLiteral>(repository: Repository<TEntity>, alias?: string): SelectQueryBuilder<TEntity>;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { type EntityMapper, type TypeOrmPaginateOptions, createPaginationQueryBuilder, paginateWithQueryBuilder, paginateWithRepository };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { T as PaginationParams, m as PaginatedResult } from "./index-C8FaNzej.mjs";
|
|
2
|
+
import { FindManyOptions, FindOptionsOrder, ObjectLiteral, Repository, SelectQueryBuilder } from "typeorm";
|
|
3
|
+
|
|
4
|
+
//#region src/adapters/typeorm/types.d.ts
|
|
5
|
+
type EntityMapper<TEntity, TDto> = (entity: TEntity) => TDto | Promise<TDto>;
|
|
6
|
+
type TypeOrmPaginateOptionsWithMapper<TEntity extends ObjectLiteral, TDto> = {
|
|
7
|
+
mapper: EntityMapper<TEntity, TDto>;
|
|
8
|
+
order?: FindOptionsOrder<TEntity>;
|
|
9
|
+
where?: FindManyOptions<TEntity>['where'];
|
|
10
|
+
relations?: FindManyOptions<TEntity>['relations'];
|
|
11
|
+
select?: FindManyOptions<TEntity>['select'];
|
|
12
|
+
};
|
|
13
|
+
type TypeOrmPaginateOptionsNoMapper<TEntity extends ObjectLiteral> = {
|
|
14
|
+
order?: FindOptionsOrder<TEntity>;
|
|
15
|
+
where?: FindManyOptions<TEntity>['where'];
|
|
16
|
+
relations?: FindManyOptions<TEntity>['relations'];
|
|
17
|
+
select?: FindManyOptions<TEntity>['select'];
|
|
18
|
+
};
|
|
19
|
+
type TypeOrmPaginateOptions<TEntity extends ObjectLiteral, TDto = TEntity> = TypeOrmPaginateOptionsWithMapper<TEntity, TDto> | TypeOrmPaginateOptionsNoMapper<TEntity>;
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/adapters/typeorm/adapter.d.ts
|
|
22
|
+
declare function paginateWithRepository<TEntity extends ObjectLiteral, TDto = TEntity>(repository: Repository<TEntity>, params: PaginationParams, options?: TypeOrmPaginateOptions<TEntity, TDto>): Promise<PaginatedResult<TEntity | TDto>>;
|
|
23
|
+
declare function paginateWithQueryBuilder<TEntity extends ObjectLiteral, TDto = TEntity>(queryBuilder: SelectQueryBuilder<TEntity>, params: PaginationParams, mapper?: EntityMapper<TEntity, TDto>): Promise<PaginatedResult<TEntity | TDto>>;
|
|
24
|
+
declare function createPaginationQueryBuilder<TEntity extends ObjectLiteral>(repository: Repository<TEntity>, alias?: string): SelectQueryBuilder<TEntity>;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { type EntityMapper, type TypeOrmPaginateOptions, createPaginationQueryBuilder, paginateWithQueryBuilder, paginateWithRepository };
|
package/dist/typeorm.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{c as e,d as t,p as n,s as r,u as i}from"./utils-CV6Ovku6.mjs";function a(e){return e!==void 0&&`mapper`in e}function o(n,r,a,o){let s=e(r,o);return{items:n,total:r,page:a,pageSize:o,totalPages:s,hasNextPage:i(a,s),hasPreviousPage:t(a)}}async function s(e,t,i){let{page:s,pageSize:c}=n(t),l={skip:r(s,c),take:c,where:i?.where,relations:i?.relations,select:i?.select,order:i?.order??{createdAt:`DESC`}},[u,d]=await e.findAndCount(l);return a(i)?o(await Promise.all(u.map(i.mapper)),d,s,c):o(u,d,s,c)}async function c(e,t,i){let{page:a,pageSize:s}=n(t),c=r(a,s);e.skip(c).take(s);let[l,u]=await e.getManyAndCount();return o(i?await Promise.all(l.map(i)):l,u,a,s)}function l(e,t){return e.createQueryBuilder(t??e.metadata.name.toLowerCase())}export{l as createPaginationQueryBuilder,c as paginateWithQueryBuilder,s as paginateWithRepository};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{z as e}from"zod";const t=e.object({page:e.literal(1),pageSize:e.literal(20),maxPageSize:e.literal(100),minPageSize:e.literal(1)}),n=e.object({page:e.number().int().positive().optional(),pageSize:e.number().int().positive().optional()}),r=e.object({limit:e.number().int().positive().optional(),offset:e.number().int().nonnegative().optional()}),i=e.object({cursor:e.string().optional(),limit:e.number().int().positive().optional()}),a={page:1,pageSize:20,maxPageSize:100,minPageSize:1};function o(t){return e.object({items:e.array(t),total:e.number().int().nonnegative(),page:e.number().int().positive(),pageSize:e.number().int().positive(),totalPages:e.number().int().nonnegative(),hasNextPage:e.boolean(),hasPreviousPage:e.boolean()})}function s(t){return e.object({items:e.array(t),total:e.number().int().nonnegative(),limit:e.number().int().nonnegative(),offset:e.number().int().nonnegative(),hasMore:e.boolean()})}function c(t){return e.object({items:e.array(t),nextCursor:e.string().nullable(),previousCursor:e.string().nullable(),hasMore:e.boolean()})}const l=e.enum([`asc`,`desc`]);function u(t){return e.object({sortBy:e.enum(t).optional(),sortOrder:l.optional()})}const d=e.object({sortBy:e.string().optional(),sortOrder:l.optional()});function f(t){return e.object({field:e.enum(t),order:l})}const p=e.object({field:e.string(),order:l});function m(t){return e.object({sort:e.array(f(t)).optional()})}const h=e.object({sort:e.array(p).optional()});function g(e){return{page:Math.max(1,Math.floor(e?.page??a.page)),pageSize:Math.min(a.maxPageSize,Math.max(a.minPageSize,Math.floor(e?.pageSize??a.pageSize)))}}function _(e){return{limit:Math.min(a.maxPageSize,Math.max(a.minPageSize,Math.floor(e?.limit??a.pageSize))),offset:Math.max(0,Math.floor(e?.offset??0))}}function v(e,t){return(e-1)*t}function y(e,t){return t<=0?0:Math.ceil(e/t)}function b(e,t){return e<t}function x(e){return e>1}function S(e,t){let n=Math.max(1,t);return{page:Math.floor(e/n)+1,pageSize:n}}function C(e,t){let n=Math.max(1,e),r=Math.max(1,t);return{offset:(n-1)*r,limit:r}}function w(e,t,n,r){let i=y(t,r);return{items:e,total:t,page:n,pageSize:r,totalPages:i,hasNextPage:b(n,i),hasPreviousPage:x(n)}}function T(e){return typeof e==`object`&&!!e}function E(e){return typeof e==`number`&&Number.isInteger(e)&&e>=1}function D(e){return typeof e==`number`&&Number.isInteger(e)&&e>=a.minPageSize&&e<=a.maxPageSize}function O(e){return typeof e==`number`&&Number.isInteger(e)&&e>=0}function k(e){return typeof e==`number`&&Number.isInteger(e)&&e>=a.minPageSize&&e<=a.maxPageSize}function A(e){if(!T(e))return!1;let t=e.page,n=e.pageSize;return(t===void 0||E(t))&&(n===void 0||D(n))}function j(e){if(!T(e))return!1;let t=e.limit,n=e.offset;return(t===void 0||k(t))&&(n===void 0||O(n))}export{n as A,c as C,i as D,a as E,r as O,u as S,o as T,p as _,D as a,m as b,y as c,x as d,_ as f,h as g,C as h,E as i,t as k,w as l,S as m,O as n,A as o,g as p,j as r,v as s,k as t,b as u,l as v,s as w,f as x,d as y};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
let e=require(`zod`);const t=e.z.object({page:e.z.literal(1),pageSize:e.z.literal(20),maxPageSize:e.z.literal(100),minPageSize:e.z.literal(1)}),n=e.z.object({page:e.z.number().int().positive().optional(),pageSize:e.z.number().int().positive().optional()}),r=e.z.object({limit:e.z.number().int().positive().optional(),offset:e.z.number().int().nonnegative().optional()}),i=e.z.object({cursor:e.z.string().optional(),limit:e.z.number().int().positive().optional()}),a={page:1,pageSize:20,maxPageSize:100,minPageSize:1};function o(t){return e.z.object({items:e.z.array(t),total:e.z.number().int().nonnegative(),page:e.z.number().int().positive(),pageSize:e.z.number().int().positive(),totalPages:e.z.number().int().nonnegative(),hasNextPage:e.z.boolean(),hasPreviousPage:e.z.boolean()})}function s(t){return e.z.object({items:e.z.array(t),total:e.z.number().int().nonnegative(),limit:e.z.number().int().nonnegative(),offset:e.z.number().int().nonnegative(),hasMore:e.z.boolean()})}function c(t){return e.z.object({items:e.z.array(t),nextCursor:e.z.string().nullable(),previousCursor:e.z.string().nullable(),hasMore:e.z.boolean()})}const l=e.z.enum([`asc`,`desc`]);function u(t){return e.z.object({sortBy:e.z.enum(t).optional(),sortOrder:l.optional()})}const d=e.z.object({sortBy:e.z.string().optional(),sortOrder:l.optional()});function f(t){return e.z.object({field:e.z.enum(t),order:l})}const p=e.z.object({field:e.z.string(),order:l});function m(t){return e.z.object({sort:e.z.array(f(t)).optional()})}const h=e.z.object({sort:e.z.array(p).optional()});function g(e){return{page:Math.max(1,Math.floor(e?.page??a.page)),pageSize:Math.min(a.maxPageSize,Math.max(a.minPageSize,Math.floor(e?.pageSize??a.pageSize)))}}function _(e){return{limit:Math.min(a.maxPageSize,Math.max(a.minPageSize,Math.floor(e?.limit??a.pageSize))),offset:Math.max(0,Math.floor(e?.offset??0))}}function v(e,t){return(e-1)*t}function y(e,t){return t<=0?0:Math.ceil(e/t)}function b(e,t){return e<t}function x(e){return e>1}function S(e,t){let n=Math.max(1,t);return{page:Math.floor(e/n)+1,pageSize:n}}function C(e,t){let n=Math.max(1,e),r=Math.max(1,t);return{offset:(n-1)*r,limit:r}}function w(e,t,n,r){let i=y(t,r);return{items:e,total:t,page:n,pageSize:r,totalPages:i,hasNextPage:b(n,i),hasPreviousPage:x(n)}}function T(e){return typeof e==`object`&&!!e}function E(e){return typeof e==`number`&&Number.isInteger(e)&&e>=1}function D(e){return typeof e==`number`&&Number.isInteger(e)&&e>=a.minPageSize&&e<=a.maxPageSize}function O(e){return typeof e==`number`&&Number.isInteger(e)&&e>=0}function k(e){return typeof e==`number`&&Number.isInteger(e)&&e>=a.minPageSize&&e<=a.maxPageSize}function A(e){if(!T(e))return!1;let t=e.page,n=e.pageSize;return(t===void 0||E(t))&&(n===void 0||D(n))}function j(e){if(!T(e))return!1;let t=e.limit,n=e.offset;return(t===void 0||k(t))&&(n===void 0||O(n))}Object.defineProperty(exports,`A`,{enumerable:!0,get:function(){return n}}),Object.defineProperty(exports,`C`,{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,`D`,{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,`E`,{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,`O`,{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,`S`,{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,`T`,{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,`_`,{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return D}}),Object.defineProperty(exports,`b`,{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return y}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return x}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,`g`,{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,`h`,{enumerable:!0,get:function(){return C}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return E}}),Object.defineProperty(exports,`k`,{enumerable:!0,get:function(){return t}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return w}}),Object.defineProperty(exports,`m`,{enumerable:!0,get:function(){return S}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return O}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return A}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return j}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return k}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,`v`,{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,`w`,{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,`x`,{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,`y`,{enumerable:!0,get:function(){return d}});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# 检查清单
|
|
2
|
+
|
|
3
|
+
## 代码变更
|
|
4
|
+
|
|
5
|
+
- [ ] `src/typeorm.ts` 文件已创建
|
|
6
|
+
- [ ] `src/index.ts` 已移除 TypeORM 相关导出
|
|
7
|
+
- [ ] `src/adapters/index.ts` 已删除
|
|
8
|
+
- [ ] `src/adapters/typeorm.adapter.ts` 保留不变
|
|
9
|
+
|
|
10
|
+
## 配置变更
|
|
11
|
+
|
|
12
|
+
- [ ] `package.json` exports 字段已添加 `./typeorm`
|
|
13
|
+
- [ ] `tsdown.config.ts` 已配置多入口
|
|
14
|
+
|
|
15
|
+
## 文档变更
|
|
16
|
+
|
|
17
|
+
- [ ] `README.md` 已更新使用示例
|
|
18
|
+
- [ ] 子路径导入说明已添加
|
|
19
|
+
- [ ] `/docs/user-guides/pagination-user-guide-v1.md` 已更新
|
|
20
|
+
- [ ] TypeORM 适配器导入路径已修改为子路径方式
|
|
21
|
+
|
|
22
|
+
## 测试验证
|
|
23
|
+
|
|
24
|
+
- [ ] 单元测试通过
|
|
25
|
+
- [ ] 类型检查通过
|
|
26
|
+
- [ ] 构建成功
|
|
27
|
+
- [ ] Lint 检查通过
|
|
28
|
+
|
|
29
|
+
## 导出验证
|
|
30
|
+
|
|
31
|
+
- [ ] 主入口 `@longzai-intelligence/pagination` 只导出核心功能
|
|
32
|
+
- [ ] 子路径 `@longzai-intelligence/pagination/typeorm` 导出 TypeORM 适配器
|
|
33
|
+
- [ ] 类型定义正确生成
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# TypeORM 适配器子路径导出规格
|
|
2
|
+
|
|
3
|
+
## 背景
|
|
4
|
+
|
|
5
|
+
当前 `@longzai-intelligence/pagination` 包将 TypeORM 适配器直接从主入口导出,这导致:
|
|
6
|
+
|
|
7
|
+
1. 主入口 `index.ts` 被 TypeORM 特定代码污染
|
|
8
|
+
2. 不使用 TypeORM 的用户也会引入 TypeORM 相关类型
|
|
9
|
+
3. 违反了可选依赖的最佳实践
|
|
10
|
+
|
|
11
|
+
## 目标
|
|
12
|
+
|
|
13
|
+
将 TypeORM 适配器改为子路径导出,实现:
|
|
14
|
+
|
|
15
|
+
1. 主入口保持纯净,只导出分页核心功能
|
|
16
|
+
2. TypeORM 适配器通过 `@longzai-intelligence/pagination/typeorm` 单独导入
|
|
17
|
+
3. 用户按需导入,减少不必要的依赖感知
|
|
18
|
+
|
|
19
|
+
## 导出结构变更
|
|
20
|
+
|
|
21
|
+
### 变更前
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
// 主入口 index.ts 同时导出核心功能和 TypeORM 适配器
|
|
25
|
+
export { paginateWithRepository, paginateWithQueryBuilder } from './adapters';
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 变更后
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
// 主入口 index.ts - 只导出核心功能
|
|
32
|
+
export { normalizePagination, calculateOffset, ... } from './utils';
|
|
33
|
+
export type { PaginationParams, PaginatedResult, ... } from './types';
|
|
34
|
+
|
|
35
|
+
// 新增 typeorm.ts 入口 - 单独导出 TypeORM 适配器
|
|
36
|
+
export { paginateWithRepository, paginateWithQueryBuilder, createPaginationQueryBuilder } from './adapters/typeorm.adapter';
|
|
37
|
+
export type { EntityMapper, TypeOrmPaginateOptions } from './adapters/typeorm.adapter';
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## package.json exports 配置
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"exports": {
|
|
45
|
+
".": {
|
|
46
|
+
"types": {
|
|
47
|
+
"import": "./dist/index.d.mts",
|
|
48
|
+
"require": "./dist/index.d.cts"
|
|
49
|
+
},
|
|
50
|
+
"import": "./dist/index.mjs",
|
|
51
|
+
"require": "./dist/index.cjs"
|
|
52
|
+
},
|
|
53
|
+
"./typeorm": {
|
|
54
|
+
"types": {
|
|
55
|
+
"import": "./dist/typeorm.d.mts",
|
|
56
|
+
"require": "./dist/typeorm.d.cts"
|
|
57
|
+
},
|
|
58
|
+
"import": "./dist/typeorm.mjs",
|
|
59
|
+
"require": "./dist/typeorm.cjs"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## 使用方式变更
|
|
66
|
+
|
|
67
|
+
### 变更前
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import { paginateWithRepository, type PaginationParams } from '@longzai-intelligence/pagination';
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 变更后
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
// 核心功能 - 从主入口导入
|
|
77
|
+
import { type PaginationParams, type PaginatedResult } from '@longzai-intelligence/pagination';
|
|
78
|
+
|
|
79
|
+
// TypeORM 适配器 - 从子路径导入
|
|
80
|
+
import { paginateWithRepository } from '@longzai-intelligence/pagination/typeorm';
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 文件变更清单
|
|
84
|
+
|
|
85
|
+
| 文件 | 操作 | 说明 |
|
|
86
|
+
|------|------|------|
|
|
87
|
+
| `src/index.ts` | 修改 | 移除 TypeORM 适配器导出 |
|
|
88
|
+
| `src/typeorm.ts` | 新增 | TypeORM 适配器独立入口 |
|
|
89
|
+
| `src/adapters/index.ts` | 删除 | 不再需要适配器聚合入口 |
|
|
90
|
+
| `package.json` | 修改 | 添加 `./typeorm` 子路径导出 |
|
|
91
|
+
| `tsdown.config.ts` | 修改 | 添加 typeorm 入口配置 |
|
|
92
|
+
| `README.md` | 修改 | 更新使用文档 |
|
|
93
|
+
| `docs/user-guides/pagination-user-guide-v1.md` | 修改 | 更新 TypeORM 适配器导入路径 |
|
|
94
|
+
|
|
95
|
+
## 影响范围
|
|
96
|
+
|
|
97
|
+
1. 现有使用 `@longzai-intelligence/pagination` 导入 TypeORM 适配器的代码需要修改导入路径
|
|
98
|
+
2. 仅使用核心功能的代码无需修改
|
|
99
|
+
|
|
100
|
+
## 风险评估
|
|
101
|
+
|
|
102
|
+
- **破坏性变更**: 是,导入路径变更
|
|
103
|
+
- **向后兼容**: 否,需要用户更新导入路径
|
|
104
|
+
- **迁移成本**: 低,仅需修改导入语句
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# 任务列表
|
|
2
|
+
|
|
3
|
+
## 1. 创建 TypeORM 独立入口文件
|
|
4
|
+
|
|
5
|
+
- [ ] 创建 `src/typeorm.ts` 文件
|
|
6
|
+
- [ ] 从 `./adapters/typeorm.adapter` 导出所有 TypeORM 相关功能和类型
|
|
7
|
+
|
|
8
|
+
## 2. 修改主入口文件
|
|
9
|
+
|
|
10
|
+
- [ ] 从 `src/index.ts` 移除 TypeORM 适配器相关导出
|
|
11
|
+
- [ ] 确保核心功能导出完整
|
|
12
|
+
|
|
13
|
+
## 3. 清理适配器目录
|
|
14
|
+
|
|
15
|
+
- [ ] 删除 `src/adapters/index.ts` 文件(不再需要)
|
|
16
|
+
- [ ] 保留 `src/adapters/typeorm.adapter.ts` 文件
|
|
17
|
+
|
|
18
|
+
## 4. 更新 package.json
|
|
19
|
+
|
|
20
|
+
- [ ] 在 `exports` 字段添加 `./typeorm` 子路径配置
|
|
21
|
+
- [ ] 确保类型定义文件路径正确
|
|
22
|
+
|
|
23
|
+
## 5. 更新构建配置
|
|
24
|
+
|
|
25
|
+
- [ ] 修改 `tsdown.config.ts` 添加多入口配置
|
|
26
|
+
- [ ] 确保 typeorm 入口正确构建
|
|
27
|
+
|
|
28
|
+
## 6. 更新文档
|
|
29
|
+
|
|
30
|
+
- [ ] 更新 `README.md` 使用示例
|
|
31
|
+
- [ ] 添加子路径导入说明
|
|
32
|
+
|
|
33
|
+
## 7. 更新用户指南
|
|
34
|
+
|
|
35
|
+
- [ ] 更新 `/docs/user-guides/pagination-user-guide-v1.md`
|
|
36
|
+
- [ ] 修改 TypeORM 适配器导入路径为子路径方式
|
|
37
|
+
- [ ] 更新所有相关代码示例
|
|
38
|
+
|
|
39
|
+
## 8. 更新测试
|
|
40
|
+
|
|
41
|
+
- [ ] 检查并更新测试文件中的导入路径
|
|
42
|
+
- [ ] 确保测试通过
|
|
43
|
+
|
|
44
|
+
## 9. 验证构建
|
|
45
|
+
|
|
46
|
+
- [ ] 运行 `bun run build` 验证构建成功
|
|
47
|
+
- [ ] 运行 `bun run typecheck` 验证类型正确
|
|
48
|
+
- [ ] 运行 `bun run lint:fix` 验证代码规范
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@longzai-intelligence/pagination",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"types": "./dist/index.d.mts",
|
|
@@ -12,6 +12,14 @@
|
|
|
12
12
|
},
|
|
13
13
|
"import": "./dist/index.mjs",
|
|
14
14
|
"require": "./dist/index.cjs"
|
|
15
|
+
},
|
|
16
|
+
"./typeorm": {
|
|
17
|
+
"types": {
|
|
18
|
+
"import": "./dist/typeorm.d.mts",
|
|
19
|
+
"require": "./dist/typeorm.d.cts"
|
|
20
|
+
},
|
|
21
|
+
"import": "./dist/typeorm.mjs",
|
|
22
|
+
"require": "./dist/typeorm.cjs"
|
|
15
23
|
}
|
|
16
24
|
},
|
|
17
25
|
"scripts": {
|
|
@@ -32,11 +40,15 @@
|
|
|
32
40
|
"upgrade-deps": "ncu -u"
|
|
33
41
|
},
|
|
34
42
|
"peerDependencies": {
|
|
35
|
-
"typeorm": "^0.3.0"
|
|
43
|
+
"typeorm": "^0.3.0",
|
|
44
|
+
"zod": "^4.0.0"
|
|
36
45
|
},
|
|
37
46
|
"peerDependenciesMeta": {
|
|
38
47
|
"typeorm": {
|
|
39
48
|
"optional": true
|
|
49
|
+
},
|
|
50
|
+
"zod": {
|
|
51
|
+
"optional": true
|
|
40
52
|
}
|
|
41
53
|
},
|
|
42
54
|
"devDependencies": {
|
|
@@ -47,7 +59,7 @@
|
|
|
47
59
|
"typescript": "^6.0.2",
|
|
48
60
|
"vitest": "^4.1.4",
|
|
49
61
|
"@longzai-intelligence/eslint-preset-library": "0.0.5",
|
|
50
|
-
"@longzai-intelligence/vitest-config": "0.0.
|
|
62
|
+
"@longzai-intelligence/vitest-config": "0.0.7",
|
|
51
63
|
"@longzai-intelligence/typescript-config": "0.0.3",
|
|
52
64
|
"tsdown": "^0.21.7",
|
|
53
65
|
"@longzai-intelligence/tsdown-config": "0.0.1"
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @file index.test.ts
|
|
3
2
|
* 主入口导出测试
|
|
4
|
-
* @author Longzai Intelligence
|
|
5
3
|
*/
|
|
6
4
|
|
|
7
5
|
import { describe, it, expect } from 'vitest';
|
|
@@ -42,9 +40,17 @@ describe('pagination 包导出', () => {
|
|
|
42
40
|
expect(module.isValidOffsetPagination).toBeDefined();
|
|
43
41
|
});
|
|
44
42
|
|
|
45
|
-
it('
|
|
43
|
+
it('主入口不应导出 TypeORM 适配器', async () => {
|
|
46
44
|
const module = await import('@/index');
|
|
47
45
|
|
|
46
|
+
expect('paginateWithRepository' in module).toBe(false);
|
|
47
|
+
expect('paginateWithQueryBuilder' in module).toBe(false);
|
|
48
|
+
expect('createPaginationQueryBuilder' in module).toBe(false);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('typeorm 子路径应正确导出适配器', async () => {
|
|
52
|
+
const module = await import('@/typeorm');
|
|
53
|
+
|
|
48
54
|
expect(module.paginateWithRepository).toBeDefined();
|
|
49
55
|
expect(module.paginateWithQueryBuilder).toBeDefined();
|
|
50
56
|
expect(module.createPaginationQueryBuilder).toBeDefined();
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 分页结果 Schema 测试
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect } from 'vitest';
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import {
|
|
8
|
+
createPaginatedResultSchema,
|
|
9
|
+
createOffsetPaginatedResultSchema,
|
|
10
|
+
createCursorPaginatedResultSchema,
|
|
11
|
+
} from '@/schemas/result.schemas';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 测试实体 Schema
|
|
15
|
+
*/
|
|
16
|
+
const TestItemSchema = z.object({
|
|
17
|
+
id: z.number(),
|
|
18
|
+
name: z.string(),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('createPaginatedResultSchema', () => {
|
|
22
|
+
it('应正确验证有效的分页结果', () => {
|
|
23
|
+
const schema = createPaginatedResultSchema(TestItemSchema);
|
|
24
|
+
const result = schema.parse({
|
|
25
|
+
items: [{ id: 1, name: 'test' }],
|
|
26
|
+
total: 100,
|
|
27
|
+
page: 1,
|
|
28
|
+
pageSize: 20,
|
|
29
|
+
totalPages: 5,
|
|
30
|
+
hasNextPage: true,
|
|
31
|
+
hasPreviousPage: false,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
expect(result.items).toHaveLength(1);
|
|
35
|
+
expect(result.total).toBe(100);
|
|
36
|
+
expect(result.page).toBe(1);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('应拒绝无效的分页结果', () => {
|
|
40
|
+
const schema = createPaginatedResultSchema(TestItemSchema);
|
|
41
|
+
|
|
42
|
+
expect(() =>
|
|
43
|
+
schema.parse({
|
|
44
|
+
items: [{ id: 'invalid', name: 'test' }],
|
|
45
|
+
total: 100,
|
|
46
|
+
page: 1,
|
|
47
|
+
pageSize: 20,
|
|
48
|
+
totalPages: 5,
|
|
49
|
+
hasNextPage: true,
|
|
50
|
+
hasPreviousPage: false,
|
|
51
|
+
}),
|
|
52
|
+
).toThrow();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('应拒绝缺少必需字段的分页结果', () => {
|
|
56
|
+
const schema = createPaginatedResultSchema(TestItemSchema);
|
|
57
|
+
|
|
58
|
+
expect(() =>
|
|
59
|
+
schema.parse({
|
|
60
|
+
items: [{ id: 1, name: 'test' }],
|
|
61
|
+
total: 100,
|
|
62
|
+
}),
|
|
63
|
+
).toThrow();
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe('createOffsetPaginatedResultSchema', () => {
|
|
68
|
+
it('应正确验证有效的 Offset 分页结果', () => {
|
|
69
|
+
const schema = createOffsetPaginatedResultSchema(TestItemSchema);
|
|
70
|
+
const result = schema.parse({
|
|
71
|
+
items: [{ id: 1, name: 'test' }],
|
|
72
|
+
total: 100,
|
|
73
|
+
limit: 20,
|
|
74
|
+
offset: 0,
|
|
75
|
+
hasMore: true,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
expect(result.items).toHaveLength(1);
|
|
79
|
+
expect(result.total).toBe(100);
|
|
80
|
+
expect(result.limit).toBe(20);
|
|
81
|
+
expect(result.offset).toBe(0);
|
|
82
|
+
expect(result.hasMore).toBe(true);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('应拒绝无效的 Offset 分页结果', () => {
|
|
86
|
+
const schema = createOffsetPaginatedResultSchema(TestItemSchema);
|
|
87
|
+
|
|
88
|
+
expect(() =>
|
|
89
|
+
schema.parse({
|
|
90
|
+
items: [{ id: 1, name: 'test' }],
|
|
91
|
+
total: -1,
|
|
92
|
+
limit: 20,
|
|
93
|
+
offset: 0,
|
|
94
|
+
hasMore: true,
|
|
95
|
+
}),
|
|
96
|
+
).toThrow();
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe('createCursorPaginatedResultSchema', () => {
|
|
101
|
+
it('应正确验证有效的游标分页结果', () => {
|
|
102
|
+
const schema = createCursorPaginatedResultSchema(TestItemSchema);
|
|
103
|
+
const result = schema.parse({
|
|
104
|
+
items: [{ id: 1, name: 'test' }],
|
|
105
|
+
nextCursor: 'cursor123',
|
|
106
|
+
previousCursor: null,
|
|
107
|
+
hasMore: true,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
expect(result.items).toHaveLength(1);
|
|
111
|
+
expect(result.nextCursor).toBe('cursor123');
|
|
112
|
+
expect(result.previousCursor).toBeNull();
|
|
113
|
+
expect(result.hasMore).toBe(true);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('应支持 null 游标', () => {
|
|
117
|
+
const schema = createCursorPaginatedResultSchema(TestItemSchema);
|
|
118
|
+
const result = schema.parse({
|
|
119
|
+
items: [],
|
|
120
|
+
nextCursor: null,
|
|
121
|
+
previousCursor: null,
|
|
122
|
+
hasMore: false,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
expect(result.items).toHaveLength(0);
|
|
126
|
+
expect(result.nextCursor).toBeNull();
|
|
127
|
+
expect(result.previousCursor).toBeNull();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('应拒绝无效的游标分页结果', () => {
|
|
131
|
+
const schema = createCursorPaginatedResultSchema(TestItemSchema);
|
|
132
|
+
|
|
133
|
+
expect(() =>
|
|
134
|
+
schema.parse({
|
|
135
|
+
items: [{ id: 1, name: 'test' }],
|
|
136
|
+
nextCursor: 123,
|
|
137
|
+
previousCursor: null,
|
|
138
|
+
hasMore: true,
|
|
139
|
+
}),
|
|
140
|
+
).toThrow();
|
|
141
|
+
});
|
|
142
|
+
});
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 排序参数 Schema 测试
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect } from 'vitest';
|
|
6
|
+
import {
|
|
7
|
+
SortOrderSchema,
|
|
8
|
+
createSortParamsSchema,
|
|
9
|
+
SortParamsSchema,
|
|
10
|
+
createSortItemSchema,
|
|
11
|
+
SortItemSchema,
|
|
12
|
+
createMultiSortParamsSchema,
|
|
13
|
+
MultiSortParamsSchema,
|
|
14
|
+
} from '@/schemas/sort.schemas';
|
|
15
|
+
|
|
16
|
+
describe('SortOrderSchema', () => {
|
|
17
|
+
it('应接受有效的排序方向', () => {
|
|
18
|
+
expect(SortOrderSchema.parse('asc')).toBe('asc');
|
|
19
|
+
expect(SortOrderSchema.parse('desc')).toBe('desc');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('应拒绝无效的排序方向', () => {
|
|
23
|
+
expect(() => SortOrderSchema.parse('invalid')).toThrow();
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe('createSortParamsSchema', () => {
|
|
28
|
+
it('应正确验证有效的排序参数', () => {
|
|
29
|
+
const schema = createSortParamsSchema(['name', 'createdAt', 'updatedAt'] as const);
|
|
30
|
+
const result = schema.parse({
|
|
31
|
+
sortBy: 'name',
|
|
32
|
+
sortOrder: 'asc',
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
expect(result.sortBy).toBe('name');
|
|
36
|
+
expect(result.sortOrder).toBe('asc');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('应支持可选的排序参数', () => {
|
|
40
|
+
const schema = createSortParamsSchema(['name', 'createdAt'] as const);
|
|
41
|
+
const result = schema.parse({});
|
|
42
|
+
|
|
43
|
+
expect(result.sortBy).toBeUndefined();
|
|
44
|
+
expect(result.sortOrder).toBeUndefined();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('应拒绝无效的排序字段', () => {
|
|
48
|
+
const schema = createSortParamsSchema(['name', 'createdAt'] as const);
|
|
49
|
+
|
|
50
|
+
expect(() =>
|
|
51
|
+
schema.parse({
|
|
52
|
+
sortBy: 'invalid',
|
|
53
|
+
sortOrder: 'asc',
|
|
54
|
+
}),
|
|
55
|
+
).toThrow();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe('SortParamsSchema', () => {
|
|
60
|
+
it('应正确验证默认排序参数', () => {
|
|
61
|
+
const result = SortParamsSchema.parse({
|
|
62
|
+
sortBy: 'anyField',
|
|
63
|
+
sortOrder: 'desc',
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
expect(result.sortBy).toBe('anyField');
|
|
67
|
+
expect(result.sortOrder).toBe('desc');
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe('createSortItemSchema', () => {
|
|
72
|
+
it('应正确验证有效的排序项', () => {
|
|
73
|
+
const schema = createSortItemSchema(['name', 'createdAt'] as const);
|
|
74
|
+
const result = schema.parse({
|
|
75
|
+
field: 'name',
|
|
76
|
+
order: 'desc',
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
expect(result.field).toBe('name');
|
|
80
|
+
expect(result.order).toBe('desc');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('应拒绝无效的排序字段', () => {
|
|
84
|
+
const schema = createSortItemSchema(['name', 'createdAt'] as const);
|
|
85
|
+
|
|
86
|
+
expect(() =>
|
|
87
|
+
schema.parse({
|
|
88
|
+
field: 'invalid',
|
|
89
|
+
order: 'asc',
|
|
90
|
+
}),
|
|
91
|
+
).toThrow();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('应拒绝缺少必需字段', () => {
|
|
95
|
+
const schema = createSortItemSchema(['name', 'createdAt'] as const);
|
|
96
|
+
|
|
97
|
+
expect(() => schema.parse({ field: 'name' })).toThrow();
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe('SortItemSchema', () => {
|
|
102
|
+
it('应正确验证默认排序项', () => {
|
|
103
|
+
const result = SortItemSchema.parse({
|
|
104
|
+
field: 'anyField',
|
|
105
|
+
order: 'asc',
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
expect(result.field).toBe('anyField');
|
|
109
|
+
expect(result.order).toBe('asc');
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe('createMultiSortParamsSchema', () => {
|
|
114
|
+
it('应正确验证有效的多字段排序参数', () => {
|
|
115
|
+
const schema = createMultiSortParamsSchema(['name', 'createdAt', 'updatedAt'] as const);
|
|
116
|
+
const result = schema.parse({
|
|
117
|
+
sort: [
|
|
118
|
+
{ field: 'name', order: 'asc' },
|
|
119
|
+
{ field: 'createdAt', order: 'desc' },
|
|
120
|
+
],
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
expect(result.sort).toHaveLength(2);
|
|
124
|
+
expect(result.sort?.[0]?.field).toBe('name');
|
|
125
|
+
expect(result.sort?.[1]?.field).toBe('createdAt');
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('应支持可选的排序参数', () => {
|
|
129
|
+
const schema = createMultiSortParamsSchema(['name', 'createdAt'] as const);
|
|
130
|
+
const result = schema.parse({});
|
|
131
|
+
|
|
132
|
+
expect(result.sort).toBeUndefined();
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('应拒绝无效的排序字段', () => {
|
|
136
|
+
const schema = createMultiSortParamsSchema(['name', 'createdAt'] as const);
|
|
137
|
+
|
|
138
|
+
expect(() =>
|
|
139
|
+
schema.parse({
|
|
140
|
+
sort: [{ field: 'invalid', order: 'asc' }],
|
|
141
|
+
}),
|
|
142
|
+
).toThrow();
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe('MultiSortParamsSchema', () => {
|
|
147
|
+
it('应正确验证默认多字段排序参数', () => {
|
|
148
|
+
const result = MultiSortParamsSchema.parse({
|
|
149
|
+
sort: [
|
|
150
|
+
{ field: 'field1', order: 'asc' },
|
|
151
|
+
{ field: 'field2', order: 'desc' },
|
|
152
|
+
],
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
expect(result.sort).toHaveLength(2);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @file typeorm.adapter.test.ts
|
|
3
2
|
* TypeORM 适配器测试
|
|
4
|
-
* @author Longzai Intelligence
|
|
5
3
|
*/
|
|
6
4
|
|
|
7
5
|
import { describe, it, expect, vi } from 'vitest';
|
|
@@ -9,7 +7,7 @@ import {
|
|
|
9
7
|
paginateWithRepository,
|
|
10
8
|
paginateWithQueryBuilder,
|
|
11
9
|
createPaginationQueryBuilder,
|
|
12
|
-
} from '@/adapters/typeorm
|
|
10
|
+
} from '@/adapters/typeorm';
|
|
13
11
|
import type { Repository, SelectQueryBuilder, FindOptionsOrder } from 'typeorm';
|
|
14
12
|
|
|
15
13
|
/**
|