midway-fatcms 0.0.7 → 0.0.9

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.
Files changed (159) hide show
  1. package/.qoder/skills/midway-fatcms/01-quick-start.md +231 -0
  2. package/.qoder/skills/midway-fatcms/02-crud-quick.md +375 -0
  3. package/.qoder/skills/midway-fatcms/03-crud-sharding.md +489 -0
  4. package/.qoder/skills/midway-fatcms/04-condition-operators.md +93 -0
  5. package/.qoder/skills/midway-fatcms/05-configuration.md +290 -0
  6. package/.qoder/skills/midway-fatcms/06-builtin-functions.md +241 -0
  7. package/.qoder/skills/midway-fatcms/07-examples.md +504 -0
  8. package/.qoder/skills/midway-fatcms/SKILL.md +96 -0
  9. package/README.md +9 -9
  10. package/dist/configuration.d.ts +10 -0
  11. package/dist/configuration.js +26 -0
  12. package/dist/controller/base/BaseApiController.d.ts +1 -2
  13. package/dist/controller/base/BaseApiController.js +0 -4
  14. package/dist/controller/gateway/DocGatewayController.js +1 -1
  15. package/dist/controller/helpers.controller.d.ts +6 -0
  16. package/dist/controller/helpers.controller.js +19 -0
  17. package/dist/controller/manage/FlowConfigManageApi.js +4 -2
  18. package/dist/controller/manage/SysConfigMangeApi.js +6 -1
  19. package/dist/controller/manage/UserAccountManageApi.js +7 -2
  20. package/dist/index.d.ts +2 -2
  21. package/dist/index.js +2 -2
  22. package/dist/libs/crud-pro/CrudPro.d.ts +51 -3
  23. package/dist/libs/crud-pro/CrudPro.js +111 -4
  24. package/dist/libs/crud-pro/exceptions.d.ts +7 -0
  25. package/dist/libs/crud-pro/exceptions.js +7 -0
  26. package/dist/libs/crud-pro/interfaces.d.ts +83 -12
  27. package/dist/libs/crud-pro/models/CrudResult.d.ts +116 -0
  28. package/dist/libs/crud-pro/models/CrudResult.js +126 -0
  29. package/dist/libs/crud-pro/models/RequestModel.d.ts +2 -2
  30. package/dist/libs/crud-pro/models/ServiceHub.d.ts +2 -0
  31. package/dist/libs/crud-pro/services/CrudProDataTypeConvertService.d.ts +70 -2
  32. package/dist/libs/crud-pro/services/CrudProDataTypeConvertService.js +205 -13
  33. package/dist/libs/crud-pro/services/CrudProExecuteSqlService.js +36 -2
  34. package/dist/libs/crud-pro/services/CrudProGenSqlCondition.js +8 -4
  35. package/dist/libs/crud-pro/services/CrudProTableMetaService.d.ts +36 -0
  36. package/dist/libs/crud-pro/services/CrudProTableMetaService.js +97 -4
  37. package/dist/libs/crud-pro/services/CurdProServiceHub.d.ts +2 -0
  38. package/dist/libs/crud-pro/services/CurdProServiceHub.js +6 -0
  39. package/dist/libs/crud-pro-quick/CrudProQuick.d.ts +382 -0
  40. package/dist/libs/crud-pro-quick/CrudProQuick.js +689 -0
  41. package/dist/libs/crud-pro-quick/fixSoftDelete.d.ts +30 -0
  42. package/dist/{service/curd → libs/crud-pro-quick}/fixSoftDelete.js +3 -6
  43. package/dist/libs/crud-pro-quick/index.d.ts +36 -0
  44. package/dist/libs/crud-pro-quick/index.js +49 -0
  45. package/dist/libs/crud-pro-quick/models.d.ts +33 -0
  46. package/dist/libs/crud-pro-quick/models.js +2 -0
  47. package/dist/libs/crud-sharding/ShardingBase.d.ts +78 -0
  48. package/dist/libs/crud-sharding/ShardingBase.js +179 -0
  49. package/dist/libs/crud-sharding/ShardingByCustomCrud.d.ts +35 -0
  50. package/dist/libs/crud-sharding/ShardingByCustomCrud.js +297 -0
  51. package/dist/libs/crud-sharding/ShardingByHashCrud.d.ts +38 -0
  52. package/dist/libs/crud-sharding/ShardingByHashCrud.js +86 -0
  53. package/dist/libs/crud-sharding/ShardingByKeyCrud.d.ts +39 -0
  54. package/dist/libs/crud-sharding/ShardingByKeyCrud.js +74 -0
  55. package/dist/libs/crud-sharding/ShardingByTimeCrud.d.ts +66 -0
  56. package/dist/libs/crud-sharding/ShardingByTimeCrud.js +524 -0
  57. package/dist/libs/crud-sharding/ShardingConfig.d.ts +25 -10
  58. package/dist/libs/crud-sharding/ShardingConfig.js +5 -5
  59. package/dist/libs/crud-sharding/ShardingMerger.d.ts +10 -18
  60. package/dist/libs/crud-sharding/ShardingMerger.js +27 -44
  61. package/dist/libs/crud-sharding/ShardingResult.d.ts +33 -0
  62. package/dist/libs/crud-sharding/ShardingResult.js +16 -0
  63. package/dist/libs/crud-sharding/ShardingTableCreator.d.ts +21 -4
  64. package/dist/libs/crud-sharding/ShardingTableCreator.js +193 -59
  65. package/dist/libs/crud-sharding/ShardingUtils.d.ts +48 -0
  66. package/dist/libs/crud-sharding/ShardingUtils.js +122 -1
  67. package/dist/libs/crud-sharding/TIME_COLUMN_CLEAN_SPEC.md +488 -0
  68. package/dist/libs/crud-sharding/index.d.ts +13 -15
  69. package/dist/libs/crud-sharding/index.js +33 -17
  70. package/dist/models/RedisKeys.d.ts +1 -0
  71. package/dist/models/RedisKeys.js +1 -0
  72. package/dist/models/bizmodels.d.ts +2 -6
  73. package/dist/service/SysAppService.d.ts +2 -2
  74. package/dist/service/SysAppService.js +16 -5
  75. package/dist/service/SysConfigService.d.ts +1 -1
  76. package/dist/service/SysConfigService.js +7 -2
  77. package/dist/service/SysDictDataService.js +14 -4
  78. package/dist/service/SysMenuService.js +7 -2
  79. package/dist/service/TableMetaCacheRedisSubscriber.d.ts +31 -0
  80. package/dist/service/TableMetaCacheRedisSubscriber.js +98 -0
  81. package/dist/service/curd/CurdMixService.d.ts +6 -4
  82. package/dist/service/curd/CurdMixService.js +16 -2
  83. package/dist/service/curd/CurdProService.d.ts +149 -29
  84. package/dist/service/curd/CurdProService.js +157 -38
  85. package/dist/service/flow/FlowConfigService.js +7 -2
  86. package/dist/service/flow/FlowInstanceCrudService.js +22 -19
  87. package/package.json +1 -1
  88. package/src/configuration.ts +27 -0
  89. package/src/controller/base/BaseApiController.ts +0 -5
  90. package/src/controller/gateway/DocGatewayController.ts +1 -1
  91. package/src/controller/helpers.controller.ts +15 -0
  92. package/src/controller/manage/CrudStandardDesignApi.ts +4 -3
  93. package/src/controller/manage/FlowConfigManageApi.ts +4 -2
  94. package/src/controller/manage/SysConfigMangeApi.ts +6 -1
  95. package/src/controller/manage/UserAccountManageApi.ts +7 -2
  96. package/src/index.ts +2 -2
  97. package/src/libs/crud-pro/CrudPro.ts +134 -7
  98. package/src/libs/crud-pro/exceptions.ts +8 -0
  99. package/src/libs/crud-pro/interfaces.ts +111 -15
  100. package/src/libs/crud-pro/models/CrudResult.ts +178 -0
  101. package/src/libs/crud-pro/models/RequestModel.ts +2 -2
  102. package/src/libs/crud-pro/models/ServiceHub.ts +4 -0
  103. package/src/libs/crud-pro/services/CrudProDataTypeConvertService.ts +238 -15
  104. package/src/libs/crud-pro/services/CrudProExecuteSqlService.ts +41 -2
  105. package/src/libs/crud-pro/services/CrudProGenSqlCondition.ts +11 -7
  106. package/src/libs/crud-pro/services/CrudProTableMetaService.ts +110 -3
  107. package/src/libs/crud-pro/services/CurdProServiceHub.ts +8 -0
  108. package/src/libs/crud-pro-quick/CrudProQuick.ts +782 -0
  109. package/src/{service/curd → libs/crud-pro-quick}/fixSoftDelete.ts +23 -13
  110. package/src/libs/crud-pro-quick/index.ts +52 -0
  111. package/src/libs/crud-pro-quick/models.ts +35 -0
  112. package/src/libs/crud-sharding/ShardingBase.ts +256 -0
  113. package/src/libs/crud-sharding/ShardingByCustomCrud.ts +329 -0
  114. package/src/libs/crud-sharding/ShardingByHashCrud.ts +111 -0
  115. package/src/libs/crud-sharding/ShardingByKeyCrud.ts +97 -0
  116. package/src/libs/crud-sharding/ShardingByTimeCrud.ts +628 -0
  117. package/src/libs/crud-sharding/ShardingConfig.ts +28 -10
  118. package/src/libs/crud-sharding/ShardingMerger.ts +35 -63
  119. package/src/libs/crud-sharding/ShardingResult.ts +29 -0
  120. package/src/libs/crud-sharding/ShardingTableCreator.ts +214 -71
  121. package/src/libs/crud-sharding/ShardingUtils.ts +137 -0
  122. package/src/libs/crud-sharding/TIME_COLUMN_CLEAN_SPEC.md +488 -0
  123. package/src/libs/crud-sharding/index.ts +30 -16
  124. package/src/models/RedisKeys.ts +1 -0
  125. package/src/models/bizmodels.ts +4 -7
  126. package/src/service/SysAppService.ts +18 -7
  127. package/src/service/SysConfigService.ts +8 -3
  128. package/src/service/SysDictDataService.ts +14 -4
  129. package/src/service/SysMenuService.ts +7 -2
  130. package/src/service/TableMetaCacheRedisSubscriber.ts +105 -0
  131. package/src/service/crudstd/CrudStdService.ts +2 -2
  132. package/src/service/curd/CurdMixService.ts +26 -5
  133. package/src/service/curd/CurdProService.ts +186 -45
  134. package/src/service/flow/FlowConfigService.ts +7 -2
  135. package/src/service/flow/FlowInstanceCrudService.ts +23 -20
  136. package/.qoder/skills/midway-fatcms-crud/SKILL.md +0 -375
  137. package/.qoder/skills/midway-fatcms-crud/examples.md +0 -990
  138. package/.qoder/skills/midway-fatcms-crud/reference.md +0 -568
  139. package/dist/libs/crud-pro/README.md +0 -809
  140. package/dist/libs/crud-pro/README_FUNC.md +0 -193
  141. package/dist/libs/crud-sharding/ROUTING_LOGIC.md +0 -944
  142. package/dist/libs/crud-sharding/ShardingCrudPro.d.ts +0 -363
  143. package/dist/libs/crud-sharding/ShardingCrudPro.js +0 -675
  144. package/dist/libs/crud-sharding/ShardingRouter.d.ts +0 -69
  145. package/dist/libs/crud-sharding/ShardingRouter.js +0 -377
  146. package/dist/models/StandardColumns.d.ts +0 -71
  147. package/dist/models/StandardColumns.js +0 -28
  148. package/dist/service/curd/CrudProQuick.d.ts +0 -190
  149. package/dist/service/curd/CrudProQuick.js +0 -319
  150. package/dist/service/curd/README.md +0 -1100
  151. package/dist/service/curd/fixSoftDelete.d.ts +0 -20
  152. package/src/libs/crud-pro/README.md +0 -809
  153. package/src/libs/crud-pro/README_FUNC.md +0 -193
  154. package/src/libs/crud-sharding/ROUTING_LOGIC.md +0 -944
  155. package/src/libs/crud-sharding/ShardingCrudPro.ts +0 -835
  156. package/src/libs/crud-sharding/ShardingRouter.ts +0 -512
  157. package/src/models/StandardColumns.ts +0 -76
  158. package/src/service/curd/CrudProQuick.ts +0 -360
  159. package/src/service/curd/README.md +0 -1100
@@ -1,28 +1,38 @@
1
1
  import { KeysOfSimpleSQL } from "@/libs/crud-pro/models/keys";
2
- import { IRequestModel } from "@/libs/crud-pro/interfaces";
3
- import { IRequestCfgModel2 } from "@/models/bizmodels";
4
- import { Context } from "@midwayjs/koa";
5
- import type { ICommonStandardColumns } from "@/models/StandardColumns";
2
+ import { IRequestModel, IVisitor } from "@/libs/crud-pro/interfaces";
3
+ import { IRequestCfgModel2, ICommonStandardColumns } from "./models";
4
+
5
+ /**
6
+ * 软删除需要的用户信息(最小子集)
7
+ */
8
+ interface ISoftDeleteUserInfo {
9
+ accountId: string;
10
+ }
11
+
12
+ /**
13
+ * 获取当前用户信息的函数类型
14
+ */
15
+ type GetCurrentUserFunc = () => ISoftDeleteUserInfo | null | undefined;
6
16
 
7
17
  /**
8
18
  * 软删除处理函数
9
- *
19
+ *
10
20
  * 当 cfgModel.enableSoftDelete === true 时,自动处理软删除逻辑:
11
- *
21
+ *
12
22
  * 1. INSERT 操作:自动设置 deleted_at = 0
13
23
  * 2. DELETE 操作:转为 UPDATE,设置 deleted_at = 时间戳, deleted_by = 当前用户
14
24
  * 3. QUERY 操作:自动添加 deleted_at = 0 条件
15
- *
25
+ *
16
26
  * @param oldSqlSimpleName 原始 SQL 类型
17
27
  * @param cfgModel 配置模型
18
28
  * @param params 请求参数(会被修改)
19
- * @param ctx 请求上下文(用于获取当前用户信息)
29
+ * @param visitor 获取当前用户信息的函数(用于软删除时记录删除人)
20
30
  */
21
31
  function fixSoftDelete(
22
32
  oldSqlSimpleName: KeysOfSimpleSQL,
23
33
  cfgModel: IRequestCfgModel2,
24
34
  params: IRequestModel,
25
- ctx?: Context
35
+ visitor?: IVisitor
26
36
  ): void {
27
37
 
28
38
  // 没有开启软删除,不做处理,直接物理删除
@@ -47,8 +57,6 @@ function fixSoftDelete(
47
57
  throw new Error('执行删除操作,必须指定删除条件');
48
58
  }
49
59
 
50
- // 获取当前用户信息
51
- const sessionInfo = ctx?.userSession?.getSessionInfo();
52
60
 
53
61
  // 在原有 data 对象上添加软删除字段
54
62
  if (!params.data) {
@@ -56,7 +64,7 @@ function fixSoftDelete(
56
64
  }
57
65
  const dataObj = params.data as ICommonStandardColumns;
58
66
  dataObj.deleted_at = Date.now();
59
- dataObj.deleted_by = sessionInfo?.accountId || '';
67
+ dataObj.deleted_by = visitor?.accountId || '';
60
68
 
61
69
  // 改为执行 UPDATE 操作
62
70
  cfgModel.sqlSimpleName = KeysOfSimpleSQL.SIMPLE_UPDATE;
@@ -77,4 +85,6 @@ function fixSoftDelete(
77
85
 
78
86
  export {
79
87
  fixSoftDelete,
80
- }
88
+ };
89
+
90
+ export type { ISoftDeleteUserInfo, GetCurrentUserFunc };
@@ -0,0 +1,52 @@
1
+ /**
2
+ * 快捷 CRUD 操作模块
3
+ *
4
+ * 在 CrudPro 之上封装便捷方法,提供简洁的 API 进行单表 CRUD 操作。
5
+ * 内部使用工厂函数模式,每次操作都会获取新的 CrudPro 实例,因此**可以安全复用**。
6
+ *
7
+ * **与 CrudPro 的关系:**
8
+ * - CrudPro 是有状态执行器,禁止复用
9
+ * - CrudProQuick 内部每次调用工厂函数获取新 CrudPro,可以安全复用
10
+ *
11
+ * **使用方式:**
12
+ * 必须通过 CurdProService.getQuickCrud() 获取实例,不要直接构造。
13
+ *
14
+ * @example
15
+ * // 通过 CurdProService 获取实例
16
+ * const quick = curdProService.getQuickCrud('mydb', SqlDbType.mysql, 't_user');
17
+ *
18
+ * // 设置公共配置
19
+ * quick.setBaseCfgModel({
20
+ * enableSoftDelete: true,
21
+ * enableStandardUpdateCfg: true,
22
+ * });
23
+ *
24
+ * // 查询列表(新 API)
25
+ * const result = await quick.findList({ condition: { status: 1 } });
26
+ * console.log(result.rows, result.count);
27
+ *
28
+ * // 插入数据(新 API)
29
+ * const insertResult = await quick.insert({ data: { name: '张三', age: 20 } });
30
+ * console.log(insertResult.affectedRows, insertResult.insertId);
31
+ */
32
+
33
+ // 核心类
34
+ export { CrudProQuick } from './CrudProQuick';
35
+
36
+ // 类型导出
37
+ export type { ICrudProQuickFactory } from './CrudProQuick';
38
+ export type { IRequestCfgModel2, ICommonStandardColumns } from './models';
39
+
40
+ // 工具函数
41
+ export { fixSoftDelete } from './fixSoftDelete';
42
+
43
+ // 重新导出结果类型
44
+ export {
45
+ CrudWriteResult,
46
+ CrudQueryOneResult,
47
+ CrudQueryListResult,
48
+ CrudQueryPageResult,
49
+ CrudExistResult,
50
+ CrudCountResult,
51
+ CrudUpsertResult,
52
+ } from '@/libs/crud-pro/models/CrudResult';
@@ -0,0 +1,35 @@
1
+ import { IRequestCfgModel } from '@/libs/crud-pro/interfaces';
2
+
3
+ /**
4
+ * 常用标准表结构字段(6个字段)
5
+ *
6
+ * 用于软删除和审计跟踪:
7
+ * - deleted_at: 删除时间戳,0=未删除
8
+ * - deleted_by: 删除人ID
9
+ * - created_by: 创建人ID
10
+ * - created_at: 创建时间(毫秒时间戳)
11
+ * - modified_by: 修改人ID
12
+ * - modified_at: 修改时间(毫秒时间戳)
13
+ */
14
+ export interface ICommonStandardColumns {
15
+ deleted_at?: number;
16
+ deleted_by?: string;
17
+ created_by?: string;
18
+ created_at?: number;
19
+ modified_by?: string;
20
+ modified_at?: number;
21
+ }
22
+
23
+ /**
24
+ * 扩展的请求配置模型
25
+ *
26
+ * 在 IRequestCfgModel 基础上添加了业务层常用的配置项:
27
+ * - enableStandardUpdateCfg: 启用标准字段自动填充
28
+ * - enableStandardUpdateCfgCondition: 启用标准字段条件注入
29
+ * - enableSoftDelete: 启用软删除
30
+ */
31
+ export interface IRequestCfgModel2 extends IRequestCfgModel {
32
+ enableStandardUpdateCfg?: boolean | string[]; // 默认为true
33
+ enableStandardUpdateCfgCondition?: boolean | string[]; // 默认为false
34
+ enableSoftDelete?: boolean;
35
+ }
@@ -0,0 +1,256 @@
1
+ import { IRequestModel, IRequestCfgModel } from '@/libs/crud-pro/interfaces';
2
+ import { ExecuteContext } from '@/libs/crud-pro/models/ExecuteContext';
3
+ import { KeysOfSimpleSQL } from '@/libs/crud-pro/models/keys';
4
+ import { IShardingConfig, IShardingRouterContext, CrudProFactory } from './ShardingConfig';
5
+ import { fixSoftDelete } from '@/libs/crud-pro-quick/fixSoftDelete';
6
+ import { ShardingTableCreator } from './ShardingTableCreator';
7
+ import {
8
+ CrudWriteResult,
9
+ CrudQueryOneResult,
10
+ CrudQueryListResult,
11
+ CrudQueryPageResult,
12
+ CrudExistResult,
13
+ CrudCountResult,
14
+ CrudUpsertResult,
15
+ } from '@/libs/crud-pro/models/CrudResult';
16
+ import { ShardingBatchInsertResult } from './ShardingResult';
17
+
18
+ /**
19
+ * 分表 CRUD 基类
20
+ *
21
+ * 提供所有分表子类共用的基础设施方法,不包含任何路由逻辑。
22
+ * 路由逻辑由各子类自行实现。
23
+ *
24
+ * 子类:
25
+ * - ShardingByTimeCrud: 时间分表(YEAR/MONTH/DAY)
26
+ * - ShardingByHashCrud: 哈希分表
27
+ * - ShardingByKeyCrud: 键值分表
28
+ * - ShardingByCustomCrud: 自定义分表
29
+ */
30
+ export abstract class ShardingBase {
31
+ protected readonly crudProFactory: CrudProFactory;
32
+ protected readonly config: IShardingConfig;
33
+ protected readonly tableCreator: ShardingTableCreator;
34
+
35
+ protected baseCfg: Partial<IRequestCfgModel> = {};
36
+ protected enableSoftDelete: boolean = false;
37
+
38
+ constructor(crudProFactory: CrudProFactory, config: IShardingConfig) {
39
+ this.config = config;
40
+
41
+ if (typeof crudProFactory === 'function') {
42
+ this.crudProFactory = crudProFactory;
43
+ } else {
44
+ throw new Error('[ShardingBase] 请使用 CrudProFactory 工厂函数模式');
45
+ }
46
+
47
+ this.tableCreator = new ShardingTableCreator(this.crudProFactory, config);
48
+ }
49
+
50
+ // ============ 配置方法 ============
51
+
52
+ public setBaseCfg(cfg: Partial<IRequestCfgModel>): this {
53
+ this.baseCfg = { ...this.baseCfg, ...cfg };
54
+ return this;
55
+ }
56
+
57
+ public getConfig(): IShardingConfig {
58
+ return this.config;
59
+ }
60
+
61
+ public setEnableSoftDelete(enable: boolean): this {
62
+ this.enableSoftDelete = enable;
63
+ return this;
64
+ }
65
+
66
+ // ============ 抽象 CRUD 方法(子类必须实现) ============
67
+
68
+ public abstract insert(reqJson: IRequestModel): Promise<CrudWriteResult>;
69
+ public abstract batchInsert(reqJson: IRequestModel): Promise<ShardingBatchInsertResult>;
70
+ public abstract update(reqJson: IRequestModel): Promise<CrudWriteResult>;
71
+ public abstract delete(reqJson: IRequestModel): Promise<CrudWriteResult>;
72
+ public abstract restore(reqJson: IRequestModel): Promise<CrudWriteResult>;
73
+ public abstract insertOrUpdate(reqJson: IRequestModel): Promise<CrudUpsertResult>;
74
+ public abstract findOne<T = Record<string, any>>(reqJson: IRequestModel): Promise<CrudQueryOneResult<T>>;
75
+ public abstract findUniqueOne<T = Record<string, any>>(reqJson: IRequestModel): Promise<CrudQueryOneResult<T>>;
76
+ public abstract findList<T = Record<string, any>>(reqJson: IRequestModel): Promise<CrudQueryListResult<T>>;
77
+ public abstract findPage<T = Record<string, any>>(reqJson: IRequestModel): Promise<CrudQueryPageResult<T>>;
78
+ public abstract findCount(reqJson: IRequestModel): Promise<CrudCountResult>;
79
+ public abstract isExist(reqJson: IRequestModel): Promise<CrudExistResult>;
80
+
81
+ /**
82
+ * 判断当前路由上下文是否处于「插入阶段」(应从 data 提取分表字段)
83
+ *
84
+ * - INSERT / BATCH_INSERT → 始终从 data
85
+ * - 其余操作(QUERY / UPDATE / DELETE / INSERT_OR_UPDATE)→ 从 condition
86
+ */
87
+ protected static isInsertPhase(ctx: IShardingRouterContext): boolean {
88
+ return [KeysOfSimpleSQL.SIMPLE_INSERT, KeysOfSimpleSQL.SIMPLE_BATCH_INSERT].includes(ctx.sqlSimpleName);
89
+ }
90
+
91
+ // ============ 执行基础设施 ============
92
+
93
+ protected buildCfg(sqlSimpleName: KeysOfSimpleSQL): IRequestCfgModel & { enableSoftDelete?: boolean } {
94
+ return {
95
+ method: `ShardingCrudProAnonymous_${sqlSimpleName}`,
96
+ ...this.baseCfg,
97
+ sqlTable: this.config.baseTable,
98
+ sqlSimpleName,
99
+ } as IRequestCfgModel & { enableSoftDelete?: boolean };
100
+ }
101
+
102
+ protected async executeOnTable(
103
+ table: string,
104
+ reqJson: IRequestModel,
105
+ sqlSimpleName: KeysOfSimpleSQL,
106
+ extraCfg?: Partial<IRequestCfgModel>
107
+ ): Promise<ExecuteContext> {
108
+ const cfg = this.buildCfg(sqlSimpleName);
109
+ cfg.sqlTable = table;
110
+ cfg.enableSoftDelete = this.enableSoftDelete;
111
+
112
+ if (extraCfg) {
113
+ Object.assign(cfg, extraCfg);
114
+ }
115
+
116
+ const crudPro = this.crudProFactory();
117
+ fixSoftDelete(sqlSimpleName, cfg as any, reqJson, crudPro.getVisitor());
118
+ return crudPro.executeCrudByCfg(reqJson, cfg);
119
+ }
120
+
121
+ // ============ 单表查询辅助 ============
122
+
123
+ protected async findCountFromTable(table: string, reqJson: IRequestModel): Promise<{ count: number; ctx: ExecuteContext | null }> {
124
+ try {
125
+ const ctx = await this.executeOnTable(table, reqJson, KeysOfSimpleSQL.SIMPLE_QUERY_COUNT);
126
+ return { count: ctx.getResModelItem('total_count') || 0, ctx };
127
+ } catch (e) {
128
+ return { count: 0, ctx: null };
129
+ }
130
+ }
131
+
132
+ protected async isExistInTable(table: string, reqJson: IRequestModel): Promise<{ exists: boolean; ctx: ExecuteContext | null }> {
133
+ try {
134
+ const ctx = await this.executeOnTable(table, reqJson, KeysOfSimpleSQL.SIMPLE_QUERY_EXIST);
135
+ return { exists: ctx.getResModelItem('is_exist') === true, ctx };
136
+ } catch (e) {
137
+ return { exists: false, ctx: null };
138
+ }
139
+ }
140
+
141
+ // ============ 表管理 ============
142
+
143
+ protected async getExistingTablesSet(skipCache = false): Promise<Set<string>> {
144
+ const { sqlDatabase, sqlDbType } = this.baseCfg;
145
+
146
+ if (!sqlDatabase || !sqlDbType) {
147
+ throw new Error('[ShardingBase] 未配置 sqlDatabase 或 sqlDbType');
148
+ }
149
+
150
+ const { tables } = await this.crudProFactory().getAllTableInfos(
151
+ { sqlDatabase, sqlDbType: sqlDbType as any },
152
+ { skipCache }
153
+ );
154
+
155
+ return new Set(tables.map(t => t.name));
156
+ }
157
+
158
+ protected async isTableExists(tableName: string): Promise<boolean> {
159
+ const existingSet = await this.getExistingTablesSet();
160
+ return existingSet.has(tableName);
161
+ }
162
+
163
+ protected async createShardingTableIfNeeded(tableName: string): Promise<void> {
164
+ if (!this.config.autoCreateTable) {
165
+ if (!(await this.isTableExists(tableName))) {
166
+ throw new Error(`[ShardingBase] 分表 ${tableName} 不存在。请先创建分表,或设置 autoCreateTable: true 自动创建`);
167
+ }
168
+ return;
169
+ }
170
+
171
+ if (!this.baseCfg.sqlDatabase || !this.baseCfg.sqlDbType) {
172
+ throw new Error('[ShardingBase] 请先调用 setBaseCfg 设置数据库配置');
173
+ }
174
+
175
+ const result = await this.tableCreator.createTableIfNeeded(
176
+ tableName,
177
+ {
178
+ sqlDatabase: this.baseCfg.sqlDatabase,
179
+ sqlDbType: this.baseCfg.sqlDbType,
180
+ },
181
+ this.config.tableCreateOptions
182
+ );
183
+
184
+ if (!result.success) {
185
+ throw result.error || new Error(`[ShardingBase] 创建分表 ${tableName} 失败`);
186
+ }
187
+
188
+ if (result.createSql) {
189
+ await this.getExistingTablesSet(true);
190
+ }
191
+ }
192
+
193
+ // ============ 辅助方法 ============
194
+
195
+ protected buildDebugInfo(sqlTable: string | undefined, condition: Record<string, any> | undefined): { sqlDatabase: string; sqlTable: string; condition?: Record<string, any> } {
196
+ const info: { sqlDatabase: string; sqlTable: string; condition?: Record<string, any> } = {
197
+ sqlDatabase: this.baseCfg.sqlDatabase || 'unknown',
198
+ sqlTable: sqlTable || this.config.baseTable,
199
+ };
200
+ if (condition) {
201
+ info.condition = condition;
202
+ }
203
+ return info;
204
+ }
205
+
206
+ protected formatUniqueError(
207
+ foundCount: number,
208
+ tables: string | string[],
209
+ condition: Record<string, any> | undefined,
210
+ isMultiTable: boolean = false
211
+ ): string {
212
+ const parts = [
213
+ `[ShardingBase] findUniqueOne 期望唯一一条记录,但查询到 ${foundCount} 条`,
214
+ ];
215
+
216
+ if (this.baseCfg.sqlDatabase) {
217
+ parts.push(`数据库: ${this.baseCfg.sqlDatabase}`);
218
+ }
219
+
220
+ if (isMultiTable && Array.isArray(tables)) {
221
+ parts.push(`基表: ${this.config.baseTable}`);
222
+ parts.push(`分表: [${tables.join(', ')}]`);
223
+ } else {
224
+ parts.push(`表: ${typeof tables === 'string' ? tables : tables[0]}`);
225
+ }
226
+
227
+ if (condition) {
228
+ try {
229
+ parts.push(`条件: ${JSON.stringify(condition)}`);
230
+ } catch {
231
+ parts.push(`条件: [无法序列化]`);
232
+ }
233
+ }
234
+
235
+ return parts.join(' | ');
236
+ }
237
+
238
+ /**
239
+ * 获取所有以 baseTable_ 开头的已存在分表(按字典序排序)
240
+ */
241
+ protected async getAllExistingShardingTables(): Promise<string[]> {
242
+ const existingTables = await this.getExistingTablesSet();
243
+ const prefix = `${this.config.baseTable}_`;
244
+ const tables = Array.from(existingTables).filter(t => t.startsWith(prefix));
245
+ tables.sort();
246
+ return tables;
247
+ }
248
+
249
+ /**
250
+ * 过滤出真实存在的分表
251
+ */
252
+ protected async filterExistingTables(candidateTables: string[]): Promise<string[]> {
253
+ const existingTables = await this.getExistingTablesSet();
254
+ return candidateTables.filter(table => existingTables.has(table));
255
+ }
256
+ }