@rex0220/kintone-sql-tools 2.6.0 → 2.8.0
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/dist-cli/ksql.js +634 -303
- package/dist-mcp/ksql-mcp.js +577 -247
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +1 -1
package/dist-cli/ksql.js
CHANGED
|
@@ -94,6 +94,7 @@ var KEYWORDS = /* @__PURE__ */ new Map([
|
|
|
94
94
|
["IS", "IS" /* IS */],
|
|
95
95
|
["NULL", "NULL" /* NULL */],
|
|
96
96
|
["LIKE", "LIKE" /* LIKE */],
|
|
97
|
+
["KLIKE", "KLIKE" /* KLIKE */],
|
|
97
98
|
["IN", "IN" /* IN */],
|
|
98
99
|
["BETWEEN", "BETWEEN" /* BETWEEN */],
|
|
99
100
|
["TODAY", "TODAY" /* TODAY */],
|
|
@@ -1619,7 +1620,7 @@ var Parser = class {
|
|
|
1619
1620
|
}
|
|
1620
1621
|
return false;
|
|
1621
1622
|
}
|
|
1622
|
-
// 比較演算子: =, !=, <>, >, <, >=, <=, LIKE, IN, IS NULL
|
|
1623
|
+
// 比較演算子: =, !=, <>, >, <, >=, <=, LIKE, KLIKE, IN, IS NULL
|
|
1623
1624
|
parseCompareExpr() {
|
|
1624
1625
|
if (this.peek().kind === "(" /* LPAREN */ && !this.isArithParen()) {
|
|
1625
1626
|
this.advance();
|
|
@@ -1655,8 +1656,12 @@ var Parser = class {
|
|
|
1655
1656
|
const pattern = this.parseSqlValue();
|
|
1656
1657
|
return { type: "BINARY", op: "NOT_LIKE", left: field, right: pattern };
|
|
1657
1658
|
}
|
|
1659
|
+
if (this.consume("KLIKE" /* KLIKE */)) {
|
|
1660
|
+
const pattern = this.parseKlikePattern();
|
|
1661
|
+
return { type: "BINARY", op: "NOT_KLIKE", left: field, right: pattern };
|
|
1662
|
+
}
|
|
1658
1663
|
throw new ParseError(
|
|
1659
|
-
"NOT \u306E\u5F8C\u306B\u306F IN \
|
|
1664
|
+
"NOT \u306E\u5F8C\u306B\u306F IN\u3001LIKE\u3001KLIKE \u306E\u3044\u305A\u308C\u304B\u304C\u5FC5\u8981\u3067\u3059",
|
|
1660
1665
|
this.peek()
|
|
1661
1666
|
);
|
|
1662
1667
|
}
|
|
@@ -1666,6 +1671,10 @@ var Parser = class {
|
|
|
1666
1671
|
this.expect(")" /* RPAREN */);
|
|
1667
1672
|
return { type: "BINARY", op: "IN", left: field, right: right2 };
|
|
1668
1673
|
}
|
|
1674
|
+
if (this.consume("KLIKE" /* KLIKE */)) {
|
|
1675
|
+
const pattern = this.parseKlikePattern();
|
|
1676
|
+
return { type: "BINARY", op: "KLIKE", left: field, right: pattern };
|
|
1677
|
+
}
|
|
1669
1678
|
const op = this.parseCompareOp();
|
|
1670
1679
|
const right = this.parseSqlValue();
|
|
1671
1680
|
return { type: "BINARY", op, left: field, right };
|
|
@@ -1691,11 +1700,27 @@ var Parser = class {
|
|
|
1691
1700
|
return "LIKE";
|
|
1692
1701
|
default:
|
|
1693
1702
|
throw new ParseError(
|
|
1694
|
-
"\u6BD4\u8F03\u6F14\u7B97\u5B50\uFF08=, !=, >, <, >=, <=, LIKE, IN, IS\uFF09\u304C\u5FC5\u8981\u3067\u3059",
|
|
1703
|
+
"\u6BD4\u8F03\u6F14\u7B97\u5B50\uFF08=, !=, >, <, >=, <=, LIKE, KLIKE, IN, IS\uFF09\u304C\u5FC5\u8981\u3067\u3059",
|
|
1695
1704
|
tok
|
|
1696
1705
|
);
|
|
1697
1706
|
}
|
|
1698
1707
|
}
|
|
1708
|
+
/** KLIKE / NOT KLIKE の右辺。kintone キーワードは文字列値だけを受け付ける。 */
|
|
1709
|
+
parseKlikePattern() {
|
|
1710
|
+
const tok = this.peek();
|
|
1711
|
+
if (tok.kind === "STRING" /* STRING */) {
|
|
1712
|
+
this.advance();
|
|
1713
|
+
return { type: "STRING", value: tok.value };
|
|
1714
|
+
}
|
|
1715
|
+
if (tok.kind === "VARIABLE" /* VARIABLE */) {
|
|
1716
|
+
this.advance();
|
|
1717
|
+
return { type: "VARIABLE", name: tok.value.slice(1).toLowerCase() };
|
|
1718
|
+
}
|
|
1719
|
+
throw new ParseError(
|
|
1720
|
+
"KLIKE / NOT KLIKE \u306E\u53F3\u8FBA\u306B\u306F\u6587\u5B57\u5217\u30EA\u30C6\u30E9\u30EB\u307E\u305F\u306F\u30D0\u30C3\u30C1\u5909\u6570\u304C\u5FC5\u8981\u3067\u3059",
|
|
1721
|
+
tok
|
|
1722
|
+
);
|
|
1723
|
+
}
|
|
1699
1724
|
// WHERE / HAVING の左辺
|
|
1700
1725
|
// - 文字列・数値関数: UPPER(f) / LENGTH(f) / ROUND(f, 2) ...
|
|
1701
1726
|
// - 集計関数(HAVING のみ): COUNT(*) / SUM(f) ...
|
|
@@ -2346,238 +2371,6 @@ function collectDmlTargetFields(stmt) {
|
|
|
2346
2371
|
return [];
|
|
2347
2372
|
}
|
|
2348
2373
|
|
|
2349
|
-
// src/core/batch.ts
|
|
2350
|
-
var MAX_TEMP_TABLES = 16;
|
|
2351
|
-
var MAX_BATCH_VARIABLES = 64;
|
|
2352
|
-
var BatchAnalysisError = class extends Error {
|
|
2353
|
-
constructor(message, statementIndex) {
|
|
2354
|
-
super(message);
|
|
2355
|
-
this.statementIndex = statementIndex;
|
|
2356
|
-
}
|
|
2357
|
-
};
|
|
2358
|
-
function collectRefs(node, tempRefs, appIds) {
|
|
2359
|
-
if (Array.isArray(node)) {
|
|
2360
|
-
for (const v of node) collectRefs(v, tempRefs, appIds);
|
|
2361
|
-
return;
|
|
2362
|
-
}
|
|
2363
|
-
if (node !== null && typeof node === "object") {
|
|
2364
|
-
const obj = node;
|
|
2365
|
-
const cte = obj["cteName"];
|
|
2366
|
-
if (typeof cte === "string" && cte.startsWith("#")) tempRefs.add(cte);
|
|
2367
|
-
const appId = obj["appId"];
|
|
2368
|
-
if (typeof appId === "number" && appId > 0) appIds.add(appId);
|
|
2369
|
-
for (const v of Object.values(obj)) collectRefs(v, tempRefs, appIds);
|
|
2370
|
-
}
|
|
2371
|
-
}
|
|
2372
|
-
function collectVariableRefs(node, refs) {
|
|
2373
|
-
if (Array.isArray(node)) {
|
|
2374
|
-
for (const v of node) collectVariableRefs(v, refs);
|
|
2375
|
-
return;
|
|
2376
|
-
}
|
|
2377
|
-
if (node !== null && typeof node === "object") {
|
|
2378
|
-
const obj = node;
|
|
2379
|
-
if (obj["type"] === "VARIABLE" && typeof obj["name"] === "string") {
|
|
2380
|
-
refs.add(obj["name"]);
|
|
2381
|
-
return;
|
|
2382
|
-
}
|
|
2383
|
-
for (const v of Object.values(obj)) collectVariableRefs(v, refs);
|
|
2384
|
-
}
|
|
2385
|
-
}
|
|
2386
|
-
function analyzeBatch(statements) {
|
|
2387
|
-
if (statements.length === 0) {
|
|
2388
|
-
throw new BatchAnalysisError("ArgumentError: SQL is empty.", 0);
|
|
2389
|
-
}
|
|
2390
|
-
if (statements.length === 1) {
|
|
2391
|
-
const t = statements[0].type;
|
|
2392
|
-
if (t === "SET_VARIABLE" || t === "DECLARE_VARIABLE") {
|
|
2393
|
-
const verb = t === "SET_VARIABLE" ? "SET" : "DECLARE";
|
|
2394
|
-
throw new BatchAnalysisError(`ArgumentError: ${verb} variable requires a batch.`, 0);
|
|
2395
|
-
}
|
|
2396
|
-
if (t === "CREATE_TEMP_TABLE" || t === "DROP_TEMP_TABLE") {
|
|
2397
|
-
const verb = t === "CREATE_TEMP_TABLE" ? "CREATE TEMP TABLE" : "DROP TEMP TABLE";
|
|
2398
|
-
throw new BatchAnalysisError(
|
|
2399
|
-
`ArgumentError: ${verb} requires a batch (temp tables are batch-scoped).`,
|
|
2400
|
-
0
|
|
2401
|
-
);
|
|
2402
|
-
}
|
|
2403
|
-
}
|
|
2404
|
-
const defined = /* @__PURE__ */ new Map();
|
|
2405
|
-
const createdOrder = [];
|
|
2406
|
-
const results = [];
|
|
2407
|
-
const variableDefs = /* @__PURE__ */ new Map();
|
|
2408
|
-
const variableOrder = [];
|
|
2409
|
-
statements.forEach((stmt, index) => {
|
|
2410
|
-
const statementType = getStatementType(stmt);
|
|
2411
|
-
const created = [];
|
|
2412
|
-
const dropped = [];
|
|
2413
|
-
const refs = /* @__PURE__ */ new Set();
|
|
2414
|
-
const stmtAppIds = /* @__PURE__ */ new Set();
|
|
2415
|
-
const dependsOn = /* @__PURE__ */ new Set();
|
|
2416
|
-
const variableRefs = /* @__PURE__ */ new Set();
|
|
2417
|
-
collectVariableRefs(stmt, variableRefs);
|
|
2418
|
-
for (const name of variableRefs) {
|
|
2419
|
-
const def = variableDefs.get(name);
|
|
2420
|
-
if (def === void 0) {
|
|
2421
|
-
throw new BatchAnalysisError(
|
|
2422
|
-
`ParseError: variable @${name} is not defined before statement ${index + 1}.`,
|
|
2423
|
-
index
|
|
2424
|
-
);
|
|
2425
|
-
}
|
|
2426
|
-
def.referencedBy.push(index);
|
|
2427
|
-
}
|
|
2428
|
-
if (stmt.type === "SET_VARIABLE" || stmt.type === "DECLARE_VARIABLE") {
|
|
2429
|
-
if (variableDefs.has(stmt.name)) {
|
|
2430
|
-
throw new BatchAnalysisError(`ParseError: variable @${stmt.name} is already defined.`, index);
|
|
2431
|
-
}
|
|
2432
|
-
variableDefs.set(stmt.name, { index, referencedBy: [] });
|
|
2433
|
-
variableOrder.push(stmt.name);
|
|
2434
|
-
if (variableOrder.length > MAX_BATCH_VARIABLES) {
|
|
2435
|
-
throw new BatchAnalysisError(
|
|
2436
|
-
`ParseError: batch exceeds ${MAX_BATCH_VARIABLES} variables.`,
|
|
2437
|
-
index
|
|
2438
|
-
);
|
|
2439
|
-
}
|
|
2440
|
-
}
|
|
2441
|
-
if (stmt.type === "CREATE_TEMP_TABLE") {
|
|
2442
|
-
collectRefs(stmt.query, refs, stmtAppIds);
|
|
2443
|
-
} else if (stmt.type === "DROP_TEMP_TABLE") {
|
|
2444
|
-
} else {
|
|
2445
|
-
collectRefs(stmt, refs, stmtAppIds);
|
|
2446
|
-
}
|
|
2447
|
-
let tempOnlySource = false;
|
|
2448
|
-
if (stmt.type === "INSERT_SELECT" || stmt.type === "UPSERT_SELECT") {
|
|
2449
|
-
const srcTemp = /* @__PURE__ */ new Set();
|
|
2450
|
-
const srcApps = /* @__PURE__ */ new Set();
|
|
2451
|
-
collectRefs(stmt.select, srcTemp, srcApps);
|
|
2452
|
-
tempOnlySource = srcTemp.size > 0 && srcApps.size === 0;
|
|
2453
|
-
}
|
|
2454
|
-
for (const name of refs) {
|
|
2455
|
-
const at = defined.get(name);
|
|
2456
|
-
if (at === void 0) {
|
|
2457
|
-
throw new BatchAnalysisError(
|
|
2458
|
-
`ParseError: temp table ${name} is not defined in this batch.`,
|
|
2459
|
-
index
|
|
2460
|
-
);
|
|
2461
|
-
}
|
|
2462
|
-
dependsOn.add(at);
|
|
2463
|
-
}
|
|
2464
|
-
if (stmt.type === "CREATE_TEMP_TABLE") {
|
|
2465
|
-
if (defined.has(stmt.name)) {
|
|
2466
|
-
throw new BatchAnalysisError(
|
|
2467
|
-
`ParseError: temp table ${stmt.name} is already defined.`,
|
|
2468
|
-
index
|
|
2469
|
-
);
|
|
2470
|
-
}
|
|
2471
|
-
defined.set(stmt.name, index);
|
|
2472
|
-
createdOrder.push(stmt.name);
|
|
2473
|
-
created.push(stmt.name);
|
|
2474
|
-
if (defined.size > MAX_TEMP_TABLES) {
|
|
2475
|
-
throw new BatchAnalysisError(
|
|
2476
|
-
`ParseError: batch exceeds ${MAX_TEMP_TABLES} temp tables.`,
|
|
2477
|
-
index
|
|
2478
|
-
);
|
|
2479
|
-
}
|
|
2480
|
-
}
|
|
2481
|
-
if (stmt.type === "DROP_TEMP_TABLE") {
|
|
2482
|
-
const at = defined.get(stmt.name);
|
|
2483
|
-
if (at === void 0) {
|
|
2484
|
-
throw new BatchAnalysisError(
|
|
2485
|
-
`ParseError: temp table ${stmt.name} is not defined in this batch.`,
|
|
2486
|
-
index
|
|
2487
|
-
);
|
|
2488
|
-
}
|
|
2489
|
-
dependsOn.add(at);
|
|
2490
|
-
dropped.push(stmt.name);
|
|
2491
|
-
defined.delete(stmt.name);
|
|
2492
|
-
}
|
|
2493
|
-
results.push({
|
|
2494
|
-
index,
|
|
2495
|
-
statementType,
|
|
2496
|
-
isDml: isDmlType(statementType),
|
|
2497
|
-
isReadOnly: isReadOnlyType(statementType),
|
|
2498
|
-
hasWhere: hasWhereClause(stmt),
|
|
2499
|
-
insertValuesCount: getInsertValuesCount(stmt),
|
|
2500
|
-
appIds: [...stmtAppIds].sort((a, b) => a - b),
|
|
2501
|
-
tempTablesCreated: created,
|
|
2502
|
-
tempTablesReferenced: [...refs],
|
|
2503
|
-
tempTablesDropped: dropped,
|
|
2504
|
-
dependsOn: [...dependsOn].sort((a, b) => a - b),
|
|
2505
|
-
tempOnlySource,
|
|
2506
|
-
targetAppId: isDmlType(statementType) && typeof stmt.appId === "number" ? stmt.appId : null
|
|
2507
|
-
});
|
|
2508
|
-
});
|
|
2509
|
-
const containsDml = results.some((r) => r.isDml);
|
|
2510
|
-
const variables = variableOrder.map((name) => ({
|
|
2511
|
-
name,
|
|
2512
|
-
referencedBy: [...variableDefs.get(name).referencedBy]
|
|
2513
|
-
}));
|
|
2514
|
-
return {
|
|
2515
|
-
statementCount: statements.length,
|
|
2516
|
-
isReadOnlyBatch: !containsDml && results.every((r) => r.isReadOnly),
|
|
2517
|
-
containsDml,
|
|
2518
|
-
tempTables: createdOrder,
|
|
2519
|
-
variables,
|
|
2520
|
-
warnings: variables.filter((v) => v.referencedBy.length === 0).map((v) => `variable @${v.name} is never used.`),
|
|
2521
|
-
statements: results
|
|
2522
|
-
};
|
|
2523
|
-
}
|
|
2524
|
-
|
|
2525
|
-
// src/core/batchVariables.ts
|
|
2526
|
-
var VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;
|
|
2527
|
-
function normalizeBatchVariableName(name) {
|
|
2528
|
-
if (!VARIABLE_NAME_RE.test(name)) {
|
|
2529
|
-
throw new Error(
|
|
2530
|
-
`ArgumentError: invalid variable name "${name}". Use a name without @ matching [A-Za-z_][A-Za-z0-9_]{0,63}.`
|
|
2531
|
-
);
|
|
2532
|
-
}
|
|
2533
|
-
return name.toLowerCase();
|
|
2534
|
-
}
|
|
2535
|
-
function normalizeBatchVariables(input) {
|
|
2536
|
-
const normalized = /* @__PURE__ */ Object.create(null);
|
|
2537
|
-
for (const [rawName, value] of Object.entries(input ?? {})) {
|
|
2538
|
-
const name = normalizeBatchVariableName(rawName);
|
|
2539
|
-
if (Object.prototype.hasOwnProperty.call(normalized, name)) {
|
|
2540
|
-
throw new Error(`ArgumentError: variable "${rawName}" is specified more than once.`);
|
|
2541
|
-
}
|
|
2542
|
-
normalized[name] = value;
|
|
2543
|
-
}
|
|
2544
|
-
return normalized;
|
|
2545
|
-
}
|
|
2546
|
-
function validateDeclaredBatchVariables(statements, input) {
|
|
2547
|
-
const normalized = normalizeBatchVariables(input);
|
|
2548
|
-
const declared = new Set(
|
|
2549
|
-
statements.filter((stmt) => stmt.type === "DECLARE_VARIABLE").map((stmt) => stmt.name)
|
|
2550
|
-
);
|
|
2551
|
-
for (const name of Object.keys(normalized)) {
|
|
2552
|
-
if (!declared.has(name)) {
|
|
2553
|
-
throw new Error(`ArgumentError: injected variable @${name} is not declared.`);
|
|
2554
|
-
}
|
|
2555
|
-
}
|
|
2556
|
-
return normalized;
|
|
2557
|
-
}
|
|
2558
|
-
|
|
2559
|
-
// src/core/scalarCompare.ts
|
|
2560
|
-
function compareScalarValues(op, leftStr, rightStr) {
|
|
2561
|
-
if (op === "=") return leftStr === rightStr;
|
|
2562
|
-
if (op === "!=" || op === "<>") return leftStr !== rightStr;
|
|
2563
|
-
const rightNum = Number(rightStr);
|
|
2564
|
-
if (leftStr === "" && rightStr !== "" && Number.isFinite(rightNum)) {
|
|
2565
|
-
return op === "<" || op === "<=";
|
|
2566
|
-
}
|
|
2567
|
-
const leftNum = Number(leftStr);
|
|
2568
|
-
const numeric = !Number.isNaN(leftNum) && !Number.isNaN(rightNum);
|
|
2569
|
-
switch (op) {
|
|
2570
|
-
case ">":
|
|
2571
|
-
return numeric ? leftNum > rightNum : leftStr > rightStr;
|
|
2572
|
-
case "<":
|
|
2573
|
-
return numeric ? leftNum < rightNum : leftStr < rightStr;
|
|
2574
|
-
case ">=":
|
|
2575
|
-
return numeric ? leftNum >= rightNum : leftStr >= rightStr;
|
|
2576
|
-
case "<=":
|
|
2577
|
-
return numeric ? leftNum <= rightNum : leftStr <= rightStr;
|
|
2578
|
-
}
|
|
2579
|
-
}
|
|
2580
|
-
|
|
2581
2374
|
// src/engine/pushDownNot.ts
|
|
2582
2375
|
function pushDownNot(expr) {
|
|
2583
2376
|
switch (expr.type) {
|
|
@@ -2627,6 +2420,10 @@ function negateOp(op) {
|
|
|
2627
2420
|
return "NOT_LIKE";
|
|
2628
2421
|
case "NOT_LIKE":
|
|
2629
2422
|
return "LIKE";
|
|
2423
|
+
case "KLIKE":
|
|
2424
|
+
return "NOT_KLIKE";
|
|
2425
|
+
case "NOT_KLIKE":
|
|
2426
|
+
return "KLIKE";
|
|
2630
2427
|
case "IN":
|
|
2631
2428
|
return "NOT_IN";
|
|
2632
2429
|
case "NOT_IN":
|
|
@@ -2641,6 +2438,9 @@ function likePatternHasWildcard(pattern) {
|
|
|
2641
2438
|
function isLike(where) {
|
|
2642
2439
|
return where.type === "BINARY" && (where.op === "LIKE" || where.op === "NOT_LIKE");
|
|
2643
2440
|
}
|
|
2441
|
+
function isKlike(where) {
|
|
2442
|
+
return where.type === "BINARY" && (where.op === "KLIKE" || where.op === "NOT_KLIKE");
|
|
2443
|
+
}
|
|
2644
2444
|
function whereHasLike(where) {
|
|
2645
2445
|
if (where === null) return false;
|
|
2646
2446
|
if (isLike(where)) return true;
|
|
@@ -2656,6 +2456,21 @@ function whereHasLike(where) {
|
|
|
2656
2456
|
return false;
|
|
2657
2457
|
}
|
|
2658
2458
|
}
|
|
2459
|
+
function whereHasKlike(where) {
|
|
2460
|
+
if (where === null) return false;
|
|
2461
|
+
if (isKlike(where)) return true;
|
|
2462
|
+
switch (where.type) {
|
|
2463
|
+
case "LOGICAL":
|
|
2464
|
+
return whereHasKlike(where.left) || whereHasKlike(where.right);
|
|
2465
|
+
case "NOT":
|
|
2466
|
+
case "GROUP":
|
|
2467
|
+
return whereHasKlike(where.expr);
|
|
2468
|
+
case "BINARY":
|
|
2469
|
+
case "NULL_CHECK":
|
|
2470
|
+
case "EXISTS":
|
|
2471
|
+
return false;
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2659
2474
|
|
|
2660
2475
|
// src/converter/whereToKintone.ts
|
|
2661
2476
|
function whereToKintone(expr) {
|
|
@@ -2704,6 +2519,10 @@ function convertOp(op) {
|
|
|
2704
2519
|
return "like";
|
|
2705
2520
|
case "NOT_LIKE":
|
|
2706
2521
|
return "not like";
|
|
2522
|
+
case "KLIKE":
|
|
2523
|
+
return "like";
|
|
2524
|
+
case "NOT_KLIKE":
|
|
2525
|
+
return "not like";
|
|
2707
2526
|
case "IN":
|
|
2708
2527
|
return "in";
|
|
2709
2528
|
case "NOT_IN":
|
|
@@ -3225,76 +3044,504 @@ function collectRequiredFieldsByTable(stmt) {
|
|
|
3225
3044
|
break;
|
|
3226
3045
|
}
|
|
3227
3046
|
}
|
|
3228
|
-
for (const join2 of stmt.joins) {
|
|
3229
|
-
addFieldRef(join2.on.left.field, join2.on.left.tableAlias, "where");
|
|
3230
|
-
addFieldRef(join2.on.right.field, join2.on.right.tableAlias, "where");
|
|
3231
|
-
}
|
|
3232
|
-
walkWhere(stmt.where, "where");
|
|
3233
|
-
for (const gk of stmt.groupBy) walkGroupByKey(gk);
|
|
3234
|
-
walkWhere(stmt.having, "having");
|
|
3235
|
-
for (const ob of stmt.orderBy) walkOrderByKey(ob.key);
|
|
3236
|
-
return states;
|
|
3237
|
-
}
|
|
3238
|
-
function collectSelectOutputNames(columns) {
|
|
3239
|
-
const names = /* @__PURE__ */ new Set();
|
|
3240
|
-
for (const col of columns) {
|
|
3241
|
-
if (col.type === "FIELD" && col.alias) {
|
|
3242
|
-
names.add(col.alias);
|
|
3243
|
-
continue;
|
|
3244
|
-
}
|
|
3245
|
-
if (col.type === "LITERAL_COL") {
|
|
3246
|
-
names.add(col.alias ?? `'${col.value}'`);
|
|
3247
|
-
continue;
|
|
3047
|
+
for (const join2 of stmt.joins) {
|
|
3048
|
+
addFieldRef(join2.on.left.field, join2.on.left.tableAlias, "where");
|
|
3049
|
+
addFieldRef(join2.on.right.field, join2.on.right.tableAlias, "where");
|
|
3050
|
+
}
|
|
3051
|
+
walkWhere(stmt.where, "where");
|
|
3052
|
+
for (const gk of stmt.groupBy) walkGroupByKey(gk);
|
|
3053
|
+
walkWhere(stmt.having, "having");
|
|
3054
|
+
for (const ob of stmt.orderBy) walkOrderByKey(ob.key);
|
|
3055
|
+
return states;
|
|
3056
|
+
}
|
|
3057
|
+
function collectSelectOutputNames(columns) {
|
|
3058
|
+
const names = /* @__PURE__ */ new Set();
|
|
3059
|
+
for (const col of columns) {
|
|
3060
|
+
if (col.type === "FIELD" && col.alias) {
|
|
3061
|
+
names.add(col.alias);
|
|
3062
|
+
continue;
|
|
3063
|
+
}
|
|
3064
|
+
if (col.type === "LITERAL_COL") {
|
|
3065
|
+
names.add(col.alias ?? `'${col.value}'`);
|
|
3066
|
+
continue;
|
|
3067
|
+
}
|
|
3068
|
+
if (col.type === "AGGREGATE") {
|
|
3069
|
+
if (col.alias) names.add(col.alias);
|
|
3070
|
+
else names.add(aggregateSyntheticName(col.func, col.distinct, col.arg));
|
|
3071
|
+
continue;
|
|
3072
|
+
}
|
|
3073
|
+
if (col.type === "ARITH_AGG_COL") {
|
|
3074
|
+
if (col.alias) names.add(col.alias);
|
|
3075
|
+
continue;
|
|
3076
|
+
}
|
|
3077
|
+
if (col.type === "ARITH_COL") {
|
|
3078
|
+
if (col.alias) names.add(col.alias);
|
|
3079
|
+
continue;
|
|
3080
|
+
}
|
|
3081
|
+
if (col.type === "CASE_COL") {
|
|
3082
|
+
names.add(col.alias ?? "case");
|
|
3083
|
+
continue;
|
|
3084
|
+
}
|
|
3085
|
+
if (col.type === "STRFUNC_COL") {
|
|
3086
|
+
if (col.alias) names.add(col.alias);
|
|
3087
|
+
continue;
|
|
3088
|
+
}
|
|
3089
|
+
if (col.type === "SCALAR_SUBQUERY_COL") {
|
|
3090
|
+
names.add(col.alias ?? "(subquery)");
|
|
3091
|
+
}
|
|
3092
|
+
}
|
|
3093
|
+
return names;
|
|
3094
|
+
}
|
|
3095
|
+
function aggregateSyntheticName(func, distinct, arg) {
|
|
3096
|
+
const argStr = arg.type === "WILDCARD" ? "*" : arithNodeLabel(arg);
|
|
3097
|
+
return distinct ? `${func}(DISTINCT ${argStr})` : `${func}(${argStr})`;
|
|
3098
|
+
}
|
|
3099
|
+
function arithNodeLabel(node) {
|
|
3100
|
+
if (node.type === "FIELD_REF") return node.field;
|
|
3101
|
+
if (node.type === "NUMBER") return String(node.value);
|
|
3102
|
+
if (node.type === "STRING_FUNC") return stringFuncLabel(node);
|
|
3103
|
+
return `(${arithNodeLabel(node.left)}${node.op}${arithNodeLabel(node.right)})`;
|
|
3104
|
+
}
|
|
3105
|
+
function stringFuncLabel(expr) {
|
|
3106
|
+
const args = expr.args.map((a) => {
|
|
3107
|
+
if (a.type === "STRING") return `'${a.value}'`;
|
|
3108
|
+
if (a.type === "STRING_FUNC") return stringFuncLabel(a);
|
|
3109
|
+
if (a.type === "AGG_REF") return aggregateSyntheticName(a.func, a.distinct, a.arg);
|
|
3110
|
+
if (a.type === "AGG_ARITH") return "agg_arith";
|
|
3111
|
+
return arithNodeLabel(a);
|
|
3112
|
+
});
|
|
3113
|
+
return `${expr.func}(${args.join(",")})`;
|
|
3114
|
+
}
|
|
3115
|
+
function isAggregateSyntheticName(name) {
|
|
3116
|
+
return /^(COUNT|SUM|AVG|MAX|MIN)\(/i.test(name);
|
|
3117
|
+
}
|
|
3118
|
+
|
|
3119
|
+
// src/core/klikeValidation.ts
|
|
3120
|
+
var KlikeValidationError = class extends Error {
|
|
3121
|
+
constructor(message) {
|
|
3122
|
+
super(`ArgumentError: ${message}`);
|
|
3123
|
+
this.name = "ArgumentError";
|
|
3124
|
+
}
|
|
3125
|
+
};
|
|
3126
|
+
function validateKlikeStatement(stmt) {
|
|
3127
|
+
validateStatement(stmt);
|
|
3128
|
+
}
|
|
3129
|
+
function validateStatement(stmt) {
|
|
3130
|
+
switch (stmt.type) {
|
|
3131
|
+
case "SELECT":
|
|
3132
|
+
validateSelect(stmt);
|
|
3133
|
+
return;
|
|
3134
|
+
case "UNION":
|
|
3135
|
+
validateUnion(stmt);
|
|
3136
|
+
return;
|
|
3137
|
+
case "WITH":
|
|
3138
|
+
validateWith(stmt);
|
|
3139
|
+
return;
|
|
3140
|
+
case "EXPLAIN":
|
|
3141
|
+
validateStatement(stmt.query);
|
|
3142
|
+
return;
|
|
3143
|
+
case "CREATE_TEMP_TABLE":
|
|
3144
|
+
validateSelectLike(stmt.query);
|
|
3145
|
+
return;
|
|
3146
|
+
case "SET_VARIABLE":
|
|
3147
|
+
case "DECLARE_VARIABLE":
|
|
3148
|
+
case "ASSERT":
|
|
3149
|
+
validateNestedSelects(stmt);
|
|
3150
|
+
return;
|
|
3151
|
+
case "INSERT":
|
|
3152
|
+
case "INSERT_SELECT":
|
|
3153
|
+
case "UPSERT":
|
|
3154
|
+
case "UPSERT_SELECT":
|
|
3155
|
+
case "UPDATE":
|
|
3156
|
+
case "DELETE":
|
|
3157
|
+
case "REORDER":
|
|
3158
|
+
if (containsKlike(stmt)) {
|
|
3159
|
+
throw new KlikeValidationError(
|
|
3160
|
+
"KLIKE / NOT KLIKE \u306F v1 \u3067\u306F\u5168 DML\uFF08UPDATE / DELETE / INSERT / UPSERT / REORDER\uFF09\u3067\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093"
|
|
3161
|
+
);
|
|
3162
|
+
}
|
|
3163
|
+
return;
|
|
3164
|
+
case "SHOW_APPS":
|
|
3165
|
+
case "DESCRIBE":
|
|
3166
|
+
case "DROP_TEMP_TABLE":
|
|
3167
|
+
return;
|
|
3168
|
+
}
|
|
3169
|
+
}
|
|
3170
|
+
function validateSelectLike(query) {
|
|
3171
|
+
if (query.type === "SELECT") validateSelect(query);
|
|
3172
|
+
else if (query.type === "UNION") validateUnion(query);
|
|
3173
|
+
else validateWith(query);
|
|
3174
|
+
}
|
|
3175
|
+
function validateUnion(stmt) {
|
|
3176
|
+
validateSelectLike(stmt.left);
|
|
3177
|
+
validateSelect(stmt.right);
|
|
3178
|
+
}
|
|
3179
|
+
function validateWith(stmt) {
|
|
3180
|
+
const inlined = buildEffectiveInlineSelect(stmt);
|
|
3181
|
+
if (inlined !== null) {
|
|
3182
|
+
validateSelect(inlined);
|
|
3183
|
+
return;
|
|
3184
|
+
}
|
|
3185
|
+
for (const cte of stmt.ctes) {
|
|
3186
|
+
if (cte.query.type === "SELECT") validateSelect(cte.query);
|
|
3187
|
+
else if (cte.query.type === "UNION") validateUnion(cte.query);
|
|
3188
|
+
}
|
|
3189
|
+
validateSelectLike(stmt.query);
|
|
3190
|
+
}
|
|
3191
|
+
function validateSelect(stmt) {
|
|
3192
|
+
validateOwnKlikeExpressions(stmt);
|
|
3193
|
+
if (whereHasKlike(stmt.where)) {
|
|
3194
|
+
const inMemorySource = stmt.from.cteName !== null || stmt.joins.some((join2) => join2.table.cteName !== null);
|
|
3195
|
+
if (inMemorySource || resolveSelectMode(stmt) === "FULL_SCAN") {
|
|
3196
|
+
throw new KlikeValidationError(
|
|
3197
|
+
"KLIKE / NOT KLIKE \u306F kintone \u3078\u62BC\u3057\u4E0B\u3052\u308B SIMPLE SELECT \u3067\u306E\u307F\u4F7F\u7528\u3067\u304D\u307E\u3059\u3002\u3053\u306E SELECT \u306F FULL_SCAN \u306B\u306A\u308A\u307E\u3059"
|
|
3198
|
+
);
|
|
3199
|
+
}
|
|
3200
|
+
}
|
|
3201
|
+
validateNestedSelects(stmt);
|
|
3202
|
+
}
|
|
3203
|
+
function validateOwnKlikeExpressions(stmt) {
|
|
3204
|
+
walkWithoutNestedSelects(stmt, (where) => {
|
|
3205
|
+
if (!isKlike(where)) return;
|
|
3206
|
+
if (!isDescendantOf(stmt.where, where)) {
|
|
3207
|
+
throw new KlikeValidationError("KLIKE / NOT KLIKE \u306F SELECT \u306E WHERE \u53E5\u3067\u306E\u307F\u4F7F\u7528\u3067\u304D\u307E\u3059");
|
|
3208
|
+
}
|
|
3209
|
+
const right = where.right;
|
|
3210
|
+
if (right.type !== "STRING" && right.type !== "VARIABLE") {
|
|
3211
|
+
throw new KlikeValidationError(
|
|
3212
|
+
"KLIKE / NOT KLIKE \u306E\u53F3\u8FBA\u306B\u306F\u6587\u5B57\u5217\u30EA\u30C6\u30E9\u30EB\u307E\u305F\u306F\u6587\u5B57\u5217\u30D0\u30C3\u30C1\u5909\u6570\u304C\u5FC5\u8981\u3067\u3059"
|
|
3213
|
+
);
|
|
3214
|
+
}
|
|
3215
|
+
if (right.type === "STRING" && right.value.includes("%")) {
|
|
3216
|
+
throw new KlikeValidationError(
|
|
3217
|
+
"KLIKE / NOT KLIKE \u306E\u691C\u7D22\u8A9E\u306B % \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002SQL \u30EF\u30A4\u30EB\u30C9\u30AB\u30FC\u30C9\u691C\u7D22\u306B\u306F LIKE \u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044"
|
|
3218
|
+
);
|
|
3219
|
+
}
|
|
3220
|
+
});
|
|
3221
|
+
}
|
|
3222
|
+
function validateNestedSelects(node) {
|
|
3223
|
+
walkObjects(node, (obj) => {
|
|
3224
|
+
if (obj.type === "SELECT") validateSelect(obj);
|
|
3225
|
+
}, true);
|
|
3226
|
+
}
|
|
3227
|
+
function buildEffectiveInlineSelect(stmt) {
|
|
3228
|
+
if (stmt.ctes.length !== 1) return null;
|
|
3229
|
+
const cte = stmt.ctes[0];
|
|
3230
|
+
if (cte.query.type !== "SELECT" || resolveSelectMode(cte.query) !== "SIMPLE") return null;
|
|
3231
|
+
if (stmt.query.type !== "SELECT") return null;
|
|
3232
|
+
const final = stmt.query;
|
|
3233
|
+
if (final.from.cteName !== cte.name || final.joins.length > 0) return null;
|
|
3234
|
+
if (final.groupBy.length > 0 || final.distinct) return null;
|
|
3235
|
+
if (final.columns.some(
|
|
3236
|
+
(column) => column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL"
|
|
3237
|
+
)) return null;
|
|
3238
|
+
const where = cte.query.where === null ? final.where : final.where === null ? cte.query.where : { type: "LOGICAL", op: "AND", left: cte.query.where, right: final.where };
|
|
3239
|
+
const columns = final.columns.every((column) => column.type === "WILDCARD") ? cte.query.columns : final.columns;
|
|
3240
|
+
return {
|
|
3241
|
+
type: "SELECT",
|
|
3242
|
+
from: cte.query.from,
|
|
3243
|
+
joins: [],
|
|
3244
|
+
columns,
|
|
3245
|
+
where,
|
|
3246
|
+
groupBy: [],
|
|
3247
|
+
having: null,
|
|
3248
|
+
orderBy: final.orderBy.length > 0 ? final.orderBy : cte.query.orderBy,
|
|
3249
|
+
limit: final.limit ?? cte.query.limit,
|
|
3250
|
+
offset: final.offset ?? cte.query.offset,
|
|
3251
|
+
distinct: false
|
|
3252
|
+
};
|
|
3253
|
+
}
|
|
3254
|
+
function containsKlike(node) {
|
|
3255
|
+
let found = false;
|
|
3256
|
+
walkObjects(node, (obj) => {
|
|
3257
|
+
if (obj.type === "BINARY" && (obj.op === "KLIKE" || obj.op === "NOT_KLIKE")) found = true;
|
|
3258
|
+
});
|
|
3259
|
+
return found;
|
|
3260
|
+
}
|
|
3261
|
+
function isDescendantOf(root, target) {
|
|
3262
|
+
if (root === null) return false;
|
|
3263
|
+
if (root === target) return true;
|
|
3264
|
+
switch (root.type) {
|
|
3265
|
+
case "LOGICAL":
|
|
3266
|
+
return isDescendantOf(root.left, target) || isDescendantOf(root.right, target);
|
|
3267
|
+
case "NOT":
|
|
3268
|
+
case "GROUP":
|
|
3269
|
+
return isDescendantOf(root.expr, target);
|
|
3270
|
+
case "BINARY":
|
|
3271
|
+
case "NULL_CHECK":
|
|
3272
|
+
case "EXISTS":
|
|
3273
|
+
return false;
|
|
3274
|
+
}
|
|
3275
|
+
}
|
|
3276
|
+
function walkWithoutNestedSelects(node, visitWhere) {
|
|
3277
|
+
if (Array.isArray(node)) {
|
|
3278
|
+
for (const value of node) walkWithoutNestedSelects(value, visitWhere);
|
|
3279
|
+
return;
|
|
3280
|
+
}
|
|
3281
|
+
if (node === null || typeof node !== "object") return;
|
|
3282
|
+
const obj = node;
|
|
3283
|
+
if (obj.type === "BINARY" || obj.type === "NULL_CHECK" || obj.type === "LOGICAL" || obj.type === "NOT" || obj.type === "GROUP" || obj.type === "EXISTS") {
|
|
3284
|
+
visitWhere(obj);
|
|
3285
|
+
}
|
|
3286
|
+
for (const value of Object.values(obj)) {
|
|
3287
|
+
if (value !== node && isSelectObject(value)) continue;
|
|
3288
|
+
walkWithoutNestedSelects(value, visitWhere);
|
|
3289
|
+
}
|
|
3290
|
+
}
|
|
3291
|
+
function walkObjects(node, visit, skipRoot = false) {
|
|
3292
|
+
if (Array.isArray(node)) {
|
|
3293
|
+
for (const value of node) walkObjects(value, visit);
|
|
3294
|
+
return;
|
|
3295
|
+
}
|
|
3296
|
+
if (node === null || typeof node !== "object") return;
|
|
3297
|
+
const obj = node;
|
|
3298
|
+
if (!skipRoot) visit(obj);
|
|
3299
|
+
for (const value of Object.values(obj)) walkObjects(value, visit);
|
|
3300
|
+
}
|
|
3301
|
+
function isSelectObject(value) {
|
|
3302
|
+
return value !== null && typeof value === "object" && value.type === "SELECT";
|
|
3303
|
+
}
|
|
3304
|
+
|
|
3305
|
+
// src/core/batch.ts
|
|
3306
|
+
var MAX_TEMP_TABLES = 16;
|
|
3307
|
+
var MAX_BATCH_VARIABLES = 64;
|
|
3308
|
+
var BatchAnalysisError = class extends Error {
|
|
3309
|
+
constructor(message, statementIndex) {
|
|
3310
|
+
super(message);
|
|
3311
|
+
this.statementIndex = statementIndex;
|
|
3312
|
+
}
|
|
3313
|
+
};
|
|
3314
|
+
function collectRefs(node, tempRefs, appIds) {
|
|
3315
|
+
if (Array.isArray(node)) {
|
|
3316
|
+
for (const v of node) collectRefs(v, tempRefs, appIds);
|
|
3317
|
+
return;
|
|
3318
|
+
}
|
|
3319
|
+
if (node !== null && typeof node === "object") {
|
|
3320
|
+
const obj = node;
|
|
3321
|
+
const cte = obj["cteName"];
|
|
3322
|
+
if (typeof cte === "string" && cte.startsWith("#")) tempRefs.add(cte);
|
|
3323
|
+
const appId = obj["appId"];
|
|
3324
|
+
if (typeof appId === "number" && appId > 0) appIds.add(appId);
|
|
3325
|
+
for (const v of Object.values(obj)) collectRefs(v, tempRefs, appIds);
|
|
3326
|
+
}
|
|
3327
|
+
}
|
|
3328
|
+
function collectVariableRefs(node, refs) {
|
|
3329
|
+
if (Array.isArray(node)) {
|
|
3330
|
+
for (const v of node) collectVariableRefs(v, refs);
|
|
3331
|
+
return;
|
|
3332
|
+
}
|
|
3333
|
+
if (node !== null && typeof node === "object") {
|
|
3334
|
+
const obj = node;
|
|
3335
|
+
if (obj["type"] === "VARIABLE" && typeof obj["name"] === "string") {
|
|
3336
|
+
refs.add(obj["name"]);
|
|
3337
|
+
return;
|
|
3338
|
+
}
|
|
3339
|
+
for (const v of Object.values(obj)) collectVariableRefs(v, refs);
|
|
3340
|
+
}
|
|
3341
|
+
}
|
|
3342
|
+
function analyzeBatch(statements) {
|
|
3343
|
+
if (statements.length === 0) {
|
|
3344
|
+
throw new BatchAnalysisError("ArgumentError: SQL is empty.", 0);
|
|
3345
|
+
}
|
|
3346
|
+
statements.forEach((stmt, index) => {
|
|
3347
|
+
try {
|
|
3348
|
+
validateKlikeStatement(stmt);
|
|
3349
|
+
} catch (error) {
|
|
3350
|
+
if (error instanceof KlikeValidationError) {
|
|
3351
|
+
throw new BatchAnalysisError(error.message, index);
|
|
3352
|
+
}
|
|
3353
|
+
throw error;
|
|
3354
|
+
}
|
|
3355
|
+
});
|
|
3356
|
+
if (statements.length === 1) {
|
|
3357
|
+
const t = statements[0].type;
|
|
3358
|
+
if (t === "SET_VARIABLE" || t === "DECLARE_VARIABLE") {
|
|
3359
|
+
const verb = t === "SET_VARIABLE" ? "SET" : "DECLARE";
|
|
3360
|
+
throw new BatchAnalysisError(`ArgumentError: ${verb} variable requires a batch.`, 0);
|
|
3361
|
+
}
|
|
3362
|
+
if (t === "CREATE_TEMP_TABLE" || t === "DROP_TEMP_TABLE") {
|
|
3363
|
+
const verb = t === "CREATE_TEMP_TABLE" ? "CREATE TEMP TABLE" : "DROP TEMP TABLE";
|
|
3364
|
+
throw new BatchAnalysisError(
|
|
3365
|
+
`ArgumentError: ${verb} requires a batch (temp tables are batch-scoped).`,
|
|
3366
|
+
0
|
|
3367
|
+
);
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3370
|
+
const defined = /* @__PURE__ */ new Map();
|
|
3371
|
+
const createdOrder = [];
|
|
3372
|
+
const results = [];
|
|
3373
|
+
const variableDefs = /* @__PURE__ */ new Map();
|
|
3374
|
+
const variableOrder = [];
|
|
3375
|
+
statements.forEach((stmt, index) => {
|
|
3376
|
+
const statementType = getStatementType(stmt);
|
|
3377
|
+
const created = [];
|
|
3378
|
+
const dropped = [];
|
|
3379
|
+
const refs = /* @__PURE__ */ new Set();
|
|
3380
|
+
const stmtAppIds = /* @__PURE__ */ new Set();
|
|
3381
|
+
const dependsOn = /* @__PURE__ */ new Set();
|
|
3382
|
+
const variableRefs = /* @__PURE__ */ new Set();
|
|
3383
|
+
collectVariableRefs(stmt, variableRefs);
|
|
3384
|
+
for (const name of variableRefs) {
|
|
3385
|
+
const def = variableDefs.get(name);
|
|
3386
|
+
if (def === void 0) {
|
|
3387
|
+
throw new BatchAnalysisError(
|
|
3388
|
+
`ParseError: variable @${name} is not defined before statement ${index + 1}.`,
|
|
3389
|
+
index
|
|
3390
|
+
);
|
|
3391
|
+
}
|
|
3392
|
+
def.referencedBy.push(index);
|
|
3248
3393
|
}
|
|
3249
|
-
if (
|
|
3250
|
-
if (
|
|
3251
|
-
|
|
3252
|
-
|
|
3394
|
+
if (stmt.type === "SET_VARIABLE" || stmt.type === "DECLARE_VARIABLE") {
|
|
3395
|
+
if (variableDefs.has(stmt.name)) {
|
|
3396
|
+
throw new BatchAnalysisError(`ParseError: variable @${stmt.name} is already defined.`, index);
|
|
3397
|
+
}
|
|
3398
|
+
variableDefs.set(stmt.name, { index, referencedBy: [] });
|
|
3399
|
+
variableOrder.push(stmt.name);
|
|
3400
|
+
if (variableOrder.length > MAX_BATCH_VARIABLES) {
|
|
3401
|
+
throw new BatchAnalysisError(
|
|
3402
|
+
`ParseError: batch exceeds ${MAX_BATCH_VARIABLES} variables.`,
|
|
3403
|
+
index
|
|
3404
|
+
);
|
|
3405
|
+
}
|
|
3253
3406
|
}
|
|
3254
|
-
if (
|
|
3255
|
-
|
|
3256
|
-
|
|
3407
|
+
if (stmt.type === "CREATE_TEMP_TABLE") {
|
|
3408
|
+
collectRefs(stmt.query, refs, stmtAppIds);
|
|
3409
|
+
} else if (stmt.type === "DROP_TEMP_TABLE") {
|
|
3410
|
+
} else {
|
|
3411
|
+
collectRefs(stmt, refs, stmtAppIds);
|
|
3257
3412
|
}
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3413
|
+
let tempOnlySource = false;
|
|
3414
|
+
if (stmt.type === "INSERT_SELECT" || stmt.type === "UPSERT_SELECT") {
|
|
3415
|
+
const srcTemp = /* @__PURE__ */ new Set();
|
|
3416
|
+
const srcApps = /* @__PURE__ */ new Set();
|
|
3417
|
+
collectRefs(stmt.select, srcTemp, srcApps);
|
|
3418
|
+
tempOnlySource = srcTemp.size > 0 && srcApps.size === 0;
|
|
3261
3419
|
}
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3420
|
+
for (const name of refs) {
|
|
3421
|
+
const at = defined.get(name);
|
|
3422
|
+
if (at === void 0) {
|
|
3423
|
+
throw new BatchAnalysisError(
|
|
3424
|
+
`ParseError: temp table ${name} is not defined in this batch.`,
|
|
3425
|
+
index
|
|
3426
|
+
);
|
|
3427
|
+
}
|
|
3428
|
+
dependsOn.add(at);
|
|
3265
3429
|
}
|
|
3266
|
-
if (
|
|
3267
|
-
if (
|
|
3268
|
-
|
|
3430
|
+
if (stmt.type === "CREATE_TEMP_TABLE") {
|
|
3431
|
+
if (defined.has(stmt.name)) {
|
|
3432
|
+
throw new BatchAnalysisError(
|
|
3433
|
+
`ParseError: temp table ${stmt.name} is already defined.`,
|
|
3434
|
+
index
|
|
3435
|
+
);
|
|
3436
|
+
}
|
|
3437
|
+
defined.set(stmt.name, index);
|
|
3438
|
+
createdOrder.push(stmt.name);
|
|
3439
|
+
created.push(stmt.name);
|
|
3440
|
+
if (defined.size > MAX_TEMP_TABLES) {
|
|
3441
|
+
throw new BatchAnalysisError(
|
|
3442
|
+
`ParseError: batch exceeds ${MAX_TEMP_TABLES} temp tables.`,
|
|
3443
|
+
index
|
|
3444
|
+
);
|
|
3445
|
+
}
|
|
3269
3446
|
}
|
|
3270
|
-
if (
|
|
3271
|
-
|
|
3447
|
+
if (stmt.type === "DROP_TEMP_TABLE") {
|
|
3448
|
+
const at = defined.get(stmt.name);
|
|
3449
|
+
if (at === void 0) {
|
|
3450
|
+
throw new BatchAnalysisError(
|
|
3451
|
+
`ParseError: temp table ${stmt.name} is not defined in this batch.`,
|
|
3452
|
+
index
|
|
3453
|
+
);
|
|
3454
|
+
}
|
|
3455
|
+
dependsOn.add(at);
|
|
3456
|
+
dropped.push(stmt.name);
|
|
3457
|
+
defined.delete(stmt.name);
|
|
3272
3458
|
}
|
|
3273
|
-
|
|
3274
|
-
|
|
3459
|
+
results.push({
|
|
3460
|
+
index,
|
|
3461
|
+
statementType,
|
|
3462
|
+
isDml: isDmlType(statementType),
|
|
3463
|
+
isReadOnly: isReadOnlyType(statementType),
|
|
3464
|
+
hasWhere: hasWhereClause(stmt),
|
|
3465
|
+
insertValuesCount: getInsertValuesCount(stmt),
|
|
3466
|
+
appIds: [...stmtAppIds].sort((a, b) => a - b),
|
|
3467
|
+
tempTablesCreated: created,
|
|
3468
|
+
tempTablesReferenced: [...refs],
|
|
3469
|
+
tempTablesDropped: dropped,
|
|
3470
|
+
dependsOn: [...dependsOn].sort((a, b) => a - b),
|
|
3471
|
+
tempOnlySource,
|
|
3472
|
+
targetAppId: isDmlType(statementType) && typeof stmt.appId === "number" ? stmt.appId : null
|
|
3473
|
+
});
|
|
3474
|
+
});
|
|
3475
|
+
const containsDml = results.some((r) => r.isDml);
|
|
3476
|
+
const variables = variableOrder.map((name) => ({
|
|
3477
|
+
name,
|
|
3478
|
+
referencedBy: [...variableDefs.get(name).referencedBy]
|
|
3479
|
+
}));
|
|
3480
|
+
return {
|
|
3481
|
+
statementCount: statements.length,
|
|
3482
|
+
isReadOnlyBatch: !containsDml && results.every((r) => r.isReadOnly),
|
|
3483
|
+
containsDml,
|
|
3484
|
+
tempTables: createdOrder,
|
|
3485
|
+
variables,
|
|
3486
|
+
warnings: variables.filter((v) => v.referencedBy.length === 0).map((v) => `variable @${v.name} is never used.`),
|
|
3487
|
+
statements: results
|
|
3488
|
+
};
|
|
3275
3489
|
}
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3490
|
+
|
|
3491
|
+
// src/core/batchVariables.ts
|
|
3492
|
+
var VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;
|
|
3493
|
+
function normalizeBatchVariableName(name) {
|
|
3494
|
+
if (!VARIABLE_NAME_RE.test(name)) {
|
|
3495
|
+
throw new Error(
|
|
3496
|
+
`ArgumentError: invalid variable name "${name}". Use a name without @ matching [A-Za-z_][A-Za-z0-9_]{0,63}.`
|
|
3497
|
+
);
|
|
3498
|
+
}
|
|
3499
|
+
return name.toLowerCase();
|
|
3279
3500
|
}
|
|
3280
|
-
function
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3501
|
+
function normalizeBatchVariables(input) {
|
|
3502
|
+
const normalized = /* @__PURE__ */ Object.create(null);
|
|
3503
|
+
for (const [rawName, value] of Object.entries(input ?? {})) {
|
|
3504
|
+
const name = normalizeBatchVariableName(rawName);
|
|
3505
|
+
if (Object.prototype.hasOwnProperty.call(normalized, name)) {
|
|
3506
|
+
throw new Error(`ArgumentError: variable "${rawName}" is specified more than once.`);
|
|
3507
|
+
}
|
|
3508
|
+
normalized[name] = value;
|
|
3509
|
+
}
|
|
3510
|
+
return normalized;
|
|
3285
3511
|
}
|
|
3286
|
-
function
|
|
3287
|
-
const
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3512
|
+
function validateDeclaredBatchVariables(statements, input) {
|
|
3513
|
+
const normalized = normalizeBatchVariables(input);
|
|
3514
|
+
const declared = new Set(
|
|
3515
|
+
statements.filter((stmt) => stmt.type === "DECLARE_VARIABLE").map((stmt) => stmt.name)
|
|
3516
|
+
);
|
|
3517
|
+
for (const name of Object.keys(normalized)) {
|
|
3518
|
+
if (!declared.has(name)) {
|
|
3519
|
+
throw new Error(`ArgumentError: injected variable @${name} is not declared.`);
|
|
3520
|
+
}
|
|
3521
|
+
}
|
|
3522
|
+
return normalized;
|
|
3295
3523
|
}
|
|
3296
|
-
|
|
3297
|
-
|
|
3524
|
+
|
|
3525
|
+
// src/core/scalarCompare.ts
|
|
3526
|
+
function compareScalarValues(op, leftStr, rightStr) {
|
|
3527
|
+
if (op === "=") return leftStr === rightStr;
|
|
3528
|
+
if (op === "!=" || op === "<>") return leftStr !== rightStr;
|
|
3529
|
+
const rightNum = Number(rightStr);
|
|
3530
|
+
if (leftStr === "" && rightStr !== "" && Number.isFinite(rightNum)) {
|
|
3531
|
+
return op === "<" || op === "<=";
|
|
3532
|
+
}
|
|
3533
|
+
const leftNum = Number(leftStr);
|
|
3534
|
+
const numeric = !Number.isNaN(leftNum) && !Number.isNaN(rightNum);
|
|
3535
|
+
switch (op) {
|
|
3536
|
+
case ">":
|
|
3537
|
+
return numeric ? leftNum > rightNum : leftStr > rightStr;
|
|
3538
|
+
case "<":
|
|
3539
|
+
return numeric ? leftNum < rightNum : leftStr < rightStr;
|
|
3540
|
+
case ">=":
|
|
3541
|
+
return numeric ? leftNum >= rightNum : leftStr >= rightStr;
|
|
3542
|
+
case "<=":
|
|
3543
|
+
return numeric ? leftNum <= rightNum : leftStr <= rightStr;
|
|
3544
|
+
}
|
|
3298
3545
|
}
|
|
3299
3546
|
|
|
3300
3547
|
// src/engine/evalFunc.ts
|
|
@@ -3553,6 +3800,9 @@ function evalOp(op, leftStr, right, row, fieldType, resolveFieldType) {
|
|
|
3553
3800
|
const pattern = resolveValue(right, row, resolveFieldType);
|
|
3554
3801
|
return !matchLike(leftStr, pattern);
|
|
3555
3802
|
}
|
|
3803
|
+
if (op === "KLIKE" || op === "NOT_KLIKE") {
|
|
3804
|
+
throw new Error("KLIKE / NOT KLIKE \u306F JavaScript \u5074\u3067\u306F\u8A55\u4FA1\u3067\u304D\u307E\u305B\u3093\uFF08SIMPLE SELECT \u3067\u306E\u307F\u4F7F\u7528\u3067\u304D\u307E\u3059\uFF09");
|
|
3805
|
+
}
|
|
3556
3806
|
const rightStr = resolveValue(right, row, resolveFieldType);
|
|
3557
3807
|
return compareScalarValues(op, leftStr, rightStr);
|
|
3558
3808
|
}
|
|
@@ -3708,6 +3958,11 @@ function matchLike(value, pattern) {
|
|
|
3708
3958
|
|
|
3709
3959
|
// src/converter/dmlToKintone.ts
|
|
3710
3960
|
function assertDmlWhereIsSafe(where) {
|
|
3961
|
+
if (whereHasKlike(where)) {
|
|
3962
|
+
throw new DmlConvertError(
|
|
3963
|
+
"UPDATE / DELETE \u306E WHERE \u306B KLIKE / NOT KLIKE \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002kintone \u30AD\u30FC\u30EF\u30FC\u30C9\u691C\u7D22\u306E\u6253\u3061\u5207\u308A\u3092\u691C\u51FA\u3067\u304D\u306A\u3044\u305F\u3081\u3001v1 \u3067\u306F\u5168 DML \u3067\u5B89\u5168\u4E0A\u62D2\u5426\u3057\u307E\u3057\u305F\u3002"
|
|
3964
|
+
);
|
|
3965
|
+
}
|
|
3711
3966
|
if (!whereHasLike(where)) return;
|
|
3712
3967
|
throw new DmlConvertError(
|
|
3713
3968
|
"UPDATE / DELETE \u306E WHERE \u306B LIKE / NOT LIKE \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002LIKE \u306F kSQL \u306E\u610F\u5473\u8AD6\u306B\u5F93\u3063\u3066 JS \u3067\u8A55\u4FA1\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u304C\u3001\u89AA\u30EC\u30B3\u30FC\u30C9 DML \u306B\u306F JS \u8A55\u4FA1\u7D4C\u8DEF\u304C\u306A\u3044\u305F\u3081\u3001\u5B89\u5168\u4E0A\u62D2\u5426\u3057\u307E\u3057\u305F\u3002SELECT \u3067\u5BFE\u8C61\u30EC\u30B3\u30FC\u30C9\u756A\u53F7\u3092\u78BA\u8A8D\u3057\u3001IN \u307E\u305F\u306F\u5B8C\u5168\u4E00\u81F4\u3067\u5BFE\u8C61\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
|
|
@@ -4236,7 +4491,8 @@ var SELECTION_IN_FIELD_TYPES = /* @__PURE__ */ new Set([
|
|
|
4236
4491
|
"DROP_DOWN",
|
|
4237
4492
|
"RADIO_BUTTON",
|
|
4238
4493
|
"CHECK_BOX",
|
|
4239
|
-
"MULTI_SELECT"
|
|
4494
|
+
"MULTI_SELECT",
|
|
4495
|
+
"STATUS"
|
|
4240
4496
|
]);
|
|
4241
4497
|
function isSelectionInComparison(expr, options) {
|
|
4242
4498
|
if (!isSelectionInCandidate(expr, options)) return false;
|
|
@@ -4887,6 +5143,7 @@ function createEmptyMetrics() {
|
|
|
4887
5143
|
deleteCalls: 0,
|
|
4888
5144
|
fieldCalls: 0,
|
|
4889
5145
|
appsCalls: 0,
|
|
5146
|
+
processStatusCalls: 0,
|
|
4890
5147
|
fetchedRows: 0,
|
|
4891
5148
|
elapsedMs: 0
|
|
4892
5149
|
};
|
|
@@ -4918,6 +5175,10 @@ function wrapClientWithMetrics(client, metrics) {
|
|
|
4918
5175
|
getFields: (appId) => {
|
|
4919
5176
|
metrics.fieldCalls += 1;
|
|
4920
5177
|
return client.getFields(appId);
|
|
5178
|
+
},
|
|
5179
|
+
getProcessStatuses: (appId) => {
|
|
5180
|
+
metrics.processStatusCalls += 1;
|
|
5181
|
+
return client.getProcessStatuses(appId);
|
|
4921
5182
|
}
|
|
4922
5183
|
};
|
|
4923
5184
|
}
|
|
@@ -4931,6 +5192,7 @@ async function executeParsedStatement(stmt, client, options, cacheContext) {
|
|
|
4931
5192
|
if (unresolved !== null) {
|
|
4932
5193
|
throw new Error(`ParseError: variable @${unresolved} is not defined in a batch.`);
|
|
4933
5194
|
}
|
|
5195
|
+
validateKlikeStatement(stmt);
|
|
4934
5196
|
switch (stmt.type) {
|
|
4935
5197
|
case "SELECT":
|
|
4936
5198
|
return executeSelect(stmt, client, options, cacheContext);
|
|
@@ -5067,6 +5329,7 @@ async function executeBatch(sql, client, options = {}) {
|
|
|
5067
5329
|
async function executeBatchStatement(stmt, info, client, options, cacheContext, tempTables, variables) {
|
|
5068
5330
|
if (stmt.type === "SET_VARIABLE") {
|
|
5069
5331
|
const resolvedStmt2 = resolveVariableRefs(stmt, variables);
|
|
5332
|
+
validateKlikeStatement(resolvedStmt2);
|
|
5070
5333
|
if (resolvedStmt2.expr.type === "SCALAR_SUBQUERY") {
|
|
5071
5334
|
try {
|
|
5072
5335
|
const value = await evaluateScalarSubquery(
|
|
@@ -5099,6 +5362,7 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
|
|
|
5099
5362
|
return {};
|
|
5100
5363
|
}
|
|
5101
5364
|
const resolvedStmt = resolveVariableRefs(stmt, variables);
|
|
5365
|
+
validateKlikeStatement(resolvedStmt);
|
|
5102
5366
|
if (resolvedStmt.type === "CREATE_TEMP_TABLE") {
|
|
5103
5367
|
const materializeOptions = {
|
|
5104
5368
|
...options,
|
|
@@ -5524,22 +5788,36 @@ function extractMainTypedPushdownCandidate(stmt) {
|
|
|
5524
5788
|
return extractTypedPushdownCandidates(stmt.where, { tableAlias: stmt.from.alias });
|
|
5525
5789
|
}
|
|
5526
5790
|
async function loadTypedPushdownMeta(stmt, client, cacheContext) {
|
|
5527
|
-
const
|
|
5528
|
-
|
|
5791
|
+
const candidatesByApp = /* @__PURE__ */ new Map();
|
|
5792
|
+
const addCandidate = (appId, candidate) => {
|
|
5793
|
+
if (candidate === null) return;
|
|
5794
|
+
const existing = candidatesByApp.get(appId);
|
|
5795
|
+
if (existing) existing.push(candidate);
|
|
5796
|
+
else candidatesByApp.set(appId, [candidate]);
|
|
5797
|
+
};
|
|
5798
|
+
addCandidate(stmt.from.appId, extractMainTypedPushdownCandidate(stmt));
|
|
5529
5799
|
if (stmt.where !== null) {
|
|
5530
5800
|
for (const join2 of stmt.joins) {
|
|
5531
5801
|
if (!join2.table.alias || join2.table.subtableCode || join2.table.cteName !== null) continue;
|
|
5532
5802
|
const candidate = extractTypedPushdownCandidates(stmt.where, {
|
|
5533
5803
|
tableAlias: join2.table.alias
|
|
5534
5804
|
});
|
|
5535
|
-
|
|
5805
|
+
addCandidate(join2.table.appId, candidate);
|
|
5536
5806
|
}
|
|
5537
5807
|
}
|
|
5538
|
-
const entries = await Promise.all([...
|
|
5808
|
+
const entries = await Promise.all([...candidatesByApp.entries()].map(async ([appId, candidates]) => {
|
|
5539
5809
|
const [fieldTypes, fieldOptions] = await Promise.all([
|
|
5540
5810
|
getFieldTypeMap(appId, client, cacheContext),
|
|
5541
5811
|
getFieldOptionSetMapByApp(appId, client, cacheContext)
|
|
5542
5812
|
]);
|
|
5813
|
+
const statusFields = collectCandidateFieldCodes(candidates).filter((fieldCode) => fieldTypes.get(fieldCode) === "STATUS");
|
|
5814
|
+
if (statusFields.length > 0) {
|
|
5815
|
+
const process2 = await getProcessStatusesCached(appId, client, cacheContext);
|
|
5816
|
+
if (process2.enable && process2.states.length > 0) {
|
|
5817
|
+
const states = new Set(process2.states);
|
|
5818
|
+
for (const fieldCode of statusFields) fieldOptions.set(fieldCode, states);
|
|
5819
|
+
}
|
|
5820
|
+
}
|
|
5543
5821
|
return [appId, fieldTypes, fieldOptions];
|
|
5544
5822
|
}));
|
|
5545
5823
|
return {
|
|
@@ -5547,6 +5825,23 @@ async function loadTypedPushdownMeta(stmt, client, cacheContext) {
|
|
|
5547
5825
|
fieldOptionsByApp: new Map(entries.map(([appId, , fieldOptions]) => [appId, fieldOptions]))
|
|
5548
5826
|
};
|
|
5549
5827
|
}
|
|
5828
|
+
function collectCandidateFieldCodes(candidates) {
|
|
5829
|
+
const fields = /* @__PURE__ */ new Set();
|
|
5830
|
+
const visit = (expr) => {
|
|
5831
|
+
if (expr.type === "BINARY") {
|
|
5832
|
+
if (expr.left.type === "FIELD") fields.add(expr.left.field);
|
|
5833
|
+
return;
|
|
5834
|
+
}
|
|
5835
|
+
if (expr.type === "LOGICAL") {
|
|
5836
|
+
visit(expr.left);
|
|
5837
|
+
visit(expr.right);
|
|
5838
|
+
return;
|
|
5839
|
+
}
|
|
5840
|
+
if (expr.type === "GROUP" || expr.type === "NOT") visit(expr.expr);
|
|
5841
|
+
};
|
|
5842
|
+
for (const candidate of candidates) visit(candidate);
|
|
5843
|
+
return [...fields];
|
|
5844
|
+
}
|
|
5550
5845
|
function collectTypedInFieldRefs(expr, out) {
|
|
5551
5846
|
if (expr === null) return;
|
|
5552
5847
|
switch (expr.type) {
|
|
@@ -6172,6 +6467,7 @@ var fieldTypeCache = /* @__PURE__ */ new Map();
|
|
|
6172
6467
|
var optionOrderCache = /* @__PURE__ */ new Map();
|
|
6173
6468
|
var sortKindCache = /* @__PURE__ */ new Map();
|
|
6174
6469
|
var fieldInfoCache = /* @__PURE__ */ new Map();
|
|
6470
|
+
var processStatusCache = /* @__PURE__ */ new Map();
|
|
6175
6471
|
function getScopedCacheValue(root, cacheContext, appId) {
|
|
6176
6472
|
return root.get(cacheContext)?.get(appId);
|
|
6177
6473
|
}
|
|
@@ -6193,6 +6489,13 @@ async function getFieldsCached(appId, client, cacheContext) {
|
|
|
6193
6489
|
setScopedCacheValue(fieldInfoCache, cacheContext, appId, loading);
|
|
6194
6490
|
return loading;
|
|
6195
6491
|
}
|
|
6492
|
+
async function getProcessStatusesCached(appId, client, cacheContext) {
|
|
6493
|
+
const cached = getScopedCacheValue(processStatusCache, cacheContext, appId);
|
|
6494
|
+
if (cached) return cached;
|
|
6495
|
+
const loading = client.getProcessStatuses(appId);
|
|
6496
|
+
setScopedCacheValue(processStatusCache, cacheContext, appId, loading);
|
|
6497
|
+
return loading;
|
|
6498
|
+
}
|
|
6196
6499
|
async function getFieldTypeMap(appId, client, cacheContext) {
|
|
6197
6500
|
const cached = getScopedCacheValue(fieldTypeCache, cacheContext, appId);
|
|
6198
6501
|
if (cached) return cached;
|
|
@@ -6928,7 +7231,9 @@ async function executeDescribe(stmt, client, cacheContext) {
|
|
|
6928
7231
|
function parseSql(sql) {
|
|
6929
7232
|
try {
|
|
6930
7233
|
const tokens = new Lexer(sql).tokenize();
|
|
6931
|
-
|
|
7234
|
+
const stmt = new Parser(tokens).parse();
|
|
7235
|
+
validateKlikeStatement(stmt);
|
|
7236
|
+
return stmt;
|
|
6932
7237
|
} catch (e) {
|
|
6933
7238
|
if (e instanceof LexError || e instanceof ParseError) {
|
|
6934
7239
|
throw e;
|
|
@@ -7039,6 +7344,7 @@ function buildBatchExplainPlans(sql, injectedVariables) {
|
|
|
7039
7344
|
statementCount: statements.length,
|
|
7040
7345
|
statements: statements.map((stmt, i) => {
|
|
7041
7346
|
const planStmt = stmt.type === "SET_VARIABLE" ? stmt.expr.type === "SCALAR_SUBQUERY" ? { ...stmt, expr: resolveVariableRefs(stmt.expr, variables) } : stmt : resolveVariableRefs(stmt, variables);
|
|
7347
|
+
validateKlikeStatement(planStmt);
|
|
7042
7348
|
const result = {
|
|
7043
7349
|
index: i,
|
|
7044
7350
|
type: analysis.statements[i].statementType,
|
|
@@ -7472,11 +7778,15 @@ var OperationCancelledError = class extends Error {
|
|
|
7472
7778
|
// src/core/sql.ts
|
|
7473
7779
|
function parseSqlStatement(sql) {
|
|
7474
7780
|
const tokens = new Lexer(sql).tokenize();
|
|
7475
|
-
|
|
7781
|
+
const stmt = new Parser(tokens).parse();
|
|
7782
|
+
validateKlikeStatement(stmt);
|
|
7783
|
+
return stmt;
|
|
7476
7784
|
}
|
|
7477
7785
|
function parseSqlStatements(sql) {
|
|
7478
7786
|
const tokens = new Lexer(sql).tokenize();
|
|
7479
|
-
|
|
7787
|
+
const statements = new Parser(tokens).parseStatements();
|
|
7788
|
+
statements.forEach(validateKlikeStatement);
|
|
7789
|
+
return statements;
|
|
7480
7790
|
}
|
|
7481
7791
|
|
|
7482
7792
|
// src/core/displayFormat.ts
|
|
@@ -7861,6 +8171,7 @@ function withRequestGate(client, gate) {
|
|
|
7861
8171
|
getRecords: (params) => gate.runReadOnly(() => client.getRecords(params)),
|
|
7862
8172
|
getApps: () => gate.runReadOnly(() => client.getApps()),
|
|
7863
8173
|
getFields: (appId) => gate.runReadOnly(() => client.getFields(appId)),
|
|
8174
|
+
getProcessStatuses: (appId) => gate.runReadOnly(() => client.getProcessStatuses(appId)),
|
|
7864
8175
|
postRecords: (params) => gate.runMutation(() => client.postRecords(params)),
|
|
7865
8176
|
putRecords: (params) => gate.runMutation(() => client.putRecords(params)),
|
|
7866
8177
|
deleteRecords: (params) => gate.runMutation(() => client.deleteRecords(params))
|
|
@@ -8095,6 +8406,16 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
|
8095
8406
|
appId
|
|
8096
8407
|
);
|
|
8097
8408
|
return flattenFormFieldProperties(res.properties);
|
|
8409
|
+
},
|
|
8410
|
+
async getProcessStatuses(appId) {
|
|
8411
|
+
const qs = new URLSearchParams();
|
|
8412
|
+
qs.set("app", String(appId));
|
|
8413
|
+
qs.set("lang", "user");
|
|
8414
|
+
const res = await requestJson(`${apiBasePath}/app/status.json?${qs.toString()}`, { method: "GET" }, appId);
|
|
8415
|
+
return {
|
|
8416
|
+
enable: res.enable,
|
|
8417
|
+
states: Object.values(res.states ?? {}).map((state) => state.name)
|
|
8418
|
+
};
|
|
8098
8419
|
}
|
|
8099
8420
|
};
|
|
8100
8421
|
}
|
|
@@ -9182,7 +9503,10 @@ function createDryRunClient() {
|
|
|
9182
9503
|
putRecords: notUsed,
|
|
9183
9504
|
deleteRecords: notUsed,
|
|
9184
9505
|
getApps: notUsed,
|
|
9185
|
-
getFields: notUsed
|
|
9506
|
+
getFields: notUsed,
|
|
9507
|
+
async getProcessStatuses() {
|
|
9508
|
+
return { enable: false, states: [] };
|
|
9509
|
+
}
|
|
9186
9510
|
};
|
|
9187
9511
|
}
|
|
9188
9512
|
async function runDiagnosticRecordGet(params) {
|
|
@@ -10199,6 +10523,13 @@ async function run() {
|
|
|
10199
10523
|
if (!routed) throw new Error(`AuthError: profile "${pName}" is not resolved for APP${appId}.`);
|
|
10200
10524
|
return routed.getFields(binding.appId);
|
|
10201
10525
|
},
|
|
10526
|
+
getProcessStatuses: (appId) => {
|
|
10527
|
+
const binding = appBindingByMappedApp.get(appId) ?? { appId, profile: profileName.toLowerCase() };
|
|
10528
|
+
const pName = binding.profile;
|
|
10529
|
+
const routed = profileClientMap.get(pName);
|
|
10530
|
+
if (!routed) throw new Error(`AuthError: profile "${pName}" is not resolved for APP${appId}.`);
|
|
10531
|
+
return routed.getProcessStatuses(binding.appId);
|
|
10532
|
+
},
|
|
10202
10533
|
getApps: () => defaultClient.getApps()
|
|
10203
10534
|
};
|
|
10204
10535
|
}
|