e10-data 0.1.0 → 0.1.2
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/README.md +3 -1
- package/bin/e10-data.mjs +66 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ e10-data --version # 验证
|
|
|
14
14
|
## 命令总览
|
|
15
15
|
|
|
16
16
|
```
|
|
17
|
-
e10-data query <--conn <connId> --model <ebuilder|flow|eteams|attend|hr|document|dw|blog> --schema <数据库> [--table-id <流程ID>] --dsl @file.json>
|
|
17
|
+
e10-data query <--conn <connId> --model <ebuilder|flow|eteams|attend|hr|document|dw|blog> --schema <数据库> [--table-id <流程ID>] [--debug true|false] --dsl @file.json>
|
|
18
18
|
e10-data ds tables|fields|list|chart|stat|count 数据源(业务模块)取数与元数据
|
|
19
19
|
e10-data doc count|list 文档查询(documentListCount + documentList)
|
|
20
20
|
e10-data noun list --skill <skillKey> 词库查询(可带 --source-type/--source-group/--source-table 三参数)
|
|
@@ -26,6 +26,7 @@ e10-data exp status|manifest|commits|file|pull|init|commit|lock|release|roll
|
|
|
26
26
|
|
|
27
27
|
- `--json`:原样输出接口 JSON(供脚本/Agent 消费);默认人读输出。
|
|
28
28
|
- 复杂 JSON/中文参数:推荐 `@文件` 承载(如 `--dsl @q.json`、`--where @cond.json`)。
|
|
29
|
+
- ⚠️ 大整数精度(自动处理):E10 的 ID 多为 19 位,超过 JS 安全整数(2^53-1≈9e15)。CLI 解析 JSON 时**自动把超范围裸整数转成字符串**再发请求/输出(实测后端接受字符串做 =/IN/BETWEEN 数值比较),无需手动加引号,也不误伤字符串正文。
|
|
29
30
|
- 认证:进程内读取 `~/.workbuddy/e10-login-cache.md`;失效提示重新执行 `e10-login oidc`。
|
|
30
31
|
- 版本更新:`npm i -g e10-data@latest`;查看源上最新 `npm view e10-data version`。
|
|
31
32
|
|
|
@@ -33,6 +34,7 @@ e10-data exp status|manifest|commits|file|pull|init|commit|lock|release|roll
|
|
|
33
34
|
|
|
34
35
|
```bash
|
|
35
36
|
e10-data query --conn 1144919996804022272 --model dw --schema dw --dsl @q.json
|
|
37
|
+
e10-data query --conn 1144919996804022272 --model dw --schema dw --debug true --dsl @q.json # debug 模式:额外打印实际执行 SQL
|
|
36
38
|
e10-data ds count --group weaver-project-servicetask --table 715738355537494016
|
|
37
39
|
e10-data ds fields --group weaver-formreport-service --table 1307487628041044060
|
|
38
40
|
e10-data doc count --name 智能问数
|
package/bin/e10-data.mjs
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* e10-data CLI —— data-assistant 专家统一数据接口命令行(2026-09-03 扩展)
|
|
5
5
|
*
|
|
6
6
|
* 覆盖(数据查询链路全部家族;登录/HRM 复用 e10-login / hrm-cli,checkEbModulePermission 已废弃不提供):
|
|
7
|
-
* e10-data query
|
|
7
|
+
* e10-data query DSL 查询 executeQueryDsl(conn/model/schema/tableId/dslQuery/debug)
|
|
8
8
|
* e10-data ds tables|fields|list|chart|stat|count 数据源(业务模块)取数与元数据
|
|
9
9
|
* e10-data doc count|list 文档查询 documentListCount / documentList
|
|
10
10
|
* e10-data noun list 词库 getChatDocsBySkillKey
|
|
@@ -77,7 +77,7 @@ async function postJson(endpoint, bodyObj, extraHeaders = {}) {
|
|
|
77
77
|
body: JSON.stringify(bodyObj),
|
|
78
78
|
});
|
|
79
79
|
const text = await resp.text();
|
|
80
|
-
let j; try { j =
|
|
80
|
+
let j; try { j = parseJsonSafe(text); } catch { throw new Error("HTTP " + resp.status + " 非JSON响应: " + text.slice(0, 300)); }
|
|
81
81
|
checkAuthFail(resp, text, j);
|
|
82
82
|
return j;
|
|
83
83
|
}
|
|
@@ -94,7 +94,7 @@ async function getUrl(url) {
|
|
|
94
94
|
},
|
|
95
95
|
});
|
|
96
96
|
const text = await resp.text();
|
|
97
|
-
let j; try { j =
|
|
97
|
+
let j; try { j = parseJsonSafe(text); } catch { throw new Error("HTTP " + resp.status + " 非JSON响应: " + text.slice(0, 300)); }
|
|
98
98
|
checkAuthFail(resp, text, j);
|
|
99
99
|
return j;
|
|
100
100
|
}
|
|
@@ -116,7 +116,7 @@ async function postMultipart(endpoint, formObj) {
|
|
|
116
116
|
body: fd,
|
|
117
117
|
});
|
|
118
118
|
const text = await resp.text();
|
|
119
|
-
let j; try { j =
|
|
119
|
+
let j; try { j = parseJsonSafe(text); } catch { throw new Error("HTTP " + resp.status + " 非JSON响应: " + text.slice(0, 300)); }
|
|
120
120
|
checkAuthFail(resp, text, j);
|
|
121
121
|
return j;
|
|
122
122
|
}
|
|
@@ -136,10 +136,56 @@ function parseArgs(argv) {
|
|
|
136
136
|
}
|
|
137
137
|
return { args, pos };
|
|
138
138
|
}
|
|
139
|
+
// ⚠️ 大整数精度保护(2026-09-03):E10 主键/ID 多为 19 位大整数,超过 JS 安全整数 2^53-1
|
|
140
|
+
// (9007199254740991)。JSON.parse 会将其舍入为近似 double(如 1297901170990161977 → ...1920),
|
|
141
|
+
// 导致 DSL 条件查不到数据(静默空结果)或返回 ID 失真。此处把 JSON 中 >2^53 的裸数字字面量
|
|
142
|
+
// 加引号转字符串(后端实测接受字符串形式做 = / IN / BETWEEN 数值比较),请求与响应两侧统一保护。
|
|
143
|
+
function protectBigInts(raw) {
|
|
144
|
+
// 逐字符扫描:跟踪 JSON 字符串状态(含转义),仅在引号外的结构层把 >2^53 的裸整数加引号,
|
|
145
|
+
// 避免误伤字符串内容(如 avatar JSON、文档正文里含 ",大数字" 片段)。
|
|
146
|
+
let out = "", inStr = false, esc = false;
|
|
147
|
+
for (let i = 0; i < raw.length; i++) {
|
|
148
|
+
const ch = raw[i];
|
|
149
|
+
if (inStr) {
|
|
150
|
+
out += ch;
|
|
151
|
+
if (esc) esc = false;
|
|
152
|
+
else if (ch === "\\") esc = true;
|
|
153
|
+
else if (ch === '"') inStr = false;
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (ch === '"') { inStr = true; out += ch; continue; }
|
|
157
|
+
if (ch === "-" || (ch >= "0" && ch <= "9")) {
|
|
158
|
+
let j = i + 1;
|
|
159
|
+
while (j < raw.length && raw[j] >= "0" && raw[j] <= "9") j++; // 纯整数 token(无小数点/指数)
|
|
160
|
+
let k = i - 1;
|
|
161
|
+
while (k >= 0 && /\s/.test(raw[k])) k--;
|
|
162
|
+
const prev = k < 0 ? "" : raw[k];
|
|
163
|
+
let n = j;
|
|
164
|
+
while (n < raw.length && /\s/.test(raw[n])) n++;
|
|
165
|
+
const next = n < raw.length ? raw[n] : "";
|
|
166
|
+
const token = raw.slice(i, j);
|
|
167
|
+
if ((prev === ":" || prev === "," || prev === "[") && (next === "," || next === "}" || next === "]")) {
|
|
168
|
+
try {
|
|
169
|
+
const bi = BigInt(token);
|
|
170
|
+
if (bi > 9007199254740991n || bi < -9007199254740991n) { out += '"' + token + '"'; i = j - 1; continue; }
|
|
171
|
+
} catch { /* 非纯整数不转换 */ }
|
|
172
|
+
}
|
|
173
|
+
out += raw.slice(i, j);
|
|
174
|
+
i = j - 1;
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
out += ch;
|
|
178
|
+
}
|
|
179
|
+
return out;
|
|
180
|
+
}
|
|
181
|
+
function parseJsonSafe(raw, label) {
|
|
182
|
+
try { return JSON.parse(protectBigInts(raw)); }
|
|
183
|
+
catch (e) { throw new Error((label || "JSON") + " 解析失败: " + e.message); }
|
|
184
|
+
}
|
|
139
185
|
function readJsonArg(val, label) {
|
|
140
186
|
let raw = val;
|
|
141
187
|
if (val.startsWith("@")) raw = fs.readFileSync(val.slice(1), "utf-8");
|
|
142
|
-
|
|
188
|
+
return parseJsonSafe(raw, label);
|
|
143
189
|
}
|
|
144
190
|
function need(arg, args) { if (!args[arg]) throw new Error("缺少必填参数 --" + arg); return args[arg]; }
|
|
145
191
|
|
|
@@ -166,8 +212,15 @@ async function cmdQuery(args, json) {
|
|
|
166
212
|
const conn = need("conn", args), model = need("model", args), schema = need("schema", args);
|
|
167
213
|
const tableId = args["table-id"] || "";
|
|
168
214
|
const dslVal = need("dsl", args);
|
|
169
|
-
const dslQuery = dslVal.startsWith("@") ? readJsonArg(dslVal, "--dsl") :
|
|
170
|
-
const
|
|
215
|
+
const dslQuery = dslVal.startsWith("@") ? readJsonArg(dslVal, "--dsl") : parseJsonSafe(dslVal, "--dsl");
|
|
216
|
+
const body = { connId: conn, model, schema, tableId, dslQuery };
|
|
217
|
+
if (args.debug !== undefined) { // --debug true|false,与 conn/model 同层级
|
|
218
|
+
const dbg = String(args.debug).toLowerCase();
|
|
219
|
+
if (dbg === "true" || dbg === "1") body.debug = true;
|
|
220
|
+
else if (dbg === "false" || dbg === "0") body.debug = false;
|
|
221
|
+
else throw new Error("--debug 值必须为 true 或 false(当前: " + args.debug + ")");
|
|
222
|
+
}
|
|
223
|
+
const r = await postJson("/api/dw/dsl/executeQueryDsl", body);
|
|
171
224
|
if (json) return r;
|
|
172
225
|
if (String(r.code) !== "200" && r.code !== undefined && String(r.code) !== "0") {
|
|
173
226
|
console.log("code=" + r.code + " msg=" + (r.msg || ""));
|
|
@@ -176,7 +229,10 @@ async function cmdQuery(args, json) {
|
|
|
176
229
|
}
|
|
177
230
|
return;
|
|
178
231
|
}
|
|
179
|
-
const
|
|
232
|
+
const d = r.data;
|
|
233
|
+
// debug=true 时 data 为 { sql, records };否则为行数组
|
|
234
|
+
const rows = Array.isArray(d) ? d : (d && Array.isArray(d.records) ? d.records : []);
|
|
235
|
+
if (d && !Array.isArray(d) && d.sql) console.log("SQL: " + d.sql);
|
|
180
236
|
if (!rows.length) { console.log("(空:0 行)"); return; }
|
|
181
237
|
printHuman("结果 " + rows.length + " 行", rows);
|
|
182
238
|
}
|
|
@@ -405,7 +461,7 @@ async function expGet(url) {
|
|
|
405
461
|
headers: { "accept": "application/json, text/plain, */*", "langType": "zh_CN", "cookie": auth.cookie, "eteamsid": auth.eteamsid, "ebbusinessid": EB_BIZ_ID, "user-agent": UA },
|
|
406
462
|
});
|
|
407
463
|
const raw = await resp.text();
|
|
408
|
-
let j; try { j =
|
|
464
|
+
let j; try { j = parseJsonSafe(raw); } catch { throw new Error("HTTP " + resp.status + " 非JSON响应: " + raw.slice(0, 300)); }
|
|
409
465
|
if (resp.status === 401 || (j && String(j.code) === "-1" && /token|登录|失效/i.test(String(j.msg || "")))) throw new Error("登录态失效,请重新 e10-login oidc 登录");
|
|
410
466
|
return { raw, j };
|
|
411
467
|
}
|
|
@@ -661,7 +717,7 @@ function usage() {
|
|
|
661
717
|
用法: node e10-data.mjs <族> <子命令> [--参数] 通用 --json 原样输出
|
|
662
718
|
|
|
663
719
|
query DSL 数据查询 executeQueryDsl
|
|
664
|
-
query --conn <connId> --model <ebuilder|flow|eteams|attend|hr|document|dw|blog> --schema <数据库> [--table-id <流程ID>] --dsl @file.json|'{...}'
|
|
720
|
+
query --conn <connId> --model <ebuilder|flow|eteams|attend|hr|document|dw|blog> --schema <数据库> [--table-id <流程ID>] [--debug true|false] --dsl @file.json|'{...}'
|
|
665
721
|
ds 数据源(业务模块)取数与元数据
|
|
666
722
|
ds tables --group <gid> [--name 关键词]
|
|
667
723
|
ds fields --group <gid> --table <tid>
|