@longzai-intelligence/pagination 0.0.2 → 0.0.3
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/README.md +36 -207
- package/dist/hono.cjs +1 -0
- package/dist/hono.d.cts +15 -0
- package/dist/hono.d.mts +15 -0
- package/dist/hono.mjs +1 -0
- package/dist/{index-C8FaNzej.d.mts → index-C4IwIpFc.d.mts} +55 -1
- package/dist/{index-CMiyhlfm.d.cts → index-DpbbjAwO.d.cts} +55 -1
- package/dist/index.cjs +1 -33
- package/dist/index.d.cts +80 -2
- package/dist/index.d.mts +80 -2
- package/dist/index.mjs +1 -1
- package/dist/typeorm.cjs +1 -129
- package/dist/typeorm.d.cts +1 -1
- package/dist/typeorm.d.mts +1 -1
- package/dist/typeorm.mjs +1 -1
- package/dist/utils-B200OLT-.cjs +1 -0
- package/dist/utils-DsM7-PZL.mjs +1 -0
- package/package.json +19 -7
- package/.turbo/turbo-build.log +0 -22
- package/.turbo/turbo-lint.log +0 -1
- package/.turbo/turbo-test$colon$coverage.log +0 -36
- package/.turbo/turbo-test.log +0 -14
- package/.turbo/turbo-typecheck.log +0 -4
- package/CHANGELOG.md +0 -18
- package/coverage/base.css +0 -224
- package/coverage/block-navigation.js +0 -87
- package/coverage/coverage-final.json +0 -16
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +0 -176
- package/coverage/prettify.css +0 -1
- package/coverage/prettify.js +0 -2
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +0 -210
- package/coverage/src/adapters/index.html +0 -116
- package/coverage/src/adapters/typeorm.adapter.ts.html +0 -940
- package/coverage/src/index.html +0 -131
- package/coverage/src/index.ts.html +0 -280
- package/coverage/src/schemas/index.html +0 -161
- package/coverage/src/schemas/index.ts.html +0 -169
- package/coverage/src/schemas/pagination.schemas.ts.html +0 -343
- package/coverage/src/schemas/result.schemas.ts.html +0 -724
- package/coverage/src/schemas/sort.schemas.ts.html +0 -544
- package/coverage/src/typeorm.ts.html +0 -154
- package/coverage/src/types/index.html +0 -176
- package/coverage/src/types/index.ts.html +0 -199
- package/coverage/src/types/pagination.types.ts.html +0 -169
- package/coverage/src/types/result.types.ts.html +0 -127
- package/coverage/src/types/sort.types.ts.html +0 -142
- package/coverage/src/types/typeorm.d.ts.html +0 -196
- package/coverage/src/utils/index.html +0 -146
- package/coverage/src/utils/index.ts.html +0 -178
- package/coverage/src/utils/pagination.util.ts.html +0 -703
- package/coverage/src/utils/validation.util.ts.html +0 -535
- package/dist/utils-CV6Ovku6.mjs +0 -1
- package/dist/utils-D_qD2YAX.cjs +0 -1
- package/docs/specs/spec-20260413-typeorm-subpath-export/checklist.md +0 -33
- package/docs/specs/spec-20260413-typeorm-subpath-export/spec.md +0 -104
- package/docs/specs/spec-20260413-typeorm-subpath-export/tasks.md +0 -48
- package/eslint.config.ts +0 -3
- package/src/__tests__/index.test.ts +0 -72
- package/src/__tests__/pagination.util.test.ts +0 -251
- package/src/__tests__/result.schemas.test.ts +0 -142
- package/src/__tests__/sort.schemas.test.ts +0 -157
- package/src/__tests__/typeorm.adapter.test.ts +0 -212
- package/src/__tests__/validation.util.test.ts +0 -120
- package/src/adapters/typeorm/adapter.ts +0 -203
- package/src/adapters/typeorm/index.ts +0 -23
- package/src/adapters/typeorm/typeorm.d.ts +0 -37
- package/src/adapters/typeorm/types.ts +0 -95
- package/src/index.ts +0 -65
- package/src/schemas/index.ts +0 -28
- package/src/schemas/pagination.schemas.ts +0 -86
- package/src/schemas/result.schemas.ts +0 -213
- package/src/schemas/sort.schemas.ts +0 -153
- package/src/typeorm.ts +0 -23
- package/src/types/index.ts +0 -38
- package/src/types/pagination.types.ts +0 -28
- package/src/types/result.types.ts +0 -14
- package/src/types/sort.types.ts +0 -19
- package/src/utils/index.ts +0 -31
- package/src/utils/pagination.util.ts +0 -206
- package/src/utils/validation.util.ts +0 -150
- package/tsconfig/.cache/app.tsbuildinfo +0 -1
- package/tsconfig/.cache/node.tsbuildinfo +0 -1
- package/tsconfig/.cache/test.tsbuildinfo +0 -1
- package/tsconfig/app.json +0 -15
- package/tsconfig/node.json +0 -11
- package/tsconfig/test.json +0 -14
- package/tsconfig.json +0 -9
- package/tsdown.config.ts +0 -13
- package/vitest.config.ts +0 -3
|
@@ -1,104 +0,0 @@
|
|
|
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
|
-
- **迁移成本**: 低,仅需修改导入语句
|
|
@@ -1,48 +0,0 @@
|
|
|
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/eslint.config.ts
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 主入口导出测试
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, it, expect } from 'vitest';
|
|
6
|
-
|
|
7
|
-
describe('pagination 包导出', () => {
|
|
8
|
-
it('应正确导出所有类型', async () => {
|
|
9
|
-
const module = await import('@/index');
|
|
10
|
-
|
|
11
|
-
expect(module.PAGINATION_DEFAULTS).toBeDefined();
|
|
12
|
-
expect(module.PAGINATION_DEFAULTS.page).toBe(1);
|
|
13
|
-
expect(module.PAGINATION_DEFAULTS.pageSize).toBe(20);
|
|
14
|
-
expect(module.PAGINATION_DEFAULTS.maxPageSize).toBe(100);
|
|
15
|
-
expect(module.PAGINATION_DEFAULTS.minPageSize).toBe(1);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('应正确导出所有工具函数', async () => {
|
|
19
|
-
const module = await import('@/index');
|
|
20
|
-
|
|
21
|
-
expect(module.normalizePagination).toBeDefined();
|
|
22
|
-
expect(module.normalizeOffsetPagination).toBeDefined();
|
|
23
|
-
expect(module.calculateOffset).toBeDefined();
|
|
24
|
-
expect(module.calculateTotalPages).toBeDefined();
|
|
25
|
-
expect(module.hasNextPage).toBeDefined();
|
|
26
|
-
expect(module.hasPreviousPage).toBeDefined();
|
|
27
|
-
expect(module.offsetToPage).toBeDefined();
|
|
28
|
-
expect(module.pageToOffset).toBeDefined();
|
|
29
|
-
expect(module.createPaginatedResult).toBeDefined();
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('应正确导出所有验证函数', async () => {
|
|
33
|
-
const module = await import('@/index');
|
|
34
|
-
|
|
35
|
-
expect(module.isValidPage).toBeDefined();
|
|
36
|
-
expect(module.isValidPageSize).toBeDefined();
|
|
37
|
-
expect(module.isValidOffset).toBeDefined();
|
|
38
|
-
expect(module.isValidLimit).toBeDefined();
|
|
39
|
-
expect(module.isValidPagination).toBeDefined();
|
|
40
|
-
expect(module.isValidOffsetPagination).toBeDefined();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('主入口不应导出 TypeORM 适配器', async () => {
|
|
44
|
-
const module = await import('@/index');
|
|
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
|
-
|
|
54
|
-
expect(module.paginateWithRepository).toBeDefined();
|
|
55
|
-
expect(module.paginateWithQueryBuilder).toBeDefined();
|
|
56
|
-
expect(module.createPaginationQueryBuilder).toBeDefined();
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('normalizePagination 应正常工作', async () => {
|
|
60
|
-
const { normalizePagination } = await import('@/index');
|
|
61
|
-
|
|
62
|
-
const result = normalizePagination({ page: 2, pageSize: 50 });
|
|
63
|
-
expect(result).toEqual({ page: 2, pageSize: 50 });
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('calculateOffset 应正常工作', async () => {
|
|
67
|
-
const { calculateOffset } = await import('@/index');
|
|
68
|
-
|
|
69
|
-
expect(calculateOffset(1, 20)).toBe(0);
|
|
70
|
-
expect(calculateOffset(2, 20)).toBe(20);
|
|
71
|
-
});
|
|
72
|
-
});
|
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 分页计算工具函数测试
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, it, expect } from 'vitest';
|
|
6
|
-
import {
|
|
7
|
-
normalizePagination,
|
|
8
|
-
normalizeOffsetPagination,
|
|
9
|
-
calculateOffset,
|
|
10
|
-
calculateTotalPages,
|
|
11
|
-
hasNextPage,
|
|
12
|
-
hasPreviousPage,
|
|
13
|
-
offsetToPage,
|
|
14
|
-
pageToOffset,
|
|
15
|
-
createPaginatedResult,
|
|
16
|
-
} from '@/utils/pagination.util';
|
|
17
|
-
import { PAGINATION_DEFAULTS } from '@/types';
|
|
18
|
-
|
|
19
|
-
describe('normalizePagination', () => {
|
|
20
|
-
it('应返回默认值当参数为空时', () => {
|
|
21
|
-
const result = normalizePagination();
|
|
22
|
-
expect(result).toEqual({
|
|
23
|
-
page: PAGINATION_DEFAULTS.page,
|
|
24
|
-
pageSize: PAGINATION_DEFAULTS.pageSize,
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('应返回默认值当参数为 undefined 时', () => {
|
|
29
|
-
const result = normalizePagination(undefined);
|
|
30
|
-
expect(result).toEqual({
|
|
31
|
-
page: PAGINATION_DEFAULTS.page,
|
|
32
|
-
pageSize: PAGINATION_DEFAULTS.pageSize,
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('应正确规范化有效的分页参数', () => {
|
|
37
|
-
const result = normalizePagination({ page: 2, pageSize: 50 });
|
|
38
|
-
expect(result).toEqual({ page: 2, pageSize: 50 });
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('应限制 pageSize 不超过最大值', () => {
|
|
42
|
-
const result = normalizePagination({ pageSize: 200 });
|
|
43
|
-
expect(result.pageSize).toBe(PAGINATION_DEFAULTS.maxPageSize);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('应限制 pageSize 不小于最小值', () => {
|
|
47
|
-
const result = normalizePagination({ pageSize: 0 });
|
|
48
|
-
expect(result.pageSize).toBe(PAGINATION_DEFAULTS.minPageSize);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('应限制 page 不小于 1', () => {
|
|
52
|
-
const result = normalizePagination({ page: -1 });
|
|
53
|
-
expect(result.page).toBe(1);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('应正确处理小数值', () => {
|
|
57
|
-
const result = normalizePagination({ page: 1.5, pageSize: 10.9 });
|
|
58
|
-
expect(result).toEqual({ page: 1, pageSize: 10 });
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('应正确处理部分参数', () => {
|
|
62
|
-
const result = normalizePagination({ page: 5 });
|
|
63
|
-
expect(result).toEqual({ page: 5, pageSize: PAGINATION_DEFAULTS.pageSize });
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
describe('normalizeOffsetPagination', () => {
|
|
68
|
-
it('应返回默认值当参数为空时', () => {
|
|
69
|
-
const result = normalizeOffsetPagination();
|
|
70
|
-
expect(result).toEqual({
|
|
71
|
-
limit: PAGINATION_DEFAULTS.pageSize,
|
|
72
|
-
offset: 0,
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('应正确规范化有效的 offset 分页参数', () => {
|
|
77
|
-
const result = normalizeOffsetPagination({ limit: 50, offset: 100 });
|
|
78
|
-
expect(result).toEqual({ limit: 50, offset: 100 });
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('应限制 limit 不超过最大值', () => {
|
|
82
|
-
const result = normalizeOffsetPagination({ limit: 200 });
|
|
83
|
-
expect(result.limit).toBe(PAGINATION_DEFAULTS.maxPageSize);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('应限制 limit 不小于最小值', () => {
|
|
87
|
-
const result = normalizeOffsetPagination({ limit: 0 });
|
|
88
|
-
expect(result.limit).toBe(PAGINATION_DEFAULTS.minPageSize);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('应限制 offset 不小于 0', () => {
|
|
92
|
-
const result = normalizeOffsetPagination({ offset: -10 });
|
|
93
|
-
expect(result.offset).toBe(0);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('应正确处理小数值', () => {
|
|
97
|
-
const result = normalizeOffsetPagination({ limit: 10.9, offset: 50.5 });
|
|
98
|
-
expect(result).toEqual({ limit: 10, offset: 50 });
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
describe('calculateOffset', () => {
|
|
103
|
-
it('应正确计算第一页的偏移量', () => {
|
|
104
|
-
expect(calculateOffset(1, 20)).toBe(0);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it('应正确计算第二页的偏移量', () => {
|
|
108
|
-
expect(calculateOffset(2, 20)).toBe(20);
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it('应正确计算任意页的偏移量', () => {
|
|
112
|
-
expect(calculateOffset(5, 10)).toBe(40);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it('应正确处理不同的页面大小', () => {
|
|
116
|
-
expect(calculateOffset(3, 50)).toBe(100);
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
describe('calculateTotalPages', () => {
|
|
121
|
-
it('应正确计算总页数', () => {
|
|
122
|
-
expect(calculateTotalPages(100, 20)).toBe(5);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('应正确处理有余数的情况', () => {
|
|
126
|
-
expect(calculateTotalPages(95, 20)).toBe(5);
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it('应正确处理总数为 0 的情况', () => {
|
|
130
|
-
expect(calculateTotalPages(0, 20)).toBe(0);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it('应正确处理总数小于页面大小的情况', () => {
|
|
134
|
-
expect(calculateTotalPages(15, 20)).toBe(1);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it('应正确处理 pageSize 为 0 的情况', () => {
|
|
138
|
-
expect(calculateTotalPages(100, 0)).toBe(0);
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
describe('hasNextPage', () => {
|
|
143
|
-
it('应返回 true 当有下一页时', () => {
|
|
144
|
-
expect(hasNextPage(1, 5)).toBe(true);
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
it('应返回 false 当在最后一页时', () => {
|
|
148
|
-
expect(hasNextPage(5, 5)).toBe(false);
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it('应返回 false 当总页数为 0 时', () => {
|
|
152
|
-
expect(hasNextPage(1, 0)).toBe(false);
|
|
153
|
-
});
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
describe('hasPreviousPage', () => {
|
|
157
|
-
it('应返回 false 当在第一页时', () => {
|
|
158
|
-
expect(hasPreviousPage(1)).toBe(false);
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
it('应返回 true 当不在第一页时', () => {
|
|
162
|
-
expect(hasPreviousPage(2)).toBe(true);
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
it('应返回 true 当在大页码时', () => {
|
|
166
|
-
expect(hasPreviousPage(100)).toBe(true);
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
describe('offsetToPage', () => {
|
|
171
|
-
it('应正确转换 offset 0 到第一页', () => {
|
|
172
|
-
expect(offsetToPage(0, 20)).toEqual({ page: 1, pageSize: 20 });
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
it('应正确转换 offset 到对应页', () => {
|
|
176
|
-
expect(offsetToPage(40, 20)).toEqual({ page: 3, pageSize: 20 });
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
it('应正确处理非整除情况', () => {
|
|
180
|
-
expect(offsetToPage(25, 20)).toEqual({ page: 2, pageSize: 20 });
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
it('应正确处理 limit 为 0 的情况', () => {
|
|
184
|
-
expect(offsetToPage(0, 0)).toEqual({ page: 1, pageSize: 1 });
|
|
185
|
-
});
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
describe('pageToOffset', () => {
|
|
189
|
-
it('应正确转换第一页到 offset 0', () => {
|
|
190
|
-
expect(pageToOffset(1, 20)).toEqual({ offset: 0, limit: 20 });
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
it('应正确转换页码到 offset', () => {
|
|
194
|
-
expect(pageToOffset(3, 20)).toEqual({ offset: 40, limit: 20 });
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
it('应正确处理 page 为 0 的情况', () => {
|
|
198
|
-
expect(pageToOffset(0, 20)).toEqual({ offset: 0, limit: 20 });
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
it('应正确处理 pageSize 为 0 的情况', () => {
|
|
202
|
-
expect(pageToOffset(1, 0)).toEqual({ offset: 0, limit: 1 });
|
|
203
|
-
});
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
describe('createPaginatedResult', () => {
|
|
207
|
-
it('应正确创建分页结果', () => {
|
|
208
|
-
const items = [1, 2, 3];
|
|
209
|
-
const result = createPaginatedResult(items, 100, 2, 20);
|
|
210
|
-
|
|
211
|
-
expect(result).toEqual({
|
|
212
|
-
items,
|
|
213
|
-
total: 100,
|
|
214
|
-
page: 2,
|
|
215
|
-
pageSize: 20,
|
|
216
|
-
totalPages: 5,
|
|
217
|
-
hasNextPage: true,
|
|
218
|
-
hasPreviousPage: true,
|
|
219
|
-
});
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
it('应正确处理第一页', () => {
|
|
223
|
-
const items = [1, 2, 3];
|
|
224
|
-
const result = createPaginatedResult(items, 100, 1, 20);
|
|
225
|
-
|
|
226
|
-
expect(result.hasPreviousPage).toBe(false);
|
|
227
|
-
expect(result.hasNextPage).toBe(true);
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
it('应正确处理最后一页', () => {
|
|
231
|
-
const items = [1, 2, 3];
|
|
232
|
-
const result = createPaginatedResult(items, 100, 5, 20);
|
|
233
|
-
|
|
234
|
-
expect(result.hasPreviousPage).toBe(true);
|
|
235
|
-
expect(result.hasNextPage).toBe(false);
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
it('应正确处理空结果', () => {
|
|
239
|
-
const result = createPaginatedResult([], 0, 1, 20);
|
|
240
|
-
|
|
241
|
-
expect(result).toEqual({
|
|
242
|
-
items: [],
|
|
243
|
-
total: 0,
|
|
244
|
-
page: 1,
|
|
245
|
-
pageSize: 20,
|
|
246
|
-
totalPages: 0,
|
|
247
|
-
hasNextPage: false,
|
|
248
|
-
hasPreviousPage: false,
|
|
249
|
-
});
|
|
250
|
-
});
|
|
251
|
-
});
|
|
@@ -1,142 +0,0 @@
|
|
|
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
|
-
});
|