midway-fatcms 0.0.5 → 0.0.7
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/.qoder/skills/midway-fatcms-crud/SKILL.md +375 -0
- package/.qoder/skills/midway-fatcms-crud/examples.md +990 -0
- package/.qoder/skills/midway-fatcms-crud/reference.md +568 -0
- package/README.md +377 -134
- package/dist/controller/manage/CrudStandardDesignApi.d.ts +0 -2
- package/dist/controller/manage/CrudStandardDesignApi.js +11 -85
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/libs/crud-pro/CrudPro.d.ts +9 -1
- package/dist/libs/crud-pro/CrudPro.js +15 -0
- package/dist/libs/crud-pro/README.md +809 -0
- package/dist/libs/crud-pro/README_FUNC.md +193 -0
- package/dist/libs/crud-pro/exceptions.d.ts +2 -0
- package/dist/libs/crud-pro/exceptions.js +2 -0
- package/dist/libs/crud-pro/interfaces.d.ts +34 -1
- package/dist/libs/crud-pro/models/ExecuteContext.d.ts +3 -3
- package/dist/libs/crud-pro/models/ExecuteContext.js +2 -0
- package/dist/libs/crud-pro/models/RequestModel.d.ts +6 -2
- package/dist/libs/crud-pro/models/RequestModel.js +20 -53
- package/dist/libs/crud-pro/models/ResModel.d.ts +6 -4
- package/dist/libs/crud-pro/models/ServiceHub.d.ts +1 -0
- package/dist/libs/crud-pro/models/keys.d.ts +6 -1
- package/dist/libs/crud-pro/models/keys.js +5 -0
- package/dist/libs/crud-pro/services/CrudProDataTypeConvertService.d.ts +52 -0
- package/dist/libs/crud-pro/services/CrudProDataTypeConvertService.js +158 -0
- package/dist/libs/crud-pro/services/CrudProExecuteSqlService.js +20 -1
- package/dist/libs/crud-pro/services/CrudProFieldValidateService.d.ts +7 -0
- package/dist/libs/crud-pro/services/CrudProFieldValidateService.js +32 -0
- package/dist/libs/crud-pro/services/CrudProGenSqlService.d.ts +13 -0
- package/dist/libs/crud-pro/services/CrudProGenSqlService.js +44 -7
- package/dist/libs/crud-pro/services/CrudProOriginToExecuteSql.d.ts +43 -0
- package/dist/libs/crud-pro/services/CrudProOriginToExecuteSql.js +132 -1
- package/dist/libs/crud-pro/services/CrudProTableMetaService.d.ts +15 -1
- package/dist/libs/crud-pro/services/CrudProTableMetaService.js +107 -0
- package/dist/libs/crud-pro/services/CurdProServiceHub.d.ts +5 -1
- package/dist/libs/crud-pro/services/CurdProServiceHub.js +11 -0
- package/dist/libs/crud-pro/utils/DateTimeUtils.d.ts +1 -0
- package/dist/libs/crud-pro/utils/DateTimeUtils.js +3 -0
- package/dist/libs/crud-pro/utils/MixinUtils.d.ts +32 -0
- package/dist/libs/crud-pro/utils/MixinUtils.js +85 -1
- package/dist/libs/crud-pro/utils/OrderByUtils.d.ts +70 -0
- package/dist/libs/crud-pro/utils/OrderByUtils.js +158 -0
- package/dist/libs/crud-pro/utils/ValidateUtils.js +1 -1
- package/dist/libs/crud-sharding/ROUTING_LOGIC.md +944 -0
- package/dist/libs/crud-sharding/ShardingConfig.d.ts +218 -0
- package/dist/libs/crud-sharding/ShardingConfig.js +32 -0
- package/dist/libs/crud-sharding/ShardingCountCache.d.ts +69 -0
- package/dist/libs/crud-sharding/ShardingCountCache.js +160 -0
- package/dist/libs/crud-sharding/ShardingCrudPro.d.ts +363 -0
- package/dist/libs/crud-sharding/ShardingCrudPro.js +675 -0
- package/dist/libs/crud-sharding/ShardingMerger.d.ts +130 -0
- package/dist/libs/crud-sharding/ShardingMerger.js +282 -0
- package/dist/libs/crud-sharding/ShardingRouter.d.ts +69 -0
- package/dist/libs/crud-sharding/ShardingRouter.js +377 -0
- package/dist/libs/crud-sharding/ShardingTableCreator.d.ts +146 -0
- package/dist/libs/crud-sharding/ShardingTableCreator.js +805 -0
- package/dist/libs/crud-sharding/ShardingUtils.d.ts +38 -0
- package/dist/libs/crud-sharding/ShardingUtils.js +77 -0
- package/dist/libs/crud-sharding/index.d.ts +45 -0
- package/dist/libs/crud-sharding/index.js +55 -0
- package/dist/models/StandardColumns.d.ts +71 -0
- package/dist/models/StandardColumns.js +28 -0
- package/dist/service/SysAppService.js +2 -2
- package/dist/service/SysConfigService.js +1 -1
- package/dist/service/SysDictDataService.js +2 -2
- package/dist/service/SysMenuService.js +1 -1
- package/dist/service/UserAccountService.d.ts +1 -1
- package/dist/service/crudstd/CrudStdService.d.ts +0 -1
- package/dist/service/crudstd/CrudStdService.js +0 -27
- package/dist/service/curd/CrudProQuick.d.ts +134 -4
- package/dist/service/curd/CrudProQuick.js +155 -3
- package/dist/service/curd/CurdMixService.d.ts +2 -1
- package/dist/service/curd/CurdMixService.js +5 -1
- package/dist/service/curd/CurdProService.d.ts +44 -2
- package/dist/service/curd/CurdProService.js +53 -1
- package/dist/service/curd/README.md +1100 -0
- package/dist/service/curd/fixSoftDelete.d.ts +14 -0
- package/dist/service/curd/fixSoftDelete.js +29 -11
- package/dist/service/flow/FlowConfigService.js +1 -1
- package/dist/service/flow/FlowInstanceCrudService.js +1 -1
- package/package.json +4 -1
- package/src/controller/gateway/AsyncTaskController.ts +1 -1
- package/src/controller/manage/CrudStandardDesignApi.ts +16 -100
- package/src/index.ts +3 -0
- package/src/libs/crud-pro/CrudPro.ts +19 -1
- package/src/libs/crud-pro/README.md +809 -0
- package/src/libs/crud-pro/README_FUNC.md +193 -0
- package/src/libs/crud-pro/exceptions.ts +2 -0
- package/src/libs/crud-pro/interfaces.ts +38 -1
- package/src/libs/crud-pro/models/ExecuteContext.ts +6 -3
- package/src/libs/crud-pro/models/RequestModel.ts +23 -65
- package/src/libs/crud-pro/models/ResModel.ts +10 -4
- package/src/libs/crud-pro/models/ServiceHub.ts +2 -0
- package/src/libs/crud-pro/models/keys.ts +5 -0
- package/src/libs/crud-pro/services/CrudProDataTypeConvertService.ts +171 -0
- package/src/libs/crud-pro/services/CrudProExecuteSqlService.ts +24 -1
- package/src/libs/crud-pro/services/CrudProFieldValidateService.ts +53 -1
- package/src/libs/crud-pro/services/CrudProGenSqlService.ts +51 -7
- package/src/libs/crud-pro/services/CrudProOriginToExecuteSql.ts +159 -2
- package/src/libs/crud-pro/services/CrudProTableMetaService.ts +139 -1
- package/src/libs/crud-pro/services/CurdProServiceHub.ts +16 -1
- package/src/libs/crud-pro/utils/DateTimeUtils.ts +3 -0
- package/src/libs/crud-pro/utils/MixinUtils.ts +97 -1
- package/src/libs/crud-pro/utils/OrderByUtils.ts +169 -0
- package/src/libs/crud-pro/utils/ValidateUtils.ts +1 -1
- package/src/libs/crud-sharding/ROUTING_LOGIC.md +944 -0
- package/src/libs/crud-sharding/ShardingConfig.ts +240 -0
- package/src/libs/crud-sharding/ShardingCountCache.ts +200 -0
- package/src/libs/crud-sharding/ShardingCrudPro.ts +835 -0
- package/src/libs/crud-sharding/ShardingMerger.ts +384 -0
- package/src/libs/crud-sharding/ShardingRouter.ts +512 -0
- package/src/libs/crud-sharding/ShardingTableCreator.ts +1007 -0
- package/src/libs/crud-sharding/ShardingUtils.ts +84 -0
- package/src/libs/crud-sharding/index.ts +64 -0
- package/src/models/StandardColumns.ts +76 -0
- package/src/service/FileCenterService.ts +1 -1
- package/src/service/SysAppService.ts +2 -2
- package/src/service/SysConfigService.ts +1 -1
- package/src/service/SysDictDataService.ts +2 -2
- package/src/service/SysMenuService.ts +2 -2
- package/src/service/WorkbenchService.ts +1 -1
- package/src/service/anyapi/AnyApiService.ts +1 -1
- package/src/service/asyncTask/AsyncTaskRunnerService.ts +1 -1
- package/src/service/crudstd/CrudStdService.ts +0 -32
- package/src/service/curd/CrudProQuick.ts +164 -5
- package/src/service/curd/CurdMixService.ts +7 -2
- package/src/service/curd/CurdProService.ts +62 -3
- package/src/service/curd/README.md +1100 -0
- package/src/service/curd/fixCfgModel.ts +1 -2
- package/src/service/curd/fixSoftDelete.ts +38 -16
- package/src/service/flow/FlowConfigService.ts +1 -1
- package/src/service/flow/FlowInstanceCrudService.ts +1 -1
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { CrudPro } from '../../libs/crud-pro/CrudPro';
|
|
2
|
+
import { IRequestModel, IRequestCfgModel } from '../../libs/crud-pro/interfaces';
|
|
3
|
+
import { ShardingCountCache } from './ShardingCountCache';
|
|
4
|
+
/**
|
|
5
|
+
* 分页查询结果
|
|
6
|
+
*/
|
|
7
|
+
export interface IShardingPageQueryResult {
|
|
8
|
+
rows: any[];
|
|
9
|
+
total_count: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* 分表查询结果合并器
|
|
13
|
+
*
|
|
14
|
+
* 处理跨多个分表的查询结果合并:
|
|
15
|
+
* - 分页查询:顺序累计查询 + 结果合并
|
|
16
|
+
* - 列表查询:并行查询 + 结果合并
|
|
17
|
+
*
|
|
18
|
+
* 使用约束(时间分表专用):
|
|
19
|
+
* - 排序字段必须是分表字段(timeColumn/created_at)
|
|
20
|
+
* - 排序方向支持 DESC(最新在前)和 ASC(最旧在前)
|
|
21
|
+
* - DESC 时表顺序为 新→旧,ASC 时表顺序为 旧→新(由 ShardingCrudPro 保证)
|
|
22
|
+
*
|
|
23
|
+
* 在上述约束下,无需内存排序,直接按表顺序拼接即可。
|
|
24
|
+
*/
|
|
25
|
+
export declare class ShardingMerger {
|
|
26
|
+
private countCache;
|
|
27
|
+
/**
|
|
28
|
+
* 设置 COUNT 缓存实例
|
|
29
|
+
*/
|
|
30
|
+
setCountCache(cache: ShardingCountCache): void;
|
|
31
|
+
/**
|
|
32
|
+
* 合并多表分页查询结果(时间分表专用,按表顺序拼接优化)
|
|
33
|
+
*
|
|
34
|
+
* 前提条件:
|
|
35
|
+
* - DESC 时 tables 已按时间倒序排列(新→旧),ASC 时已按时间正序排列(旧→新)
|
|
36
|
+
* - orderBy 为 timeColumn DESC 或 timeColumn ASC
|
|
37
|
+
*
|
|
38
|
+
* 执行流程:
|
|
39
|
+
* 1. 并行统计各分表记录数
|
|
40
|
+
* 2. 根据累计数量直接定位目标表,跳过无关表
|
|
41
|
+
* 3. 只查询包含目标数据的分表,精确计算表内偏移
|
|
42
|
+
*
|
|
43
|
+
* @param crudPro CrudPro 实例
|
|
44
|
+
* @param tables 分表列表(DESC: 新→旧,ASC: 旧→新)
|
|
45
|
+
* @param reqJson 请求参数
|
|
46
|
+
* @param cfgJson 配置
|
|
47
|
+
* @returns 分页结果
|
|
48
|
+
*/
|
|
49
|
+
mergePageQuery(crudPro: CrudPro, tables: string[], reqJson: IRequestModel, cfgJson: IRequestCfgModel): Promise<IShardingPageQueryResult>;
|
|
50
|
+
/**
|
|
51
|
+
* 合并多表普通查询结果(时间分表专用,按表顺序拼接优化)
|
|
52
|
+
*
|
|
53
|
+
* 前提条件:
|
|
54
|
+
* - DESC 时 tables 已按时间倒序排列(新→旧),ASC 时已按时间正序排列(旧→新)
|
|
55
|
+
* - orderBy 为 timeColumn DESC 或 timeColumn ASC
|
|
56
|
+
*
|
|
57
|
+
* 执行流程:
|
|
58
|
+
* 1. 串行查询分表,按表顺序拼接
|
|
59
|
+
* 2. 达到 maxRows 上限后立即停止,避免查询无关表
|
|
60
|
+
*
|
|
61
|
+
* @param crudPro CrudPro 实例
|
|
62
|
+
* @param tables 分表列表(DESC: 新→旧,ASC: 旧→新)
|
|
63
|
+
* @param reqJson 请求参数
|
|
64
|
+
* @param cfgJson 配置
|
|
65
|
+
* @param maxRows 最大返回行数(默认 10000,防止 OOM)
|
|
66
|
+
* @returns 数据列表
|
|
67
|
+
*/
|
|
68
|
+
mergeQuery(crudPro: CrudPro, tables: string[], reqJson: IRequestModel, cfgJson: IRequestCfgModel, maxRows?: number): Promise<any[]>;
|
|
69
|
+
/**
|
|
70
|
+
* 根据各表数量和分页偏移,直接定位目标表
|
|
71
|
+
*
|
|
72
|
+
* 核心优化:跳过不包含目标数据的分表,只返回需要查询的表及其表内偏移
|
|
73
|
+
*
|
|
74
|
+
* 示例:
|
|
75
|
+
* tables: [t_order_202403, t_order_202402, t_order_202401]
|
|
76
|
+
* counts: [5, 20, 1000]
|
|
77
|
+
* 累计: [5, 25, 1025]
|
|
78
|
+
*
|
|
79
|
+
* offset=990, targetEnd=1000
|
|
80
|
+
* → 202403 累计5 < 990,跳过
|
|
81
|
+
* → 202402 累计25 < 990,跳过
|
|
82
|
+
* → 202401 累计1025 >= 990,命中
|
|
83
|
+
* innerOffset = 990 - 25 = 965
|
|
84
|
+
* innerLimit = min(1000-25, 1025-990) = 10
|
|
85
|
+
*
|
|
86
|
+
* @param tables 分表列表
|
|
87
|
+
* @param counts 各表记录数
|
|
88
|
+
* @param offset 全局偏移
|
|
89
|
+
* @param targetEnd 全局截止位置
|
|
90
|
+
*/
|
|
91
|
+
private locateTargetTables;
|
|
92
|
+
/**
|
|
93
|
+
* 安全查询记录数(表不存在时返回0)
|
|
94
|
+
*
|
|
95
|
+
* 支持 COUNT 缓存:历史时间分表使用缓存,当前表实时查询
|
|
96
|
+
*/
|
|
97
|
+
private queryCountSafe;
|
|
98
|
+
/**
|
|
99
|
+
* 安全查询数据行(表不存在时返回空数组)
|
|
100
|
+
*/
|
|
101
|
+
private queryRowsSafe;
|
|
102
|
+
/**
|
|
103
|
+
* 安全查询数据行(支持表内偏移,表不存在时返回空数组)
|
|
104
|
+
*
|
|
105
|
+
* 用于分页定位后,直接从某张表指定偏移处取数据
|
|
106
|
+
*
|
|
107
|
+
* @param crudPro CrudPro 实例
|
|
108
|
+
* @param table 分表名
|
|
109
|
+
* @param reqJson 请求参数
|
|
110
|
+
* @param cfgJson 配置
|
|
111
|
+
* @param innerOffset 表内偏移(跳过前 N 条)
|
|
112
|
+
* @param innerLimit 取多少条
|
|
113
|
+
*/
|
|
114
|
+
private queryRowsSafeWithOffset;
|
|
115
|
+
/**
|
|
116
|
+
* 执行 COUNT 查询
|
|
117
|
+
*/
|
|
118
|
+
private executeCountQuery;
|
|
119
|
+
/**
|
|
120
|
+
* 执行数据查询
|
|
121
|
+
*/
|
|
122
|
+
private executeQuery;
|
|
123
|
+
/**
|
|
124
|
+
* 执行数据查询(带表内偏移)
|
|
125
|
+
*
|
|
126
|
+
* 用于分页定位后,直接从指定偏移处取数据
|
|
127
|
+
* innerOffset=965, innerLimit=10 表示跳过该表前 965 条,取 10 条
|
|
128
|
+
*/
|
|
129
|
+
private executeQueryWithOffset;
|
|
130
|
+
}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ShardingMerger = void 0;
|
|
4
|
+
const keys_1 = require("../../libs/crud-pro/models/keys");
|
|
5
|
+
const ShardingCountCache_1 = require("./ShardingCountCache");
|
|
6
|
+
/**
|
|
7
|
+
* 分表查询结果合并器
|
|
8
|
+
*
|
|
9
|
+
* 处理跨多个分表的查询结果合并:
|
|
10
|
+
* - 分页查询:顺序累计查询 + 结果合并
|
|
11
|
+
* - 列表查询:并行查询 + 结果合并
|
|
12
|
+
*
|
|
13
|
+
* 使用约束(时间分表专用):
|
|
14
|
+
* - 排序字段必须是分表字段(timeColumn/created_at)
|
|
15
|
+
* - 排序方向支持 DESC(最新在前)和 ASC(最旧在前)
|
|
16
|
+
* - DESC 时表顺序为 新→旧,ASC 时表顺序为 旧→新(由 ShardingCrudPro 保证)
|
|
17
|
+
*
|
|
18
|
+
* 在上述约束下,无需内存排序,直接按表顺序拼接即可。
|
|
19
|
+
*/
|
|
20
|
+
class ShardingMerger {
|
|
21
|
+
/**
|
|
22
|
+
* 设置 COUNT 缓存实例
|
|
23
|
+
*/
|
|
24
|
+
setCountCache(cache) {
|
|
25
|
+
this.countCache = cache;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 合并多表分页查询结果(时间分表专用,按表顺序拼接优化)
|
|
29
|
+
*
|
|
30
|
+
* 前提条件:
|
|
31
|
+
* - DESC 时 tables 已按时间倒序排列(新→旧),ASC 时已按时间正序排列(旧→新)
|
|
32
|
+
* - orderBy 为 timeColumn DESC 或 timeColumn ASC
|
|
33
|
+
*
|
|
34
|
+
* 执行流程:
|
|
35
|
+
* 1. 并行统计各分表记录数
|
|
36
|
+
* 2. 根据累计数量直接定位目标表,跳过无关表
|
|
37
|
+
* 3. 只查询包含目标数据的分表,精确计算表内偏移
|
|
38
|
+
*
|
|
39
|
+
* @param crudPro CrudPro 实例
|
|
40
|
+
* @param tables 分表列表(DESC: 新→旧,ASC: 旧→新)
|
|
41
|
+
* @param reqJson 请求参数
|
|
42
|
+
* @param cfgJson 配置
|
|
43
|
+
* @returns 分页结果
|
|
44
|
+
*/
|
|
45
|
+
async mergePageQuery(crudPro, tables, reqJson, cfgJson) {
|
|
46
|
+
const { pageNo = 1, pageSize = 10 } = reqJson;
|
|
47
|
+
const offset = (pageNo - 1) * pageSize;
|
|
48
|
+
const targetEnd = offset + pageSize; // 需要取到第几条
|
|
49
|
+
// 1. 并行查询所有分表的记录数
|
|
50
|
+
const countPromises = tables.map(table => this.queryCountSafe(crudPro, table, reqJson, cfgJson));
|
|
51
|
+
const counts = await Promise.all(countPromises);
|
|
52
|
+
const totalCount = counts.reduce((sum, c) => sum + c, 0);
|
|
53
|
+
// 总数为0,直接返回
|
|
54
|
+
if (totalCount === 0) {
|
|
55
|
+
return { rows: [], total_count: 0 };
|
|
56
|
+
}
|
|
57
|
+
// 2. 根据累计数量直接定位目标表
|
|
58
|
+
const targetTables = this.locateTargetTables(tables, counts, offset, targetEnd);
|
|
59
|
+
// 3. 只查询包含目标数据的分表
|
|
60
|
+
let allRows = [];
|
|
61
|
+
for (const target of targetTables) {
|
|
62
|
+
const rows = await this.queryRowsSafeWithOffset(crudPro, target.table, reqJson, cfgJson, target.innerOffset, target.innerLimit);
|
|
63
|
+
allRows = allRows.concat(rows);
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
rows: allRows,
|
|
67
|
+
total_count: totalCount,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 合并多表普通查询结果(时间分表专用,按表顺序拼接优化)
|
|
72
|
+
*
|
|
73
|
+
* 前提条件:
|
|
74
|
+
* - DESC 时 tables 已按时间倒序排列(新→旧),ASC 时已按时间正序排列(旧→新)
|
|
75
|
+
* - orderBy 为 timeColumn DESC 或 timeColumn ASC
|
|
76
|
+
*
|
|
77
|
+
* 执行流程:
|
|
78
|
+
* 1. 串行查询分表,按表顺序拼接
|
|
79
|
+
* 2. 达到 maxRows 上限后立即停止,避免查询无关表
|
|
80
|
+
*
|
|
81
|
+
* @param crudPro CrudPro 实例
|
|
82
|
+
* @param tables 分表列表(DESC: 新→旧,ASC: 旧→新)
|
|
83
|
+
* @param reqJson 请求参数
|
|
84
|
+
* @param cfgJson 配置
|
|
85
|
+
* @param maxRows 最大返回行数(默认 10000,防止 OOM)
|
|
86
|
+
* @returns 数据列表
|
|
87
|
+
*/
|
|
88
|
+
async mergeQuery(crudPro, tables, reqJson, cfgJson, maxRows = 10000) {
|
|
89
|
+
// 串行查询分表,按表顺序拼接,达到上限即停
|
|
90
|
+
let allRows = [];
|
|
91
|
+
for (const table of tables) {
|
|
92
|
+
const needMore = maxRows - allRows.length;
|
|
93
|
+
if (needMore <= 0) {
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
const rows = await this.queryRowsSafe(crudPro, table, reqJson, cfgJson, needMore);
|
|
97
|
+
allRows = allRows.concat(rows);
|
|
98
|
+
// 达到上限后停止,不再查询后续表
|
|
99
|
+
if (allRows.length >= maxRows) {
|
|
100
|
+
allRows = allRows.slice(0, maxRows);
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return allRows;
|
|
105
|
+
}
|
|
106
|
+
// ============ 私有方法:分页定位 ============
|
|
107
|
+
/**
|
|
108
|
+
* 根据各表数量和分页偏移,直接定位目标表
|
|
109
|
+
*
|
|
110
|
+
* 核心优化:跳过不包含目标数据的分表,只返回需要查询的表及其表内偏移
|
|
111
|
+
*
|
|
112
|
+
* 示例:
|
|
113
|
+
* tables: [t_order_202403, t_order_202402, t_order_202401]
|
|
114
|
+
* counts: [5, 20, 1000]
|
|
115
|
+
* 累计: [5, 25, 1025]
|
|
116
|
+
*
|
|
117
|
+
* offset=990, targetEnd=1000
|
|
118
|
+
* → 202403 累计5 < 990,跳过
|
|
119
|
+
* → 202402 累计25 < 990,跳过
|
|
120
|
+
* → 202401 累计1025 >= 990,命中
|
|
121
|
+
* innerOffset = 990 - 25 = 965
|
|
122
|
+
* innerLimit = min(1000-25, 1025-990) = 10
|
|
123
|
+
*
|
|
124
|
+
* @param tables 分表列表
|
|
125
|
+
* @param counts 各表记录数
|
|
126
|
+
* @param offset 全局偏移
|
|
127
|
+
* @param targetEnd 全局截止位置
|
|
128
|
+
*/
|
|
129
|
+
locateTargetTables(tables, counts, offset, targetEnd) {
|
|
130
|
+
const result = [];
|
|
131
|
+
let accumulated = 0; // 累计已跳过的记录数
|
|
132
|
+
for (let i = 0; i < tables.length; i++) {
|
|
133
|
+
const count = counts[i];
|
|
134
|
+
// 跳过空表
|
|
135
|
+
if (count === 0)
|
|
136
|
+
continue;
|
|
137
|
+
// 当前表的累计终点
|
|
138
|
+
const tableEnd = accumulated + count;
|
|
139
|
+
// 当前表完全在目标范围之前,跳过
|
|
140
|
+
if (tableEnd <= offset) {
|
|
141
|
+
accumulated = tableEnd;
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
// 当前表完全在目标范围之后,停止
|
|
145
|
+
if (accumulated >= targetEnd) {
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
// 当前表与目标范围有交集,计算表内偏移
|
|
149
|
+
const innerOffset = Math.max(0, offset - accumulated);
|
|
150
|
+
const innerEnd = Math.min(count, targetEnd - accumulated);
|
|
151
|
+
const innerLimit = innerEnd - innerOffset;
|
|
152
|
+
result.push({
|
|
153
|
+
table: tables[i],
|
|
154
|
+
innerOffset,
|
|
155
|
+
innerLimit,
|
|
156
|
+
});
|
|
157
|
+
accumulated = tableEnd;
|
|
158
|
+
// 已经取够数据,停止
|
|
159
|
+
if (accumulated >= targetEnd) {
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return result;
|
|
164
|
+
}
|
|
165
|
+
// ============ 私有方法:查询执行 ============
|
|
166
|
+
/**
|
|
167
|
+
* 安全查询记录数(表不存在时返回0)
|
|
168
|
+
*
|
|
169
|
+
* 支持 COUNT 缓存:历史时间分表使用缓存,当前表实时查询
|
|
170
|
+
*/
|
|
171
|
+
async queryCountSafe(crudPro, table, reqJson, cfgJson) {
|
|
172
|
+
const conditionHash = (0, ShardingCountCache_1.shardingHashCondition)(reqJson.condition);
|
|
173
|
+
// 尝试从缓存获取(历史表)
|
|
174
|
+
if (this.countCache) {
|
|
175
|
+
const cachedCount = this.countCache.get(table, conditionHash);
|
|
176
|
+
if (cachedCount !== undefined) {
|
|
177
|
+
return cachedCount;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// 缓存未命中或当前表,执行真实查询
|
|
181
|
+
try {
|
|
182
|
+
const ctx = await this.executeCountQuery(crudPro, table, reqJson, cfgJson);
|
|
183
|
+
const count = ctx.getResModelItem('total_count') || 0;
|
|
184
|
+
// 写入缓存(仅历史表会被缓存)
|
|
185
|
+
if (this.countCache) {
|
|
186
|
+
this.countCache.set(table, conditionHash, count);
|
|
187
|
+
}
|
|
188
|
+
return count;
|
|
189
|
+
}
|
|
190
|
+
catch (e) {
|
|
191
|
+
// 表不存在或其他错误,返回0
|
|
192
|
+
return 0;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* 安全查询数据行(表不存在时返回空数组)
|
|
197
|
+
*/
|
|
198
|
+
async queryRowsSafe(crudPro, table, reqJson, cfgJson, limit) {
|
|
199
|
+
try {
|
|
200
|
+
const ctx = await this.executeQuery(crudPro, table, reqJson, cfgJson, limit);
|
|
201
|
+
return ctx.getResRows() || [];
|
|
202
|
+
}
|
|
203
|
+
catch (e) {
|
|
204
|
+
// 表不存在或其他错误,返回空数组
|
|
205
|
+
return [];
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* 安全查询数据行(支持表内偏移,表不存在时返回空数组)
|
|
210
|
+
*
|
|
211
|
+
* 用于分页定位后,直接从某张表指定偏移处取数据
|
|
212
|
+
*
|
|
213
|
+
* @param crudPro CrudPro 实例
|
|
214
|
+
* @param table 分表名
|
|
215
|
+
* @param reqJson 请求参数
|
|
216
|
+
* @param cfgJson 配置
|
|
217
|
+
* @param innerOffset 表内偏移(跳过前 N 条)
|
|
218
|
+
* @param innerLimit 取多少条
|
|
219
|
+
*/
|
|
220
|
+
async queryRowsSafeWithOffset(crudPro, table, reqJson, cfgJson, innerOffset, innerLimit) {
|
|
221
|
+
try {
|
|
222
|
+
const ctx = await this.executeQueryWithOffset(crudPro, table, reqJson, cfgJson, innerOffset, innerLimit);
|
|
223
|
+
return ctx.getResRows() || [];
|
|
224
|
+
}
|
|
225
|
+
catch (e) {
|
|
226
|
+
// 表不存在或其他错误,返回空数组
|
|
227
|
+
return [];
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* 执行 COUNT 查询
|
|
232
|
+
*/
|
|
233
|
+
async executeCountQuery(crudPro, table, reqJson, cfgJson) {
|
|
234
|
+
const tempCfg = {
|
|
235
|
+
...cfgJson,
|
|
236
|
+
sqlTable: table,
|
|
237
|
+
sqlSimpleName: keys_1.KeysOfSimpleSQL.SIMPLE_QUERY_COUNT,
|
|
238
|
+
};
|
|
239
|
+
return crudPro.executeCrudByCfg({ condition: reqJson.condition }, tempCfg);
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* 执行数据查询
|
|
243
|
+
*/
|
|
244
|
+
async executeQuery(crudPro, table, reqJson, cfgJson, limit) {
|
|
245
|
+
const tempCfg = {
|
|
246
|
+
...cfgJson,
|
|
247
|
+
sqlTable: table,
|
|
248
|
+
};
|
|
249
|
+
const queryReq = {
|
|
250
|
+
condition: reqJson.condition,
|
|
251
|
+
columns: reqJson.columns,
|
|
252
|
+
orderBy: reqJson.orderBy,
|
|
253
|
+
};
|
|
254
|
+
// 设置查询限制
|
|
255
|
+
if (limit) {
|
|
256
|
+
queryReq.pageNo = 1;
|
|
257
|
+
queryReq.pageSize = limit;
|
|
258
|
+
}
|
|
259
|
+
return crudPro.executeCrudByCfg(queryReq, tempCfg);
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* 执行数据查询(带表内偏移)
|
|
263
|
+
*
|
|
264
|
+
* 用于分页定位后,直接从指定偏移处取数据
|
|
265
|
+
* innerOffset=965, innerLimit=10 表示跳过该表前 965 条,取 10 条
|
|
266
|
+
*/
|
|
267
|
+
async executeQueryWithOffset(crudPro, table, reqJson, cfgJson, innerOffset, innerLimit) {
|
|
268
|
+
const tempCfg = {
|
|
269
|
+
...cfgJson,
|
|
270
|
+
sqlTable: table,
|
|
271
|
+
};
|
|
272
|
+
const queryReq = {
|
|
273
|
+
condition: reqJson.condition,
|
|
274
|
+
columns: reqJson.columns,
|
|
275
|
+
orderBy: reqJson.orderBy,
|
|
276
|
+
offset: innerOffset,
|
|
277
|
+
limit: innerLimit,
|
|
278
|
+
};
|
|
279
|
+
return crudPro.executeCrudByCfg(queryReq, tempCfg);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
exports.ShardingMerger = ShardingMerger;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { IShardingConfig, IShardingRouterContext } from './ShardingConfig';
|
|
2
|
+
/**
|
|
3
|
+
* 表信息提供者接口
|
|
4
|
+
* 用于获取数据库中真实存在的表
|
|
5
|
+
*/
|
|
6
|
+
export interface ITableInfoProvider {
|
|
7
|
+
/**
|
|
8
|
+
* 获取所有真实存在的表名
|
|
9
|
+
* @returns 表名集合
|
|
10
|
+
*/
|
|
11
|
+
getExistingTables(): Promise<Set<string>>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 分表路由器
|
|
15
|
+
*/
|
|
16
|
+
export declare class ShardingRouter {
|
|
17
|
+
/**
|
|
18
|
+
* 插入类操作专用路由(从 data 提取字段)
|
|
19
|
+
*/
|
|
20
|
+
resolveForInsert(config: IShardingConfig, context: IShardingRouterContext): string;
|
|
21
|
+
/**
|
|
22
|
+
* 条件类操作专用路由(从 condition 提取字段)
|
|
23
|
+
*/
|
|
24
|
+
resolveForCondition(config: IShardingConfig, context: IShardingRouterContext): string | string[];
|
|
25
|
+
/**
|
|
26
|
+
* 查询专用路由(带表存在性过滤)
|
|
27
|
+
*/
|
|
28
|
+
resolveQuery(config: IShardingConfig, context: IShardingRouterContext, tableInfoProvider: ITableInfoProvider): Promise<string[]>;
|
|
29
|
+
/**
|
|
30
|
+
* 过滤出真实存在的分表
|
|
31
|
+
*/
|
|
32
|
+
filterExistingTables(candidateTables: string | string[], existingTables: Set<string>): string[];
|
|
33
|
+
private validateConfig;
|
|
34
|
+
private resolveTimeForInsert;
|
|
35
|
+
private resolveTimeForCondition;
|
|
36
|
+
private resolveRangeForInsert;
|
|
37
|
+
private resolveRangeForCondition;
|
|
38
|
+
private resolveHashForInsert;
|
|
39
|
+
private resolveHashForCondition;
|
|
40
|
+
private resolveCustomForInsert;
|
|
41
|
+
private resolveCustomForCondition;
|
|
42
|
+
private isTimeSharding;
|
|
43
|
+
private getRecentExistingTablesFromAll;
|
|
44
|
+
private intersectWithCondition;
|
|
45
|
+
private intersectTablesByTimeRange;
|
|
46
|
+
/**
|
|
47
|
+
* 将分表按时间后缀降序排列(新→旧)
|
|
48
|
+
*
|
|
49
|
+
* 分表名格式为 baseTable_suffix,后缀为时间格式(如 202403、20240101),
|
|
50
|
+
* 字典序即时间序,降序即新→旧。
|
|
51
|
+
*/
|
|
52
|
+
private sortTablesByTimeDesc;
|
|
53
|
+
private extractFromData;
|
|
54
|
+
private extractFromCondition;
|
|
55
|
+
private parseTimeValue;
|
|
56
|
+
private parseColumnValue;
|
|
57
|
+
private extractTimeFromData;
|
|
58
|
+
private tryExtractTimeFromCondition;
|
|
59
|
+
private extractTimeRange;
|
|
60
|
+
private extractColumnFromData;
|
|
61
|
+
private extractColumnFromCondition;
|
|
62
|
+
private generateTablesInRange;
|
|
63
|
+
private getRecentTables;
|
|
64
|
+
private getRecentCountByGranularity;
|
|
65
|
+
private calculateRangeIndex;
|
|
66
|
+
private calculateHash;
|
|
67
|
+
private simpleHash;
|
|
68
|
+
private formatTableName;
|
|
69
|
+
}
|