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 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 run|... DSL 查询 executeQueryDsl(conn/model/schema/tableId/dslQuery)
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 = JSON.parse(text); } catch { throw new Error("HTTP " + resp.status + " 非JSON响应: " + text.slice(0, 300)); }
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 = JSON.parse(text); } catch { throw new Error("HTTP " + resp.status + " 非JSON响应: " + text.slice(0, 300)); }
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 = JSON.parse(text); } catch { throw new Error("HTTP " + resp.status + " 非JSON响应: " + text.slice(0, 300)); }
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
- try { return JSON.parse(raw); } catch (e) { throw new Error(label + " JSON 解析失败: " + e.message); }
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") : JSON.parse(dslVal);
170
- const r = await postJson("/api/dw/dsl/executeQueryDsl", { connId: conn, model, schema, tableId, dslQuery });
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 rows = r.data || [];
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 = JSON.parse(raw); } catch { throw new Error("HTTP " + resp.status + " 非JSON响应: " + raw.slice(0, 300)); }
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>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "e10-data",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "泛微 E10 数据接口统一 CLI(data-assistant 专家配套):DSL 查询/数据源/文档/词库/关联字段翻译/专家包版本管理,认证复用 weaver-e10-login 登录态",
5
5
  "author": "e10-dw",
6
6
  "license": "MIT",