@taicode/common-server 1.0.4 → 1.0.5

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.
@@ -77,15 +77,42 @@ export declare function fuzzQueryBodySchema<F extends ZodType, E extends ZodEnum
77
77
  range: z.ZodTuple<[z.ZodISODateTime, z.ZodISODateTime], null>;
78
78
  }, z.core.$strip>;
79
79
  /**
80
- * 标准响应 Schema
80
+ * 标准响应数据内容 Schema
81
81
  * 用于定义统一的 API 响应结构
82
82
  * @param t - 响应数据的类型
83
83
  * @param s - 状态码的枚举类型
84
84
  * @returns 标准响应的 Schema
85
85
  */
86
- export declare function responseSchema<T extends ZodType, S extends ZodEnum>(t: T, s: S): z.ZodObject<{
86
+ export declare function responseDataSchema<T extends ZodType, S extends ZodEnum>(t: T, s: S): z.ZodObject<{
87
87
  data: T;
88
88
  status: S;
89
89
  message: z.ZodString;
90
90
  }, z.core.$strip>;
91
+ export declare function responseSchema<T extends ZodType, S extends ZodEnum, E extends ZodEnum>(t: T, u: S, e: E): {
92
+ '200': z.ZodObject<{
93
+ data: T;
94
+ status: z.ZodEnum<{
95
+ SUCCESS: "SUCCESS";
96
+ }>;
97
+ message: z.ZodString;
98
+ }, z.core.$strip>;
99
+ '400': z.ZodObject<{
100
+ data: z.ZodNull;
101
+ status: S;
102
+ message: z.ZodString;
103
+ }, z.core.$strip>;
104
+ '500': z.ZodObject<{
105
+ data: z.ZodNull;
106
+ status: E;
107
+ message: z.ZodString;
108
+ }, z.core.$strip>;
109
+ };
110
+ interface RouterSchema {
111
+ tags: string[];
112
+ summary: string;
113
+ operationId: string;
114
+ description: string;
115
+ }
116
+ export declare function routerSchema<T extends RouterSchema>(schema: T & RouterSchema): T & RouterSchema;
117
+ export {};
91
118
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/schema/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AA2BzC;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC;;;kBAKxD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC;;;kBAKvD;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;;;;;;;;;;;;;kBAMhF;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;;;;;;;;;;kBAMrF;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;;;;;;;;;;kBAMpF;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;;;;kBAM9E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/schema/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AA2BzC;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC;;;kBAKxD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC;;;kBAKvD;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;;;;;;;;;;;;;kBAMhF;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;;;;;;;;;;kBAMrF;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;;;;;;;;;;kBAMpF;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;;;;kBAMlF;AAED,wBAAgB,cAAc,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;;;;;;;;;;;;;;;;;;EAMvG;AAED,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,wBAAgB,YAAY,CAAC,CAAC,SAAS,YAAY,EAAE,MAAM,EAAE,CAAC,GAAG,YAAY,GAAG,CAAC,GAAG,YAAY,CAY/F"}
@@ -89,16 +89,34 @@ export function fuzzQueryBodySchema(f, e) {
89
89
  });
90
90
  }
91
91
  /**
92
- * 标准响应 Schema
92
+ * 标准响应数据内容 Schema
93
93
  * 用于定义统一的 API 响应结构
94
94
  * @param t - 响应数据的类型
95
95
  * @param s - 状态码的枚举类型
96
96
  * @returns 标准响应的 Schema
97
97
  */
98
- export function responseSchema(t, s) {
98
+ export function responseDataSchema(t, s) {
99
99
  return z.object({
100
100
  data: t.describe('响应数据'),
101
101
  status: s.describe('响应状态码'),
102
102
  message: z.string().describe('响应消息'),
103
103
  });
104
104
  }
105
+ export function responseSchema(t, u, e) {
106
+ return {
107
+ '200': responseDataSchema(t, z.enum(['SUCCESS'])),
108
+ '400': responseDataSchema(z.null(), u),
109
+ '500': responseDataSchema(z.null(), e),
110
+ };
111
+ }
112
+ export function routerSchema(schema) {
113
+ // 验证必需字段
114
+ if (!schema.operationId) {
115
+ throw new Error('routerSchema requires operationId');
116
+ }
117
+ // 如果没有提供 tags,设置默认值
118
+ if (!schema.tags) {
119
+ schema.tags = ['默认'];
120
+ }
121
+ return { ...schema };
122
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taicode/common-server",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "author": "Alain",
5
5
  "license": "ISC",
6
6
  "description": "",
@@ -1,30 +0,0 @@
1
- /**
2
- * mockFunction 主要用于在不依赖特定测试工具(如 jest、vitest)的情况下
3
- * 实现通用的 mock 能力,便于在多种环境下进行函数模拟、调用记录和行为控制。
4
- * 适用于需要脱离测试框架、或在生产/脚本环境下也能复用的场景。
5
- */
6
- /**
7
- * Mock 函数接口
8
- */
9
- interface MockFunction {
10
- (...args: any[]): any;
11
- mockCalls: any[][];
12
- mockResults: Array<{
13
- type: 'return' | 'throw';
14
- value: any;
15
- }>;
16
- mockImplementation: (fn: Function) => MockFunction;
17
- mockReturnValue: (value: any) => MockFunction;
18
- mockResolvedValue: (value: any) => MockFunction;
19
- mockRejectedValue: (error: any) => MockFunction;
20
- mockClear: () => void;
21
- mockReset: () => void;
22
- }
23
- /**
24
- * 创建 Mock 函数
25
- * 可记录调用参数、返回值、异常,并支持动态切换实现、固定返回、异步返回、异常抛出等能力。
26
- * 适合在无测试框架依赖的环境下灵活使用。
27
- */
28
- export declare function mockFunction(implementation?: Function): MockFunction;
29
- export {};
30
- //# sourceMappingURL=function.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"function.d.ts","sourceRoot":"","sources":["../../../source/mock/function/function.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,UAAU,YAAY;IACpB,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,GAAG,CAAA;IACrB,SAAS,EAAE,GAAG,EAAE,EAAE,CAAA;IAClB,WAAW,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAC,KAAK,EAAE,GAAG,CAAA;KAAE,CAAC,CAAA;IAC5D,kBAAkB,EAAE,CAAC,EAAE,EAAE,QAAQ,KAAK,YAAY,CAAA;IAClD,eAAe,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,YAAY,CAAA;IAC7C,iBAAiB,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,YAAY,CAAA;IAC/C,iBAAiB,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,YAAY,CAAA;IAC/C,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,SAAS,EAAE,MAAM,IAAI,CAAA;CACtB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,cAAc,CAAC,EAAE,QAAQ,GAAG,YAAY,CAyDpE"}
@@ -1,58 +0,0 @@
1
- /**
2
- * mockFunction 主要用于在不依赖特定测试工具(如 jest、vitest)的情况下
3
- * 实现通用的 mock 能力,便于在多种环境下进行函数模拟、调用记录和行为控制。
4
- * 适用于需要脱离测试框架、或在生产/脚本环境下也能复用的场景。
5
- */
6
- /**
7
- * 创建 Mock 函数
8
- * 可记录调用参数、返回值、异常,并支持动态切换实现、固定返回、异步返回、异常抛出等能力。
9
- * 适合在无测试框架依赖的环境下灵活使用。
10
- */
11
- export function mockFunction(implementation) {
12
- const mockCalls = [];
13
- const mockResults = [];
14
- let mockImpl = implementation;
15
- const mockFn = function (...args) {
16
- mockCalls.push(args);
17
- if (mockImpl) {
18
- try {
19
- const result = mockImpl(...args);
20
- mockResults.push({ type: 'return', value: result });
21
- return result;
22
- }
23
- catch (error) {
24
- mockResults.push({ type: 'throw', value: error });
25
- throw error;
26
- }
27
- }
28
- return undefined;
29
- };
30
- mockFn.mockCalls = mockCalls;
31
- mockFn.mockResults = mockResults;
32
- mockFn.mockImplementation = (fn) => {
33
- mockImpl = fn;
34
- return mockFn;
35
- };
36
- mockFn.mockReturnValue = (value) => {
37
- mockImpl = () => value;
38
- return mockFn;
39
- };
40
- mockFn.mockResolvedValue = (value) => {
41
- mockImpl = () => Promise.resolve(value);
42
- return mockFn;
43
- };
44
- mockFn.mockRejectedValue = (error) => {
45
- mockImpl = () => Promise.reject(error);
46
- return mockFn;
47
- };
48
- mockFn.mockClear = () => {
49
- mockCalls.length = 0;
50
- mockResults.length = 0;
51
- };
52
- mockFn.mockReset = () => {
53
- mockCalls.length = 0;
54
- mockResults.length = 0;
55
- mockImpl = implementation;
56
- };
57
- return mockFn;
58
- }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=function.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"function.test.d.ts","sourceRoot":"","sources":["../../../source/mock/function/function.test.ts"],"names":[],"mappings":""}
@@ -1,55 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { mockFunction } from './function';
3
- describe('mockFunction', () => {
4
- it('应能记录调用参数和返回值', () => {
5
- const fn = mockFunction((a, b) => a + b);
6
- expect(fn(1, 2)).toBe(3);
7
- expect(fn(2, 3)).toBe(5);
8
- expect(fn.mockCalls).toEqual([[1, 2], [2, 3]]);
9
- expect(fn.mockResults[0]).toEqual({ type: 'return', value: 3 });
10
- expect(fn.mockResults[1]).toEqual({ type: 'return', value: 5 });
11
- });
12
- it('应能记录抛出的异常', () => {
13
- const error = new Error('fail');
14
- const fn = mockFunction(() => { throw error; });
15
- expect(() => fn(1)).toThrow(error);
16
- expect(fn.mockResults[0]).toEqual({ type: 'throw', value: error });
17
- });
18
- it('mockImplementation 可动态替换实现', () => {
19
- const fn = mockFunction((x) => x + 1);
20
- expect(fn(1)).toBe(2);
21
- fn.mockImplementation((x) => x * 2);
22
- expect(fn(2)).toBe(4);
23
- });
24
- it('mockReturnValue 可设置固定返回值', () => {
25
- const fn = mockFunction().mockReturnValue(42);
26
- expect(fn()).toBe(42);
27
- expect(fn(1, 2)).toBe(42);
28
- });
29
- it('mockResolvedValue 应返回 Promise.resolve', async () => {
30
- const fn = mockFunction().mockResolvedValue('ok');
31
- await expect(fn()).resolves.toBe('ok');
32
- });
33
- it('mockRejectedValue 应返回 Promise.reject', async () => {
34
- const fn = mockFunction().mockRejectedValue('fail');
35
- await expect(fn()).rejects.toBe('fail');
36
- });
37
- it('mockClear 应清空调用记录', () => {
38
- const fn = mockFunction((x) => x);
39
- fn(1);
40
- fn(2);
41
- fn.mockClear();
42
- expect(fn.mockCalls.length).toBe(0);
43
- expect(fn.mockResults.length).toBe(0);
44
- });
45
- it('mockReset 应重置实现和调用记录', () => {
46
- const fn = mockFunction((x) => x + 1);
47
- fn(1);
48
- fn.mockImplementation((x) => x + 10);
49
- fn(2);
50
- fn.mockReset();
51
- expect(fn.mockCalls.length).toBe(0);
52
- expect(fn.mockResults.length).toBe(0);
53
- expect(fn(3)).toBe(4); // 恢复为初始实现
54
- });
55
- });
@@ -1,2 +0,0 @@
1
- export { mockFunction } from './function';
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../source/mock/function/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA"}
@@ -1 +0,0 @@
1
- export { mockFunction } from './function';
@@ -1,3 +0,0 @@
1
- export * from './function';
2
- export * from './prismaClient';
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/mock/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA"}
@@ -1,3 +0,0 @@
1
- // mock 目录根 index.ts,统一导出所有 mock 能力
2
- export * from './function';
3
- export * from './prismaClient';
@@ -1,2 +0,0 @@
1
- export { mockPrismaClient } from './prismaClient';
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../source/mock/prismaClient/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA"}
@@ -1 +0,0 @@
1
- export { mockPrismaClient } from './prismaClient';
@@ -1,257 +0,0 @@
1
- import { PrismaClient } from '@prisma/client';
2
- /**
3
- * Prisma 支持的数据库操作方法列表
4
- * 包含所有常用的 CRUD 和聚合操作
5
- */
6
- declare const DB_METHODS: readonly ["create", "createMany", "findFirst", "findUnique", "findMany", "update", "updateMany", "delete", "deleteMany", "upsert", "count", "aggregate", "groupBy", "findFirstOrThrow", "findUniqueOrThrow"];
7
- type DbMethod = typeof DB_METHODS[number];
8
- /**
9
- * 数据库调用记录接口
10
- * 记录每次数据库操作的详细信息
11
- */
12
- interface CallRecord {
13
- /** 调用的方法名 */
14
- method: DbMethod;
15
- /** 调用时间戳 */
16
- timestamp: Date;
17
- /** 调用参数 */
18
- args: any[];
19
- /** 调用返回值(如果有的话) */
20
- returnValue?: any;
21
- /** 调用是否抛出异常 */
22
- isError?: boolean;
23
- /** 异常信息(如果有的话) */
24
- error?: any;
25
- }
26
- /**
27
- * Mock 返回值配置接口
28
- */
29
- interface MockReturnConfig {
30
- /** 返回值 */
31
- value?: any;
32
- /** 是否抛出异常 */
33
- shouldThrow?: boolean;
34
- /** 是否返回 Promise */
35
- isAsync?: boolean;
36
- /** 调用次数限制(可选) */
37
- times?: number;
38
- }
39
- /**
40
- * 扩展的 Mock Prisma Client 接口
41
- * 在原有 PrismaClient 基础上添加测试辅助方法
42
- */
43
- interface MockPrismaClient extends PrismaClient {
44
- /**
45
- * 获取调用历史记录
46
- * @param table 可选,指定表名过滤
47
- * @param method 可选,指定方法名过滤
48
- * @returns 调用记录数组
49
- */
50
- __getCallHistory(table?: string, method?: DbMethod): CallRecord[];
51
- /**
52
- * 清空调用历史记录
53
- * @param table 可选,指定表名。不传则清空所有记录
54
- */
55
- __clearCallHistory(table?: string): void;
56
- /**
57
- * 获取最后一次调用记录
58
- * @param table 表名
59
- * @param method 方法名
60
- * @returns 最后一次调用记录或 undefined
61
- */
62
- __getLastCall(table: string, method: DbMethod): CallRecord | undefined;
63
- /**
64
- * 获取指定方法的调用次数
65
- * @param table 表名
66
- * @param method 方法名
67
- * @returns 调用次数
68
- */
69
- __getCallCount(table: string, method: DbMethod): number;
70
- /**
71
- * 设置方法的返回值(同步)
72
- * @param table 表名
73
- * @param method 方法名
74
- * @param value 返回值
75
- */
76
- __mockReturnValue(table: string, method: DbMethod, value: any): void;
77
- /**
78
- * 设置方法的返回值(异步成功)
79
- * @param table 表名
80
- * @param method 方法名
81
- * @param value 返回值
82
- */
83
- __mockResolvedValue(table: string, method: DbMethod, value: any): void;
84
- /**
85
- * 设置方法抛出异常(异步失败)
86
- * @param table 表名
87
- * @param method 方法名
88
- * @param error 异常
89
- */
90
- __mockRejectedValue(table: string, method: DbMethod, error: any): void;
91
- /**
92
- * 高级 Mock 配置
93
- * @param table 表名
94
- * @param method 方法名
95
- * @param config Mock 配置
96
- */
97
- __mockAdvanced(table: string, method: DbMethod, config: MockReturnConfig): void;
98
- /**
99
- * 重置所有 Mock 配置
100
- * @param table 可选,指定表名。不传则重置所有表
101
- */
102
- __resetMocks(table?: string): void;
103
- /**
104
- * 获取所有被访问过的表名
105
- * @returns 表名数组
106
- */
107
- __getAccessedTables(): string[];
108
- /**
109
- * 验证方法是否被调用
110
- * @param table 表名
111
- * @param method 方法名
112
- * @param times 可选,期望的调用次数
113
- * @returns 是否符合期望
114
- */
115
- __wasCalledWith(table: string, method: DbMethod, times?: number): boolean;
116
- /**
117
- * 验证方法是否被特定参数调用
118
- * @param table 表名
119
- * @param method 方法名
120
- * @param expectedArgs 期望的参数
121
- * @returns 是否符合期望
122
- */
123
- __wasCalledWithArgs(table: string, method: DbMethod, expectedArgs: any): boolean;
124
- /**
125
- * 创建数据快照,用于测试前后数据对比
126
- * @returns 当前调用历史的快照
127
- */
128
- __createSnapshot(): string;
129
- /**
130
- * 恢复到指定快照状态
131
- * @param snapshot 快照字符串
132
- */
133
- __restoreSnapshot(snapshot: string): void;
134
- /**
135
- * 批量设置多个表的 mock 返回值
136
- * @param configs 批量配置对象
137
- * @example
138
- * mockDb.__batchMock({
139
- * 'user.findMany': { value: [{ id: 1, name: 'John' }] },
140
- * 'post.create': { value: { id: 1, title: 'Hello' } }
141
- * })
142
- */
143
- __batchMock(configs: Record<string, MockReturnConfig>): void;
144
- /**
145
- * 等待异步操作完成(用于复杂异步测试场景)
146
- * @param ms 等待毫秒数
147
- */
148
- __waitForAsyncOperations(ms?: number): Promise<void>;
149
- /**
150
- * 验证调用序列是否符合预期
151
- * @param expectedSequence 期望的调用序列
152
- * @returns 是否符合期望
153
- * @example
154
- * mockDb.__verifyCallSequence([
155
- * { table: 'user', method: 'findUnique' },
156
- * { table: 'post', method: 'create' }
157
- * ])
158
- */
159
- __verifyCallSequence(expectedSequence: Array<{
160
- table: string;
161
- method: DbMethod;
162
- }>): boolean;
163
- /**
164
- * 获取详细的调用统计信息
165
- * @returns 调用统计数据
166
- */
167
- __getCallStatistics(): {
168
- totalCalls: number;
169
- tableStats: Record<string, number>;
170
- methodStats: Record<string, number>;
171
- timeRange: {
172
- earliest: Date;
173
- latest: Date;
174
- } | null;
175
- };
176
- }
177
- /**
178
- * 创建模拟的 Prisma Client
179
- * 提供完整的数据库操作模拟能力和测试辅助功能
180
- *
181
- * 主要特性:
182
- * - 动态创建数据库表代理,支持所有 Prisma 操作
183
- * - 记录所有方法调用历史,包括参数、返回值、异常等
184
- * - 支持灵活的 mock 返回值配置(同步/异步/异常)
185
- * - 提供丰富的断言和验证方法
186
- * - 支持调用序列验证和统计分析
187
- * - 支持快照和批量操作
188
- *
189
- * @example 基础用法
190
- * ```typescript
191
- * const mockDb = createPrismaClient()
192
- *
193
- * // 设置返回值
194
- * mockDb.__mockResolvedValue('user', 'findMany', [{ id: 1, name: 'John' }])
195
- *
196
- * // 执行操作
197
- * const users = await mockDb.user.findMany()
198
- *
199
- * // 验证调用
200
- * expect(mockDb.__getCallCount('user', 'findMany')).toBe(1)
201
- * expect(users).toEqual([{ id: 1, name: 'John' }])
202
- * ```
203
- *
204
- * @example 高级 mock 配置
205
- * ```typescript
206
- * // 限制调用次数的 mock
207
- * mockDb.__mockAdvanced('user', 'create', {
208
- * value: { id: 1, name: 'John' },
209
- * times: 2 // 只在前2次调用时返回此值
210
- * })
211
- *
212
- * // 批量设置 mock
213
- * mockDb.__batchMock({
214
- * 'user.findMany': { value: [] },
215
- * 'post.create': { value: { id: 1, title: 'Hello' } },
216
- * 'comment.delete': { shouldThrow: true, value: new Error('删除失败') }
217
- * })
218
- * ```
219
- *
220
- * @example 调用验证和统计
221
- * ```typescript
222
- * // 验证调用历史
223
- * expect(mockDb.__wasCalledWith('user', 'findMany')).toBe(true)
224
- * expect(mockDb.__wasCalledWithArgs('user', 'create', [{ name: 'John' }])).toBe(true)
225
- *
226
- * // 验证调用序列
227
- * expect(mockDb.__verifyCallSequence([
228
- * { table: 'user', method: 'findUnique' },
229
- * { table: 'post', method: 'create' }
230
- * ])).toBe(true)
231
- *
232
- * // 获取统计信息
233
- * const stats = mockDb.__getCallStatistics()
234
- * console.log(`总调用次数: ${stats.totalCalls}`)
235
- * ```
236
- *
237
- * @example 快照和重置
238
- * ```typescript
239
- * // 创建快照
240
- * const snapshot = mockDb.__createSnapshot()
241
- *
242
- * // 执行一些操作...
243
- * await mockDb.user.create({ data: { name: 'John' } })
244
- *
245
- * // 恢复到快照状态
246
- * mockDb.__restoreSnapshot(snapshot)
247
- *
248
- * // 重置特定表的 mock
249
- * mockDb.__resetMocks('user')
250
- *
251
- * // 清空所有调用历史
252
- * mockDb.__clearCallHistory()
253
- * ```
254
- */
255
- export declare function mockPrismaClient(): MockPrismaClient;
256
- export {};
257
- //# sourceMappingURL=prismaClient.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"prismaClient.d.ts","sourceRoot":"","sources":["../../../source/mock/prismaClient/prismaClient.ts"],"names":[],"mappings":"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"}
@@ -1,399 +0,0 @@
1
- import { mockFunction } from '../function/function';
2
- /**
3
- * Prisma 支持的数据库操作方法列表
4
- * 包含所有常用的 CRUD 和聚合操作
5
- */
6
- const DB_METHODS = [
7
- 'create', 'createMany',
8
- 'findFirst', 'findUnique', 'findMany',
9
- 'update', 'updateMany',
10
- 'delete', 'deleteMany',
11
- 'upsert', 'count', 'aggregate',
12
- 'groupBy', 'findFirstOrThrow', 'findUniqueOrThrow'
13
- ];
14
- /**
15
- * 创建模拟的 Prisma Client
16
- * 提供完整的数据库操作模拟能力和测试辅助功能
17
- *
18
- * 主要特性:
19
- * - 动态创建数据库表代理,支持所有 Prisma 操作
20
- * - 记录所有方法调用历史,包括参数、返回值、异常等
21
- * - 支持灵活的 mock 返回值配置(同步/异步/异常)
22
- * - 提供丰富的断言和验证方法
23
- * - 支持调用序列验证和统计分析
24
- * - 支持快照和批量操作
25
- *
26
- * @example 基础用法
27
- * ```typescript
28
- * const mockDb = createPrismaClient()
29
- *
30
- * // 设置返回值
31
- * mockDb.__mockResolvedValue('user', 'findMany', [{ id: 1, name: 'John' }])
32
- *
33
- * // 执行操作
34
- * const users = await mockDb.user.findMany()
35
- *
36
- * // 验证调用
37
- * expect(mockDb.__getCallCount('user', 'findMany')).toBe(1)
38
- * expect(users).toEqual([{ id: 1, name: 'John' }])
39
- * ```
40
- *
41
- * @example 高级 mock 配置
42
- * ```typescript
43
- * // 限制调用次数的 mock
44
- * mockDb.__mockAdvanced('user', 'create', {
45
- * value: { id: 1, name: 'John' },
46
- * times: 2 // 只在前2次调用时返回此值
47
- * })
48
- *
49
- * // 批量设置 mock
50
- * mockDb.__batchMock({
51
- * 'user.findMany': { value: [] },
52
- * 'post.create': { value: { id: 1, title: 'Hello' } },
53
- * 'comment.delete': { shouldThrow: true, value: new Error('删除失败') }
54
- * })
55
- * ```
56
- *
57
- * @example 调用验证和统计
58
- * ```typescript
59
- * // 验证调用历史
60
- * expect(mockDb.__wasCalledWith('user', 'findMany')).toBe(true)
61
- * expect(mockDb.__wasCalledWithArgs('user', 'create', [{ name: 'John' }])).toBe(true)
62
- *
63
- * // 验证调用序列
64
- * expect(mockDb.__verifyCallSequence([
65
- * { table: 'user', method: 'findUnique' },
66
- * { table: 'post', method: 'create' }
67
- * ])).toBe(true)
68
- *
69
- * // 获取统计信息
70
- * const stats = mockDb.__getCallStatistics()
71
- * console.log(`总调用次数: ${stats.totalCalls}`)
72
- * ```
73
- *
74
- * @example 快照和重置
75
- * ```typescript
76
- * // 创建快照
77
- * const snapshot = mockDb.__createSnapshot()
78
- *
79
- * // 执行一些操作...
80
- * await mockDb.user.create({ data: { name: 'John' } })
81
- *
82
- * // 恢复到快照状态
83
- * mockDb.__restoreSnapshot(snapshot)
84
- *
85
- * // 重置特定表的 mock
86
- * mockDb.__resetMocks('user')
87
- *
88
- * // 清空所有调用历史
89
- * mockDb.__clearCallHistory()
90
- * ```
91
- */
92
- export function mockPrismaClient() {
93
- const callHistory = new Map();
94
- const mockReturnValues = new Map();
95
- const accessedTables = new Set();
96
- /**
97
- * 记录方法调用
98
- */
99
- function recordCall(table, method, args, returnValue, error) {
100
- accessedTables.add(table);
101
- if (!callHistory.has(table)) {
102
- callHistory.set(table, []);
103
- }
104
- callHistory.get(table).push({
105
- method,
106
- args: JSON.parse(JSON.stringify(args)), // 深拷贝避免引用问题
107
- timestamp: new Date(),
108
- returnValue,
109
- isError: !!error,
110
- error
111
- });
112
- }
113
- /**
114
- * 获取默认返回值
115
- * 根据不同的数据库操作类型返回合理的默认值
116
- */
117
- function getDefaultReturnValue(method) {
118
- switch (method) {
119
- case 'count':
120
- return Promise.resolve(0);
121
- case 'aggregate':
122
- return Promise.resolve({});
123
- case 'findMany':
124
- return Promise.resolve([]);
125
- case 'findFirst':
126
- case 'findUnique':
127
- return Promise.resolve(null);
128
- case 'findFirstOrThrow':
129
- case 'findUniqueOrThrow':
130
- return Promise.resolve({ id: 'mock-id', createdAt: new Date(), updatedAt: new Date() });
131
- case 'create':
132
- case 'update':
133
- case 'upsert':
134
- return Promise.resolve({ id: 'mock-id', createdAt: new Date(), updatedAt: new Date() });
135
- case 'createMany':
136
- return Promise.resolve({ count: 1 });
137
- case 'delete':
138
- case 'deleteMany':
139
- case 'updateMany':
140
- return Promise.resolve({ count: 1 });
141
- case 'groupBy':
142
- return Promise.resolve([]);
143
- default:
144
- return Promise.resolve(null);
145
- }
146
- }
147
- /**
148
- * 创建方法的 mock 函数
149
- * 支持复杂的 mock 行为配置,包括调用次数限制、异常处理等
150
- */
151
- function createMethodMock(table, method) {
152
- return mockFunction(async (...args) => {
153
- const key = `${table}.${method}`;
154
- const config = mockReturnValues.get(key);
155
- try {
156
- let result;
157
- if (config) {
158
- // 检查调用次数限制
159
- if (config.times !== undefined) {
160
- const currentCount = callHistory.get(table)?.filter(c => c.method === method).length || 0;
161
- if (currentCount >= config.times) {
162
- // 超过限制次数,使用默认返回值
163
- result = getDefaultReturnValue(method);
164
- }
165
- else {
166
- if (config.shouldThrow) {
167
- throw config.value;
168
- }
169
- result = config.isAsync ? Promise.resolve(config.value) : config.value;
170
- }
171
- }
172
- else {
173
- if (config.shouldThrow) {
174
- throw config.value;
175
- }
176
- result = config.isAsync ? Promise.resolve(config.value) : config.value;
177
- }
178
- }
179
- else {
180
- result = getDefaultReturnValue(method);
181
- }
182
- // 确保返回 Promise
183
- const finalResult = result instanceof Promise ? await result : result;
184
- recordCall(table, method, args, finalResult);
185
- return finalResult;
186
- }
187
- catch (error) {
188
- recordCall(table, method, args, undefined, error);
189
- throw error;
190
- }
191
- });
192
- }
193
- /**
194
- * 动态创建表代理
195
- */
196
- function createTableProxy(tableName) {
197
- return new Proxy({}, {
198
- get(target, prop) {
199
- if (typeof prop === 'string' && DB_METHODS.includes(prop)) {
200
- if (!target[prop]) {
201
- target[prop] = createMethodMock(tableName, prop);
202
- }
203
- return target[prop];
204
- }
205
- // 支持其他可能的 Prisma 属性
206
- if (typeof prop === 'string') {
207
- return target[prop] || mockFunction();
208
- }
209
- return target[prop];
210
- }
211
- });
212
- }
213
- /**
214
- * 创建主数据库代理
215
- */
216
- const dbProxy = new Proxy({}, {
217
- get(target, prop) {
218
- if (typeof prop === 'string') {
219
- // 测试辅助方法实现
220
- switch (prop) {
221
- case '__getCallHistory':
222
- return (table, method) => {
223
- if (!table) {
224
- const allCalls = [];
225
- for (const [tableName, calls] of callHistory.entries()) {
226
- allCalls.push(...calls.map(call => ({ ...call, table: tableName })));
227
- }
228
- return allCalls.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
229
- }
230
- const calls = callHistory.get(table) || [];
231
- return method ? calls.filter(call => call.method === method) : calls;
232
- };
233
- case '__clearCallHistory':
234
- return (table) => {
235
- if (table) {
236
- callHistory.delete(table);
237
- }
238
- else {
239
- callHistory.clear();
240
- accessedTables.clear();
241
- }
242
- };
243
- case '__getLastCall':
244
- return (table, method) => {
245
- const calls = callHistory.get(table) || [];
246
- const methodCalls = calls.filter(call => call.method === method);
247
- return methodCalls[methodCalls.length - 1];
248
- };
249
- case '__getCallCount':
250
- return (table, method) => {
251
- const calls = callHistory.get(table) || [];
252
- return calls.filter(call => call.method === method).length;
253
- };
254
- case '__mockReturnValue':
255
- return (table, method, value) => {
256
- mockReturnValues.set(`${table}.${method}`, { value, isAsync: false });
257
- };
258
- case '__mockResolvedValue':
259
- return (table, method, value) => {
260
- mockReturnValues.set(`${table}.${method}`, { value, isAsync: true });
261
- };
262
- case '__mockRejectedValue':
263
- return (table, method, error) => {
264
- mockReturnValues.set(`${table}.${method}`, { value: error, shouldThrow: true, isAsync: true });
265
- };
266
- case '__mockAdvanced':
267
- return (table, method, config) => {
268
- mockReturnValues.set(`${table}.${method}`, { ...config });
269
- };
270
- case '__resetMocks':
271
- return (table) => {
272
- if (table) {
273
- const keysToDelete = Array.from(mockReturnValues.keys()).filter(key => key.startsWith(`${table}.`));
274
- keysToDelete.forEach(key => mockReturnValues.delete(key));
275
- }
276
- else {
277
- mockReturnValues.clear();
278
- }
279
- };
280
- case '__getAccessedTables':
281
- return () => Array.from(accessedTables);
282
- case '__wasCalledWith':
283
- return (table, method, times) => {
284
- const callCount = callHistory.get(table)?.filter(call => call.method === method).length || 0;
285
- return times !== undefined ? callCount === times : callCount > 0;
286
- };
287
- case '__wasCalledWithArgs':
288
- return (table, method, expectedArgs) => {
289
- const calls = callHistory.get(table) || [];
290
- return calls.some(call => call.method === method &&
291
- JSON.stringify(call.args) === JSON.stringify(expectedArgs));
292
- };
293
- case '__createSnapshot':
294
- return () => {
295
- return JSON.stringify({
296
- callHistory: Array.from(callHistory.entries()),
297
- mockReturnValues: Array.from(mockReturnValues.entries()),
298
- accessedTables: Array.from(accessedTables)
299
- });
300
- };
301
- case '__restoreSnapshot':
302
- return (snapshot) => {
303
- try {
304
- const data = JSON.parse(snapshot);
305
- callHistory.clear();
306
- mockReturnValues.clear();
307
- accessedTables.clear();
308
- data.callHistory.forEach(([table, calls]) => {
309
- callHistory.set(table, calls.map(call => ({
310
- ...call,
311
- timestamp: new Date(call.timestamp)
312
- })));
313
- });
314
- data.mockReturnValues.forEach(([key, config]) => {
315
- mockReturnValues.set(key, config);
316
- });
317
- data.accessedTables.forEach((table) => {
318
- accessedTables.add(table);
319
- });
320
- }
321
- catch (error) {
322
- throw new Error('无效的快照数据');
323
- }
324
- };
325
- case '__batchMock':
326
- return (configs) => {
327
- Object.entries(configs).forEach(([key, config]) => {
328
- mockReturnValues.set(key, { ...config });
329
- });
330
- };
331
- case '__waitForAsyncOperations':
332
- return async (ms = 10) => {
333
- await new Promise(resolve => setTimeout(resolve, ms));
334
- };
335
- case '__verifyCallSequence':
336
- return (expectedSequence) => {
337
- const allCalls = [];
338
- for (const [tableName, calls] of callHistory.entries()) {
339
- allCalls.push(...calls.map(call => ({
340
- table: tableName,
341
- method: call.method,
342
- timestamp: call.timestamp
343
- })));
344
- }
345
- // 按时间戳排序
346
- allCalls.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
347
- if (allCalls.length < expectedSequence.length) {
348
- return false;
349
- }
350
- // 检查序列是否匹配
351
- for (let i = 0; i < expectedSequence.length; i++) {
352
- const expected = expectedSequence[i];
353
- const actual = allCalls[i];
354
- if (actual.table !== expected.table || actual.method !== expected.method) {
355
- return false;
356
- }
357
- }
358
- return true;
359
- };
360
- case '__getCallStatistics':
361
- return () => {
362
- let totalCalls = 0;
363
- const tableStats = {};
364
- const methodStats = {};
365
- let earliest = null;
366
- let latest = null;
367
- for (const [tableName, calls] of callHistory.entries()) {
368
- tableStats[tableName] = calls.length;
369
- totalCalls += calls.length;
370
- calls.forEach(call => {
371
- const methodKey = `${tableName}.${call.method}`;
372
- methodStats[methodKey] = (methodStats[methodKey] || 0) + 1;
373
- if (!earliest || call.timestamp < earliest) {
374
- earliest = call.timestamp;
375
- }
376
- if (!latest || call.timestamp > latest) {
377
- latest = call.timestamp;
378
- }
379
- });
380
- }
381
- return {
382
- totalCalls,
383
- tableStats,
384
- methodStats,
385
- timeRange: earliest && latest ? { earliest, latest } : null
386
- };
387
- };
388
- }
389
- // 数据库表代理
390
- if (!target[prop]) {
391
- target[prop] = createTableProxy(prop);
392
- }
393
- return target[prop];
394
- }
395
- return target[prop];
396
- }
397
- });
398
- return dbProxy;
399
- }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=prismaClient.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"prismaClient.test.d.ts","sourceRoot":"","sources":["../../../source/mock/prismaClient/prismaClient.test.ts"],"names":[],"mappings":""}
@@ -1,91 +0,0 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
- import { mockPrismaClient } from './prismaClient';
3
- describe('mockPrismaClient', () => {
4
- let db;
5
- beforeEach(() => {
6
- db = mockPrismaClient();
7
- });
8
- it('应支持 mockResolvedValue 并记录调用', async () => {
9
- db.__mockResolvedValue('user', 'findMany', [{ id: 1, name: '张三' }]);
10
- const users = await db.user.findMany();
11
- expect(users).toEqual([{ id: 1, name: '张三' }]);
12
- expect(db.__getCallCount('user', 'findMany')).toBe(1);
13
- const lastCall = db.__getLastCall('user', 'findMany');
14
- expect(lastCall?.args).toEqual([]);
15
- expect(lastCall?.returnValue).toEqual([{ id: 1, name: '张三' }]);
16
- });
17
- it('应支持 mockRejectedValue 并捕获异常', async () => {
18
- db.__mockRejectedValue('user', 'create', new Error('创建失败'));
19
- await expect(db.user.create({ data: { name: '李四' } })).rejects.toThrow('创建失败');
20
- expect(db.__getCallCount('user', 'create')).toBe(1);
21
- const lastCall = db.__getLastCall('user', 'create');
22
- expect(lastCall?.isError).toBe(true);
23
- expect(lastCall?.error).toBeInstanceOf(Error);
24
- });
25
- it('应支持 mockReturnValue 返回同步值', async () => {
26
- db.__mockReturnValue('post', 'count', 5);
27
- const count = await db.post.count();
28
- expect(count).toBe(5);
29
- });
30
- it('应支持 __getCallHistory 和 __clearCallHistory', async () => {
31
- db.__mockResolvedValue('user', 'findMany', []);
32
- await db.user.findMany();
33
- await db.user.findMany({ where: { id: 1 } });
34
- expect(db.__getCallHistory('user', 'findMany').length).toBe(2);
35
- db.__clearCallHistory('user');
36
- expect(db.__getCallHistory('user', 'findMany').length).toBe(0);
37
- });
38
- it('应支持 __resetMocks', async () => {
39
- db.__mockReturnValue('user', 'count', 10);
40
- await db.user.count();
41
- db.__resetMocks('user');
42
- const count = await db.user.count();
43
- expect(count).toBe(0); // 恢复为默认值
44
- });
45
- it('应支持 __batchMock 批量设置', async () => {
46
- db.__batchMock({
47
- 'user.findMany': { value: [{ id: 1 }], isAsync: true },
48
- 'post.create': { value: { id: 2 }, isAsync: true }
49
- });
50
- expect(await db.user.findMany()).toEqual([{ id: 1 }]);
51
- expect(await db.post.create({ data: { title: 't' } })).toEqual({ id: 2 });
52
- });
53
- it('应支持 __createSnapshot 和 __restoreSnapshot', async () => {
54
- db.__mockReturnValue('user', 'count', 7);
55
- await db.user.count();
56
- const snapshot = db.__createSnapshot();
57
- db.__mockReturnValue('user', 'count', 1);
58
- await db.user.count();
59
- db.__restoreSnapshot(snapshot);
60
- expect(await db.user.count()).toBe(7);
61
- });
62
- it('应支持 __wasCalledWith 和 __wasCalledWithArgs', async () => {
63
- db.__mockResolvedValue('user', 'findUnique', { id: 1 });
64
- await db.user.findUnique({ where: { id: 1 } });
65
- expect(db.__wasCalledWith('user', 'findUnique')).toBe(true);
66
- expect(db.__wasCalledWithArgs('user', 'findUnique', [{ where: { id: 1 } }])).toBe(true);
67
- });
68
- it('应支持 __verifyCallSequence', async () => {
69
- db.__mockResolvedValue('user', 'findUnique', { id: 1 });
70
- db.__mockResolvedValue('post', 'create', { id: 2 });
71
- await db.user.findUnique({ where: { id: 1 } });
72
- await db.post.create({ data: { title: 't' } });
73
- expect(db.__verifyCallSequence([
74
- { table: 'user', method: 'findUnique' },
75
- { table: 'post', method: 'create' }
76
- ])).toBe(true);
77
- });
78
- it('应支持 __getCallStatistics', async () => {
79
- db.__mockResolvedValue('user', 'findMany', []);
80
- db.__mockResolvedValue('post', 'count', 3);
81
- await db.user.findMany();
82
- await db.post.count();
83
- const stats = db.__getCallStatistics();
84
- expect(stats.totalCalls).toBe(2);
85
- expect(stats.tableStats.user).toBe(1);
86
- expect(stats.tableStats.post).toBe(1);
87
- expect(stats.methodStats['user.findMany']).toBe(1);
88
- expect(stats.methodStats['post.count']).toBe(1);
89
- expect(stats.timeRange).not.toBeNull();
90
- });
91
- });