@rex0220/kintone-sql-tools 2.16.0 → 2.17.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
@@ -123,6 +123,11 @@ var KEYWORDS = /* @__PURE__ */ new Map([
123
123
  ["COALESCE", "COALESCE" /* COALESCE */],
124
124
  ["NULLIF", "NULLIF" /* NULLIF */],
125
125
  ["ISNULL", "ISNULL" /* ISNULL */],
126
+ ["INSTR", "INSTR" /* INSTR */],
127
+ ["GREATEST", "GREATEST" /* GREATEST */],
128
+ ["LEAST", "LEAST" /* LEAST */],
129
+ ["LPAD", "LPAD" /* LPAD */],
130
+ ["RPAD", "RPAD" /* RPAD */],
126
131
  ["CAST", "CAST" /* CAST */],
127
132
  ["CONVERT", "CONVERT" /* CONVERT */],
128
133
  ["FORMAT", "FORMAT" /* FORMAT */],
@@ -130,6 +135,8 @@ var KEYWORDS = /* @__PURE__ */ new Map([
130
135
  ["FLOOR", "FLOOR" /* FLOOR */],
131
136
  ["CEIL", "CEIL" /* CEIL */],
132
137
  ["CEILING", "CEILING" /* CEILING */],
138
+ ["TRUNCATE", "TRUNCATE" /* TRUNCATE */],
139
+ ["TRUNC", "TRUNC" /* TRUNC */],
133
140
  ["ABS", "ABS" /* ABS */],
134
141
  ["MOD", "MOD" /* MOD */],
135
142
  ["POWER", "POWER" /* POWER */],
@@ -141,6 +148,7 @@ var KEYWORDS = /* @__PURE__ */ new Map([
141
148
  ["DATE_FORMAT", "DATE_FORMAT" /* DATE_FORMAT */],
142
149
  ["DATEDIFF", "DATEDIFF" /* DATEDIFF */],
143
150
  ["DATE_ADD", "DATE_ADD" /* DATE_ADD */],
151
+ ["LAST_DAY", "LAST_DAY" /* LAST_DAY */],
144
152
  ["IF", "IF" /* IF */]
145
153
  ]);
146
154
 
@@ -486,6 +494,13 @@ var FUNC_CALL_PREFIX_KINDS = /* @__PURE__ */ new Set([
486
494
  "COALESCE" /* COALESCE */,
487
495
  "NULLIF" /* NULLIF */,
488
496
  "ISNULL" /* ISNULL */,
497
+ "LEFT" /* LEFT */,
498
+ "RIGHT" /* RIGHT */,
499
+ "INSTR" /* INSTR */,
500
+ "GREATEST" /* GREATEST */,
501
+ "LEAST" /* LEAST */,
502
+ "LPAD" /* LPAD */,
503
+ "RPAD" /* RPAD */,
489
504
  "CAST" /* CAST */,
490
505
  "CONVERT" /* CONVERT */,
491
506
  "FORMAT" /* FORMAT */,
@@ -493,6 +508,8 @@ var FUNC_CALL_PREFIX_KINDS = /* @__PURE__ */ new Set([
493
508
  "FLOOR" /* FLOOR */,
494
509
  "CEIL" /* CEIL */,
495
510
  "CEILING" /* CEILING */,
511
+ "TRUNCATE" /* TRUNCATE */,
512
+ "TRUNC" /* TRUNC */,
496
513
  "ABS" /* ABS */,
497
514
  "MOD" /* MOD */,
498
515
  "POWER" /* POWER */,
@@ -504,6 +521,7 @@ var FUNC_CALL_PREFIX_KINDS = /* @__PURE__ */ new Set([
504
521
  "DATE_FORMAT" /* DATE_FORMAT */,
505
522
  "DATEDIFF" /* DATEDIFF */,
506
523
  "DATE_ADD" /* DATE_ADD */,
524
+ "LAST_DAY" /* LAST_DAY */,
507
525
  "IF" /* IF */
508
526
  ]);
509
527
  function needsSpaceBetween(prev, cur) {
@@ -1376,6 +1394,10 @@ var Parser = class {
1376
1394
  // arg: 文字列リテラル / 算術式(フィールド参照・数値含む)/ ネスト文字列関数
1377
1395
  // ──────────────────────────────────────────────────
1378
1396
  tryStringFuncName() {
1397
+ if (this.peekAt(1).kind === "(" /* LPAREN */) {
1398
+ if (this.peek().kind === "LEFT" /* LEFT */) return "LEFT";
1399
+ if (this.peek().kind === "RIGHT" /* RIGHT */) return "RIGHT";
1400
+ }
1379
1401
  const map = {
1380
1402
  ["UPPER" /* UPPER */]: "UPPER",
1381
1403
  ["LOWER" /* LOWER */]: "LOWER",
@@ -1390,6 +1412,11 @@ var Parser = class {
1390
1412
  ["COALESCE" /* COALESCE */]: "COALESCE",
1391
1413
  ["NULLIF" /* NULLIF */]: "NULLIF",
1392
1414
  ["ISNULL" /* ISNULL */]: "ISNULL",
1415
+ ["INSTR" /* INSTR */]: "INSTR",
1416
+ ["GREATEST" /* GREATEST */]: "GREATEST",
1417
+ ["LEAST" /* LEAST */]: "LEAST",
1418
+ ["LPAD" /* LPAD */]: "LPAD",
1419
+ ["RPAD" /* RPAD */]: "RPAD",
1393
1420
  ["CAST" /* CAST */]: "CAST",
1394
1421
  ["CONVERT" /* CONVERT */]: "CAST",
1395
1422
  // CONVERT → CAST に正規化
@@ -1399,12 +1426,16 @@ var Parser = class {
1399
1426
  ["CEIL" /* CEIL */]: "CEIL",
1400
1427
  ["CEILING" /* CEILING */]: "CEIL",
1401
1428
  // CEILING → CEIL に正規化
1429
+ ["TRUNCATE" /* TRUNCATE */]: "TRUNCATE",
1430
+ ["TRUNC" /* TRUNC */]: "TRUNCATE",
1431
+ // TRUNC → TRUNCATE に正規化
1402
1432
  ["YEAR" /* YEAR */]: "YEAR",
1403
1433
  ["MONTH" /* MONTH */]: "MONTH",
1404
1434
  ["DAY" /* DAY */]: "DAY",
1405
1435
  ["DATE_FORMAT" /* DATE_FORMAT */]: "DATE_FORMAT",
1406
1436
  ["DATEDIFF" /* DATEDIFF */]: "DATEDIFF",
1407
1437
  ["DATE_ADD" /* DATE_ADD */]: "DATE_ADD",
1438
+ ["LAST_DAY" /* LAST_DAY */]: "LAST_DAY",
1408
1439
  ["ABS" /* ABS */]: "ABS",
1409
1440
  ["MOD" /* MOD */]: "MOD",
1410
1441
  ["POWER" /* POWER */]: "POWER",
@@ -4143,6 +4174,25 @@ function compareScalarValues(op, leftStr, rightStr) {
4143
4174
  return numeric ? leftNum <= rightNum : leftStr <= rightStr;
4144
4175
  }
4145
4176
  }
4177
+ function selectScalarExtreme(values, extreme) {
4178
+ if (extreme === "least" && values.includes("")) return "";
4179
+ const candidates = extreme === "greatest" ? values.filter((value) => value !== "") : [...values];
4180
+ if (candidates.length === 0) return "";
4181
+ const numeric = candidates.every((value) => !Number.isNaN(Number(value)));
4182
+ const compare = (left, right) => {
4183
+ if (numeric) {
4184
+ const leftNum = Number(left);
4185
+ const rightNum = Number(right);
4186
+ if (leftNum < rightNum) return -1;
4187
+ if (leftNum > rightNum) return 1;
4188
+ }
4189
+ return left < right ? -1 : left > right ? 1 : 0;
4190
+ };
4191
+ return candidates.reduce((best, candidate) => {
4192
+ const cmp = compare(candidate, best);
4193
+ return extreme === "greatest" ? cmp > 0 ? candidate : best : cmp < 0 ? candidate : best;
4194
+ });
4195
+ }
4146
4196
 
4147
4197
  // src/engine/evalFunc.ts
4148
4198
  function evalArithExpr(expr, row) {
@@ -4191,6 +4241,36 @@ function evalStringFunc(expr, row) {
4191
4241
  const len = args[2] !== void 0 ? Number(args[2]) : void 0;
4192
4242
  return len !== void 0 ? str.slice(start, start + len) : str.slice(start);
4193
4243
  }
4244
+ case "LEFT": {
4245
+ assertArity("LEFT", args, 2, 2);
4246
+ const str = args[0];
4247
+ const n = Math.trunc(Number(args[1]));
4248
+ return Number.isNaN(n) || n <= 0 ? "" : str.slice(0, n);
4249
+ }
4250
+ case "RIGHT": {
4251
+ assertArity("RIGHT", args, 2, 2);
4252
+ const str = args[0];
4253
+ const n = Math.trunc(Number(args[1]));
4254
+ return Number.isNaN(n) || n <= 0 ? "" : str.slice(Math.max(0, str.length - n));
4255
+ }
4256
+ case "INSTR":
4257
+ assertArity("INSTR", args, 2, 2);
4258
+ return String(args[0].indexOf(args[1]) + 1);
4259
+ case "LPAD":
4260
+ case "RPAD": {
4261
+ assertArity(expr.func, args, 2, 3);
4262
+ const str = args[0];
4263
+ const n = Math.trunc(Number(args[1]));
4264
+ if (Number.isNaN(n) || n <= 0) return "";
4265
+ if (str.length >= n) return str.slice(0, n);
4266
+ const pad = args[2] ?? " ";
4267
+ if (pad === "") return str;
4268
+ return expr.func === "LPAD" ? str.padStart(n, pad) : str.padEnd(n, pad);
4269
+ }
4270
+ case "GREATEST":
4271
+ case "LEAST":
4272
+ assertArity(expr.func, args, 2);
4273
+ return selectScalarExtreme(args, expr.func === "GREATEST" ? "greatest" : "least");
4194
4274
  case "CONCAT":
4195
4275
  return args.join("");
4196
4276
  case "REPLACE": {
@@ -4211,6 +4291,9 @@ function evalStringFunc(expr, row) {
4211
4291
  return applyRoundOp("floor", Number(args[0] ?? "0"), Number(args[1] ?? "0"));
4212
4292
  case "CEIL":
4213
4293
  return applyRoundOp("ceil", Number(args[0] ?? "0"), Number(args[1] ?? "0"));
4294
+ case "TRUNCATE":
4295
+ assertArity("TRUNCATE", args, 1, 2);
4296
+ return applyRoundOp("trunc", Number(args[0]), Number(args[1] ?? "0"));
4214
4297
  case "CAST": {
4215
4298
  const val = args[0] ?? "";
4216
4299
  const castType = args[1] ?? "TEXT";
@@ -4243,6 +4326,9 @@ function evalStringFunc(expr, row) {
4243
4326
  return applyDateDiff(args[0] ?? "", args[1] ?? "");
4244
4327
  case "DATE_ADD":
4245
4328
  return applyDateAdd(args[0] ?? "", Number(args[1] ?? "0"), (args[2] ?? "DAY").toUpperCase());
4329
+ case "LAST_DAY":
4330
+ assertArity("LAST_DAY", args, 1, 1);
4331
+ return applyLastDay(args[0]);
4246
4332
  case "ABS":
4247
4333
  return String(Math.abs(Number(args[0] ?? "0")));
4248
4334
  case "MOD": {
@@ -4265,6 +4351,11 @@ function evalStringFunc(expr, row) {
4265
4351
  return (/* @__PURE__ */ new Date()).toISOString();
4266
4352
  }
4267
4353
  }
4354
+ function assertArity(func, args, min, max = Number.POSITIVE_INFINITY) {
4355
+ if (args.length >= min && args.length <= max) return;
4356
+ const expected = min === max ? String(min) : max === Number.POSITIVE_INFINITY ? `${min} or more` : `${min} to ${max}`;
4357
+ throw new Error(`ArgumentError: ${func} expects ${expected} argument(s).`);
4358
+ }
4268
4359
  function parseDateParts(s) {
4269
4360
  return {
4270
4361
  y: s.slice(0, 4) || "0000",
@@ -4289,6 +4380,9 @@ function applyDateDiff(date1, date2) {
4289
4380
  return String(Math.round((d1 - d2) / 864e5));
4290
4381
  }
4291
4382
  function applyDateAdd(dateStr, n, unit) {
4383
+ if (unit !== "YEAR" && unit !== "MONTH" && unit !== "DAY") {
4384
+ throw new Error("ArgumentError: DATE_ADD unit must be YEAR, MONTH, or DAY.");
4385
+ }
4292
4386
  if (!dateStr || dateStr.length < 10) return dateStr;
4293
4387
  const { y, mo, d } = parseDateParts(dateStr);
4294
4388
  const dt = new Date(Date.UTC(+y, +mo - 1, +d));
@@ -4299,7 +4393,7 @@ function applyDateAdd(dateStr, n, unit) {
4299
4393
  case "MONTH":
4300
4394
  dt.setUTCMonth(dt.getUTCMonth() + n);
4301
4395
  break;
4302
- default:
4396
+ case "DAY":
4303
4397
  dt.setUTCDate(dt.getUTCDate() + n);
4304
4398
  break;
4305
4399
  }
@@ -4308,6 +4402,15 @@ function applyDateAdd(dateStr, n, unit) {
4308
4402
  const rd = String(dt.getUTCDate()).padStart(2, "0");
4309
4403
  return `${ry}-${rmo}-${rd}`;
4310
4404
  }
4405
+ function applyLastDay(dateStr) {
4406
+ if (!dateStr || dateStr.length < 10) return dateStr;
4407
+ const { y, mo } = parseDateParts(dateStr);
4408
+ const dt = new Date(Date.UTC(+y, +mo, 0));
4409
+ const ry = String(dt.getUTCFullYear()).padStart(4, "0");
4410
+ const rmo = String(dt.getUTCMonth() + 1).padStart(2, "0");
4411
+ const rd = String(dt.getUTCDate()).padStart(2, "0");
4412
+ return `${ry}-${rmo}-${rd}`;
4413
+ }
4311
4414
  function applyFormat(num, pattern) {
4312
4415
  if (/^-?\d+$/.test(pattern.trim())) {
4313
4416
  return formatWithComma(num, Math.max(0, Number(pattern)));
@@ -31035,6 +31035,11 @@ var KEYWORDS = /* @__PURE__ */ new Map([
31035
31035
  ["COALESCE", "COALESCE" /* COALESCE */],
31036
31036
  ["NULLIF", "NULLIF" /* NULLIF */],
31037
31037
  ["ISNULL", "ISNULL" /* ISNULL */],
31038
+ ["INSTR", "INSTR" /* INSTR */],
31039
+ ["GREATEST", "GREATEST" /* GREATEST */],
31040
+ ["LEAST", "LEAST" /* LEAST */],
31041
+ ["LPAD", "LPAD" /* LPAD */],
31042
+ ["RPAD", "RPAD" /* RPAD */],
31038
31043
  ["CAST", "CAST" /* CAST */],
31039
31044
  ["CONVERT", "CONVERT" /* CONVERT */],
31040
31045
  ["FORMAT", "FORMAT" /* FORMAT */],
@@ -31042,6 +31047,8 @@ var KEYWORDS = /* @__PURE__ */ new Map([
31042
31047
  ["FLOOR", "FLOOR" /* FLOOR */],
31043
31048
  ["CEIL", "CEIL" /* CEIL */],
31044
31049
  ["CEILING", "CEILING" /* CEILING */],
31050
+ ["TRUNCATE", "TRUNCATE" /* TRUNCATE */],
31051
+ ["TRUNC", "TRUNC" /* TRUNC */],
31045
31052
  ["ABS", "ABS" /* ABS */],
31046
31053
  ["MOD", "MOD" /* MOD */],
31047
31054
  ["POWER", "POWER" /* POWER */],
@@ -31053,6 +31060,7 @@ var KEYWORDS = /* @__PURE__ */ new Map([
31053
31060
  ["DATE_FORMAT", "DATE_FORMAT" /* DATE_FORMAT */],
31054
31061
  ["DATEDIFF", "DATEDIFF" /* DATEDIFF */],
31055
31062
  ["DATE_ADD", "DATE_ADD" /* DATE_ADD */],
31063
+ ["LAST_DAY", "LAST_DAY" /* LAST_DAY */],
31056
31064
  ["IF", "IF" /* IF */]
31057
31065
  ]);
31058
31066
 
@@ -31398,6 +31406,13 @@ var FUNC_CALL_PREFIX_KINDS = /* @__PURE__ */ new Set([
31398
31406
  "COALESCE" /* COALESCE */,
31399
31407
  "NULLIF" /* NULLIF */,
31400
31408
  "ISNULL" /* ISNULL */,
31409
+ "LEFT" /* LEFT */,
31410
+ "RIGHT" /* RIGHT */,
31411
+ "INSTR" /* INSTR */,
31412
+ "GREATEST" /* GREATEST */,
31413
+ "LEAST" /* LEAST */,
31414
+ "LPAD" /* LPAD */,
31415
+ "RPAD" /* RPAD */,
31401
31416
  "CAST" /* CAST */,
31402
31417
  "CONVERT" /* CONVERT */,
31403
31418
  "FORMAT" /* FORMAT */,
@@ -31405,6 +31420,8 @@ var FUNC_CALL_PREFIX_KINDS = /* @__PURE__ */ new Set([
31405
31420
  "FLOOR" /* FLOOR */,
31406
31421
  "CEIL" /* CEIL */,
31407
31422
  "CEILING" /* CEILING */,
31423
+ "TRUNCATE" /* TRUNCATE */,
31424
+ "TRUNC" /* TRUNC */,
31408
31425
  "ABS" /* ABS */,
31409
31426
  "MOD" /* MOD */,
31410
31427
  "POWER" /* POWER */,
@@ -31416,6 +31433,7 @@ var FUNC_CALL_PREFIX_KINDS = /* @__PURE__ */ new Set([
31416
31433
  "DATE_FORMAT" /* DATE_FORMAT */,
31417
31434
  "DATEDIFF" /* DATEDIFF */,
31418
31435
  "DATE_ADD" /* DATE_ADD */,
31436
+ "LAST_DAY" /* LAST_DAY */,
31419
31437
  "IF" /* IF */
31420
31438
  ]);
31421
31439
  function needsSpaceBetween(prev, cur) {
@@ -32288,6 +32306,10 @@ var Parser = class {
32288
32306
  // arg: 文字列リテラル / 算術式(フィールド参照・数値含む)/ ネスト文字列関数
32289
32307
  // ──────────────────────────────────────────────────
32290
32308
  tryStringFuncName() {
32309
+ if (this.peekAt(1).kind === "(" /* LPAREN */) {
32310
+ if (this.peek().kind === "LEFT" /* LEFT */) return "LEFT";
32311
+ if (this.peek().kind === "RIGHT" /* RIGHT */) return "RIGHT";
32312
+ }
32291
32313
  const map2 = {
32292
32314
  ["UPPER" /* UPPER */]: "UPPER",
32293
32315
  ["LOWER" /* LOWER */]: "LOWER",
@@ -32302,6 +32324,11 @@ var Parser = class {
32302
32324
  ["COALESCE" /* COALESCE */]: "COALESCE",
32303
32325
  ["NULLIF" /* NULLIF */]: "NULLIF",
32304
32326
  ["ISNULL" /* ISNULL */]: "ISNULL",
32327
+ ["INSTR" /* INSTR */]: "INSTR",
32328
+ ["GREATEST" /* GREATEST */]: "GREATEST",
32329
+ ["LEAST" /* LEAST */]: "LEAST",
32330
+ ["LPAD" /* LPAD */]: "LPAD",
32331
+ ["RPAD" /* RPAD */]: "RPAD",
32305
32332
  ["CAST" /* CAST */]: "CAST",
32306
32333
  ["CONVERT" /* CONVERT */]: "CAST",
32307
32334
  // CONVERT → CAST に正規化
@@ -32311,12 +32338,16 @@ var Parser = class {
32311
32338
  ["CEIL" /* CEIL */]: "CEIL",
32312
32339
  ["CEILING" /* CEILING */]: "CEIL",
32313
32340
  // CEILING → CEIL に正規化
32341
+ ["TRUNCATE" /* TRUNCATE */]: "TRUNCATE",
32342
+ ["TRUNC" /* TRUNC */]: "TRUNCATE",
32343
+ // TRUNC → TRUNCATE に正規化
32314
32344
  ["YEAR" /* YEAR */]: "YEAR",
32315
32345
  ["MONTH" /* MONTH */]: "MONTH",
32316
32346
  ["DAY" /* DAY */]: "DAY",
32317
32347
  ["DATE_FORMAT" /* DATE_FORMAT */]: "DATE_FORMAT",
32318
32348
  ["DATEDIFF" /* DATEDIFF */]: "DATEDIFF",
32319
32349
  ["DATE_ADD" /* DATE_ADD */]: "DATE_ADD",
32350
+ ["LAST_DAY" /* LAST_DAY */]: "LAST_DAY",
32320
32351
  ["ABS" /* ABS */]: "ABS",
32321
32352
  ["MOD" /* MOD */]: "MOD",
32322
32353
  ["POWER" /* POWER */]: "POWER",
@@ -35043,6 +35074,25 @@ function compareScalarValues(op, leftStr, rightStr) {
35043
35074
  return numeric ? leftNum <= rightNum : leftStr <= rightStr;
35044
35075
  }
35045
35076
  }
35077
+ function selectScalarExtreme(values, extreme) {
35078
+ if (extreme === "least" && values.includes("")) return "";
35079
+ const candidates = extreme === "greatest" ? values.filter((value) => value !== "") : [...values];
35080
+ if (candidates.length === 0) return "";
35081
+ const numeric = candidates.every((value) => !Number.isNaN(Number(value)));
35082
+ const compare = (left, right) => {
35083
+ if (numeric) {
35084
+ const leftNum = Number(left);
35085
+ const rightNum = Number(right);
35086
+ if (leftNum < rightNum) return -1;
35087
+ if (leftNum > rightNum) return 1;
35088
+ }
35089
+ return left < right ? -1 : left > right ? 1 : 0;
35090
+ };
35091
+ return candidates.reduce((best, candidate) => {
35092
+ const cmp = compare(candidate, best);
35093
+ return extreme === "greatest" ? cmp > 0 ? candidate : best : cmp < 0 ? candidate : best;
35094
+ });
35095
+ }
35046
35096
 
35047
35097
  // src/engine/evalFunc.ts
35048
35098
  function evalArithExpr(expr, row) {
@@ -35091,6 +35141,36 @@ function evalStringFunc(expr, row) {
35091
35141
  const len = args[2] !== void 0 ? Number(args[2]) : void 0;
35092
35142
  return len !== void 0 ? str.slice(start, start + len) : str.slice(start);
35093
35143
  }
35144
+ case "LEFT": {
35145
+ assertArity("LEFT", args, 2, 2);
35146
+ const str = args[0];
35147
+ const n = Math.trunc(Number(args[1]));
35148
+ return Number.isNaN(n) || n <= 0 ? "" : str.slice(0, n);
35149
+ }
35150
+ case "RIGHT": {
35151
+ assertArity("RIGHT", args, 2, 2);
35152
+ const str = args[0];
35153
+ const n = Math.trunc(Number(args[1]));
35154
+ return Number.isNaN(n) || n <= 0 ? "" : str.slice(Math.max(0, str.length - n));
35155
+ }
35156
+ case "INSTR":
35157
+ assertArity("INSTR", args, 2, 2);
35158
+ return String(args[0].indexOf(args[1]) + 1);
35159
+ case "LPAD":
35160
+ case "RPAD": {
35161
+ assertArity(expr.func, args, 2, 3);
35162
+ const str = args[0];
35163
+ const n = Math.trunc(Number(args[1]));
35164
+ if (Number.isNaN(n) || n <= 0) return "";
35165
+ if (str.length >= n) return str.slice(0, n);
35166
+ const pad = args[2] ?? " ";
35167
+ if (pad === "") return str;
35168
+ return expr.func === "LPAD" ? str.padStart(n, pad) : str.padEnd(n, pad);
35169
+ }
35170
+ case "GREATEST":
35171
+ case "LEAST":
35172
+ assertArity(expr.func, args, 2);
35173
+ return selectScalarExtreme(args, expr.func === "GREATEST" ? "greatest" : "least");
35094
35174
  case "CONCAT":
35095
35175
  return args.join("");
35096
35176
  case "REPLACE": {
@@ -35111,6 +35191,9 @@ function evalStringFunc(expr, row) {
35111
35191
  return applyRoundOp("floor", Number(args[0] ?? "0"), Number(args[1] ?? "0"));
35112
35192
  case "CEIL":
35113
35193
  return applyRoundOp("ceil", Number(args[0] ?? "0"), Number(args[1] ?? "0"));
35194
+ case "TRUNCATE":
35195
+ assertArity("TRUNCATE", args, 1, 2);
35196
+ return applyRoundOp("trunc", Number(args[0]), Number(args[1] ?? "0"));
35114
35197
  case "CAST": {
35115
35198
  const val = args[0] ?? "";
35116
35199
  const castType = args[1] ?? "TEXT";
@@ -35143,6 +35226,9 @@ function evalStringFunc(expr, row) {
35143
35226
  return applyDateDiff(args[0] ?? "", args[1] ?? "");
35144
35227
  case "DATE_ADD":
35145
35228
  return applyDateAdd(args[0] ?? "", Number(args[1] ?? "0"), (args[2] ?? "DAY").toUpperCase());
35229
+ case "LAST_DAY":
35230
+ assertArity("LAST_DAY", args, 1, 1);
35231
+ return applyLastDay(args[0]);
35146
35232
  case "ABS":
35147
35233
  return String(Math.abs(Number(args[0] ?? "0")));
35148
35234
  case "MOD": {
@@ -35165,6 +35251,11 @@ function evalStringFunc(expr, row) {
35165
35251
  return (/* @__PURE__ */ new Date()).toISOString();
35166
35252
  }
35167
35253
  }
35254
+ function assertArity(func, args, min, max = Number.POSITIVE_INFINITY) {
35255
+ if (args.length >= min && args.length <= max) return;
35256
+ const expected = min === max ? String(min) : max === Number.POSITIVE_INFINITY ? `${min} or more` : `${min} to ${max}`;
35257
+ throw new Error(`ArgumentError: ${func} expects ${expected} argument(s).`);
35258
+ }
35168
35259
  function parseDateParts(s) {
35169
35260
  return {
35170
35261
  y: s.slice(0, 4) || "0000",
@@ -35189,6 +35280,9 @@ function applyDateDiff(date1, date22) {
35189
35280
  return String(Math.round((d1 - d2) / 864e5));
35190
35281
  }
35191
35282
  function applyDateAdd(dateStr, n, unit) {
35283
+ if (unit !== "YEAR" && unit !== "MONTH" && unit !== "DAY") {
35284
+ throw new Error("ArgumentError: DATE_ADD unit must be YEAR, MONTH, or DAY.");
35285
+ }
35192
35286
  if (!dateStr || dateStr.length < 10) return dateStr;
35193
35287
  const { y, mo, d } = parseDateParts(dateStr);
35194
35288
  const dt = new Date(Date.UTC(+y, +mo - 1, +d));
@@ -35199,7 +35293,7 @@ function applyDateAdd(dateStr, n, unit) {
35199
35293
  case "MONTH":
35200
35294
  dt.setUTCMonth(dt.getUTCMonth() + n);
35201
35295
  break;
35202
- default:
35296
+ case "DAY":
35203
35297
  dt.setUTCDate(dt.getUTCDate() + n);
35204
35298
  break;
35205
35299
  }
@@ -35208,6 +35302,15 @@ function applyDateAdd(dateStr, n, unit) {
35208
35302
  const rd = String(dt.getUTCDate()).padStart(2, "0");
35209
35303
  return `${ry}-${rmo}-${rd}`;
35210
35304
  }
35305
+ function applyLastDay(dateStr) {
35306
+ if (!dateStr || dateStr.length < 10) return dateStr;
35307
+ const { y, mo } = parseDateParts(dateStr);
35308
+ const dt = new Date(Date.UTC(+y, +mo, 0));
35309
+ const ry = String(dt.getUTCFullYear()).padStart(4, "0");
35310
+ const rmo = String(dt.getUTCMonth() + 1).padStart(2, "0");
35311
+ const rd = String(dt.getUTCDate()).padStart(2, "0");
35312
+ return `${ry}-${rmo}-${rd}`;
35313
+ }
35211
35314
  function applyFormat(num, pattern) {
35212
35315
  if (/^-?\d+$/.test(pattern.trim())) {
35213
35316
  return formatWithComma(num, Math.max(0, Number(pattern)));
@@ -42554,7 +42657,7 @@ Options:
42554
42657
  -h, --help Show help
42555
42658
  `);
42556
42659
  }
42557
- var SERVER_VERSION = true ? "2.16.0" : "0.0.0-dev";
42660
+ var SERVER_VERSION = true ? "2.17.0" : "0.0.0-dev";
42558
42661
  function createServer(args) {
42559
42662
  const server = new McpServer({
42560
42663
  name: "ksql-mcp",
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rex0220/kintone-sql-tools",
3
- "version": "2.16.0",
3
+ "version": "2.17.0",
4
4
  "description": "kintone SQL plugin, CLI, and MCP tools (ksql)",
5
5
  "publishConfig": {
6
6
  "access": "public"