@rex0220/kintone-sql-tools 1.13.1 → 2.0.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 CHANGED
@@ -2407,6 +2407,29 @@ function negateOp(op) {
2407
2407
  }
2408
2408
  }
2409
2409
 
2410
+ // src/core/like.ts
2411
+ function likePatternHasWildcard(pattern) {
2412
+ return pattern.includes("%") || pattern.includes("_");
2413
+ }
2414
+ function isLike(where) {
2415
+ return where.type === "BINARY" && (where.op === "LIKE" || where.op === "NOT_LIKE");
2416
+ }
2417
+ function whereHasLike(where) {
2418
+ if (where === null) return false;
2419
+ if (isLike(where)) return true;
2420
+ switch (where.type) {
2421
+ case "LOGICAL":
2422
+ return whereHasLike(where.left) || whereHasLike(where.right);
2423
+ case "NOT":
2424
+ case "GROUP":
2425
+ return whereHasLike(where.expr);
2426
+ case "BINARY":
2427
+ case "NULL_CHECK":
2428
+ case "EXISTS":
2429
+ return false;
2430
+ }
2431
+ }
2432
+
2410
2433
  // src/converter/whereToKintone.ts
2411
2434
  function whereToKintone(expr) {
2412
2435
  switch (expr.type) {
@@ -2425,6 +2448,11 @@ function whereToKintone(expr) {
2425
2448
  }
2426
2449
  }
2427
2450
  function convertBinary(expr) {
2451
+ if (isLike(expr)) {
2452
+ throw new KintoneQueryError(
2453
+ "LIKE / NOT LIKE \u306F kintone \u30AF\u30A8\u30EA\u306B\u5909\u63DB\u3067\u304D\u307E\u305B\u3093\uFF08\u5E38\u306B JS \u8A55\u4FA1\u304C\u5FC5\u8981\u3067\u3059\uFF09"
2454
+ );
2455
+ }
2428
2456
  const left = convertField(expr.left);
2429
2457
  const op = convertOp(expr.op);
2430
2458
  const right = convertValue(expr.right, expr.op);
@@ -2550,22 +2578,22 @@ function resolveSelectMode(stmt) {
2550
2578
  if (stmt.columns.some(
2551
2579
  (c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "SCALAR_SUBQUERY_COL" || c.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr(c.expr)
2552
2580
  )) return "FULL_SCAN";
2553
- if (hasWhereFunc(stmt.where)) return "FULL_SCAN";
2581
+ if (whereRequiresJsEval(stmt.where)) return "FULL_SCAN";
2554
2582
  if (stmt.orderBy.some((o) => o.key.type !== "FIELD_NAME")) return "FULL_SCAN";
2555
2583
  return "SIMPLE";
2556
2584
  }
2557
- function hasWhereFunc(where) {
2585
+ function whereRequiresJsEval(where) {
2558
2586
  if (where === null) return false;
2559
2587
  switch (where.type) {
2560
2588
  case "BINARY":
2561
- return isFunc(where.left) || where.right.type === "ARITH_VALUE" || where.right.type === "CASE_VALUE" || where.right.type === "SUBQUERY_IN_LIST" || where.right.type === "SCALAR_SUBQUERY";
2589
+ return isFunc(where.left) || where.right.type === "ARITH_VALUE" || where.right.type === "CASE_VALUE" || where.right.type === "SUBQUERY_IN_LIST" || where.right.type === "SCALAR_SUBQUERY" || isLike(where);
2562
2590
  case "NULL_CHECK":
2563
2591
  return isFunc(where.field);
2564
2592
  case "LOGICAL":
2565
- return hasWhereFunc(where.left) || hasWhereFunc(where.right);
2593
+ return whereRequiresJsEval(where.left) || whereRequiresJsEval(where.right);
2566
2594
  case "NOT":
2567
2595
  case "GROUP":
2568
- return hasWhereFunc(where.expr);
2596
+ return whereRequiresJsEval(where.expr);
2569
2597
  case "EXISTS":
2570
2598
  return true;
2571
2599
  }
@@ -2601,7 +2629,7 @@ function selectToKintoneParams(stmt) {
2601
2629
  }
2602
2630
  function selectToFetchAllParams(stmt, appId) {
2603
2631
  const queryParts = [];
2604
- if (stmt.where !== null && stmt.joins.length === 0 && !hasWhereFunc(stmt.where)) {
2632
+ if (stmt.where !== null && stmt.joins.length === 0 && !whereRequiresJsEval(stmt.where)) {
2605
2633
  queryParts.push(whereToKintone(stmt.where));
2606
2634
  }
2607
2635
  return {
@@ -3339,6 +3367,8 @@ function resolveValue(value, row) {
3339
3367
  case "SCALAR_SUBQUERY":
3340
3368
  return value.resolved;
3341
3369
  case "ARITH_VALUE":
3370
+ if (value.expr.type === "FIELD_REF") return resolveFieldRef(row, value.expr.field);
3371
+ if (value.expr.type === "STRING_FUNC") return evalStringFunc(value.expr, row);
3342
3372
  return String(evalArithExpr(value.expr, row));
3343
3373
  case "CASE_VALUE":
3344
3374
  return evalCaseWhen(value.expr, row);
@@ -3382,7 +3412,7 @@ function resolveKintoneFunc(name) {
3382
3412
  var likeRegexCache = /* @__PURE__ */ new Map();
3383
3413
  var LIKE_REGEX_CACHE_MAX = 200;
3384
3414
  function matchLike(value, pattern) {
3385
- if (!pattern.includes("%") && !pattern.includes("_")) {
3415
+ if (!likePatternHasWildcard(pattern)) {
3386
3416
  return value.includes(pattern);
3387
3417
  }
3388
3418
  let regex = likeRegexCache.get(pattern);
@@ -3407,6 +3437,12 @@ function matchLike(value, pattern) {
3407
3437
  }
3408
3438
 
3409
3439
  // src/converter/dmlToKintone.ts
3440
+ function assertDmlWhereIsSafe(where) {
3441
+ if (!whereHasLike(where)) return;
3442
+ throw new DmlConvertError(
3443
+ "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"
3444
+ );
3445
+ }
3410
3446
  var USER_TYPES = /* @__PURE__ */ new Set(["USER_SELECT", "ORGANIZATION_SELECT", "GROUP_SELECT"]);
3411
3447
  var ARRAY_TYPES = /* @__PURE__ */ new Set(["CHECK_BOX", "MULTI_SELECT"]);
3412
3448
  function insertToPostBatches(stmt, fieldTypes = /* @__PURE__ */ new Map()) {
@@ -3431,6 +3467,7 @@ function buildInsertRecord(fields, row, fieldTypes) {
3431
3467
  return record;
3432
3468
  }
3433
3469
  function updateToGetQuery(stmt) {
3470
+ assertDmlWhereIsSafe(stmt.where);
3434
3471
  return {
3435
3472
  app: stmt.appId,
3436
3473
  query: whereToKintone(stmt.where),
@@ -3459,6 +3496,7 @@ function hasArithAssignment(stmt) {
3459
3496
  );
3460
3497
  }
3461
3498
  function updateToGetQueryForArith(stmt) {
3499
+ assertDmlWhereIsSafe(stmt.where);
3462
3500
  const refFields = /* @__PURE__ */ new Set();
3463
3501
  for (const { value } of stmt.assignments) {
3464
3502
  if (value.type === "ARITH") {
@@ -3604,6 +3642,7 @@ function resolveArithOperand(operand, raw) {
3604
3642
  return n;
3605
3643
  }
3606
3644
  function deleteToGetQuery(stmt) {
3645
+ assertDmlWhereIsSafe(stmt.where);
3607
3646
  return {
3608
3647
  app: stmt.appId,
3609
3648
  query: whereToKintone(stmt.where),
@@ -3888,6 +3927,7 @@ async function resolveDmlTargetIds(getRecords, app, query, options) {
3888
3927
  function extractTableCondition(where, tableAlias) {
3889
3928
  switch (where.type) {
3890
3929
  case "BINARY":
3930
+ if (isLike(where)) return null;
3891
3931
  if (!isSingleTableField(where.left, tableAlias)) return null;
3892
3932
  if (!isPushDownableRight(where.right)) return null;
3893
3933
  return where;
@@ -3927,7 +3967,7 @@ function isPushDownableRight(value) {
3927
3967
  function referencesOnlyTable(expr, tableAlias) {
3928
3968
  switch (expr.type) {
3929
3969
  case "BINARY":
3930
- return isSingleTableField(expr.left, tableAlias) && isPushDownableRight(expr.right);
3970
+ return !isLike(expr) && isSingleTableField(expr.left, tableAlias) && isPushDownableRight(expr.right);
3931
3971
  case "NULL_CHECK":
3932
3972
  return isSingleTableField(expr.field, tableAlias);
3933
3973
  case "LOGICAL":
@@ -6486,8 +6526,10 @@ function collectFullScanReasons(stmt) {
6486
6526
  r.push("\u96C6\u8A08\u95A2\u6570\uFF08COUNT / SUM \u7B49\uFF09\u3042\u308A");
6487
6527
  if (stmt.columns.some((c) => c.type === "SCALAR_SUBQUERY_COL"))
6488
6528
  r.push("SELECT \u5217\u306B\u30B9\u30AB\u30E9\u30FC\u30B5\u30D6\u30AF\u30A8\u30EA");
6489
- if (hasWhereFunc(stmt.where))
6529
+ if (whereRequiresJsEval(stmt.where))
6490
6530
  r.push("WHERE \u53E5\u306B JS \u8A55\u4FA1\u304C\u5FC5\u8981\u306A\u5F0F");
6531
+ if (whereHasLike(stmt.where))
6532
+ r.push("LIKE \u306F\u5E38\u306B JS \u8A55\u4FA1\u306E\u305F\u3081\u5168\u4EF6\u53D6\u5F97");
6491
6533
  if (stmt.orderBy.some((o) => o.key.type !== "FIELD_NAME"))
6492
6534
  r.push("ORDER BY \u306B\u5F0F");
6493
6535
  return r;
@@ -6540,7 +6582,7 @@ function buildInsertPlan(stmt, label) {
6540
6582
  const lines = [];
6541
6583
  if (label) lines.push(label);
6542
6584
  lines.push(` [INSERT]`);
6543
- lines.push(` app: APP${stmt.appId} (${stmt.appId})`);
6585
+ lines.push(` target: APP${stmt.appId} (${stmt.appId})`);
6544
6586
  lines.push(` records: ${totalRows} \u4EF6\uFF08\u30D0\u30C3\u30C1 ${batchCount} \u56DE \xD7 \u6700\u5927 100 \u4EF6\uFF09`);
6545
6587
  lines.push(` api: POST /k/v1/records.json \xD7 ${batchCount}`);
6546
6588
  lines.push(` fields: ${stmt.fields.join(", ")}`);
@@ -6550,7 +6592,7 @@ function buildInsertSelectPlan(stmt, label) {
6550
6592
  const lines = [];
6551
6593
  if (label) lines.push(label);
6552
6594
  lines.push(` [INSERT SELECT]`);
6553
- lines.push(` app: APP${stmt.appId} (${stmt.appId})`);
6595
+ lines.push(` target: APP${stmt.appId} (${stmt.appId})`);
6554
6596
  lines.push(` fields: ${stmt.fields.join(", ")}`);
6555
6597
  lines.push(` api: POST /k/v1/records.json\uFF08\u4EF6\u6570\u306F SELECT \u7D50\u679C\u306B\u4F9D\u5B58\u3001100 \u4EF6\u3054\u3068\u306B\u30D0\u30C3\u30C1\uFF09`);
6556
6598
  lines.push("");
@@ -6563,7 +6605,7 @@ function buildUpdatePlan(stmt, label) {
6563
6605
  const lines = [];
6564
6606
  if (label) lines.push(label);
6565
6607
  lines.push(` [UPDATE]`);
6566
- lines.push(` app: APP${stmt.appId} (${stmt.appId})`);
6608
+ lines.push(` target: APP${stmt.appId} (${stmt.appId})`);
6567
6609
  lines.push(` kintone query: ${safeWhereToKintone(stmt.where)}`);
6568
6610
  lines.push(` api: GET /k/v1/records.json \u2192 PUT /k/v1/records.json`);
6569
6611
  const setTypes = [];
@@ -6593,7 +6635,7 @@ function buildDeletePlan(stmt, label) {
6593
6635
  const lines = [];
6594
6636
  if (label) lines.push(label);
6595
6637
  lines.push(` [DELETE]`);
6596
- lines.push(` app: APP${stmt.appId} (${stmt.appId})`);
6638
+ lines.push(` target: APP${stmt.appId} (${stmt.appId})`);
6597
6639
  lines.push(` kintone query: ${safeWhereToKintone(stmt.where)}`);
6598
6640
  lines.push(` api: GET /k/v1/records.json \u2192 DELETE /k/v1/records.json`);
6599
6641
  return lines;
@@ -6604,7 +6646,7 @@ function buildUpsertPlan(stmt, label) {
6604
6646
  return [
6605
6647
  ...label ? [label] : [],
6606
6648
  ` [UPSERT]`,
6607
- ` app: APP${stmt.appId} (${stmt.appId})`,
6649
+ ` target: APP${stmt.appId} (${stmt.appId})`,
6608
6650
  ` records: ${totalRows} \u4EF6\uFF08\u30D0\u30C3\u30C1 ${batchCount} \u56DE \xD7 \u6700\u5927 100 \u4EF6\uFF09`,
6609
6651
  ` key fields: ${stmt.keyFields.join(", ")}`,
6610
6652
  ` fields: ${stmt.fields.join(", ")}`,
@@ -6615,7 +6657,7 @@ function buildUpsertSelectPlan(stmt, label) {
6615
6657
  const lines = [
6616
6658
  ...label ? [label] : [],
6617
6659
  ` [UPSERT SELECT]`,
6618
- ` app: APP${stmt.appId} (${stmt.appId})`,
6660
+ ` target: APP${stmt.appId} (${stmt.appId})`,
6619
6661
  ` key fields: ${stmt.keyFields.join(", ")}`,
6620
6662
  ` fields: ${stmt.fields.join(", ")}`,
6621
6663
  ` api: GET /k/v1/records.json\uFF08\u91CD\u8907\u5224\u5B9A\uFF09\u2192 POST \u307E\u305F\u306F PUT /k/v1/records.json\uFF08100 \u4EF6\u3054\u3068\u306B\u30D0\u30C3\u30C1\uFF09`,
@@ -6631,7 +6673,7 @@ function buildReorderPlan(stmt, label) {
6631
6673
  const lines = [
6632
6674
  ...label ? [label] : [],
6633
6675
  ` [REORDER]`,
6634
- ` app: APP${stmt.appId} (${stmt.appId})`,
6676
+ ` target: APP${stmt.appId} (${stmt.appId})`,
6635
6677
  ` table: ${target}`,
6636
6678
  ` scope: ${scope}`,
6637
6679
  ` by: ${byStr}`,
@@ -7710,6 +7752,14 @@ function tryParseStatements(sql) {
7710
7752
  // src/node/sqlDiagnostics.ts
7711
7753
  function restoreSqlDiagnosticValue(value, bindings) {
7712
7754
  if (typeof value === "string") {
7755
+ const dmlTarget = value.match(/^(\s*target:\s*)APP(\d+) \((\d+)\)\s*$/);
7756
+ if (dmlTarget && dmlTarget[2] === dmlTarget[3]) {
7757
+ const binding = bindings.get(Number(dmlTarget[2]));
7758
+ if (binding) {
7759
+ const target = binding.source === "logical" ? `LAPP_${binding.logicalName} -> APP${binding.appId}@${binding.profile}` : `APP${binding.appId}@${binding.profile}`;
7760
+ return `${dmlTarget[1]}${target}`;
7761
+ }
7762
+ }
7713
7763
  let restored = value;
7714
7764
  for (const binding of bindings.values()) {
7715
7765
  const internal = `APP${binding.mappedAppId}`;
@@ -9453,13 +9503,16 @@ query=${label}`);
9453
9503
  });
9454
9504
  return writeBatchOutput(batchResult, { format, noHeader, pretty, displayOptions, outputPath, quiet });
9455
9505
  }
9456
- const result = args.dryRun ? await execute(`EXPLAIN ${sql}`, client, { maxRecords, onLimitReached: onLimit, cacheContext }) : await execute(sql, client, {
9506
+ let result = args.dryRun ? await execute(`EXPLAIN ${sql}`, client, { maxRecords, onLimitReached: onLimit, cacheContext }) : await execute(sql, client, {
9457
9507
  maxRecords,
9458
9508
  fetchParallel,
9459
9509
  onLimitReached: onLimit,
9460
9510
  confirm: isDmlStatement ? confirm : void 0,
9461
9511
  cacheContext
9462
9512
  });
9513
+ if (args.dryRun && sqlDiagnosticContext) {
9514
+ result = restoreSqlDiagnosticValue(result, sqlDiagnosticContext.appBindingByMappedApp);
9515
+ }
9463
9516
  if (result.type === "ASSERT") {
9464
9517
  const output2 = buildAssertOutput(result, format, pretty);
9465
9518
  if (outputPath) (0, import_fs2.writeFileSync)(outputPath, `${output2}
@@ -33308,6 +33308,29 @@ function negateOp(op) {
33308
33308
  }
33309
33309
  }
33310
33310
 
33311
+ // src/core/like.ts
33312
+ function likePatternHasWildcard(pattern) {
33313
+ return pattern.includes("%") || pattern.includes("_");
33314
+ }
33315
+ function isLike(where) {
33316
+ return where.type === "BINARY" && (where.op === "LIKE" || where.op === "NOT_LIKE");
33317
+ }
33318
+ function whereHasLike(where) {
33319
+ if (where === null) return false;
33320
+ if (isLike(where)) return true;
33321
+ switch (where.type) {
33322
+ case "LOGICAL":
33323
+ return whereHasLike(where.left) || whereHasLike(where.right);
33324
+ case "NOT":
33325
+ case "GROUP":
33326
+ return whereHasLike(where.expr);
33327
+ case "BINARY":
33328
+ case "NULL_CHECK":
33329
+ case "EXISTS":
33330
+ return false;
33331
+ }
33332
+ }
33333
+
33311
33334
  // src/converter/whereToKintone.ts
33312
33335
  function whereToKintone(expr) {
33313
33336
  switch (expr.type) {
@@ -33326,6 +33349,11 @@ function whereToKintone(expr) {
33326
33349
  }
33327
33350
  }
33328
33351
  function convertBinary(expr) {
33352
+ if (isLike(expr)) {
33353
+ throw new KintoneQueryError(
33354
+ "LIKE / NOT LIKE \u306F kintone \u30AF\u30A8\u30EA\u306B\u5909\u63DB\u3067\u304D\u307E\u305B\u3093\uFF08\u5E38\u306B JS \u8A55\u4FA1\u304C\u5FC5\u8981\u3067\u3059\uFF09"
33355
+ );
33356
+ }
33329
33357
  const left = convertField(expr.left);
33330
33358
  const op = convertOp(expr.op);
33331
33359
  const right = convertValue(expr.right, expr.op);
@@ -33451,22 +33479,22 @@ function resolveSelectMode(stmt) {
33451
33479
  if (stmt.columns.some(
33452
33480
  (c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "SCALAR_SUBQUERY_COL" || c.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr(c.expr)
33453
33481
  )) return "FULL_SCAN";
33454
- if (hasWhereFunc(stmt.where)) return "FULL_SCAN";
33482
+ if (whereRequiresJsEval(stmt.where)) return "FULL_SCAN";
33455
33483
  if (stmt.orderBy.some((o) => o.key.type !== "FIELD_NAME")) return "FULL_SCAN";
33456
33484
  return "SIMPLE";
33457
33485
  }
33458
- function hasWhereFunc(where) {
33486
+ function whereRequiresJsEval(where) {
33459
33487
  if (where === null) return false;
33460
33488
  switch (where.type) {
33461
33489
  case "BINARY":
33462
- return isFunc(where.left) || where.right.type === "ARITH_VALUE" || where.right.type === "CASE_VALUE" || where.right.type === "SUBQUERY_IN_LIST" || where.right.type === "SCALAR_SUBQUERY";
33490
+ return isFunc(where.left) || where.right.type === "ARITH_VALUE" || where.right.type === "CASE_VALUE" || where.right.type === "SUBQUERY_IN_LIST" || where.right.type === "SCALAR_SUBQUERY" || isLike(where);
33463
33491
  case "NULL_CHECK":
33464
33492
  return isFunc(where.field);
33465
33493
  case "LOGICAL":
33466
- return hasWhereFunc(where.left) || hasWhereFunc(where.right);
33494
+ return whereRequiresJsEval(where.left) || whereRequiresJsEval(where.right);
33467
33495
  case "NOT":
33468
33496
  case "GROUP":
33469
- return hasWhereFunc(where.expr);
33497
+ return whereRequiresJsEval(where.expr);
33470
33498
  case "EXISTS":
33471
33499
  return true;
33472
33500
  }
@@ -33502,7 +33530,7 @@ function selectToKintoneParams(stmt) {
33502
33530
  }
33503
33531
  function selectToFetchAllParams(stmt, appId) {
33504
33532
  const queryParts = [];
33505
- if (stmt.where !== null && stmt.joins.length === 0 && !hasWhereFunc(stmt.where)) {
33533
+ if (stmt.where !== null && stmt.joins.length === 0 && !whereRequiresJsEval(stmt.where)) {
33506
33534
  queryParts.push(whereToKintone(stmt.where));
33507
33535
  }
33508
33536
  return {
@@ -34240,6 +34268,8 @@ function resolveValue(value, row) {
34240
34268
  case "SCALAR_SUBQUERY":
34241
34269
  return value.resolved;
34242
34270
  case "ARITH_VALUE":
34271
+ if (value.expr.type === "FIELD_REF") return resolveFieldRef(row, value.expr.field);
34272
+ if (value.expr.type === "STRING_FUNC") return evalStringFunc(value.expr, row);
34243
34273
  return String(evalArithExpr(value.expr, row));
34244
34274
  case "CASE_VALUE":
34245
34275
  return evalCaseWhen(value.expr, row);
@@ -34283,7 +34313,7 @@ function resolveKintoneFunc(name) {
34283
34313
  var likeRegexCache = /* @__PURE__ */ new Map();
34284
34314
  var LIKE_REGEX_CACHE_MAX = 200;
34285
34315
  function matchLike(value, pattern) {
34286
- if (!pattern.includes("%") && !pattern.includes("_")) {
34316
+ if (!likePatternHasWildcard(pattern)) {
34287
34317
  return value.includes(pattern);
34288
34318
  }
34289
34319
  let regex = likeRegexCache.get(pattern);
@@ -34308,6 +34338,12 @@ function matchLike(value, pattern) {
34308
34338
  }
34309
34339
 
34310
34340
  // src/converter/dmlToKintone.ts
34341
+ function assertDmlWhereIsSafe(where) {
34342
+ if (!whereHasLike(where)) return;
34343
+ throw new DmlConvertError(
34344
+ "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"
34345
+ );
34346
+ }
34311
34347
  var USER_TYPES = /* @__PURE__ */ new Set(["USER_SELECT", "ORGANIZATION_SELECT", "GROUP_SELECT"]);
34312
34348
  var ARRAY_TYPES = /* @__PURE__ */ new Set(["CHECK_BOX", "MULTI_SELECT"]);
34313
34349
  function insertToPostBatches(stmt, fieldTypes = /* @__PURE__ */ new Map()) {
@@ -34332,6 +34368,7 @@ function buildInsertRecord(fields, row, fieldTypes) {
34332
34368
  return record2;
34333
34369
  }
34334
34370
  function updateToGetQuery(stmt) {
34371
+ assertDmlWhereIsSafe(stmt.where);
34335
34372
  return {
34336
34373
  app: stmt.appId,
34337
34374
  query: whereToKintone(stmt.where),
@@ -34360,6 +34397,7 @@ function hasArithAssignment(stmt) {
34360
34397
  );
34361
34398
  }
34362
34399
  function updateToGetQueryForArith(stmt) {
34400
+ assertDmlWhereIsSafe(stmt.where);
34363
34401
  const refFields = /* @__PURE__ */ new Set();
34364
34402
  for (const { value } of stmt.assignments) {
34365
34403
  if (value.type === "ARITH") {
@@ -34505,6 +34543,7 @@ function resolveArithOperand(operand, raw) {
34505
34543
  return n;
34506
34544
  }
34507
34545
  function deleteToGetQuery(stmt) {
34546
+ assertDmlWhereIsSafe(stmt.where);
34508
34547
  return {
34509
34548
  app: stmt.appId,
34510
34549
  query: whereToKintone(stmt.where),
@@ -34789,6 +34828,7 @@ async function resolveDmlTargetIds(getRecords, app, query, options) {
34789
34828
  function extractTableCondition(where, tableAlias) {
34790
34829
  switch (where.type) {
34791
34830
  case "BINARY":
34831
+ if (isLike(where)) return null;
34792
34832
  if (!isSingleTableField(where.left, tableAlias)) return null;
34793
34833
  if (!isPushDownableRight(where.right)) return null;
34794
34834
  return where;
@@ -34828,7 +34868,7 @@ function isPushDownableRight(value) {
34828
34868
  function referencesOnlyTable(expr, tableAlias) {
34829
34869
  switch (expr.type) {
34830
34870
  case "BINARY":
34831
- return isSingleTableField(expr.left, tableAlias) && isPushDownableRight(expr.right);
34871
+ return !isLike(expr) && isSingleTableField(expr.left, tableAlias) && isPushDownableRight(expr.right);
34832
34872
  case "NULL_CHECK":
34833
34873
  return isSingleTableField(expr.field, tableAlias);
34834
34874
  case "LOGICAL":
@@ -37387,8 +37427,10 @@ function collectFullScanReasons(stmt) {
37387
37427
  r.push("\u96C6\u8A08\u95A2\u6570\uFF08COUNT / SUM \u7B49\uFF09\u3042\u308A");
37388
37428
  if (stmt.columns.some((c) => c.type === "SCALAR_SUBQUERY_COL"))
37389
37429
  r.push("SELECT \u5217\u306B\u30B9\u30AB\u30E9\u30FC\u30B5\u30D6\u30AF\u30A8\u30EA");
37390
- if (hasWhereFunc(stmt.where))
37430
+ if (whereRequiresJsEval(stmt.where))
37391
37431
  r.push("WHERE \u53E5\u306B JS \u8A55\u4FA1\u304C\u5FC5\u8981\u306A\u5F0F");
37432
+ if (whereHasLike(stmt.where))
37433
+ r.push("LIKE \u306F\u5E38\u306B JS \u8A55\u4FA1\u306E\u305F\u3081\u5168\u4EF6\u53D6\u5F97");
37392
37434
  if (stmt.orderBy.some((o) => o.key.type !== "FIELD_NAME"))
37393
37435
  r.push("ORDER BY \u306B\u5F0F");
37394
37436
  return r;
@@ -37441,7 +37483,7 @@ function buildInsertPlan(stmt, label) {
37441
37483
  const lines = [];
37442
37484
  if (label) lines.push(label);
37443
37485
  lines.push(` [INSERT]`);
37444
- lines.push(` app: APP${stmt.appId} (${stmt.appId})`);
37486
+ lines.push(` target: APP${stmt.appId} (${stmt.appId})`);
37445
37487
  lines.push(` records: ${totalRows} \u4EF6\uFF08\u30D0\u30C3\u30C1 ${batchCount} \u56DE \xD7 \u6700\u5927 100 \u4EF6\uFF09`);
37446
37488
  lines.push(` api: POST /k/v1/records.json \xD7 ${batchCount}`);
37447
37489
  lines.push(` fields: ${stmt.fields.join(", ")}`);
@@ -37451,7 +37493,7 @@ function buildInsertSelectPlan(stmt, label) {
37451
37493
  const lines = [];
37452
37494
  if (label) lines.push(label);
37453
37495
  lines.push(` [INSERT SELECT]`);
37454
- lines.push(` app: APP${stmt.appId} (${stmt.appId})`);
37496
+ lines.push(` target: APP${stmt.appId} (${stmt.appId})`);
37455
37497
  lines.push(` fields: ${stmt.fields.join(", ")}`);
37456
37498
  lines.push(` api: POST /k/v1/records.json\uFF08\u4EF6\u6570\u306F SELECT \u7D50\u679C\u306B\u4F9D\u5B58\u3001100 \u4EF6\u3054\u3068\u306B\u30D0\u30C3\u30C1\uFF09`);
37457
37499
  lines.push("");
@@ -37464,7 +37506,7 @@ function buildUpdatePlan(stmt, label) {
37464
37506
  const lines = [];
37465
37507
  if (label) lines.push(label);
37466
37508
  lines.push(` [UPDATE]`);
37467
- lines.push(` app: APP${stmt.appId} (${stmt.appId})`);
37509
+ lines.push(` target: APP${stmt.appId} (${stmt.appId})`);
37468
37510
  lines.push(` kintone query: ${safeWhereToKintone(stmt.where)}`);
37469
37511
  lines.push(` api: GET /k/v1/records.json \u2192 PUT /k/v1/records.json`);
37470
37512
  const setTypes = [];
@@ -37494,7 +37536,7 @@ function buildDeletePlan(stmt, label) {
37494
37536
  const lines = [];
37495
37537
  if (label) lines.push(label);
37496
37538
  lines.push(` [DELETE]`);
37497
- lines.push(` app: APP${stmt.appId} (${stmt.appId})`);
37539
+ lines.push(` target: APP${stmt.appId} (${stmt.appId})`);
37498
37540
  lines.push(` kintone query: ${safeWhereToKintone(stmt.where)}`);
37499
37541
  lines.push(` api: GET /k/v1/records.json \u2192 DELETE /k/v1/records.json`);
37500
37542
  return lines;
@@ -37505,7 +37547,7 @@ function buildUpsertPlan(stmt, label) {
37505
37547
  return [
37506
37548
  ...label ? [label] : [],
37507
37549
  ` [UPSERT]`,
37508
- ` app: APP${stmt.appId} (${stmt.appId})`,
37550
+ ` target: APP${stmt.appId} (${stmt.appId})`,
37509
37551
  ` records: ${totalRows} \u4EF6\uFF08\u30D0\u30C3\u30C1 ${batchCount} \u56DE \xD7 \u6700\u5927 100 \u4EF6\uFF09`,
37510
37552
  ` key fields: ${stmt.keyFields.join(", ")}`,
37511
37553
  ` fields: ${stmt.fields.join(", ")}`,
@@ -37516,7 +37558,7 @@ function buildUpsertSelectPlan(stmt, label) {
37516
37558
  const lines = [
37517
37559
  ...label ? [label] : [],
37518
37560
  ` [UPSERT SELECT]`,
37519
- ` app: APP${stmt.appId} (${stmt.appId})`,
37561
+ ` target: APP${stmt.appId} (${stmt.appId})`,
37520
37562
  ` key fields: ${stmt.keyFields.join(", ")}`,
37521
37563
  ` fields: ${stmt.fields.join(", ")}`,
37522
37564
  ` api: GET /k/v1/records.json\uFF08\u91CD\u8907\u5224\u5B9A\uFF09\u2192 POST \u307E\u305F\u306F PUT /k/v1/records.json\uFF08100 \u4EF6\u3054\u3068\u306B\u30D0\u30C3\u30C1\uFF09`,
@@ -37532,7 +37574,7 @@ function buildReorderPlan(stmt, label) {
37532
37574
  const lines = [
37533
37575
  ...label ? [label] : [],
37534
37576
  ` [REORDER]`,
37535
- ` app: APP${stmt.appId} (${stmt.appId})`,
37577
+ ` target: APP${stmt.appId} (${stmt.appId})`,
37536
37578
  ` table: ${target}`,
37537
37579
  ` scope: ${scope}`,
37538
37580
  ` by: ${byStr}`,
@@ -37669,6 +37711,14 @@ function buildBatchEnvelope(batch, options = {}) {
37669
37711
  // src/node/sqlDiagnostics.ts
37670
37712
  function restoreSqlDiagnosticValue(value, bindings) {
37671
37713
  if (typeof value === "string") {
37714
+ const dmlTarget = value.match(/^(\s*target:\s*)APP(\d+) \((\d+)\)\s*$/);
37715
+ if (dmlTarget && dmlTarget[2] === dmlTarget[3]) {
37716
+ const binding = bindings.get(Number(dmlTarget[2]));
37717
+ if (binding) {
37718
+ const target = binding.source === "logical" ? `LAPP_${binding.logicalName} -> APP${binding.appId}@${binding.profile}` : `APP${binding.appId}@${binding.profile}`;
37719
+ return `${dmlTarget[1]}${target}`;
37720
+ }
37721
+ }
37672
37722
  let restored = value;
37673
37723
  for (const binding of bindings.values()) {
37674
37724
  const internal = `APP${binding.mappedAppId}`;
@@ -39653,7 +39703,7 @@ Options:
39653
39703
  -h, --help Show help
39654
39704
  `);
39655
39705
  }
39656
- var SERVER_VERSION = true ? "1.13.1" : "0.0.0-dev";
39706
+ var SERVER_VERSION = true ? "2.0.0" : "0.0.0-dev";
39657
39707
  function createServer(args) {
39658
39708
  const server = new McpServer({
39659
39709
  name: "ksql-mcp",
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rex0220/kintone-sql-tools",
3
- "version": "1.13.1",
3
+ "version": "2.0.0",
4
4
  "description": "kintone SQL plugin, CLI, and MCP tools (ksql)",
5
5
  "publishConfig": {
6
6
  "access": "public"