mcp-xdx-schema-ctx 1.1.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.
- package/.env.example +43 -0
- package/README.md +269 -0
- package/dist/config.d.ts +131 -0
- package/dist/config.js +138 -0
- package/dist/config.js.map +1 -0
- package/dist/crypto-utils.d.ts +29 -0
- package/dist/crypto-utils.js +118 -0
- package/dist/crypto-utils.js.map +1 -0
- package/dist/db.d.ts +10 -0
- package/dist/db.js +149 -0
- package/dist/db.js.map +1 -0
- package/dist/diff-utils.d.ts +42 -0
- package/dist/diff-utils.js +130 -0
- package/dist/diff-utils.js.map +1 -0
- package/dist/encrypt-secrets.d.ts +12 -0
- package/dist/encrypt-secrets.js +190 -0
- package/dist/encrypt-secrets.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/migrate-utils.d.ts +91 -0
- package/dist/migrate-utils.js +399 -0
- package/dist/migrate-utils.js.map +1 -0
- package/dist/schema-compat.d.ts +46 -0
- package/dist/schema-compat.js +169 -0
- package/dist/schema-compat.js.map +1 -0
- package/dist/shared.d.ts +70 -0
- package/dist/shared.js +197 -0
- package/dist/shared.js.map +1 -0
- package/dist/sql-build.d.ts +121 -0
- package/dist/sql-build.js +254 -0
- package/dist/sql-build.js.map +1 -0
- package/dist/tool-availability.d.ts +35 -0
- package/dist/tool-availability.js +90 -0
- package/dist/tool-availability.js.map +1 -0
- package/dist/tools/data-tools.d.ts +2 -0
- package/dist/tools/data-tools.js +243 -0
- package/dist/tools/data-tools.js.map +1 -0
- package/dist/tools/dataflow-tools.d.ts +2 -0
- package/dist/tools/dataflow-tools.js +434 -0
- package/dist/tools/dataflow-tools.js.map +1 -0
- package/dist/tools/dbo-tools.d.ts +2 -0
- package/dist/tools/dbo-tools.js +228 -0
- package/dist/tools/dbo-tools.js.map +1 -0
- package/dist/tools/diff-tools.d.ts +2 -0
- package/dist/tools/diff-tools.js +224 -0
- package/dist/tools/diff-tools.js.map +1 -0
- package/dist/tools/form-tools.d.ts +2 -0
- package/dist/tools/form-tools.js +715 -0
- package/dist/tools/form-tools.js.map +1 -0
- package/dist/tools/migrate-tools.d.ts +2 -0
- package/dist/tools/migrate-tools.js +423 -0
- package/dist/tools/migrate-tools.js.map +1 -0
- package/dist/tools/system-tools.d.ts +2 -0
- package/dist/tools/system-tools.js +1102 -0
- package/dist/tools/system-tools.js.map +1 -0
- package/dist/tools/table-tools.d.ts +2 -0
- package/dist/tools/table-tools.js +1322 -0
- package/dist/tools/table-tools.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DPAPI 凭据加密工具
|
|
3
|
+
*
|
|
4
|
+
* Windows: 使用 System.Security.Cryptography.ProtectedData(绑定当前用户+机器)
|
|
5
|
+
* 非 Windows: 降级为 Base64 混淆(仅防无意泄露,不防定向攻击)
|
|
6
|
+
*/
|
|
7
|
+
import { execSync } from "child_process";
|
|
8
|
+
import { platform } from "os";
|
|
9
|
+
const DPAPI_PREFIX = "dpapi:";
|
|
10
|
+
const OBFUSCATED_PREFIX = "obfuscated:";
|
|
11
|
+
/** 需要加密的凭据字段名 */
|
|
12
|
+
export const SENSITIVE_FIELDS = [
|
|
13
|
+
"DB_SERVER",
|
|
14
|
+
"DB_PASSWORD",
|
|
15
|
+
"DB_B_SERVER",
|
|
16
|
+
"DB_B_PASSWORD",
|
|
17
|
+
];
|
|
18
|
+
/** DPAPI 后缀映射:DB_PASSWORD → DB_PASSWORD_DPAPI */
|
|
19
|
+
export function dpapiField(field) {
|
|
20
|
+
return `${field}_DPAPI`;
|
|
21
|
+
}
|
|
22
|
+
/** 反向:DB_PASSWORD_DPAPI → DB_PASSWORD */
|
|
23
|
+
export function originalField(dpapiField) {
|
|
24
|
+
return dpapiField.replace(/_DPAPI$/, "");
|
|
25
|
+
}
|
|
26
|
+
/** 检测当前平台是否支持 DPAPI */
|
|
27
|
+
export function isDpapiAvailable() {
|
|
28
|
+
return platform() === "win32";
|
|
29
|
+
}
|
|
30
|
+
/** 将 PowerShell 脚本编码为 Base64(UTF-16LE,PowerShell -EncodedCommand 需要) */
|
|
31
|
+
function encodePsCommand(script) {
|
|
32
|
+
return Buffer.from(script, "utf16le").toString("base64");
|
|
33
|
+
}
|
|
34
|
+
/** 执行固定 PowerShell 脚本,通过环境变量传递敏感数据 */
|
|
35
|
+
function runPs(script, env) {
|
|
36
|
+
return execSync(`powershell -NoProfile -NonInteractive -EncodedCommand ${encodePsCommand(script)}`, {
|
|
37
|
+
encoding: "utf-8",
|
|
38
|
+
windowsHide: true,
|
|
39
|
+
env: env ? { ...process.env, ...env } : undefined,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
const PS_ENCRYPT = `
|
|
43
|
+
$ProgressPreference = 'SilentlyContinue'
|
|
44
|
+
Add-Type -AssemblyName System.Security
|
|
45
|
+
$bytes = [System.Text.Encoding]::UTF8.GetBytes($env:XDX_ENC_PWD)
|
|
46
|
+
[Convert]::ToBase64String(
|
|
47
|
+
[System.Security.Cryptography.ProtectedData]::Protect($bytes, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)
|
|
48
|
+
)
|
|
49
|
+
`;
|
|
50
|
+
const PS_DECRYPT = `
|
|
51
|
+
$ProgressPreference = 'SilentlyContinue'
|
|
52
|
+
Add-Type -AssemblyName System.Security
|
|
53
|
+
[System.Text.Encoding]::UTF8.GetString(
|
|
54
|
+
[System.Security.Cryptography.ProtectedData]::Unprotect([Convert]::FromBase64String($env:XDX_DEC_PAYLOAD), $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)
|
|
55
|
+
)
|
|
56
|
+
`;
|
|
57
|
+
/**
|
|
58
|
+
* 加密明文 → 密文(前缀 dpapi:)
|
|
59
|
+
* Windows 上使用 DPAPI,非 Windows 使用 Base64 混淆
|
|
60
|
+
*/
|
|
61
|
+
export function encrypt(plaintext) {
|
|
62
|
+
if (!isDpapiAvailable()) {
|
|
63
|
+
// 非 Windows 平台:使用 Base64 混淆(非加密,仅防无意泄露)
|
|
64
|
+
return `${OBFUSCATED_PREFIX}${Buffer.from(plaintext, "utf-8").toString("base64")}`;
|
|
65
|
+
}
|
|
66
|
+
const result = runPs(PS_ENCRYPT, { XDX_ENC_PWD: plaintext });
|
|
67
|
+
return `${DPAPI_PREFIX}${result.trim()}`;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 解密密文 → 原文
|
|
71
|
+
* 自动识别 dpapi: / obfuscated: 前缀
|
|
72
|
+
*/
|
|
73
|
+
export function decrypt(encrypted) {
|
|
74
|
+
if (encrypted.startsWith("dpapi:")) {
|
|
75
|
+
const payload = encrypted.slice(DPAPI_PREFIX.length);
|
|
76
|
+
const result = runPs(PS_DECRYPT, { XDX_DEC_PAYLOAD: payload });
|
|
77
|
+
return result.trim();
|
|
78
|
+
}
|
|
79
|
+
if (encrypted.startsWith("obfuscated:")) {
|
|
80
|
+
return Buffer.from(encrypted.slice(OBFUSCATED_PREFIX.length), "base64").toString("utf-8");
|
|
81
|
+
}
|
|
82
|
+
// 兼容旧版 base64: 前缀
|
|
83
|
+
if (encrypted.startsWith("base64:")) {
|
|
84
|
+
return Buffer.from(encrypted.slice(7), "base64").toString("utf-8");
|
|
85
|
+
}
|
|
86
|
+
// 无前缀 → 视为明文(向后兼容)
|
|
87
|
+
return encrypted;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* 遍历 process.env,解密所有 *_DPAPI 字段并注入为原始字段名
|
|
91
|
+
* 在 dotenv 加载之后、zod 校验之前调用
|
|
92
|
+
*/
|
|
93
|
+
export function decryptEnv() {
|
|
94
|
+
const failedFields = [];
|
|
95
|
+
for (const key of Object.keys(process.env)) {
|
|
96
|
+
if (!key.endsWith("_DPAPI"))
|
|
97
|
+
continue;
|
|
98
|
+
const val = process.env[key];
|
|
99
|
+
if (!val || val.length === 0)
|
|
100
|
+
continue;
|
|
101
|
+
const orig = originalField(key);
|
|
102
|
+
try {
|
|
103
|
+
const decrypted = decrypt(val);
|
|
104
|
+
if (decrypted) {
|
|
105
|
+
process.env[orig] = decrypted;
|
|
106
|
+
console.error(`[crypto] ✓ 已解密 ${key} → ${orig}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
failedFields.push(orig);
|
|
111
|
+
console.error(`[crypto] ✗ 解密 ${key} 失败:`, err.message);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (failedFields.length > 0) {
|
|
115
|
+
console.error(`[crypto] ⚠ 以下字段解密失败,请检查 _DPAPI 密文是否正确,或使用明文配置: ${failedFields.join(", ")}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=crypto-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto-utils.js","sourceRoot":"","sources":["../src/crypto-utils.ts"],"names":[],"mappings":"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"}
|
package/dist/db.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import sql from "mssql";
|
|
2
|
+
import { table, schemaSource, targetDatabases, envDb, envTable, userDb } from "./config.js";
|
|
3
|
+
export declare function assertReadOnly(queryString: string): void;
|
|
4
|
+
export declare function query<T = Record<string, unknown>>(queryString: string, poolName?: string): Promise<T[]>;
|
|
5
|
+
/**
|
|
6
|
+
* 参数化只读查询 — 值通过 request.input() 绑定,杜绝字符串拼接注入。
|
|
7
|
+
* 用于 query_table_data 等需要把用户输入作为值传入的场景。
|
|
8
|
+
*/
|
|
9
|
+
export declare function queryWithParams<T = Record<string, unknown>>(queryString: string, params: Record<string, string | number | boolean | null>, poolName?: string): Promise<T[]>;
|
|
10
|
+
export { sql, table, schemaSource, targetDatabases, envDb, envTable, userDb };
|
package/dist/db.js
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import sql from "mssql";
|
|
2
|
+
import { env, table, schemaSource, targetDatabases, envDb, envTable, userDb, getSystemConfig, } from "./config.js";
|
|
3
|
+
// ============================================================
|
|
4
|
+
// 服务器地址解析 — 支持 host,port / host\instance / host/instance
|
|
5
|
+
// ============================================================
|
|
6
|
+
function parseServerAddress(serverStr) {
|
|
7
|
+
// 命名实例:host\instance 或 host/instance(贪婪匹配最后一个分隔符,
|
|
8
|
+
// 兼容 Windows 路径习惯误写的双反斜杠,如 localhost\\MSSQLSERVER2019)
|
|
9
|
+
const named = /^(.*)[\\/](.*)$/.exec(serverStr);
|
|
10
|
+
if (named) {
|
|
11
|
+
const server = named[1].trim().replace(/[\\/]+$/, "");
|
|
12
|
+
const rest = named[2].trim();
|
|
13
|
+
// 兼容 host\instance,port 形式
|
|
14
|
+
const comma = rest.lastIndexOf(",");
|
|
15
|
+
if (comma !== -1) {
|
|
16
|
+
const port = Number.parseInt(rest.slice(comma + 1).trim(), 10);
|
|
17
|
+
return {
|
|
18
|
+
server,
|
|
19
|
+
port: Number.isInteger(port) ? port : undefined,
|
|
20
|
+
instanceName: rest.slice(0, comma).trim() || undefined,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
return { server, instanceName: rest || undefined };
|
|
24
|
+
}
|
|
25
|
+
// host,port 形式
|
|
26
|
+
const commaIdx = serverStr.lastIndexOf(",");
|
|
27
|
+
if (commaIdx !== -1) {
|
|
28
|
+
const port = Number.parseInt(serverStr.slice(commaIdx + 1).trim(), 10);
|
|
29
|
+
return {
|
|
30
|
+
server: serverStr.slice(0, commaIdx).trim(),
|
|
31
|
+
port: Number.isInteger(port) ? port : undefined,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
return { server: serverStr.trim() };
|
|
35
|
+
}
|
|
36
|
+
// ============================================================
|
|
37
|
+
// 连接配置工厂 — 根据池名构建不同系统的连接参数
|
|
38
|
+
// ============================================================
|
|
39
|
+
function buildDbConfig(poolName) {
|
|
40
|
+
const sysCfg = poolName === "b" ? getSystemConfig("b") : getSystemConfig("default");
|
|
41
|
+
const { server, port, instanceName } = parseServerAddress(sysCfg.server);
|
|
42
|
+
return {
|
|
43
|
+
server,
|
|
44
|
+
...(port !== undefined && Number.isInteger(port) ? { port } : {}),
|
|
45
|
+
user: sysCfg.user,
|
|
46
|
+
password: sysCfg.password,
|
|
47
|
+
database: sysCfg.database,
|
|
48
|
+
options: {
|
|
49
|
+
...(instanceName ? { instanceName } : {}),
|
|
50
|
+
trustServerCertificate: env.DB_TRUST_SERVER_CERT === "true",
|
|
51
|
+
encrypt: env.DB_ENCRYPT === "true",
|
|
52
|
+
appName: "mcp-xdx-schema-ctx-readonly",
|
|
53
|
+
},
|
|
54
|
+
pool: {
|
|
55
|
+
max: parseInt(env.DB_POOL_MAX, 10),
|
|
56
|
+
min: parseInt(env.DB_POOL_MIN, 10),
|
|
57
|
+
idleTimeoutMillis: parseInt(env.DB_POOL_IDLE_TIMEOUT, 10),
|
|
58
|
+
},
|
|
59
|
+
// 单条语句超时(防止 query_table_data 等大表查询长时间占用)
|
|
60
|
+
requestTimeout: statementTimeout(),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// ============================================================
|
|
64
|
+
// 连接池管理
|
|
65
|
+
// ============================================================
|
|
66
|
+
const pools = new Map();
|
|
67
|
+
async function getPool(poolName = "default") {
|
|
68
|
+
const existing = pools.get(poolName);
|
|
69
|
+
if (existing?.connected)
|
|
70
|
+
return existing;
|
|
71
|
+
const config = buildDbConfig(poolName);
|
|
72
|
+
const newPool = await sql.connect(config);
|
|
73
|
+
pools.set(poolName, newPool);
|
|
74
|
+
return newPool;
|
|
75
|
+
}
|
|
76
|
+
// ============================================================
|
|
77
|
+
// 只读查询守卫
|
|
78
|
+
// ============================================================
|
|
79
|
+
/** 禁止的写操作关键字 */
|
|
80
|
+
const FORBIDDEN = [
|
|
81
|
+
"INSERT",
|
|
82
|
+
"UPDATE",
|
|
83
|
+
"DELETE",
|
|
84
|
+
"DROP",
|
|
85
|
+
"CREATE",
|
|
86
|
+
"ALTER",
|
|
87
|
+
"TRUNCATE",
|
|
88
|
+
"MERGE",
|
|
89
|
+
"EXEC",
|
|
90
|
+
"EXECUTE",
|
|
91
|
+
"GRANT",
|
|
92
|
+
"REVOKE",
|
|
93
|
+
];
|
|
94
|
+
/** 检测 SELECT INTO(建表语法,即使以 SELECT 开头也应禁止) */
|
|
95
|
+
function hasSelectInto(stmt) {
|
|
96
|
+
// 正则:SELECT ... INTO ...(非 INTO 作为普通列名的情况)
|
|
97
|
+
return /\bSELECT\b.+\bINTO\b/i.test(stmt);
|
|
98
|
+
}
|
|
99
|
+
// 只读查询 — 逐语句扫描,覆盖 SELECT 前缀绕过 + 多语句注入
|
|
100
|
+
export function assertReadOnly(queryString) {
|
|
101
|
+
const statements = queryString.split(";");
|
|
102
|
+
for (const raw of statements) {
|
|
103
|
+
const stmt = raw.trim().toUpperCase();
|
|
104
|
+
if (!stmt)
|
|
105
|
+
continue;
|
|
106
|
+
const head = stmt.split(/\s+/)[0] ?? "";
|
|
107
|
+
if (FORBIDDEN.includes(head)) {
|
|
108
|
+
throw new Error(`写操作被禁止: ${head}`);
|
|
109
|
+
}
|
|
110
|
+
for (const kw of FORBIDDEN) {
|
|
111
|
+
if (new RegExp(`\\b${kw}\\b`).test(stmt)) {
|
|
112
|
+
throw new Error(`写操作被禁止(语句内): ${kw}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// 单独检测 SELECT INTO
|
|
116
|
+
if (hasSelectInto(raw)) {
|
|
117
|
+
throw new Error("写操作被禁止: SELECT INTO");
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/** 统一的语句超时(毫秒) */
|
|
122
|
+
function statementTimeout() {
|
|
123
|
+
const t = Number.parseInt(env.DB_QUERY_TIMEOUT, 10);
|
|
124
|
+
return Number.isFinite(t) && t > 0 ? t : 30_000;
|
|
125
|
+
}
|
|
126
|
+
export async function query(queryString, poolName = "default") {
|
|
127
|
+
assertReadOnly(queryString);
|
|
128
|
+
const p = await getPool(poolName);
|
|
129
|
+
const request = p.request();
|
|
130
|
+
const result = await request.query(queryString);
|
|
131
|
+
return result.recordset;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* 参数化只读查询 — 值通过 request.input() 绑定,杜绝字符串拼接注入。
|
|
135
|
+
* 用于 query_table_data 等需要把用户输入作为值传入的场景。
|
|
136
|
+
*/
|
|
137
|
+
export async function queryWithParams(queryString, params, poolName = "default") {
|
|
138
|
+
assertReadOnly(queryString);
|
|
139
|
+
const p = await getPool(poolName);
|
|
140
|
+
const request = p.request();
|
|
141
|
+
for (const [key, value] of Object.entries(params)) {
|
|
142
|
+
request.input(key, value);
|
|
143
|
+
}
|
|
144
|
+
const result = await request.query(queryString);
|
|
145
|
+
return result.recordset;
|
|
146
|
+
}
|
|
147
|
+
// Re-export
|
|
148
|
+
export { sql, table, schemaSource, targetDatabases, envDb, envTable, userDb };
|
|
149
|
+
//# sourceMappingURL=db.js.map
|
package/dist/db.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,OAAO,CAAC;AACxB,OAAO,EACL,GAAG,EACH,KAAK,EACL,YAAY,EACZ,eAAe,EACf,KAAK,EACL,QAAQ,EACR,MAAM,EACN,eAAe,GAChB,MAAM,aAAa,CAAC;AAGrB,+DAA+D;AAC/D,yDAAyD;AACzD,+DAA+D;AAC/D,SAAS,kBAAkB,CAAC,SAAiB;IAK3C,kDAAkD;IAClD,uDAAuD;IACvD,MAAM,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAChD,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QACtD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7B,2BAA2B;QAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;YAC/D,OAAO;gBACL,MAAM;gBACN,IAAI,EAAE,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;gBAC/C,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,IAAI,SAAS;aACvD,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,IAAI,SAAS,EAAE,CAAC;IACrD,CAAC;IAED,eAAe;IACf,MAAM,QAAQ,GAAG,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAC5C,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QACvE,OAAO;YACL,MAAM,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,EAAE;YAC3C,IAAI,EAAE,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;SAChD,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;AACtC,CAAC;AAED,+DAA+D;AAC/D,2BAA2B;AAC3B,+DAA+D;AAC/D,SAAS,aAAa,CAAC,QAAgB;IACrC,MAAM,MAAM,GACV,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;IACvE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,kBAAkB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAEzE,OAAO;QACL,MAAM;QACN,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjE,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,OAAO,EAAE;YACP,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzC,sBAAsB,EAAE,GAAG,CAAC,oBAAoB,KAAK,MAAM;YAC3D,OAAO,EAAE,GAAG,CAAC,UAAU,KAAK,MAAM;YAClC,OAAO,EAAE,6BAA6B;SACvC;QACD,IAAI,EAAE;YACJ,GAAG,EAAE,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC;YAClC,GAAG,EAAE,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC;YAClC,iBAAiB,EAAE,QAAQ,CAAC,GAAG,CAAC,oBAAoB,EAAE,EAAE,CAAC;SAC1D;QACD,yCAAyC;QACzC,cAAc,EAAE,gBAAgB,EAAE;KACnC,CAAC;AACJ,CAAC;AAED,+DAA+D;AAC/D,QAAQ;AACR,+DAA+D;AAC/D,MAAM,KAAK,GAAG,IAAI,GAAG,EAA8B,CAAC;AAEpD,KAAK,UAAU,OAAO,CAAC,QAAQ,GAAG,SAAS;IACzC,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACrC,IAAI,QAAQ,EAAE,SAAS;QAAE,OAAO,QAAQ,CAAC;IACzC,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC7B,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,+DAA+D;AAC/D,SAAS;AACT,+DAA+D;AAE/D,gBAAgB;AAChB,MAAM,SAAS,GAAG;IAChB,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,MAAM;IACN,QAAQ;IACR,OAAO;IACP,UAAU;IACV,OAAO;IACP,MAAM;IACN,SAAS;IACT,OAAO;IACP,QAAQ;CACT,CAAC;AAEF,6CAA6C;AAC7C,SAAS,aAAa,CAAC,IAAY;IACjC,2CAA2C;IAC3C,OAAO,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC5C,CAAC;AAED,sCAAsC;AACtC,MAAM,UAAU,cAAc,CAAC,WAAmB;IAChD,MAAM,UAAU,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC1C,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACtC,IAAI,CAAC,IAAI;YAAE,SAAS;QAEpB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACxC,IAAI,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;QACrC,CAAC;QACD,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;YAC3B,IAAI,IAAI,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzC,MAAM,IAAI,KAAK,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;QAED,mBAAmB;QACnB,IAAI,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;AACH,CAAC;AAED,kBAAkB;AAClB,SAAS,gBAAgB;IACvB,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;IACpD,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AAClD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,KAAK,CACzB,WAAmB,EACnB,QAAQ,GAAG,SAAS;IAEpB,cAAc,CAAC,WAAW,CAAC,CAAC;IAE5B,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClC,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAChD,OAAO,MAAM,CAAC,SAAgB,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,WAAmB,EACnB,MAAwD,EACxD,QAAQ,GAAG,SAAS;IAEpB,cAAc,CAAC,WAAW,CAAC,CAAC;IAE5B,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClC,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;IAC5B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC5B,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAChD,OAAO,MAAM,CAAC,SAAgB,CAAC;AACjC,CAAC;AAED,YAAY;AACZ,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { TableKey } from "./config.js";
|
|
2
|
+
import type { Pagination } from "./shared.js";
|
|
3
|
+
export type DiffStatus = "identical" | "added" | "removed" | "modified";
|
|
4
|
+
export interface DiffDetail {
|
|
5
|
+
entityType: string;
|
|
6
|
+
businessKey: string;
|
|
7
|
+
status: DiffStatus;
|
|
8
|
+
diffFields?: {
|
|
9
|
+
field: string;
|
|
10
|
+
valueA: unknown;
|
|
11
|
+
valueB: unknown;
|
|
12
|
+
}[];
|
|
13
|
+
sourceRow?: Record<string, unknown>;
|
|
14
|
+
targetRow?: Record<string, unknown>;
|
|
15
|
+
}
|
|
16
|
+
export interface DiffResult {
|
|
17
|
+
summary: {
|
|
18
|
+
totalCompared: number;
|
|
19
|
+
identical: number;
|
|
20
|
+
addedInB: number;
|
|
21
|
+
removedInB: number;
|
|
22
|
+
modified: number;
|
|
23
|
+
};
|
|
24
|
+
details: DiffDetail[];
|
|
25
|
+
page: DiffDetail[];
|
|
26
|
+
pagination: Pagination;
|
|
27
|
+
}
|
|
28
|
+
/** 生成业务键字符串 */
|
|
29
|
+
export declare function bizKey(row: Record<string, unknown>, fields: string[]): string;
|
|
30
|
+
/**
|
|
31
|
+
* 通用表比对:分别查询两个系统,在 JS 内存中做 FULL OUTER JOIN,
|
|
32
|
+
* 按业务键字段匹配,比较指定字段的差异。
|
|
33
|
+
*
|
|
34
|
+
* @param tableKey 表名键(如 "tableDef")
|
|
35
|
+
* @param bkFields 业务键字段(如 ["TableName"])
|
|
36
|
+
* @param cmpFields 需要比较的字段(如 ["Description", "ModuleID"])
|
|
37
|
+
* @param selectA 系统A 的 SELECT 语句(可覆盖默认的 SELECT * FROM T(...))
|
|
38
|
+
* @param selectB 系统B 的 SELECT 语句
|
|
39
|
+
* @param page 页码,默认 1
|
|
40
|
+
* @param pageSize 每页数量,默认 50
|
|
41
|
+
*/
|
|
42
|
+
export declare function diffTable(tableKey: TableKey, bkFields: string[], cmpFields: string[], selectA?: string, selectB?: string, page?: number, pageSize?: number): Promise<DiffResult>;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { query } from "./db.js";
|
|
2
|
+
import { T, T2, paginate } from "./shared.js";
|
|
3
|
+
// ============================================================
|
|
4
|
+
// 工具函数
|
|
5
|
+
// ============================================================
|
|
6
|
+
/** 生成业务键字符串 */
|
|
7
|
+
export function bizKey(row, fields) {
|
|
8
|
+
return fields.map((f) => String(row[f] ?? "")).join("|");
|
|
9
|
+
}
|
|
10
|
+
/** 比对新旧两个值是否相等 */
|
|
11
|
+
function valuesEqual(a, b) {
|
|
12
|
+
if (a === b)
|
|
13
|
+
return true;
|
|
14
|
+
if (a === null || b === null)
|
|
15
|
+
return a === b;
|
|
16
|
+
if (a === undefined || b === undefined)
|
|
17
|
+
return a === b;
|
|
18
|
+
return String(a) === String(b);
|
|
19
|
+
}
|
|
20
|
+
// ============================================================
|
|
21
|
+
// 通用比对引擎
|
|
22
|
+
// ============================================================
|
|
23
|
+
/**
|
|
24
|
+
* 通用表比对:分别查询两个系统,在 JS 内存中做 FULL OUTER JOIN,
|
|
25
|
+
* 按业务键字段匹配,比较指定字段的差异。
|
|
26
|
+
*
|
|
27
|
+
* @param tableKey 表名键(如 "tableDef")
|
|
28
|
+
* @param bkFields 业务键字段(如 ["TableName"])
|
|
29
|
+
* @param cmpFields 需要比较的字段(如 ["Description", "ModuleID"])
|
|
30
|
+
* @param selectA 系统A 的 SELECT 语句(可覆盖默认的 SELECT * FROM T(...))
|
|
31
|
+
* @param selectB 系统B 的 SELECT 语句
|
|
32
|
+
* @param page 页码,默认 1
|
|
33
|
+
* @param pageSize 每页数量,默认 50
|
|
34
|
+
*/
|
|
35
|
+
export async function diffTable(tableKey, bkFields, cmpFields, selectA, selectB, page, pageSize) {
|
|
36
|
+
const sqlA = selectA ?? `SELECT * FROM ${T(tableKey)}`;
|
|
37
|
+
const sqlB = selectB ?? `SELECT * FROM ${T2(tableKey)}`;
|
|
38
|
+
const rowsA = await query(sqlA, "default");
|
|
39
|
+
const rowsB = await query(sqlB, "b");
|
|
40
|
+
// 构建业务键索引 — 检测重复键并警告
|
|
41
|
+
const mapB = new Map();
|
|
42
|
+
for (const row of rowsB) {
|
|
43
|
+
const key = bizKey(row, bkFields);
|
|
44
|
+
if (mapB.has(key)) {
|
|
45
|
+
console.error(`[diff] 警告: 系统B中存在重复业务键 "${key}",仅保留最后一条`);
|
|
46
|
+
}
|
|
47
|
+
mapB.set(key, row);
|
|
48
|
+
}
|
|
49
|
+
const details = [];
|
|
50
|
+
const seenInB = new Set();
|
|
51
|
+
for (const rowA of rowsA) {
|
|
52
|
+
const key = bizKey(rowA, bkFields);
|
|
53
|
+
const rowB = mapB.get(key);
|
|
54
|
+
if (!rowB) {
|
|
55
|
+
// A 有,B 无 → 系统B缺失
|
|
56
|
+
details.push({
|
|
57
|
+
entityType: tableKey,
|
|
58
|
+
businessKey: key,
|
|
59
|
+
status: "removed",
|
|
60
|
+
sourceRow: rowA,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
seenInB.add(key);
|
|
65
|
+
// 两边都有 → 比较字段
|
|
66
|
+
const diffFields = [];
|
|
67
|
+
for (const f of cmpFields) {
|
|
68
|
+
if (!valuesEqual(rowA[f], rowB[f])) {
|
|
69
|
+
diffFields.push({ field: f, valueA: rowA[f], valueB: rowB[f] });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (diffFields.length > 0) {
|
|
73
|
+
details.push({
|
|
74
|
+
entityType: tableKey,
|
|
75
|
+
businessKey: key,
|
|
76
|
+
status: "modified",
|
|
77
|
+
diffFields,
|
|
78
|
+
sourceRow: rowA,
|
|
79
|
+
targetRow: rowB,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
// identical 的不入 details(避免数据量过大),仅统计
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// B 有,A 无 → 系统B新增
|
|
86
|
+
for (const [key, rowB] of mapB) {
|
|
87
|
+
if (!seenInB.has(key)) {
|
|
88
|
+
details.push({
|
|
89
|
+
entityType: tableKey,
|
|
90
|
+
businessKey: key,
|
|
91
|
+
status: "added",
|
|
92
|
+
targetRow: rowB,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const { identical, added, removed, modified } = countStatus(details, rowsA.length);
|
|
97
|
+
const p = page ?? 1;
|
|
98
|
+
const ps = pageSize ?? 50;
|
|
99
|
+
const { page: pagedDetails, pagination } = paginate(details, p, ps);
|
|
100
|
+
return {
|
|
101
|
+
summary: {
|
|
102
|
+
totalCompared: removed + added + modified + identical,
|
|
103
|
+
identical,
|
|
104
|
+
addedInB: added,
|
|
105
|
+
removedInB: removed,
|
|
106
|
+
modified,
|
|
107
|
+
},
|
|
108
|
+
details,
|
|
109
|
+
page: pagedDetails,
|
|
110
|
+
pagination,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/** 根据 details 和系统A行数推算 identical 数量 */
|
|
114
|
+
function countStatus(details, totalA) {
|
|
115
|
+
let added = 0;
|
|
116
|
+
let removed = 0;
|
|
117
|
+
let modified = 0;
|
|
118
|
+
for (const d of details) {
|
|
119
|
+
if (d.status === "added")
|
|
120
|
+
added++;
|
|
121
|
+
else if (d.status === "removed")
|
|
122
|
+
removed++;
|
|
123
|
+
else if (d.status === "modified")
|
|
124
|
+
modified++;
|
|
125
|
+
}
|
|
126
|
+
// identical = 系统A中未出现在 details 的行数(即 A 中有且相同)
|
|
127
|
+
const identical = totalA - removed - modified;
|
|
128
|
+
return { identical, added, removed, modified };
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=diff-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff-utils.js","sourceRoot":"","sources":["../src/diff-utils.ts"],"names":[],"mappings":"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"}
|