midway-fatcms 0.0.19 → 0.0.20

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/.prettierrc.js CHANGED
@@ -1,4 +1,5 @@
1
1
  module.exports = {
2
2
  ...require('mwts/.prettierrc.json'),
3
3
  printWidth: 500, // 与ESLint的max-len保持一致
4
+ endOfLine: 'crlf',
4
5
  }
@@ -28,7 +28,7 @@ let ProxyApiMangeApi = class ProxyApiMangeApi extends BaseApiController_1.BaseAp
28
28
  return this.executeSysSimpleSQL(SystemTables_1.SystemTables.sys_proxyapi, keys_1.KeysOfSimpleSQL.SIMPLE_INSERT, {
29
29
  validateCfg: {
30
30
  'data.proxy_name': [keys_1.KeysOfValidators.REQUIRED, keys_1.KeysOfValidators.STRING],
31
- 'data.path_prefix': [keys_1.KeysOfValidators.REQUIRED, keys_1.KeysOfValidators.STRING],
31
+ 'data.path_prefix': [keys_1.KeysOfValidators.STRING],
32
32
  'data.upstream_code': [keys_1.KeysOfValidators.REQUIRED, keys_1.KeysOfValidators.STRING],
33
33
  },
34
34
  });
@@ -37,6 +37,7 @@ let ProxyApiMangeApi = class ProxyApiMangeApi extends BaseApiController_1.BaseAp
37
37
  return this.executeSysSimpleSQL(SystemTables_1.SystemTables.sys_proxyapi, keys_1.KeysOfSimpleSQL.SIMPLE_UPDATE, {
38
38
  validateCfg: {
39
39
  'condition.id': [keys_1.KeysOfValidators.REQUIRED, keys_1.KeysOfValidators.NUMERIC],
40
+ 'data.path_prefix': [keys_1.KeysOfValidators.STRING],
40
41
  },
41
42
  });
42
43
  }
@@ -13,23 +13,9 @@ const REGEX_STRING_TYPE = /^(varchar|char|text|longtext|mediumtext|tinytext|nvar
13
13
  /** PG / MySQL 原生 boolean 列名 */
14
14
  const REGEX_NATIVE_BOOLEAN_TYPE = /^(boolean|bool)$/;
15
15
  /** 含 WHERE 条件的操作类型(查询/删除/更新) */
16
- const CONDITION_TYPES = new Set([
17
- keys_1.KeysOfSimpleSQL.SIMPLE_QUERY,
18
- keys_1.KeysOfSimpleSQL.SIMPLE_QUERY_ONE,
19
- keys_1.KeysOfSimpleSQL.SIMPLE_QUERY_PAGE,
20
- keys_1.KeysOfSimpleSQL.SIMPLE_QUERY_COUNT,
21
- keys_1.KeysOfSimpleSQL.SIMPLE_QUERY_EXIST,
22
- keys_1.KeysOfSimpleSQL.SIMPLE_DELETE,
23
- keys_1.KeysOfSimpleSQL.SIMPLE_UPDATE,
24
- ]);
16
+ const CONDITION_TYPES = new Set([keys_1.KeysOfSimpleSQL.SIMPLE_QUERY, keys_1.KeysOfSimpleSQL.SIMPLE_QUERY_ONE, keys_1.KeysOfSimpleSQL.SIMPLE_QUERY_PAGE, keys_1.KeysOfSimpleSQL.SIMPLE_QUERY_COUNT, keys_1.KeysOfSimpleSQL.SIMPLE_QUERY_EXIST, keys_1.KeysOfSimpleSQL.SIMPLE_DELETE, keys_1.KeysOfSimpleSQL.SIMPLE_UPDATE]);
25
17
  /** INSERT/UPDATE 操作类型 */
26
- const INSERT_OR_UPDATE_TYPES = new Set([
27
- keys_1.KeysOfSimpleSQL.SIMPLE_INSERT,
28
- keys_1.KeysOfSimpleSQL.SIMPLE_UPDATE,
29
- keys_1.KeysOfSimpleSQL.SIMPLE_INSERT_ON_DUPLICATE_UPDATE,
30
- keys_1.KeysOfSimpleSQL.SIMPLE_INSERT_OR_UPDATE,
31
- keys_1.KeysOfSimpleSQL.SIMPLE_BATCH_INSERT,
32
- ]);
18
+ const INSERT_OR_UPDATE_TYPES = new Set([keys_1.KeysOfSimpleSQL.SIMPLE_INSERT, keys_1.KeysOfSimpleSQL.SIMPLE_UPDATE, keys_1.KeysOfSimpleSQL.SIMPLE_INSERT_ON_DUPLICATE_UPDATE, keys_1.KeysOfSimpleSQL.SIMPLE_INSERT_OR_UPDATE, keys_1.KeysOfSimpleSQL.SIMPLE_BATCH_INSERT]);
33
19
  // ============ 工具函数 ============
34
20
  function isIntegerType(type) {
35
21
  return REGEX_INTEGER_TYPE.test(type);
@@ -265,9 +251,7 @@ class DataConvertHandler {
265
251
  if (typeof value === 'boolean') {
266
252
  return value ? 't' : 'f';
267
253
  }
268
- const escaped = ('' + value)
269
- .replace(/\\/g, '\\\\')
270
- .replace(/"/g, '\\"');
254
+ const escaped = ('' + value).replace(/\\/g, '\\\\').replace(/"/g, '\\"');
271
255
  return '"' + escaped + '"';
272
256
  }
273
257
  /** 对象/数组 → JSON 字符串,跳过 $sqlFunc、Date、Buffer */
@@ -1,6 +1,6 @@
1
- import { KeysOfSimpleSQL } from "../../libs/crud-pro/models/keys";
2
- import { IRequestModel, IVisitor } from "../../libs/crud-pro/interfaces";
3
- import { IRequestCfgModel2 } from "./models";
1
+ import { KeysOfSimpleSQL } from '../../libs/crud-pro/models/keys';
2
+ import { IRequestModel, IVisitor } from '../../libs/crud-pro/interfaces';
3
+ import { IRequestCfgModel2 } from './models';
4
4
  /**
5
5
  * 软删除处理函数
6
6
  *
@@ -10,4 +10,4 @@ import { IRequestCfgModel2 } from "./models";
10
10
  * @param visitor 获取当前用户信息的函数(用于软删除时记录删除人)
11
11
  */
12
12
  declare function fixSoftDelete(oldSqlSimpleName: KeysOfSimpleSQL, cfgModel: IRequestCfgModel2, params: IRequestModel, visitor?: IVisitor): void;
13
- export { fixSoftDelete, };
13
+ export { fixSoftDelete };
@@ -43,9 +43,7 @@ function fixSoftDelete1(oldSqlSimpleName, cfgModel, params, visitor) {
43
43
  cfgModel.sqlSimpleName = keys_1.KeysOfSimpleSQL.SIMPLE_UPDATE;
44
44
  }
45
45
  // QUERY 操作:强制查询未删除的记录
46
- if (keys_1.KeysOfSimpleSQL.SIMPLE_QUERY_ONE === oldSqlSimpleName
47
- || keys_1.KeysOfSimpleSQL.SIMPLE_QUERY === oldSqlSimpleName
48
- || keys_1.KeysOfSimpleSQL.SIMPLE_QUERY_PAGE === oldSqlSimpleName) {
46
+ if (keys_1.KeysOfSimpleSQL.SIMPLE_QUERY_ONE === oldSqlSimpleName || keys_1.KeysOfSimpleSQL.SIMPLE_QUERY === oldSqlSimpleName || keys_1.KeysOfSimpleSQL.SIMPLE_QUERY_PAGE === oldSqlSimpleName) {
49
47
  if (!params.condition) {
50
48
  params.condition = {};
51
49
  }
@@ -78,9 +76,7 @@ function fixSoftDelete2(oldSqlSimpleName, cfgModel, params, visitor) {
78
76
  cfgModel.sqlSimpleName = keys_1.KeysOfSimpleSQL.SIMPLE_UPDATE;
79
77
  }
80
78
  // QUERY 操作:强制查询未删除的记录
81
- if (keys_1.KeysOfSimpleSQL.SIMPLE_QUERY_ONE === oldSqlSimpleName
82
- || keys_1.KeysOfSimpleSQL.SIMPLE_QUERY === oldSqlSimpleName
83
- || keys_1.KeysOfSimpleSQL.SIMPLE_QUERY_PAGE === oldSqlSimpleName) {
79
+ if (keys_1.KeysOfSimpleSQL.SIMPLE_QUERY_ONE === oldSqlSimpleName || keys_1.KeysOfSimpleSQL.SIMPLE_QUERY === oldSqlSimpleName || keys_1.KeysOfSimpleSQL.SIMPLE_QUERY_PAGE === oldSqlSimpleName) {
84
80
  if (!params.condition) {
85
81
  params.condition = {};
86
82
  }
@@ -1,7 +1,7 @@
1
1
  import { ColumnRelation, IRequestCfgModel, IRequestModel, ISqlCfgModel, ITableListResult, ITableNamesOptions, ITableNamesQuery, ExecuteSQLResult } from '../../libs/crud-pro/interfaces';
2
2
  import { IRequestCfgModel2 } from '../../models/bizmodels';
3
3
  import { ExecuteContext } from '../../libs/crud-pro/models/ExecuteContext';
4
- import { ShardingBase } from "../../libs/crud-sharding";
4
+ import { ShardingBase } from '../../libs/crud-sharding';
5
5
  import { IGetQuickCrudParam, IGetShardingCrudParam } from './CurdProService';
6
6
  export interface ILinkColumnRelationParam {
7
7
  columnsRelations: ColumnRelation[];
@@ -76,7 +76,8 @@ let ProxyApiLoadService = class ProxyApiLoadService extends BaseService_1.BaseSe
76
76
  for (let i = 0; i < entities.length; i++) {
77
77
  const entity = entities[i];
78
78
  if (entity.status === 1) {
79
- const path_prefix2 = '/' + entity.upstream_code + entity.path_prefix;
79
+ const pathPrefix = (0, ProxyApiUtils_1.normalizePathPrefix)(entity.path_prefix);
80
+ const path_prefix2 = '/' + entity.upstream_code + pathPrefix;
80
81
  routeTrie.addRoute(path_prefix2, new RouteHandler_1.RouteHandler(entity));
81
82
  }
82
83
  }
@@ -12,4 +12,6 @@ export declare const BALANCE_STRATEGY: {
12
12
  * @param str
13
13
  * @param mod
14
14
  */
15
+ /** path_prefix 为空表示代理上游根路径;单独的 "/" 会在路由树中注册无效节点,统一归一化为空 */
16
+ export declare function normalizePathPrefix(path_prefix: string | null | undefined): string;
15
17
  export declare function stringHashMod(str: string, mod: number): number;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.stringHashMod = exports.BALANCE_STRATEGY = void 0;
3
+ exports.stringHashMod = exports.normalizePathPrefix = exports.BALANCE_STRATEGY = void 0;
4
4
  const md5 = require("md5");
5
5
  exports.BALANCE_STRATEGY = {
6
6
  ROUND_ROBIN: 'ROUND_ROBIN',
@@ -16,6 +16,14 @@ exports.BALANCE_STRATEGY = {
16
16
  * @param str
17
17
  * @param mod
18
18
  */
19
+ /** path_prefix 为空表示代理上游根路径;单独的 "/" 会在路由树中注册无效节点,统一归一化为空 */
20
+ function normalizePathPrefix(path_prefix) {
21
+ if (path_prefix === '/' || path_prefix == null) {
22
+ return '';
23
+ }
24
+ return path_prefix;
25
+ }
26
+ exports.normalizePathPrefix = normalizePathPrefix;
19
27
  function stringHashMod(str, mod) {
20
28
  if (!str) {
21
29
  throw new Error('stringHashMod str is required');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "midway-fatcms",
3
- "version": "0.0.19",
3
+ "version": "0.0.20",
4
4
  "description": "This is a midway component sample",
5
5
  "main": "dist/index.js",
6
6
  "typings": "index.d.ts",
@@ -36,16 +36,17 @@ export class HomeController extends BaseApiController {
36
36
  return this.ctx.render('404_workbench', infos);
37
37
  }
38
38
 
39
-
40
39
  const html_content = workbenchInfo.html_content || '未配置HTML模版';
41
40
 
42
41
  const userInfo = await this.getUserAndRefreshSessionInfo();
43
42
 
44
43
  // 形如(不带域名):/ns/app/abc-app-path?aa=2332
45
- const urlcsrftoken = await privateAES.time_encrypt_utf8_base64(JSON.stringify({
46
- url: this.ctx.req.url,
47
- timestamp: Date.now(),
48
- }));
44
+ const urlcsrftoken = await privateAES.time_encrypt_utf8_base64(
45
+ JSON.stringify({
46
+ url: this.ctx.req.url,
47
+ timestamp: Date.now(),
48
+ })
49
+ );
49
50
  const fatcmscsrftoken = await privateAES.time_encrypt_utf8_base64('' + Date.now());
50
51
 
51
52
  const utils = createRenderUtils({
@@ -70,7 +71,6 @@ export class HomeController extends BaseApiController {
70
71
  return await this.authService.refreshSession(userSessionInfo);
71
72
  }
72
73
 
73
-
74
74
  @Get('/robots.txt')
75
75
  async robots(): Promise<string> {
76
76
  return `User-agent: * \nDisallow: /ns/api/manage/`;
@@ -27,7 +27,7 @@ export class ProxyApiMangeApi extends BaseApiController {
27
27
  return this.executeSysSimpleSQL(SystemTables.sys_proxyapi, KeysOfSimpleSQL.SIMPLE_INSERT, {
28
28
  validateCfg: {
29
29
  'data.proxy_name': [KeysOfValidators.REQUIRED, KeysOfValidators.STRING],
30
- 'data.path_prefix': [KeysOfValidators.REQUIRED, KeysOfValidators.STRING],
30
+ 'data.path_prefix': [KeysOfValidators.STRING],
31
31
  'data.upstream_code': [KeysOfValidators.REQUIRED, KeysOfValidators.STRING],
32
32
  },
33
33
  });
@@ -38,6 +38,7 @@ export class ProxyApiMangeApi extends BaseApiController {
38
38
  return this.executeSysSimpleSQL(SystemTables.sys_proxyapi, KeysOfSimpleSQL.SIMPLE_UPDATE, {
39
39
  validateCfg: {
40
40
  'condition.id': [KeysOfValidators.REQUIRED, KeysOfValidators.NUMERIC],
41
+ 'data.path_prefix': [KeysOfValidators.STRING],
41
42
  },
42
43
  });
43
44
  }
@@ -10,24 +10,24 @@ export interface ICrudProCfg {
10
10
  methodsCacheTime?: number; //鍐呭瓨缂撳瓨鏃堕棿榛樿 1鍒嗛挓
11
11
  dictItemTableName?: string; // 瀛楀吀椤硅〃鍚嶇О锛岄粯璁わ細sys_data_dict_item
12
12
  sysConfigTableName?: string; // 瀛楀吀椤硅〃鍚嶇О锛岄粯璁わ細sys_configs
13
- tableMetaCacheTime?: number; // 琛ㄦ牸鍏冧俊鎭紦瀛樻椂闂?
13
+ tableMetaCacheTime?: number; // 琛ㄦ牸鍏冧俊鎭紦瀛樻椂闂?
14
14
  }
15
15
 
16
16
  export interface ITableColumn {
17
- name: string; // 瀛楁鍚?
17
+ name: string; // 瀛楁鍚?
18
18
  type: string; // 鏁版嵁绫诲瀷
19
19
  isNullable: boolean; // 鏄惁鍙┖
20
20
  isPrimaryKey?: boolean; // 鏄惁涓婚敭
21
- isIdentity?: boolean; // 鏄惁鑷鍒楋紙SQL Server锛?
22
- defaultValue?: any; // 榛樿鍊?
23
- maxLength?: number; // 鏈€澶ч暱搴?
21
+ isIdentity?: boolean; // 鏄惁鑷鍒楋紙SQL Server锛?
22
+ defaultValue?: any; // 榛樿鍊?
23
+ maxLength?: number; // 鏈€澶ч暱搴?
24
24
  comment?: string; // 瀛楁娉ㄩ噴
25
25
  }
26
26
 
27
27
  export interface ITableMeta {
28
28
  expiredTime: number; // 杩囨湡鏃堕棿
29
- tableColumns: string[]; // 琛ㄦ牸鎵€鏈夊瓧娈?
30
- columnDetails?: ITableColumn[]; // 璇︾粏鐨勫瓧娈典俊鎭?
29
+ tableColumns: string[]; // 琛ㄦ牸鎵€鏈夊瓧娈?
30
+ columnDetails?: ITableColumn[]; // 璇︾粏鐨勫瓧娈典俊鎭?
31
31
  }
32
32
 
33
33
  export interface IConnectionPool {
@@ -50,19 +50,19 @@ export interface IPoolConnectionClient {
50
50
  }
51
51
 
52
52
  /**
53
- * 璇锋眰妯″瀷涓?data 瀛楁鐨勫€肩被鍨?
53
+ * 璇锋眰妯″瀷涓?data 瀛楁鐨勫€肩被鍨?
54
54
  *
55
- * 閫氱敤绫诲瀷锛圡ySQL / PostgreSQL / SQL Server 鍧囨敮鎸侊級锛?
55
+ * 閫氱敤绫诲瀷锛圡ySQL / PostgreSQL / SQL Server 鍧囨敮鎸侊級锛?
56
56
  * - string : 瀛楃涓插垪锛坴archar, char, text, nvarchar 绛夛級
57
57
  * - number : 鏁存暟 / 娴偣鏁板垪锛坕nt, bigint, decimal, float 绛夛級
58
- * - boolean : 甯冨皵鍒楋紙MySQL tinyint(1) 鏄犲皠锛汸G 鍘熺敓 boolean锛汼S bit(1)锛?
58
+ * - boolean : 甯冨皵鍒楋紙MySQL tinyint(1) 鏄犲皠锛汸G 鍘熺敓 boolean锛汼S bit(1)锛?
59
59
  * - Date : 鏃ユ湡鏃堕棿鍒楋紙datetime, timestamp, date 绛夛級
60
- * - null : 绌哄€?
60
+ * - null : 绌哄€?
61
61
  *
62
- * MySQL 涓撴湁锛?
62
+ * MySQL 涓撴湁锛?
63
63
  * - Record<string, any> : MySQL JSON 鍒楋紙5.7+锛夛紝CrudProDataTypeConvertService 鑷姩 JSON.stringify()
64
64
  *
65
- * PostgreSQL 涓撴湁锛?
65
+ * PostgreSQL 涓撴湁锛?
66
66
  * - any[] : PG ARRAY 鍒楋紙濡?int[], text[]锛夛紝CrudProDataTypeConvertService
67
67
  * 浼氳嚜鍔ㄨ浆涓?PG 鏁扮粍瀛楅潰閲?{1,2,3}
68
68
  * - Record<string, any> : PG JSONB / JSON 鍒楋紝CrudProDataTypeConvertService 鑷姩 JSON.stringify()
@@ -71,24 +71,24 @@ export interface IPoolConnectionClient {
71
71
  * - any[] : longtext/varchar 绛夐潪 JSON 鍒楀瓨鏁扮粍鏃讹紝CrudProDataTypeConvertService 涔熶細鑷姩 JSON.stringify()
72
72
  * - Record<string, any> : longtext/varchar 绛夐潪 JSON 鍒楀瓨瀵硅薄鏃讹紝鍚屼笂
73
73
  *
74
- * SQL Server 璇存槑锛?
74
+ * SQL Server 璇存槑锛?
75
75
  * - 鍘熺敓 JSON 鍒楀湪 SS 涓檷绾т负 NVARCHAR(MAX)锛屼絾 longtext 瀛?JSON 瀵硅薄鐨勫満鏅悓鏍疯瑕嗙洊
76
76
  * - XML 鍒楀悓鐞嗭紝浼?string
77
77
  *
78
78
  * 閫氱敤浜岃繘鍒讹紙MySQL / PostgreSQL / SQL Server锛夛細
79
- * - Buffer : BLOB / LONGBLOB (MySQL)銆丅YTEA (PG)銆乂ARBINARY (SS) 绛変簩杩涘埗鍒?
79
+ * - Buffer : BLOB / LONGBLOB (MySQL)銆丅YTEA (PG)銆乂ARBINARY (SS) 绛変簩杩涘埗鍒?
80
80
  * 涓夌椹卞姩锛坢ysql2 / pg / mssql锛夊師鐢熸敮鎸?Buffer 鍙傛暟锛屾棤闇€棰濆杞崲
81
81
  */
82
82
  export type IRequestModelDataFieldValue =
83
- | string // 閫氱敤锛氬瓧绗︿覆鍒?
83
+ | string // 閫氱敤锛氬瓧绗︿覆鍒?
84
84
  | number // 閫氱敤锛氭暟鍊煎垪
85
- | boolean // 閫氱敤锛氬竷灏斿垪锛圡ySQL tinyint(1) / PG boolean / SS bit(1)锛?
85
+ | boolean // 閫氱敤锛氬竷灏斿垪锛圡ySQL tinyint(1) / PG boolean / SS bit(1)锛?
86
86
  | Date // 閫氱敤锛氭棩鏈熸椂闂村垪
87
- | null // 閫氱敤锛氱┖鍊?
88
- | any[] // PG ARRAY 列:转为 PG 数组字面量;其他列存数组:自动 JSON.stringify()
89
- | Record<string, any> // json/jsonb/longtext 等列存对象:按值类型自动 JSON.stringify(),不依赖列类型
90
- | Buffer // 通用二进制:MySQL BLOB / PG BYTEA / SS VARBINARY,驱动原生支持无需转换
91
- | ISqlFuncArg; // 表达式:UPDATE SET / INSERT VALUES 中生成非参数化 SQL 片段(NOW/UUID/INC/DEC/MUL/FN 等)
87
+ | null // 閫氱敤锛氱┖鍊?
88
+ | any[] // PG ARRAY 列:转为 PG 数组字面量;其他列存数组:自动 JSON.stringify()
89
+ | Record<string, any> // json/jsonb/longtext 等列存对象:按值类型自动 JSON.stringify(),不依赖列类型
90
+ | Buffer // 通用二进制:MySQL BLOB / PG BYTEA / SS VARBINARY,驱动原生支持无需转换
91
+ | ISqlFuncArg; // 表达式:UPDATE SET / INSERT VALUES 中生成非参数化 SQL 片段(NOW/UUID/INC/DEC/MUL/FN 等)
92
92
 
93
93
 
94
94
  export type IRequestEntity = Record<string, IRequestModelDataFieldValue>;
@@ -102,7 +102,7 @@ export interface IRequestModel {
102
102
  method?: string;
103
103
  columns?: string | string[]; // "columns": "id,name,age,sex,addr",
104
104
  condition?: IRequestCondition; // 鎷兼帴鏌ヨ鏉′欢
105
- data?: IRequestModelData, // 鍗曟潯鎴栨壒閲忔彃鍏?鏇存柊鐨勬暟鎹儴鍒?
105
+ data?: IRequestModelData, // 鍗曟潯鎴栨壒閲忔彃鍏?鏇存柊鐨勬暟鎹儴鍒?
106
106
  orderBy?: string | IOrderByItem[];
107
107
  limit?: number;
108
108
  offset?: number;
@@ -113,53 +113,53 @@ export interface IRequestModel {
113
113
  type IBasicType = boolean | string | number;
114
114
 
115
115
  /**
116
- * 姣旇緝鎿嶄綔绗︽潯浠?
116
+ * 姣旇緝鎿嶄綔绗︽潯浠?
117
117
  * 鏀寔 MongoDB 椋庢牸鐨勬墍鏈夋煡璇㈡搷浣滅
118
118
  */
119
119
  export interface ICompareCondition {
120
- // 姣旇緝鎿嶄綔绗?
121
- $ne?: IBasicType; // 涓嶇瓑浜?
120
+ // 姣旇緝鎿嶄綔绗?
121
+ $ne?: IBasicType; // 涓嶇瓑浜?
122
122
  $lt?: IBasicType; // 灏忎簬
123
- $lte?: IBasicType; // 灏忎簬鎴栫瓑浜?
123
+ $lte?: IBasicType; // 灏忎簬鎴栫瓑浜?
124
124
  $gt?: IBasicType; // 澶т簬
125
- $gte?: IBasicType; // 澶т簬鎴栫瓑浜?
125
+ $gte?: IBasicType; // 澶т簬鎴栫瓑浜?
126
126
 
127
- // 闆嗗悎鎿嶄綔绗?
127
+ // 闆嗗悎鎿嶄綔绗?
128
128
  $in?: IBasicType[]; // 鍦ㄩ泦鍚堜腑
129
- $nin?: IBasicType[]; // 涓嶅湪闆嗗悎涓?
129
+ $nin?: IBasicType[]; // 涓嶅湪闆嗗悎涓?
130
130
 
131
- // 鑼冨洿鎿嶄綔绗?
131
+ // 鑼冨洿鎿嶄綔绗?
132
132
  $range?: [number, number]; // 鑼冨洿鏌ヨ [min, max]
133
133
 
134
- // 妯$硦鍖归厤鎿嶄綔绗?
134
+ // 妯$硦鍖归厤鎿嶄綔绗?
135
135
  $like?: string; // 鍓嶇紑鍖归厤 A%
136
136
  $notLike?: string; // 闈炲墠缂€鍖归厤
137
137
  $likeInclude?: string; // 鍖呭惈鍖归厤 %A%
138
- $notLikeInclude?: string; // 涓嶅寘鍚尮閰?
138
+ $notLikeInclude?: string; // 涓嶅寘鍚尮閰?
139
139
 
140
- // 鍏ㄦ枃绱㈠紩鎿嶄綔绗?
140
+ // 鍏ㄦ枃绱㈠紩鎿嶄綔绗?
141
141
  $match?: string; // MySQL 鍏ㄦ枃绱㈠紩
142
142
  $matchBool?: string | boolean; // MySQL 甯冨皵鍏ㄦ枃绱㈠紩
143
143
 
144
- // NULL 鍒ゆ柇鎿嶄綔绗?
144
+ // NULL 鍒ゆ柇鎿嶄綔绗?
145
145
  $null?: boolean; // IS NULL
146
146
  $notNull?: boolean; // IS NOT NULL
147
147
 
148
- // JSON 鎿嶄綔绗?
148
+ // JSON 鎿嶄綔绗?
149
149
  $jsonArrayContains?: string; // JSON 鏁扮粍鍖呭惈
150
150
  }
151
151
 
152
152
  /**
153
- * 閫昏緫鎿嶄綔绗︽潯浠?
153
+ * 閫昏緫鎿嶄綔绗︽潯浠?
154
154
  */
155
155
  export interface ILogicalCondition {
156
- $or?: IRequestCondition[]; // 閫昏緫鎴?
157
- $and?: IRequestCondition[]; // 閫昏緫涓?
156
+ $or?: IRequestCondition[]; // 閫昏緫鎴?
157
+ $and?: IRequestCondition[]; // 閫昏緫涓?
158
158
  }
159
159
 
160
160
  /**
161
161
  * 鏌ヨ鏉′欢绫诲瀷
162
- * 鏀寔瀛楁鍊肩洿鎺ュ尮閰嶆垨姣旇緝鎿嶄綔绗?
162
+ * 鏀寔瀛楁鍊肩洿鎺ュ尮閰嶆垨姣旇緝鎿嶄綔绗?
163
163
  * 鏀寔 $or, $and 閫昏緫缁勫悎
164
164
  */
165
165
  export interface IRequestCondition extends Record<string, IBasicType | ICompareCondition | ILogicalCondition | IRequestCondition[] | undefined>, ILogicalCondition {
@@ -183,7 +183,7 @@ export interface IVisitor {
183
183
  */
184
184
  export enum BasicRecordEnum {
185
185
  dict = 'dict', // 鍏宠仈鏁版嵁瀛楀吀
186
- sysCfgEnum = 'sysCfgEnum', // 閰嶇疆鏂囦欢涓紝蹇呴』鍖呭惈code涓€鍒楋紝浣滀负鍞竴閿€?
186
+ sysCfgEnum = 'sysCfgEnum', // 閰嶇疆鏂囦欢涓紝蹇呴』鍖呭惈code涓€鍒楋紝浣滀负鍞竴閿€?
187
187
  }
188
188
 
189
189
  export interface CopyAttr {
@@ -194,7 +194,7 @@ export interface CopyAttr {
194
194
  export interface ColumnRelation {
195
195
  relatedType: any; // 濡傦細 dict
196
196
  relatedCode?: string; // SexEnum
197
- sourceColumn: string; // 浠巖ow涓彇鍊肩殑瀛楁鍚?
197
+ sourceColumn: string; // 浠巖ow涓彇鍊肩殑瀛楁鍚?
198
198
  targetColumns?: CopyAttr[]; //[{from:'label', to:'user_sex_text'}]
199
199
  }
200
200
 
@@ -202,57 +202,57 @@ export interface ColumnRelation {
202
202
  * 鍩烘湰鍝嶅簲閰嶇疆
203
203
  */
204
204
  export interface IBaseCfgModel {
205
- sqlTable?: string; // 鍙互涓虹┖. originSql涓笉鍖呭惈@@table鏃跺彲浠ヤ负绌?
205
+ sqlTable?: string; // 鍙互涓虹┖. originSql涓笉鍖呭惈@@table鏃跺彲浠ヤ负绌?
206
206
  sqlSchema?: string; // 鍙互涓虹┖
207
207
  sqlDatabase?: string; // 鍙互涓虹┖锛岀敤姝ゅ瓧娈佃繘琛宑onnection鐨勯€夋嫨鍜屽垏鎹€傞厤鍚坓etBizConnectionPool浣跨敤
208
208
  sqlDbType?: SqlDbType; // 鏁版嵁搴撶被鍨嬶紝mysql(榛樿) 銆乸ostgres
209
209
  maxLimit?: number; // 鏈€澶т竴娆℃€ц繑鍥炵殑鏁伴噺
210
210
  columns?: string | string[]; // "columns": "id,name,age,sex,addr",
211
211
  columnsRelation?: ColumnRelation[];
212
- autoSnowflakeId?: boolean; // INSERT 鏃惰嚜鍔ㄤ负绌?id 瀛楁濉厖闆姳ID锛堥粯璁?false锛?
212
+ autoSnowflakeId?: boolean; // INSERT 鏃惰嚜鍔ㄤ负绌?id 瀛楁濉厖闆姳ID锛堥粯璁?false锛?
213
213
  }
214
214
 
215
215
  export type IFunctionParam = IFuncCfgModel | string | number | boolean | null;
216
216
  export interface IFuncCfgModel extends Record<any, any> {
217
- ___PLAIN_OBJECT___?: boolean; // 鏈韩灏辨槸涓€涓璞?
218
- functionName?: string; // 鍑芥暟鍚?
217
+ ___PLAIN_OBJECT___?: boolean; // 鏈韩灏辨槸涓€涓璞?
218
+ functionName?: string; // 鍑芥暟鍚?
219
219
  functionParams?: IFunctionParam[]; // 鍑芥暟鍙傛暟
220
220
 
221
221
  const?: any; // 甯搁噺,浠绘剰绫诲瀷銆傚彲浠ユ槸json瀵硅薄
222
- constString?: any; // 甯搁噺瀛楃涓?
223
- constNumber?: number; // 甯搁噺鏁板瓧锛屼换鎰忓舰寮? int,bigDecimal,bigInteger锛屽瓧绗︿覆锛岀瓑銆?
222
+ constString?: any; // 甯搁噺瀛楃涓?
223
+ constNumber?: number; // 甯搁噺鏁板瓧锛屼换鎰忓舰寮? int,bigDecimal,bigInteger锛屽瓧绗︿覆锛岀瓑銆?
224
224
  constBool?: boolean; // 甯搁噺bool鍊笺€備笌js鐨勫垽鏂€昏緫涓€鑷达紝false, null, 0 , "" 琚涓烘槸 false锛屽叾浠栬涓烘槸true
225
225
 
226
- context?: string; // 浠巆ontext涓彇鍊?
227
- contextAsString?: string; // 浠巆ontext涓彇鍊?
228
- contextAsNumber?: string; // 浠巆ontext涓彇鍊?
229
- contextAsBool?: string; // 浠巆ontext涓彇鍊?
226
+ context?: string; // 浠巆ontext涓彇鍊?
227
+ contextAsString?: string; // 浠巆ontext涓彇鍊?
228
+ contextAsNumber?: string; // 浠巆ontext涓彇鍊?
229
+ contextAsBool?: string; // 浠巆ontext涓彇鍊?
230
230
 
231
- executeExpressReturnObject?: string; // 鎵ц琛ㄨ揪寮忥紝杩斿洖瀵硅薄銆傚彲浠ュ寘鍚玞ontext涓殑鍙橀噺銆?
232
- executeExpressReturnString?: string; // 鎵ц琛ㄨ揪寮忥紝杩斿洖瀛楃涓层€傚彲浠ュ寘鍚玞ontext涓殑鍙橀噺銆?
231
+ executeExpressReturnObject?: string; // 鎵ц琛ㄨ揪寮忥紝杩斿洖瀵硅薄銆傚彲浠ュ寘鍚玞ontext涓殑鍙橀噺銆?
232
+ executeExpressReturnString?: string; // 鎵ц琛ㄨ揪寮忥紝杩斿洖瀛楃涓层€傚彲浠ュ寘鍚玞ontext涓殑鍙橀噺銆?
233
233
 
234
- message?: string; // 鍦ㄦ牎楠岄樁娈垫湁鐢紝鍏朵粬闃舵娌℃湁鐢?
234
+ message?: string; // 鍦ㄦ牎楠岄樁娈垫湁鐢紝鍏朵粬闃舵娌℃湁鐢?
235
235
  }
236
236
 
237
237
  export interface ISqlCfgModel extends IBaseCfgModel {
238
238
  resName?: string;
239
239
  resPicker?: string;
240
240
  originSql?: string; // 鏈夌壒娈婂崰浣嶇鐨凷QL, 鍘熷鐨凷QL
241
- validate?: IFuncCfgModel; //鎵ц鍓嶏紝杩涜鏍¢獙锛屾牎楠屼笉閫氳繃灏辨姏鍑哄紓甯? 鏍¢獙鍑芥暟鍙互杩斿洖 boolean鎴栫洿鎺ユ姏鍑哄紓甯?
241
+ validate?: IFuncCfgModel; //鎵ц鍓嶏紝杩涜鏍¢獙锛屾牎楠屼笉閫氳繃灏辨姏鍑哄紓甯? 鏍¢獙鍑芥暟鍙互杩斿洖 boolean鎴栫洿鎺ユ姏鍑哄紓甯?
242
242
  executeWhen?: IFuncCfgModel; //婊¤冻琛ㄨ揪寮忕殑缁撴灉锛屾墠鑳芥墽琛屻€?榛樿锛歵rue 鏍¢獙鍑芥暟蹇呴』杩斿洖 boolean
243
- isNativeSQL?: boolean; // 鍙互杩愯鐨凷QL銆傚湪postgres/sqlserver鐜涓嬩篃鍙互浣跨敤闂彿銆?
244
- executeSql?: string; // 鍙互杩愯鐨凷QL銆傚湪postgres/sqlserver鐜涓嬩篃鍙互浣跨敤闂彿銆?
245
- executeSqlArgs?: any[]; //鍙互杩愯鐨凷QL鐨勫弬鏁?
243
+ isNativeSQL?: boolean; // 鍙互杩愯鐨凷QL銆傚湪postgres/sqlserver鐜涓嬩篃鍙互浣跨敤闂彿銆?
244
+ executeSql?: string; // 鍙互杩愯鐨凷QL銆傚湪postgres/sqlserver鐜涓嬩篃鍙互浣跨敤闂彿銆?
245
+ executeSqlArgs?: any[]; //鍙互杩愯鐨凷QL鐨勫弬鏁?
246
246
  crudType?: string;
247
247
  }
248
248
 
249
249
  /**
250
250
  * executeSQL 鐨勮繑鍥炵粨鏋滅被鍨嬭鏄庯紙鏈鍖呰鐨勭洿鎺ョ粨鏋滐級
251
251
  *
252
- * 娉ㄦ剰锛歟xecuteSQL 杩斿洖鐨勬槸鏁版嵁搴撴煡璇㈢殑鍘熷缁撴灉锛屾病鏈?{code, data, message} 鍖呰灞傘€?
253
- * 杩斿洖绫诲瀷鍙栧喅浜?resPicker 閰嶇疆锛岃鏍规嵁瀹為檯 SQL 绫诲瀷閫夋嫨鍚堥€傜殑绫诲瀷鏂█銆?
252
+ * 娉ㄦ剰锛歟xecuteSQL 杩斿洖鐨勬槸鏁版嵁搴撴煡璇㈢殑鍘熷缁撴灉锛屾病鏈?{code, data, message} 鍖呰灞傘€?
253
+ * 杩斿洖绫诲瀷鍙栧喅浜?resPicker 閰嶇疆锛岃鏍规嵁瀹為檯 SQL 绫诲瀷閫夋嫨鍚堥€傜殑绫诲瀷鏂█銆?
254
254
  *
255
- * 浣跨敤绀轰緥锛?
255
+ * 浣跨敤绀轰緥锛?
256
256
  * // 鏌ヨ鍒楄〃 - 杩斿洖鏁扮粍
257
257
  * const rows = await executeSQL({ executeSql: 'SELECT * FROM users', resPicker: KeysOfSqlResPicker.RESULT_ROWS }) as ExecuteSQLRowResult<User>;
258
258
  *
@@ -265,7 +265,7 @@ export interface ISqlCfgModel extends IBaseCfgModel {
265
265
  * // 鍒ゆ柇瀛樺湪 - 杩斿洖甯冨皵
266
266
  * const exists = await executeSQL({ executeSql: 'SELECT 1 as is_exist FROM users WHERE id=?', executeSqlArgs: [1], resPicker: KeysOfSqlResPicker.RESULT_IS_EXIST }) as ExecuteSQLExistResult;
267
267
  *
268
- * // 澧炲垹鏀规搷浣?- 杩斿洖鍙楀奖鍝嶈鏁颁俊鎭?
268
+ * // 澧炲垹鏀规搷浣?- 杩斿洖鍙楀奖鍝嶈鏁颁俊鎭?
269
269
  * const result = await executeSQL({ executeSql: 'INSERT INTO users(name) VALUES(?)', executeSqlArgs: ['寮犱笁'], resPicker: KeysOfSqlResPicker.UPDATE_RESULT }) as ExecuteSQLUpdateResult;
270
270
  */
271
271
 
@@ -290,15 +290,15 @@ export interface ExecuteSQLUpdateResult {
290
290
  }
291
291
 
292
292
  /**
293
- * executeSQL 鐨勯€氱敤杩斿洖绫诲瀷锛堟湭琚寘瑁呯殑鐩存帴缁撴灉锛?
293
+ * executeSQL 鐨勯€氱敤杩斿洖绫诲瀷锛堟湭琚寘瑁呯殑鐩存帴缁撴灉锛?
294
294
  * 鏍规嵁 resPicker 鐨勪笉鍚岄厤缃紝瀹為檯杩斿洖绫诲瀷鍙兘鏄細
295
295
  * - ExecuteSQLRowResult<T> : 澶氳鏁版嵁锛堥粯璁わ級
296
296
  * - ExecuteSQLSingleResult<T> : 鍗曡鏁版嵁鎴杗ull
297
297
  * - ExecuteSQLCountResult : 鏁板瓧
298
- * - ExecuteSQLExistResult : 甯冨皵鍊?
299
- * - ExecuteSQLUpdateResult : 澧炲垹鏀圭粨鏋?
298
+ * - ExecuteSQLExistResult : 甯冨皵鍊?
299
+ * - ExecuteSQLUpdateResult : 澧炲垹鏀圭粨鏋?
300
300
  *
301
- * 璀﹀憡锛氭绫诲瀷涓鸿仈鍚堢被鍨嬶紝浣跨敤鏃跺缓璁牴鎹疄闄?resPicker 杩涜绫诲瀷鏂█浠ヨ幏寰楃簿纭被鍨嬫彁绀?
301
+ * 璀﹀憡锛氭绫诲瀷涓鸿仈鍚堢被鍨嬶紝浣跨敤鏃跺缓璁牴鎹疄闄?resPicker 杩涜绫诲瀷鏂█浠ヨ幏寰楃簿纭被鍨嬫彁绀?
302
302
  */
303
303
  export type ExecuteSQLResult<T = Record<string, any>> =
304
304
  | ExecuteSQLRowsResult<T>
@@ -389,7 +389,7 @@ export interface ITableNamesOptions {
389
389
  }
390
390
 
391
391
  /**
392
- * 琛ㄤ俊鎭」锛堝寘鍚〃鍚嶅拰绫诲瀷锛?
392
+ * 琛ㄤ俊鎭」锛堝寘鍚〃鍚嶅拰绫诲瀷锛?
393
393
  */
394
394
  export interface ITableInfo {
395
395
  name: string; // 琛ㄥ悕
@@ -397,10 +397,10 @@ export interface ITableInfo {
397
397
  }
398
398
 
399
399
  /**
400
- * 琛ㄤ俊鎭煡璇㈢粨鏋?
400
+ * 琛ㄤ俊鎭煡璇㈢粨鏋?
401
401
  */
402
402
  export interface ITableListResult {
403
- tables: ITableInfo[]; // 鎵€鏈夎〃鍜岃鍥?
404
- tableNames: string[]; // 浠呰〃鍚嶏紙涓嶅惈瑙嗗浘锛?
403
+ tables: ITableInfo[]; // 鎵€鏈夎〃鍜岃鍥?
404
+ tableNames: string[]; // 浠呰〃鍚嶏紙涓嶅惈瑙嗗浘锛?
405
405
  viewNames: string[]; // 浠呰鍥惧悕
406
406
  }
@@ -19,24 +19,10 @@ const REGEX_STRING_TYPE = /^(varchar|char|text|longtext|mediumtext|tinytext|nvar
19
19
  const REGEX_NATIVE_BOOLEAN_TYPE = /^(boolean|bool)$/;
20
20
 
21
21
  /** 含 WHERE 条件的操作类型(查询/删除/更新) */
22
- const CONDITION_TYPES = new Set<string>([
23
- KeysOfSimpleSQL.SIMPLE_QUERY,
24
- KeysOfSimpleSQL.SIMPLE_QUERY_ONE,
25
- KeysOfSimpleSQL.SIMPLE_QUERY_PAGE,
26
- KeysOfSimpleSQL.SIMPLE_QUERY_COUNT,
27
- KeysOfSimpleSQL.SIMPLE_QUERY_EXIST,
28
- KeysOfSimpleSQL.SIMPLE_DELETE,
29
- KeysOfSimpleSQL.SIMPLE_UPDATE,
30
- ]);
22
+ const CONDITION_TYPES = new Set<string>([KeysOfSimpleSQL.SIMPLE_QUERY, KeysOfSimpleSQL.SIMPLE_QUERY_ONE, KeysOfSimpleSQL.SIMPLE_QUERY_PAGE, KeysOfSimpleSQL.SIMPLE_QUERY_COUNT, KeysOfSimpleSQL.SIMPLE_QUERY_EXIST, KeysOfSimpleSQL.SIMPLE_DELETE, KeysOfSimpleSQL.SIMPLE_UPDATE]);
31
23
 
32
24
  /** INSERT/UPDATE 操作类型 */
33
- const INSERT_OR_UPDATE_TYPES = new Set<string>([
34
- KeysOfSimpleSQL.SIMPLE_INSERT,
35
- KeysOfSimpleSQL.SIMPLE_UPDATE,
36
- KeysOfSimpleSQL.SIMPLE_INSERT_ON_DUPLICATE_UPDATE,
37
- KeysOfSimpleSQL.SIMPLE_INSERT_OR_UPDATE,
38
- KeysOfSimpleSQL.SIMPLE_BATCH_INSERT,
39
- ]);
25
+ const INSERT_OR_UPDATE_TYPES = new Set<string>([KeysOfSimpleSQL.SIMPLE_INSERT, KeysOfSimpleSQL.SIMPLE_UPDATE, KeysOfSimpleSQL.SIMPLE_INSERT_ON_DUPLICATE_UPDATE, KeysOfSimpleSQL.SIMPLE_INSERT_OR_UPDATE, KeysOfSimpleSQL.SIMPLE_BATCH_INSERT]);
40
26
 
41
27
  // ============ 工具函数 ============
42
28
 
@@ -92,9 +78,7 @@ function isInsertOrUpdateType(sqlSimpleName: string): boolean {
92
78
  }
93
79
 
94
80
  /** 获取表元数据,失败时 warn 并返回 null */
95
- async function getTableMetaOrWarn(
96
- serviceHub: any, logger: any, cfgModel: RequestCfgModel, actionName: string
97
- ) {
81
+ async function getTableMetaOrWarn(serviceHub: any, logger: any, cfgModel: RequestCfgModel, actionName: string) {
98
82
  const query: ITableMetaQuery = {
99
83
  sqlTable: cfgModel.sqlTable,
100
84
  sqlDatabase: cfgModel.sqlDatabase,
@@ -187,8 +171,11 @@ class DataConvertHandler {
187
171
  const typeMap = buildColumnTypeMap(tableMeta);
188
172
 
189
173
  // 按列类型强转基础值(boolean 等适配实际 DB 字段)
190
- if (isBatch) { for (const row of data) this.convertDataFieldsByType(row, typeMap, cfgModel.sqlDbType); }
191
- else { this.convertDataFieldsByType(data, typeMap, cfgModel.sqlDbType); }
174
+ if (isBatch) {
175
+ for (const row of data) this.convertDataFieldsByType(row, typeMap, cfgModel.sqlDbType);
176
+ } else {
177
+ this.convertDataFieldsByType(data, typeMap, cfgModel.sqlDbType);
178
+ }
192
179
 
193
180
  // PostgreSQL:ARRAY 列 JS 数组 → PG 数组字面量
194
181
  if (cfgModel.sqlDbType === SqlDbType.postgres) {
@@ -199,23 +186,25 @@ class DataConvertHandler {
199
186
  }
200
187
  }
201
188
  if (arrayFieldSet.size > 0) {
202
- if (isBatch) { for (const row of data) this.convertPgArrayFields(row, arrayFieldSet); }
203
- else { this.convertPgArrayFields(data, arrayFieldSet); }
189
+ if (isBatch) {
190
+ for (const row of data) this.convertPgArrayFields(row, arrayFieldSet);
191
+ } else {
192
+ this.convertPgArrayFields(data, arrayFieldSet);
193
+ }
204
194
  }
205
195
  }
206
196
  }
207
197
 
208
198
  // 三库通用:对象/数组 → JSON.stringify(不依赖列类型)
209
- if (isBatch) { for (const row of data) this.serializeObjectValues(row); }
210
- else { this.serializeObjectValues(data); }
199
+ if (isBatch) {
200
+ for (const row of data) this.serializeObjectValues(row);
201
+ } else {
202
+ this.serializeObjectValues(data);
203
+ }
211
204
  }
212
205
 
213
206
  /** 按表字段类型转换 data 中的基础类型值 */
214
- private convertDataFieldsByType(
215
- dataObj: Record<string, any>,
216
- typeMap: Map<string, string>,
217
- sqlDbType: SqlDbType
218
- ): void {
207
+ private convertDataFieldsByType(dataObj: Record<string, any>, typeMap: Map<string, string>, sqlDbType: SqlDbType): void {
219
208
  for (const key of Object.keys(dataObj)) {
220
209
  const value = dataObj[key];
221
210
  if (value === null || value === undefined) {
@@ -291,9 +280,7 @@ class DataConvertHandler {
291
280
  if (typeof value === 'boolean') {
292
281
  return value ? 't' : 'f';
293
282
  }
294
- const escaped = ('' + value)
295
- .replace(/\\/g, '\\\\')
296
- .replace(/"/g, '\\"');
283
+ const escaped = ('' + value).replace(/\\/g, '\\\\').replace(/"/g, '\\"');
297
284
  return '"' + escaped + '"';
298
285
  }
299
286
 
@@ -349,11 +336,7 @@ class ConditionConvertHandler {
349
336
  }
350
337
 
351
338
  /** 递归遍历 condition,支持 $or/$and 嵌套 */
352
- private convertConditionFields(
353
- condition: IRequestCondition,
354
- typeMap: Map<string, string>,
355
- sqlDbType: SqlDbType
356
- ): void {
339
+ private convertConditionFields(condition: IRequestCondition, typeMap: Map<string, string>, sqlDbType: SqlDbType): void {
357
340
  if (!condition || typeof condition !== 'object') {
358
341
  return;
359
342
  }
@@ -410,7 +393,6 @@ class ConditionConvertHandler {
410
393
  * data/condition 类型强转、PG ARRAY 字面量、对象/数组 JSON 序列化
411
394
  */
412
395
  class CrudProDataTypeConvertService extends CrudProServiceBase {
413
-
414
396
  async convertDataTypeByTableMeta(reqModel: RequestModel, cfgModel: RequestCfgModel): Promise<void> {
415
397
  return new DataConvertHandler(this.serviceHub, this.logger).convertDataTypeByTableMeta(reqModel, cfgModel);
416
398
  }