midway-fatcms 0.0.4 → 0.0.6

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 (126) hide show
  1. package/README.md +635 -352
  2. package/dist/controller/manage/CrudStandardDesignApi.d.ts +0 -2
  3. package/dist/controller/manage/CrudStandardDesignApi.js +11 -85
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.js +2 -0
  6. package/dist/libs/crud-pro/CrudPro.d.ts +9 -1
  7. package/dist/libs/crud-pro/CrudPro.js +15 -0
  8. package/dist/libs/crud-pro/README.md +809 -0
  9. package/dist/libs/crud-pro/README_FUNC.md +193 -0
  10. package/dist/libs/crud-pro/exceptions.d.ts +2 -0
  11. package/dist/libs/crud-pro/exceptions.js +2 -0
  12. package/dist/libs/crud-pro/interfaces.d.ts +34 -1
  13. package/dist/libs/crud-pro/models/ExecuteContext.d.ts +3 -3
  14. package/dist/libs/crud-pro/models/ExecuteContext.js +2 -0
  15. package/dist/libs/crud-pro/models/RequestModel.d.ts +41 -1
  16. package/dist/libs/crud-pro/models/RequestModel.js +103 -39
  17. package/dist/libs/crud-pro/models/ResModel.d.ts +6 -4
  18. package/dist/libs/crud-pro/models/ServiceHub.d.ts +1 -0
  19. package/dist/libs/crud-pro/models/keys.d.ts +6 -1
  20. package/dist/libs/crud-pro/models/keys.js +5 -0
  21. package/dist/libs/crud-pro/services/CrudProDataTypeConvertService.d.ts +52 -0
  22. package/dist/libs/crud-pro/services/CrudProDataTypeConvertService.js +158 -0
  23. package/dist/libs/crud-pro/services/CrudProExecuteSqlService.js +20 -1
  24. package/dist/libs/crud-pro/services/CrudProFieldValidateService.d.ts +7 -0
  25. package/dist/libs/crud-pro/services/CrudProFieldValidateService.js +32 -0
  26. package/dist/libs/crud-pro/services/CrudProGenSqlService.d.ts +13 -0
  27. package/dist/libs/crud-pro/services/CrudProGenSqlService.js +44 -7
  28. package/dist/libs/crud-pro/services/CrudProOriginToExecuteSql.d.ts +43 -0
  29. package/dist/libs/crud-pro/services/CrudProOriginToExecuteSql.js +132 -1
  30. package/dist/libs/crud-pro/services/CrudProTableMetaService.d.ts +15 -1
  31. package/dist/libs/crud-pro/services/CrudProTableMetaService.js +107 -0
  32. package/dist/libs/crud-pro/services/CurdProServiceHub.d.ts +5 -1
  33. package/dist/libs/crud-pro/services/CurdProServiceHub.js +11 -0
  34. package/dist/libs/crud-pro/utils/DateTimeUtils.d.ts +1 -0
  35. package/dist/libs/crud-pro/utils/DateTimeUtils.js +3 -0
  36. package/dist/libs/crud-pro/utils/MixinUtils.d.ts +32 -0
  37. package/dist/libs/crud-pro/utils/MixinUtils.js +85 -1
  38. package/dist/libs/crud-pro/utils/ValidateUtils.js +1 -1
  39. package/dist/libs/crud-sharding/ROUTING_LOGIC.md +944 -0
  40. package/dist/libs/crud-sharding/ShardingConfig.d.ts +218 -0
  41. package/dist/libs/crud-sharding/ShardingConfig.js +32 -0
  42. package/dist/libs/crud-sharding/ShardingCountCache.d.ts +69 -0
  43. package/dist/libs/crud-sharding/ShardingCountCache.js +160 -0
  44. package/dist/libs/crud-sharding/ShardingCrudPro.d.ts +363 -0
  45. package/dist/libs/crud-sharding/ShardingCrudPro.js +699 -0
  46. package/dist/libs/crud-sharding/ShardingMerger.d.ts +130 -0
  47. package/dist/libs/crud-sharding/ShardingMerger.js +280 -0
  48. package/dist/libs/crud-sharding/ShardingRouter.d.ts +69 -0
  49. package/dist/libs/crud-sharding/ShardingRouter.js +377 -0
  50. package/dist/libs/crud-sharding/ShardingTableCreator.d.ts +146 -0
  51. package/dist/libs/crud-sharding/ShardingTableCreator.js +805 -0
  52. package/dist/libs/crud-sharding/ShardingUtils.d.ts +38 -0
  53. package/dist/libs/crud-sharding/ShardingUtils.js +77 -0
  54. package/dist/libs/crud-sharding/index.d.ts +45 -0
  55. package/dist/libs/crud-sharding/index.js +55 -0
  56. package/dist/models/StandardColumns.d.ts +71 -0
  57. package/dist/models/StandardColumns.js +28 -0
  58. package/dist/service/SysAppService.js +2 -2
  59. package/dist/service/SysConfigService.js +1 -1
  60. package/dist/service/SysDictDataService.js +2 -2
  61. package/dist/service/SysMenuService.js +1 -1
  62. package/dist/service/UserAccountService.d.ts +1 -1
  63. package/dist/service/crudstd/CrudStdService.d.ts +0 -1
  64. package/dist/service/crudstd/CrudStdService.js +0 -27
  65. package/dist/service/curd/CrudProQuick.d.ts +134 -4
  66. package/dist/service/curd/CrudProQuick.js +155 -3
  67. package/dist/service/curd/CurdMixService.d.ts +2 -1
  68. package/dist/service/curd/CurdMixService.js +5 -1
  69. package/dist/service/curd/CurdProService.d.ts +44 -2
  70. package/dist/service/curd/CurdProService.js +53 -1
  71. package/dist/service/curd/README.md +1001 -0
  72. package/dist/service/curd/fixSoftDelete.d.ts +14 -0
  73. package/dist/service/curd/fixSoftDelete.js +29 -11
  74. package/dist/service/flow/FlowConfigService.js +1 -1
  75. package/dist/service/flow/FlowInstanceCrudService.js +1 -1
  76. package/package.json +3 -1
  77. package/src/controller/gateway/AsyncTaskController.ts +1 -1
  78. package/src/controller/manage/CrudStandardDesignApi.ts +16 -100
  79. package/src/index.ts +3 -0
  80. package/src/libs/crud-pro/CrudPro.ts +19 -1
  81. package/src/libs/crud-pro/README.md +809 -0
  82. package/src/libs/crud-pro/README_FUNC.md +193 -0
  83. package/src/libs/crud-pro/exceptions.ts +2 -0
  84. package/src/libs/crud-pro/interfaces.ts +38 -1
  85. package/src/libs/crud-pro/models/ExecuteContext.ts +6 -3
  86. package/src/libs/crud-pro/models/RequestModel.ts +108 -44
  87. package/src/libs/crud-pro/models/ResModel.ts +10 -4
  88. package/src/libs/crud-pro/models/ServiceHub.ts +2 -0
  89. package/src/libs/crud-pro/models/keys.ts +5 -0
  90. package/src/libs/crud-pro/services/CrudProDataTypeConvertService.ts +171 -0
  91. package/src/libs/crud-pro/services/CrudProExecuteSqlService.ts +24 -1
  92. package/src/libs/crud-pro/services/CrudProFieldValidateService.ts +53 -1
  93. package/src/libs/crud-pro/services/CrudProGenSqlService.ts +51 -7
  94. package/src/libs/crud-pro/services/CrudProOriginToExecuteSql.ts +159 -2
  95. package/src/libs/crud-pro/services/CrudProTableMetaService.ts +139 -1
  96. package/src/libs/crud-pro/services/CurdProServiceHub.ts +16 -1
  97. package/src/libs/crud-pro/utils/DateTimeUtils.ts +3 -0
  98. package/src/libs/crud-pro/utils/MixinUtils.ts +97 -1
  99. package/src/libs/crud-pro/utils/ValidateUtils.ts +1 -1
  100. package/src/libs/crud-sharding/ROUTING_LOGIC.md +944 -0
  101. package/src/libs/crud-sharding/ShardingConfig.ts +240 -0
  102. package/src/libs/crud-sharding/ShardingCountCache.ts +200 -0
  103. package/src/libs/crud-sharding/ShardingCrudPro.ts +856 -0
  104. package/src/libs/crud-sharding/ShardingMerger.ts +382 -0
  105. package/src/libs/crud-sharding/ShardingRouter.ts +512 -0
  106. package/src/libs/crud-sharding/ShardingTableCreator.ts +1007 -0
  107. package/src/libs/crud-sharding/ShardingUtils.ts +84 -0
  108. package/src/libs/crud-sharding/index.ts +64 -0
  109. package/src/models/StandardColumns.ts +76 -0
  110. package/src/service/FileCenterService.ts +1 -1
  111. package/src/service/SysAppService.ts +2 -2
  112. package/src/service/SysConfigService.ts +1 -1
  113. package/src/service/SysDictDataService.ts +2 -2
  114. package/src/service/SysMenuService.ts +2 -2
  115. package/src/service/WorkbenchService.ts +1 -1
  116. package/src/service/anyapi/AnyApiService.ts +1 -1
  117. package/src/service/asyncTask/AsyncTaskRunnerService.ts +1 -1
  118. package/src/service/crudstd/CrudStdService.ts +0 -32
  119. package/src/service/curd/CrudProQuick.ts +164 -5
  120. package/src/service/curd/CurdMixService.ts +7 -2
  121. package/src/service/curd/CurdProService.ts +62 -3
  122. package/src/service/curd/README.md +1001 -0
  123. package/src/service/curd/fixCfgModel.ts +1 -2
  124. package/src/service/curd/fixSoftDelete.ts +38 -16
  125. package/src/service/flow/FlowConfigService.ts +1 -1
  126. package/src/service/flow/FlowInstanceCrudService.ts +1 -1
@@ -0,0 +1,809 @@
1
+ # CrudPro 使用指南
2
+
3
+ CrudPro 是一个功能强大的 CRUD 操作库,支持多种数据库(MySQL、PostgreSQL、SQL Server),提供了配置化的 SQL 执行方式,包括简单 SQL 模式和自定义 SQL 模式。
4
+
5
+ ## 目录
6
+
7
+ - [快速开始](#快速开始)
8
+ - [核心概念](#核心概念)
9
+ - [配置详解](#配置详解)
10
+ - [使用示例](#使用示例)
11
+ - [高级特性](#高级特性)
12
+ - [API 参考](#api-参考)
13
+
14
+ ## 快速开始
15
+
16
+ ### 1. 基础初始化
17
+
18
+ ```typescript
19
+ import { CrudPro } from './CrudPro';
20
+ import { Transaction } from './models/Transaction';
21
+ import { IConnectionPool } from './interfaces';
22
+
23
+ // 创建 CrudPro 实例
24
+ const crudPro = new CrudPro();
25
+
26
+ // 设置事务管理器
27
+ const transaction = new Transaction();
28
+ crudPro.transaction = transaction;
29
+
30
+ // 设置日志器
31
+ const logger = {
32
+ info: (msg: any, ...args: any[]) => console.log('[INFO]', msg, ...args),
33
+ debug: (msg: any, ...args: any[]) => console.log('[DEBUG]', msg, ...args),
34
+ error: (msg: any, ...args: any[]) => console.error('[ERROR]', msg, ...args),
35
+ warn: (msg: any, ...args: any[]) => console.warn('[WARN]', msg, ...args),
36
+ };
37
+ crudPro.logger = logger;
38
+
39
+ // 设置访问者信息(用于权限校验)
40
+ const visitor = {
41
+ isLogin: true,
42
+ isSuperAdmin: false,
43
+ accountId: 'user123',
44
+ nickName: '张三',
45
+ roleCodes: ['admin', 'editor'],
46
+ functionCodes: ['user:create', 'user:read'],
47
+ };
48
+ crudPro.visitor = visitor;
49
+ ```
50
+
51
+ ### 2. 执行第一个查询
52
+
53
+ ```typescript
54
+ import { IRequestModel, IRequestCfgModel } from './interfaces';
55
+
56
+ // 请求参数
57
+ const reqJson: IRequestModel = {
58
+ method: 'user.getList', // 非必须,executeCrudByCfg 会使用 cfgJson.method
59
+ columns: 'id,name,email',
60
+ condition: { status: 1 },
61
+ pageNo: 1,
62
+ pageSize: 10,
63
+ orderBy: 'created_at-',
64
+ };
65
+
66
+ // 配置(可以从数据库读取)
67
+ const cfgJson: IRequestCfgModel = {
68
+ method: 'user.getList',
69
+ sqlTable: 'sys_user',
70
+ sqlDatabase: 'default_db',
71
+ sqlSimpleName: KeysOfSimpleSQL.SIMPLE_QUERY_PAGE, // 使用简单分页查询
72
+ };
73
+
74
+ // 执行
75
+ const result = await crudPro.executeCrudByCfg(reqJson, cfgJson);
76
+ console.log(result.getResRows()); // 获取查询结果
77
+ ```
78
+
79
+ ## 核心概念
80
+
81
+ ### 执行流程
82
+
83
+ ```
84
+ 1. 接收请求 (RequestModel)
85
+
86
+ 2. 加载配置 (RequestCfgModel)
87
+
88
+ 3. 字段过滤 (filterDataByTableMeta) ← 根据表结构过滤不存在的字段
89
+
90
+ 4. 数据类型转换 (convertDataTypeByTableMeta) ← 根据表结构字段类型自动转换
91
+
92
+ 5. 数据校验 (validateByAllow/rejectCfg/validateCfg)
93
+
94
+ 6. 权限校验 (validateByAuthCfg)
95
+
96
+ 7. 默认值设置 (updateByCfg)
97
+
98
+ 8. 生成 SQL (generateSQLList)
99
+
100
+ 9. 执行 SQL (executeSQLList)
101
+
102
+ 10. 返回结果 (ExecuteContext)
103
+ ```
104
+
105
+ ### 简单 SQL 类型 (sqlSimpleName)
106
+
107
+ | 类型 | 说明 | 适用场景 |
108
+ |------|------|----------|
109
+ | `SIMPLE_QUERY` | 简单查询 | 列表查询 |
110
+ | `SIMPLE_QUERY_ONE` | 查询单条 | 详情查询 |
111
+ | `SIMPLE_QUERY_PAGE` | 分页查询 | 分页列表 |
112
+ | `SIMPLE_QUERY_COUNT` | 查询数量 | 统计总数 |
113
+ | `SIMPLE_QUERY_EXIST` | 判断存在 | 存在性检查 |
114
+ | `SIMPLE_UPDATE` | 更新操作 | 修改数据 |
115
+ | `SIMPLE_INSERT` | 插入操作 | 新增单条 |
116
+ | `SIMPLE_BATCH_INSERT` | 批量插入 | 批量新增 |
117
+ | `SIMPLE_DELETE` | 删除操作 | 删除数据 |
118
+ | `SIMPLE_INSERT_ON_DUPLICATE_UPDATE` | 插入或更新 | MySQL 特有 |
119
+ | `SIMPLE_INSERT_OR_UPDATE` | 插入或更新 | PostgreSQL/SQL Server |
120
+ | `CUSTOM` | 自定义 SQL | 复杂查询 |
121
+
122
+ ### 查询条件操作符
123
+
124
+ 支持 MongoDB 风格的查询条件:
125
+
126
+ ```typescript
127
+ const condition = {
128
+ // 基础等于
129
+ status: 1,
130
+
131
+ // 比较操作
132
+ age: { $gt: 18 }, // 大于
133
+ score: { $gte: 60 }, // 大于等于
134
+ price: { $lt: 100 }, // 小于
135
+ count: { $lte: 10 }, // 小于等于
136
+ type: { $ne: 'deleted' }, // 不等于
137
+
138
+ // 范围查询
139
+ id: { $in: [1, 2, 3] }, // IN
140
+ code: { $nin: ['a', 'b'] }, // NOT IN
141
+ amount: { $range: [100, 200] }, // BETWEEN
142
+
143
+ // 模糊查询
144
+ name: { $like: '张' }, // 前缀匹配 (张%)
145
+ title: { $likeInclude: '文章' }, // 包含匹配 (%文章%)
146
+
147
+ // NULL 判断
148
+ deleted_at: { $null: true }, // IS NULL
149
+ updated_at: { $notNull: true }, // IS NOT NULL
150
+
151
+ // 逻辑组合
152
+ $or: [
153
+ { name: { $like: '张' } },
154
+ { name: { $like: '李' } },
155
+ ],
156
+ };
157
+ ```
158
+
159
+ ## 配置详解
160
+
161
+ ### 请求配置 (IRequestCfgModel)
162
+
163
+ ```typescript
164
+ interface IRequestCfgModel {
165
+ method: string; // 方法标识(必填)
166
+ sqlTable?: string; // 表名
167
+ sqlSchema?: string; // Schema(PostgreSQL/SQL Server)
168
+ sqlDatabase?: string; // 数据库名
169
+ sqlDbType?: 'mysql' | 'postgres' | 'sqlserver';
170
+
171
+ // 执行模式(二选一,sqlCfgList 优先级更高)
172
+ sqlSimpleName?: KeysOfSimpleSQL; // 简单 SQL 类型
173
+ sqlCfgList?: ISqlCfgModel[]; // 自定义 SQL 列表
174
+
175
+ // 事务控制
176
+ transactionEnable?: boolean; // 是否开启事务
177
+ transactionIsolation?: number; // 事务隔离级别
178
+
179
+ // 数据操作配置
180
+ uniqueColumn?: string[]; // 唯一键列(用于 UPSERT)
181
+ updateCfg?: Record<string, IFuncCfgModel>; // 字段默认值配置
182
+ allowCfg?: Record<string, string[]>; // 允许修改的字段
183
+ rejectCfg?: Record<string, string[]>; // 拒绝修改的字段
184
+ validateCfg?: Record<string, IValidatorCfgItem[]>; // 字段校验规则
185
+
186
+ // 权限配置
187
+ authType?: 'free' | 'login' | 'byRoleCode' | 'byFuncCode';
188
+ authConfig?: string | string[]; // 角色码或功能点码
189
+ }
190
+ ```
191
+
192
+ ### 自定义 SQL 配置 (ISqlCfgModel)
193
+
194
+ ```typescript
195
+ interface ISqlCfgModel {
196
+ resName?: string; // 结果名称
197
+ resPicker?: string; // 结果提取器
198
+
199
+ // 表配置
200
+ sqlTable?: string;
201
+ sqlSchema?: string;
202
+ sqlDatabase?: string;
203
+ sqlDbType?: SqlDbType;
204
+ columns?: string | string[];
205
+ columnsRelation?: ColumnRelation[];
206
+
207
+ // SQL 配置
208
+ originSql?: string; // 原始 SQL(含占位符)
209
+ executeSql?: string; // 可执行 SQL
210
+ executeSqlArgs?: any[]; // SQL 参数
211
+ isNativeSQL?: boolean; // 是否原生 SQL
212
+
213
+ // 执行控制
214
+ validate?: IFuncCfgModel; // 前置校验
215
+ executeWhen?: IFuncCfgModel; // 执行条件
216
+ }
217
+ ```
218
+
219
+ ### SQL 占位符
220
+
221
+ ```sql
222
+ -- 表名占位符
223
+ SELECT * FROM @@table WHERE id = 1
224
+
225
+ -- 列名占位符
226
+ SELECT @@columns FROM @@table
227
+
228
+ -- 条件占位符
229
+ SELECT * FROM @@table WHERE @@asWhere:condition
230
+
231
+ -- 更新占位符
232
+ UPDATE @@table SET @@asUpdate:data WHERE id = @@condition.id
233
+
234
+ -- 插入占位符
235
+ INSERT INTO @@table (@@asInsertKeys:data) VALUES (@@asInsertValues:data)
236
+
237
+ -- 批量插入
238
+ INSERT INTO @@table (@@asBatchInsertKeys:data) VALUES @@asBatchInsertValues:data
239
+
240
+ -- 分页和排序
241
+ SELECT * FROM @@table @@asWhere:condition @@orderBys @@offsetLimit
242
+
243
+ -- 从请求中取单个值
244
+ SELECT * FROM @@table WHERE id = @@data.id
245
+ SELECT * FROM @@table WHERE status = @@condition.status
246
+
247
+ -- 从结果中提取值(多 SQL 场景)
248
+ SELECT * FROM @@table WHERE id = @@pickResAsNumber:rows[0].id
249
+ SELECT * FROM @@table WHERE name = @@pickResAsString:row.name
250
+
251
+ ```
252
+
253
+ ## @@function 说明
254
+
255
+ @@function 不是执行数据库的内置函数,而是执行CrudProExecuteFuncService提供的内置函数。完整的内置函数列表和用法请参考 [README_FUNC.md](./README_FUNC.md)。
256
+
257
+
258
+ ## 使用示例
259
+
260
+ ### 示例 1:简单分页查询
261
+
262
+ ```typescript
263
+ // 配置
264
+ const cfgJson: IRequestCfgModel = {
265
+ method: 'article.list',
266
+ sqlTable: 'article',
267
+ sqlSimpleName: KeysOfSimpleSQL.SIMPLE_QUERY_PAGE,
268
+ };
269
+
270
+ // 请求
271
+ const reqJson: IRequestModel = {
272
+ method: 'article.list', // 非必须,executeCrudByCfg 会使用 cfgJson.method
273
+ columns: 'id,title,content,author_id,created_at',
274
+ condition: {
275
+ status: 1,
276
+ category_id: { $in: [1, 2, 3] },
277
+ created_at: { $gte: '2024-01-01' },
278
+ },
279
+ pageNo: 1,
280
+ pageSize: 20,
281
+ orderBy: 'created_at-',
282
+ };
283
+
284
+ const ctx = await crudPro.executeCrudByCfg(reqJson, cfgJson);
285
+ const { rows, total_count } = ctx.getResModelForQueryPage();
286
+ ```
287
+
288
+ ### 示例 2:单条数据插入
289
+
290
+ ```typescript
291
+ // 配置:带默认值和字段白名单
292
+ const cfgJson: IRequestCfgModel = {
293
+ method: 'user.create', // 非必须,此处仅用于打印日志或调试跟踪记录
294
+ sqlTable: 'sys_user',
295
+ sqlSimpleName: KeysOfSimpleSQL.SIMPLE_INSERT,
296
+ sqlDatabase: 'default_db',
297
+ allowCfg: {
298
+ data: ['name', 'email', 'phone', 'status'], // 只允许这些字段
299
+ },
300
+ updateCfg: {
301
+ 'data.created_at': { functionName: 'getCurrentTimeString' }, // 设置创建时间
302
+ 'data.created_by': { context: 'visitor.accountId' }, // 设置创建人
303
+ },
304
+ validateCfg: {
305
+ 'data.name': ['required', 'string', 'length:2,50'],
306
+ 'data.email': ['required', 'email'],
307
+ 'data.phone': ['phone:cn'],
308
+ },
309
+ };
310
+
311
+ // 请求
312
+ const reqJson: IRequestModel = {
313
+ method: 'user.create', // 非必须,executeCrudByCfg 会使用 cfgJson.method
314
+ data: {
315
+ name: '张三',
316
+ email: 'zhangsan@example.com',
317
+ phone: '13800138000',
318
+ status: 1,
319
+ },
320
+ };
321
+
322
+ const ctx = await crudPro.executeCrudByCfg(reqJson, cfgJson);
323
+ console.log('插入结果:', ctx.getResModel().affected);
324
+ ```
325
+
326
+ ### 示例 3:批量插入
327
+
328
+ ```typescript
329
+ const cfgJson: IRequestCfgModel = {
330
+ method: 'log.batchCreate',
331
+ sqlTable: 'operation_log',
332
+ sqlSimpleName: KeysOfSimpleSQL.SIMPLE_BATCH_INSERT,
333
+ };
334
+
335
+ const reqJson: IRequestModel = {
336
+ method: 'log.batchCreate', // 非必须,executeCrudByCfg 会使用 cfgJson.method
337
+ data: [
338
+ { action: 'login', user_id: '1', created_at: new Date() },
339
+ { action: 'logout', user_id: '1', created_at: new Date() },
340
+ { action: 'login', user_id: '2', created_at: new Date() },
341
+ ],
342
+ };
343
+
344
+ const ctx = await crudPro.executeCrudByCfg(reqJson, cfgJson);
345
+ ```
346
+
347
+ ### 示例 4:带事务的多 SQL 操作
348
+
349
+ ```typescript
350
+ const cfgJson: IRequestCfgModel = {
351
+ method: 'order.create',
352
+ sqlTable: 'orders',
353
+ transactionEnable: true, // 开启事务
354
+ functionCfg: {
355
+ uuid: { functionName: 'uuid' }
356
+ },
357
+ sqlCfgList: [
358
+ // 第一步:插入订单
359
+ {
360
+ resName: 'order',
361
+ resPicker: KeysOfSqlResPicker.UPDATE_RESULT,
362
+ sqlTable: 'orders',
363
+ originSql: `INSERT INTO @@table (order_no, user_id, amount, status)
364
+ VALUES (@@function:uuid(), @@data.user_id, @@data.amount, 0)`,
365
+ },
366
+ // 第二步:插入订单明细
367
+ {
368
+ resName: 'items',
369
+ sqlTable: 'order_items',
370
+ resPicker: null, // INSERT、UPDATE语句自动使用:KeysOfSqlResPicker.UPDATE_RESULT
371
+ originSql: `INSERT INTO @@table (order_id, product_id, quantity, price)
372
+ VALUES (@@pickResAsString:order.insertId, @@data.product_id, @@data.quantity, @@data.price)`,
373
+ },
374
+ // 第三步:扣减库存
375
+ {
376
+ resName: 'stockResult',
377
+ sqlTable: 'product_stock',
378
+ originSql: `UPDATE @@table
379
+ SET stock = stock - @@data.quantity
380
+ WHERE product_id = @@data.product_id`,
381
+ },
382
+ ],
383
+ };
384
+
385
+ const reqJson: IRequestModel = {
386
+ method: 'order.create', // 非必须,executeCrudByCfg 会使用 cfgJson.method
387
+ data: {
388
+ user_id: 'user123',
389
+ amount: 199.99,
390
+ product_id: 'prod456',
391
+ quantity: 2,
392
+ price: 99.99,
393
+ },
394
+ };
395
+
396
+ const ctx = await crudPro.executeCrudByCfg(reqJson, cfgJson);
397
+ console.log('订单创建成功:', ctx.getResModelItem('order'));
398
+ ```
399
+
400
+ ### 示例 5:权限控制
401
+
402
+ ```typescript
403
+ // 登录即可访问
404
+ const cfg1: IRequestCfgModel = {
405
+ method: 'user.profile',
406
+ sqlTable: 'sys_user',
407
+ sqlSimpleName: KeysOfSimpleSQL.SIMPLE_QUERY_ONE,
408
+ authType: 'login',
409
+ };
410
+
411
+ // 需要特定角色
412
+ const cfg2: IRequestCfgModel = {
413
+ method: 'admin.userList',
414
+ sqlTable: 'sys_user',
415
+ sqlSimpleName: KeysOfSimpleSQL.SIMPLE_QUERY_PAGE,
416
+ authType: 'byRoleCode',
417
+ authConfig: 'admin', // 或 ['admin', 'super_admin']
418
+ };
419
+
420
+ // 需要特定功能点
421
+ const cfg3: IRequestCfgModel = {
422
+ method: 'user.delete',
423
+ sqlTable: 'sys_user',
424
+ sqlSimpleName: KeysOfSimpleSQL.SIMPLE_DELETE,
425
+ authType: 'byFuncCode',
426
+ authConfig: 'user:delete',
427
+ };
428
+ ```
429
+
430
+ ### 示例 6:直接执行 SQL
431
+
432
+ ```typescript
433
+ import { ISqlCfgModel } from './interfaces';
434
+
435
+ // 框架自动转换占位符(? → $1/$2 或 @fatcms_ms1/@fatcms_ms2)
436
+ // 自动转换虽然方便,但当 SQL 中包含非参数绑定的问号(如正则表达式、字符串常量中的 ?)时会被误替换,
437
+ // 此时需使用 isNativeSQL: true 并手写数据库原生占位符,详见示例 6b
438
+ const sqlCfg: ISqlCfgModel = {
439
+ sqlTable: 'sys_user',
440
+ sqlDatabase: 'default_db',
441
+ executeSql: 'SELECT * FROM sys_user WHERE status = ? AND created_at > ?',
442
+ executeSqlArgs: [1, '2024-01-01'],
443
+ };
444
+
445
+ const result = await crudPro.executeSQL(sqlCfg);
446
+ console.log(result);
447
+ ```
448
+
449
+ ### 示例 6b:原生 SQL 模式(isNativeSQL)
450
+
451
+ 当 `isNativeSQL: true` 时,框架不转换占位符,SQL 按原样发送到数据库驱动。
452
+
453
+ ```typescript
454
+ // PostgreSQL:直接使用 $1、$2 占位符
455
+ const pgSqlCfg: ISqlCfgModel = {
456
+ isNativeSQL: true,
457
+ sqlDatabase: 'default_db',
458
+ executeSql: 'SELECT * FROM sys_user WHERE status = $1 AND created_at > $2',
459
+ executeSqlArgs: [1, '2024-01-01'],
460
+ };
461
+
462
+ // SQL Server:直接使用 @param 占位符
463
+ const mssqlSqlCfg: ISqlCfgModel = {
464
+ isNativeSQL: true,
465
+ sqlDatabase: 'default_db',
466
+ executeSql: 'SELECT * FROM sys_user WHERE status = @p1 AND created_at > @p2',
467
+ executeSqlArgs: [1, '2024-01-01'],
468
+ };
469
+
470
+ const result = await crudPro.executeSQL(pgSqlCfg);
471
+ ```
472
+
473
+ ### 示例 7:从数据库加载配置
474
+
475
+ ```typescript
476
+ // 假设数据库中已存储了配置
477
+ const reqJson: IRequestModel = {
478
+ method: 'article.list', // 通过 method 查找配置
479
+ condition: { status: 1 },
480
+ pageNo: 1,
481
+ pageSize: 10,
482
+ };
483
+
484
+ // 从数据库加载配置并执行(启用缓存)
485
+ const ctx = await crudPro.executeCrud(reqJson, true);
486
+ ```
487
+
488
+ ## 高级特性
489
+
490
+ ### 1. 字段校验规则
491
+
492
+ ```typescript
493
+ const validateCfg = {
494
+ 'data.name': [
495
+ 'required', // 必填
496
+ 'string', // 字符串类型
497
+ 'length:2,50', // 长度 2-50
498
+ 'name', // 必须是合法标识符
499
+ ],
500
+ 'data.email': [
501
+ 'required',
502
+ 'email', // 邮箱格式
503
+ ],
504
+ 'data.age': [
505
+ 'integer', // 整数
506
+ 'scale:[0,150]', // 范围 0-150
507
+ ],
508
+ 'data.status': [
509
+ 'enum:0,1,2', // 枚举值
510
+ ],
511
+ 'data.phone': [
512
+ 'phone:cn', // 中国手机号
513
+ ],
514
+ 'data.birthday': [
515
+ 'moment:YYYY-MM-DD', // 日期格式
516
+ ],
517
+ 'data.remark': [
518
+ (value: string) => { // 自定义校验函数
519
+ if (value && value.length > 500) {
520
+ throw { code: 'REMARK_TOO_LONG', message: '备注不能超过500字' };
521
+ }
522
+ },
523
+ ],
524
+ };
525
+ ```
526
+
527
+ ### 2. 字段默认值设置(强制使用更新后的值,避免非法数据)
528
+
529
+ ```typescript
530
+ const updateCfg = {
531
+ // 常量值
532
+ 'data.status': { const: 1 },
533
+ 'data.version': { constNumber: 1 },
534
+ 'data.is_deleted': { constBool: false },
535
+
536
+ // 从上下文取值
537
+ 'data.created_by': { context: 'visitor.accountId' },
538
+ 'data.updated_by': { context: 'visitor.nickName' },
539
+
540
+ // 函数调用(uuid 为内置函数,generateOrderNo 需自定义注册, 参考README_FUNC.md)
541
+ 'data.id': { functionName: 'uuid' },
542
+ 'data.order_no': { functionName: 'generateOrderNo', functionParams: ['PRE'] },
543
+
544
+ // 表达式执行(使用 EJS 模板语法,上下文变量为 reqModel / resModel / currentValue)
545
+ 'data.full_name': { executeExpressReturnString: '<%= reqModel.data.first_name %> <%= reqModel.data.last_name %>' },
546
+ };
547
+ ```
548
+
549
+ ### 3. 关联查询(columnsRelation)
550
+
551
+ > `columnsRelation` 的关联数据填充在应用服务层实现(`src/service/curd/`),不在 crud-pro 库内。
552
+ > 完整文档请参考 [src/service/curd/README.md](../../service/curd/README.md)。
553
+
554
+
555
+ ### 4. 排序语法
556
+
557
+ ```typescript
558
+ // 标准 SQL 格式
559
+ orderBy: 'created_at DESC, amount ASC'
560
+
561
+ // 简写格式(+ 升序,- 降序)
562
+ orderBy: 'created_at-, amount+'
563
+ orderBy: 'name, age-' // 默认升序
564
+
565
+ // 数组格式(字符串 + 对象混合)
566
+ orderBy: [
567
+ 'order_id',
568
+ { fieldName: 'created_at', orderType: 'desc' },
569
+ 'amount+',
570
+ ]
571
+ ```
572
+
573
+ ### 5. 分页方式
574
+
575
+ ```typescript
576
+ // 方式 1:使用 pageNo/pageSize
577
+ const req1: IRequestModel = {
578
+ pageNo: 2, // 第 2 页
579
+ pageSize: 20, // 每页 20 条
580
+ };
581
+
582
+ // 方式 2:使用 limit/offset
583
+ const req2: IRequestModel = {
584
+ limit: 20,
585
+ offset: 20, // 跳过 20 条
586
+ };
587
+ ```
588
+
589
+ ### 6. 数据类型自动转换
590
+
591
+ CrudPro 在执行 INSERT/UPDATE 操作前,会根据表结构字段类型自动转换数据格式,确保数据与数据库方言兼容。
592
+
593
+ #### PostgreSQL ARRAY 类型
594
+
595
+ PostgreSQL 的 ARRAY 字段要求使用数组字面量语法 `{"a","b","c"}`,而前端/Node.js 层通常传递 JSON 格式 `["a","b","c"]`。CrudPro 会自动完成转换:
596
+
597
+ ```typescript
598
+ // 无需手动处理,CrudPro 自动转换
599
+ const cfgJson: IRequestCfgModel = {
600
+ method: 'article.create',
601
+ sqlTable: 'article',
602
+ sqlDatabase: 'my_pg_db',
603
+ sqlDbType: SqlDbType.postgres,
604
+ sqlSimpleName: KeysOfSimpleSQL.SIMPLE_INSERT,
605
+ };
606
+
607
+ // 前端传入 JSON 数组
608
+ const reqJson: IRequestModel = {
609
+ data: {
610
+ title: '文章标题',
611
+ tags: ['技术', '前端', 'React'], // JSON 数组 → 自动转为 {"技术","前端","React"}
612
+ categories: '[1,2,3]', // JSON 字符串 → 自动转为 {"1","2","3"}
613
+ },
614
+ };
615
+
616
+ // 执行后,tags 和 categories 字段会自动转为 PG 数组字面量格式
617
+ ```
618
+
619
+ **支持的转换:**
620
+
621
+ | 源数据格式 | 转换结果 | 说明 |
622
+ |-----------|---------|------|
623
+ | `["a","b","c"]` | `{"a","b","c"}` | 字符串数组:双引号包裹 |
624
+ | `[1,2,3]` | `{1,2,3}` | 数字数组:不加引号 |
625
+ | `[true,false]` | `{t,f}` | 布尔数组:转为 t/f |
626
+ | `[1,null,3]` | `{1,NULL,3}` | 含 null:输出 NULL |
627
+ | `[]` | `{}` | 空数组 |
628
+ | `['he"llo']` | `{"he\"llo"}` | 特殊字符自动转义 |
629
+ | `'[1,2,3]'` | `{1,2,3}` | JSON 字符串自动解析后转换 |
630
+
631
+ **适用操作:**
632
+
633
+ - `SIMPLE_INSERT`
634
+ - `SIMPLE_UPDATE`
635
+ - `SIMPLE_INSERT_ON_DUPLICATE_UPDATE`
636
+ - `SIMPLE_INSERT_OR_UPDATE`
637
+ - `SIMPLE_BATCH_INSERT`(批量插入时逐行转换)
638
+
639
+ > 此功能仅对 PostgreSQL 生效,MySQL 和 SQL Server 不需要此转换。
640
+ > 转换依赖 `getTableMeta()` 获取表字段类型信息,已复用缓存机制,不会产生额外查询开销。
641
+
642
+ ## API 参考
643
+
644
+ ### CrudPro 类
645
+
646
+ #### 属性设置
647
+
648
+ | 属性 | 类型 | 必填 | 说明 |
649
+ |------|------|------|------|
650
+ | `transaction` | `Transaction` | 是 | 事务管理器 |
651
+ | `logger` | `ILogger` | 是 | 日志器 |
652
+ | `visitor` | `IVisitor` | 是 | 访问者信息 |
653
+ | `contextFunc` | `IExecuteContextFunc` | 否 | 上下文函数扩展 |
654
+ | `contextCfg` | `ICrudProCfg` | 否 | 全局配置 |
655
+
656
+ #### 核心方法
657
+
658
+ ##### `executeCrudByCfg(reqJson, cfgJson)`
659
+
660
+ 核心执行方法,通过配置执行 CRUD 操作。
661
+
662
+ ```typescript
663
+ public async executeCrudByCfg(
664
+ reqJson: IRequestModel,
665
+ cfgJson: IRequestCfgModel
666
+ ): Promise<ExecuteContext>
667
+ ```
668
+
669
+ **参数:**
670
+ - `reqJson`: 请求参数
671
+ - `cfgJson`: 执行配置
672
+
673
+ **返回:** `ExecuteContext` - 执行上下文,包含结果数据
674
+
675
+ ---
676
+
677
+ ##### `executeCrud(reqJson, isEnableCache)`
678
+
679
+ 从数据库加载配置并执行。
680
+
681
+ ```typescript
682
+ public async executeCrud(
683
+ reqJson: IRequestModel,
684
+ isEnableCache: boolean
685
+ ): Promise<ExecuteContext>
686
+ ```
687
+
688
+ **参数:**
689
+ - `reqJson`: 请求参数(必须包含 `method`)
690
+ - `isEnableCache`: 是否启用配置缓存
691
+
692
+ ---
693
+
694
+ ##### `executeSQL(sqlCfgModel)`
695
+
696
+ 直接执行 SQL。
697
+
698
+ ```typescript
699
+ public async executeSQL(sqlCfgModel: ISqlCfgModel): Promise<any>
700
+ ```
701
+
702
+ ---
703
+
704
+ ##### `getCachedCfgByMethod(method, isEnableCache)`
705
+
706
+ 从缓存或数据库获取配置。
707
+
708
+ ```typescript
709
+ public async getCachedCfgByMethod(
710
+ method: string,
711
+ isEnableCache: boolean
712
+ ): Promise<IRequestCfgModel>
713
+ ```
714
+
715
+ ---
716
+
717
+ ##### `getAllTableInfos(query, options?)`
718
+
719
+ 获取数据库中的所有表信息。
720
+
721
+ ```typescript
722
+ public async getAllTableInfos(
723
+ query: ITableNamesQuery,
724
+ options?: ITableNamesOptions
725
+ ): Promise<ITableListResult>
726
+ ```
727
+
728
+ ### ExecuteContext 结果处理
729
+
730
+ | 方法 | 说明 |
731
+ |------|------|
732
+ | `getResRows()` | 获取查询结果数组 |
733
+ | `getOneObj()` | 获取单条结果(key 为 'row') |
734
+ | `getResModelItem(name)` | 获取指定名称的结果 |
735
+ | `getResModelItemLodash(name)` | 支持路径获取(如 'rows[0].id') |
736
+ | `getResModelForQueryPage()` | 获取分页查询结果(含 total_count) |
737
+ | `getResMessage()` | 获取执行消息 |
738
+
739
+ ### 全局配置 (ICrudProCfg)
740
+
741
+ ```typescript
742
+ interface ICrudProCfg {
743
+ sysDatabaseName?: string; // 默认:fatcms
744
+ sysDatabaseDbType?: SqlDbType; // 默认:mysql
745
+ methodsTableName?: string; // 默认:sys_crud_methods
746
+ methodsCacheTime?: number; // 默认:60000 (毫秒)
747
+ dictItemTableName?: string; // 默认:sys_data_dict_item
748
+ sysConfigTableName?: string; // 默认:sys_configs
749
+ tableMetaCacheTime?: number; // 表结构缓存时间
750
+ }
751
+ ```
752
+
753
+ ## 异常处理
754
+
755
+ CrudPro 使用 `CommonException` 抛出异常,可通过 `code` 字段识别错误类型:
756
+
757
+ ```typescript
758
+ try {
759
+ await crudPro.executeCrudByCfg(reqJson, cfgJson);
760
+ } catch (e) {
761
+ if (e instanceof CommonException) {
762
+ console.log('错误码:', e.code);
763
+ console.log('错误消息:', e.message);
764
+
765
+ // 常见错误码处理
766
+ switch (e.code) {
767
+ case 'NO_AUTH':
768
+ // 权限不足
769
+ break;
770
+ case 'NOT_LOGIN':
771
+ // 未登录
772
+ break;
773
+ case 'CFG_NOT_FOUND':
774
+ // 配置不存在
775
+ break;
776
+ case 'VALIDATE_EXCEPTION':
777
+ // 数据校验失败
778
+ break;
779
+ case 'RUN_SQL_EXCEPTION_ER_DUP_ENTRY':
780
+ // 数据重复
781
+ break;
782
+ }
783
+ }
784
+ }
785
+ ```
786
+
787
+ ### 常见错误码
788
+
789
+ | 错误码 | 说明 |
790
+ |--------|------|
791
+ | `NO_AUTH` | 没有权限 |
792
+ | `NOT_LOGIN` | 未登录 |
793
+ | `CFG_NOT_FOUND` | 配置不存在 |
794
+ | `CFG_METHOD_EMPTY` | 方法名为空 |
795
+ | `VALIDATE_EXCEPTION` | 数据校验失败 |
796
+ | `VALIDATE_ALLOW_ERR` | 包含不允许的字段 |
797
+ | `VALIDATE_REJECT_ERR` | 包含被拒绝的字段 |
798
+ | `RUN_SQL_EXCEPTION_ER_DUP_ENTRY` | 数据重复 |
799
+ | `RUN_SQL_EXCEPTION_ER_NO_SUCH_TABLE` | 表不存在 |
800
+
801
+ ## 最佳实践
802
+
803
+ 1. **配置管理**:将常用配置存储到数据库,通过 `method` 动态加载
804
+ 2. **缓存策略**:生产环境启用配置缓存,减少数据库查询
805
+ 3. **权限控制**:合理使用 `authType` 和 `authConfig` 保护接口
806
+ 4. **字段过滤**:使用 `allowCfg` 和 `rejectCfg` 控制可操作的字段
807
+ 5. **数据校验**:配置 `validateCfg` 确保数据有效性
808
+ 6. **事务管理**:多 SQL 操作开启 `transactionEnable` 保证数据一致性
809
+ 7. **日志记录**:实现 `ILogger` 接口记录执行日志