@rex0220/kintone-sql-tools 2.15.0 → 2.16.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 +154 -14
- package/dist-mcp/ksql-mcp.js +155 -15
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +1 -1
package/dist-cli/ksql.js
CHANGED
|
@@ -88,6 +88,9 @@ var KEYWORDS = /* @__PURE__ */ new Map([
|
|
|
88
88
|
["MAX", "MAX" /* MAX */],
|
|
89
89
|
["MIN", "MIN" /* MIN */],
|
|
90
90
|
["GROUP_CONCAT", "GROUP_CONCAT" /* GROUP_CONCAT */],
|
|
91
|
+
["ROW_NUMBER", "ROW_NUMBER" /* ROW_NUMBER */],
|
|
92
|
+
["RANK", "RANK" /* RANK */],
|
|
93
|
+
["DENSE_RANK", "DENSE_RANK" /* DENSE_RANK */],
|
|
91
94
|
["ASSERT", "ASSERT" /* ASSERT */],
|
|
92
95
|
["AND", "AND" /* AND */],
|
|
93
96
|
["OR", "OR" /* OR */],
|
|
@@ -464,6 +467,9 @@ var FUNC_CALL_PREFIX_KINDS = /* @__PURE__ */ new Set([
|
|
|
464
467
|
"AVG" /* AVG */,
|
|
465
468
|
"MAX" /* MAX */,
|
|
466
469
|
"MIN" /* MIN */,
|
|
470
|
+
"ROW_NUMBER" /* ROW_NUMBER */,
|
|
471
|
+
"RANK" /* RANK */,
|
|
472
|
+
"DENSE_RANK" /* DENSE_RANK */,
|
|
467
473
|
"TODAY" /* TODAY */,
|
|
468
474
|
"NOW" /* NOW */,
|
|
469
475
|
"LOGINUSER" /* LOGINUSER */,
|
|
@@ -982,6 +988,11 @@ var Parser = class {
|
|
|
982
988
|
const orderBy = this.consume("ORDER" /* ORDER */) ? (this.expect("BY" /* BY */), this.parseOrderBy()) : [];
|
|
983
989
|
const limit = this.consume("LIMIT" /* LIMIT */) ? this.parseUnsignedInt() : null;
|
|
984
990
|
const offset = this.consume("OFFSET" /* OFFSET */) ? this.parseUnsignedInt() : null;
|
|
991
|
+
const hasWindow = columns.some((column) => column.type === "WINDOW_COL");
|
|
992
|
+
const hasAggregate = columns.some((column) => this.selectColumnHasAggregate(column));
|
|
993
|
+
if (hasWindow && (groupBy.length > 0 || hasAggregate)) {
|
|
994
|
+
throw new ParseError("\u30A6\u30A3\u30F3\u30C9\u30A6\u95A2\u6570\u306F GROUP BY / \u96C6\u8A08\u95A2\u6570\u3068\u540C\u3058 SELECT \u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", this.peek());
|
|
995
|
+
}
|
|
985
996
|
return {
|
|
986
997
|
type: "SELECT",
|
|
987
998
|
distinct,
|
|
@@ -1046,6 +1057,10 @@ var Parser = class {
|
|
|
1046
1057
|
if (this.consume("*" /* STAR */)) {
|
|
1047
1058
|
return { type: "WILDCARD" };
|
|
1048
1059
|
}
|
|
1060
|
+
const windowFunc = this.tryWindowFunc();
|
|
1061
|
+
if (windowFunc !== null) {
|
|
1062
|
+
return this.parseWindowColumn(windowFunc);
|
|
1063
|
+
}
|
|
1049
1064
|
if (this.peek().kind === "CASE" /* CASE */) {
|
|
1050
1065
|
const expr = this.parseCaseWhenExpr();
|
|
1051
1066
|
const alias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
|
|
@@ -1117,6 +1132,56 @@ var Parser = class {
|
|
|
1117
1132
|
const alias = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
|
|
1118
1133
|
return { type: "FIELD", field, alias };
|
|
1119
1134
|
}
|
|
1135
|
+
tryWindowFunc() {
|
|
1136
|
+
switch (this.peek().kind) {
|
|
1137
|
+
case "ROW_NUMBER" /* ROW_NUMBER */:
|
|
1138
|
+
return "ROW_NUMBER";
|
|
1139
|
+
case "RANK" /* RANK */:
|
|
1140
|
+
return "RANK";
|
|
1141
|
+
case "DENSE_RANK" /* DENSE_RANK */:
|
|
1142
|
+
return "DENSE_RANK";
|
|
1143
|
+
default:
|
|
1144
|
+
return null;
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
parseWindowColumn(func) {
|
|
1148
|
+
this.advance();
|
|
1149
|
+
this.expect("(" /* LPAREN */);
|
|
1150
|
+
if (this.peek().kind !== ")" /* RPAREN */) {
|
|
1151
|
+
throw new ParseError(`${func} \u306F\u5F15\u6570\u3092\u53D7\u3051\u4ED8\u3051\u307E\u305B\u3093`, this.peek());
|
|
1152
|
+
}
|
|
1153
|
+
this.expect(")" /* RPAREN */);
|
|
1154
|
+
this.expectSoftKeyword("OVER", `${func} \u306B\u306F OVER (...) \u304C\u5FC5\u8981\u3067\u3059`);
|
|
1155
|
+
this.expect("(" /* LPAREN */);
|
|
1156
|
+
const partitionBy = [];
|
|
1157
|
+
if (this.isSoftKeyword("PARTITION")) {
|
|
1158
|
+
this.advance();
|
|
1159
|
+
this.expect("BY" /* BY */, "PARTITION \u306E\u5F8C\u306B\u306F BY \u304C\u5FC5\u8981\u3067\u3059");
|
|
1160
|
+
do {
|
|
1161
|
+
const ref = this.parseQualifiedIdent();
|
|
1162
|
+
partitionBy.push({ type: "FIELD", tableAlias: ref.tableAlias, field: ref.field });
|
|
1163
|
+
} while (this.consume("," /* COMMA */));
|
|
1164
|
+
}
|
|
1165
|
+
const orderBy = this.consume("ORDER" /* ORDER */) ? (this.expect("BY" /* BY */), this.parseOrderBy()) : [];
|
|
1166
|
+
this.expect(")" /* RPAREN */);
|
|
1167
|
+
if (!this.consume("AS" /* AS */)) {
|
|
1168
|
+
throw new ParseError("\u30A6\u30A3\u30F3\u30C9\u30A6\u95A2\u6570\u306B\u306F AS alias \u304C\u5FC5\u8981\u3067\u3059", this.peek());
|
|
1169
|
+
}
|
|
1170
|
+
const alias = this.parseAliasName();
|
|
1171
|
+
return { type: "WINDOW_COL", func, partitionBy, orderBy, alias };
|
|
1172
|
+
}
|
|
1173
|
+
selectColumnHasAggregate(column) {
|
|
1174
|
+
if (column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL") return true;
|
|
1175
|
+
if (column.type !== "STRFUNC_COL") return false;
|
|
1176
|
+
return column.expr.args.some((arg) => this.stringFuncArgHasAggregate(arg));
|
|
1177
|
+
}
|
|
1178
|
+
stringFuncArgHasAggregate(arg) {
|
|
1179
|
+
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
|
|
1180
|
+
if (arg.type === "STRING_FUNC") {
|
|
1181
|
+
return arg.args.some((nested) => this.stringFuncArgHasAggregate(nested));
|
|
1182
|
+
}
|
|
1183
|
+
return false;
|
|
1184
|
+
}
|
|
1120
1185
|
isArithOp(kind) {
|
|
1121
1186
|
return kind === "+" /* PLUS */ || kind === "-" /* MINUS */ || kind === "*" /* STAR */ || kind === "/" /* SLASH */ || kind === "%" /* PERCENT */;
|
|
1122
1187
|
}
|
|
@@ -2898,12 +2963,16 @@ var KintoneQueryError = class extends Error {
|
|
|
2898
2963
|
};
|
|
2899
2964
|
|
|
2900
2965
|
// src/converter/selectToKintone.ts
|
|
2966
|
+
function hasWindowColumns(columns) {
|
|
2967
|
+
return columns.some((column) => column.type === "WINDOW_COL");
|
|
2968
|
+
}
|
|
2901
2969
|
function resolveSelectMode(stmt) {
|
|
2902
2970
|
if (stmt.from.subtableCode) return "FULL_SCAN";
|
|
2903
2971
|
if (stmt.joins.some((j) => j.table.subtableCode)) return "FULL_SCAN";
|
|
2904
2972
|
if (stmt.joins.length > 0) return "FULL_SCAN";
|
|
2905
2973
|
if (stmt.groupBy.length > 0) return "FULL_SCAN";
|
|
2906
2974
|
if (stmt.distinct) return "FULL_SCAN";
|
|
2975
|
+
if (hasWindowColumns(stmt.columns)) return "FULL_SCAN";
|
|
2907
2976
|
if (stmt.columns.some(
|
|
2908
2977
|
(c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "SCALAR_SUBQUERY_COL" || c.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr(c.expr)
|
|
2909
2978
|
)) return "FULL_SCAN";
|
|
@@ -3275,16 +3344,16 @@ function collectRequiredFieldsByTable(stmt) {
|
|
|
3275
3344
|
}
|
|
3276
3345
|
walkStringFunc(k.expr, "groupBy");
|
|
3277
3346
|
};
|
|
3278
|
-
const walkOrderByKey = (k) => {
|
|
3347
|
+
const walkOrderByKey = (k, phase = "orderBy") => {
|
|
3279
3348
|
if (k.type === "FIELD_NAME") {
|
|
3280
|
-
addFieldName(k.name,
|
|
3349
|
+
addFieldName(k.name, phase);
|
|
3281
3350
|
return;
|
|
3282
3351
|
}
|
|
3283
3352
|
if (k.type === "ARITH_KEY") {
|
|
3284
|
-
walkArith(k.expr,
|
|
3353
|
+
walkArith(k.expr, phase);
|
|
3285
3354
|
return;
|
|
3286
3355
|
}
|
|
3287
|
-
walkStringFunc(k.expr,
|
|
3356
|
+
walkStringFunc(k.expr, phase);
|
|
3288
3357
|
};
|
|
3289
3358
|
for (const col of stmt.columns) {
|
|
3290
3359
|
switch (col.type) {
|
|
@@ -3316,6 +3385,10 @@ function collectRequiredFieldsByTable(stmt) {
|
|
|
3316
3385
|
break;
|
|
3317
3386
|
case "SCALAR_SUBQUERY_COL":
|
|
3318
3387
|
break;
|
|
3388
|
+
case "WINDOW_COL":
|
|
3389
|
+
for (const ref of col.partitionBy) addFieldRef(ref.field, ref.tableAlias, "select");
|
|
3390
|
+
for (const item of col.orderBy) walkOrderByKey(item.key, "select");
|
|
3391
|
+
break;
|
|
3319
3392
|
}
|
|
3320
3393
|
}
|
|
3321
3394
|
for (const join2 of stmt.joins) {
|
|
@@ -3362,6 +3435,10 @@ function collectSelectOutputNames(columns) {
|
|
|
3362
3435
|
}
|
|
3363
3436
|
if (col.type === "SCALAR_SUBQUERY_COL") {
|
|
3364
3437
|
names.add(col.alias ?? "(subquery)");
|
|
3438
|
+
continue;
|
|
3439
|
+
}
|
|
3440
|
+
if (col.type === "WINDOW_COL") {
|
|
3441
|
+
names.add(col.alias);
|
|
3365
3442
|
}
|
|
3366
3443
|
}
|
|
3367
3444
|
return names;
|
|
@@ -5309,6 +5386,10 @@ function buildDistinctKeyBuilder(rows, columns) {
|
|
|
5309
5386
|
values.push(row[col.field] ?? "");
|
|
5310
5387
|
continue;
|
|
5311
5388
|
}
|
|
5389
|
+
if (col.type === "WINDOW_COL") {
|
|
5390
|
+
values.push(row[col.alias] ?? "");
|
|
5391
|
+
continue;
|
|
5392
|
+
}
|
|
5312
5393
|
if (col.type === "PARENT_WILDCARD") {
|
|
5313
5394
|
for (const k of sortedParentKeys) {
|
|
5314
5395
|
values.push(row[k] !== void 0 ? row[k] : null);
|
|
@@ -5320,6 +5401,9 @@ function buildDistinctKeyBuilder(rows, columns) {
|
|
|
5320
5401
|
}
|
|
5321
5402
|
function applyOrderBy(rows, orderBy, optionOrders, sortKinds) {
|
|
5322
5403
|
if (orderBy.length === 0) return rows;
|
|
5404
|
+
return sortDecoratedRows(rows, orderBy, optionOrders, sortKinds).rows.map((item) => item.row);
|
|
5405
|
+
}
|
|
5406
|
+
function sortDecoratedRows(rows, orderBy, optionOrders, sortKinds) {
|
|
5323
5407
|
const keyMeta = orderBy.map(({ key }) => ({
|
|
5324
5408
|
orderMap: key.type === "FIELD_NAME" ? optionOrders?.get(key.name) : void 0,
|
|
5325
5409
|
sortKind: key.type === "FIELD_NAME" ? sortKinds?.get(key.name) : void 0
|
|
@@ -5338,14 +5422,16 @@ function applyOrderBy(rows, orderBy, optionOrders, sortKinds) {
|
|
|
5338
5422
|
};
|
|
5339
5423
|
})
|
|
5340
5424
|
}));
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5425
|
+
const compare = (a, b) => compareDecoratedRows(a, b, orderBy, keyMeta);
|
|
5426
|
+
decorated.sort(compare);
|
|
5427
|
+
return { rows: decorated, compare };
|
|
5428
|
+
}
|
|
5429
|
+
function compareDecoratedRows(a, b, orderBy, keyMeta) {
|
|
5430
|
+
for (let i = 0; i < orderBy.length; i++) {
|
|
5431
|
+
const cmp = compareSortKeys(a.keys[i], b.keys[i], keyMeta[i]);
|
|
5432
|
+
if (cmp !== 0) return orderBy[i].direction === "ASC" ? cmp : -cmp;
|
|
5433
|
+
}
|
|
5434
|
+
return 0;
|
|
5349
5435
|
}
|
|
5350
5436
|
function compareSortKeys(a, b, meta) {
|
|
5351
5437
|
if (meta.orderMap) {
|
|
@@ -5390,6 +5476,38 @@ function minChoiceIndex(values, orderMap) {
|
|
|
5390
5476
|
}
|
|
5391
5477
|
return min;
|
|
5392
5478
|
}
|
|
5479
|
+
function applyWindow(rows, columns, optionOrders, sortKinds) {
|
|
5480
|
+
const windows = columns.filter((column) => column.type === "WINDOW_COL");
|
|
5481
|
+
if (rows.length === 0 || windows.length === 0) return rows;
|
|
5482
|
+
for (const window of windows) {
|
|
5483
|
+
const partitions = /* @__PURE__ */ new Map();
|
|
5484
|
+
for (const row of rows) {
|
|
5485
|
+
const key = JSON.stringify(window.partitionBy.map((ref) => resolveWindowField(row, ref)));
|
|
5486
|
+
const partition = partitions.get(key);
|
|
5487
|
+
if (partition) partition.push(row);
|
|
5488
|
+
else partitions.set(key, [row]);
|
|
5489
|
+
}
|
|
5490
|
+
for (const partition of partitions.values()) {
|
|
5491
|
+
const sortedResult = sortDecoratedRows(partition, window.orderBy, optionOrders, sortKinds);
|
|
5492
|
+
const sorted = sortedResult.rows;
|
|
5493
|
+
let rank = 1;
|
|
5494
|
+
let denseRank = 1;
|
|
5495
|
+
for (let index = 0; index < sorted.length; index++) {
|
|
5496
|
+
if (index > 0 && sortedResult.compare(sorted[index - 1], sorted[index]) !== 0) {
|
|
5497
|
+
rank = index + 1;
|
|
5498
|
+
denseRank++;
|
|
5499
|
+
}
|
|
5500
|
+
const value = window.func === "ROW_NUMBER" ? index + 1 : window.func === "RANK" ? rank : denseRank;
|
|
5501
|
+
sorted[index].row[window.alias] = String(value);
|
|
5502
|
+
}
|
|
5503
|
+
}
|
|
5504
|
+
}
|
|
5505
|
+
return rows;
|
|
5506
|
+
}
|
|
5507
|
+
function resolveWindowField(row, ref) {
|
|
5508
|
+
const name = ref.tableAlias ? `${ref.tableAlias}.${ref.field}` : ref.field;
|
|
5509
|
+
return resolveFieldRef(row, name);
|
|
5510
|
+
}
|
|
5393
5511
|
function applyLimit(rows, limit, offset) {
|
|
5394
5512
|
const start = offset ?? 0;
|
|
5395
5513
|
if (limit === null) return rows.slice(start);
|
|
@@ -5480,6 +5598,12 @@ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns) {
|
|
|
5480
5598
|
if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
|
|
5481
5599
|
break;
|
|
5482
5600
|
}
|
|
5601
|
+
case "WINDOW_COL": {
|
|
5602
|
+
const key = outputKeys?.[colIdx] ?? col.alias;
|
|
5603
|
+
out[key] = row[col.alias] ?? "";
|
|
5604
|
+
if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
|
|
5605
|
+
break;
|
|
5606
|
+
}
|
|
5483
5607
|
}
|
|
5484
5608
|
}
|
|
5485
5609
|
return out;
|
|
@@ -5520,6 +5644,8 @@ function computeOutputKey(col, colIdx, defaultFieldKeys) {
|
|
|
5520
5644
|
return col.alias ?? stringFuncDefaultKey(col.expr);
|
|
5521
5645
|
case "SCALAR_SUBQUERY_COL":
|
|
5522
5646
|
return col.alias ?? "(subquery)";
|
|
5647
|
+
case "WINDOW_COL":
|
|
5648
|
+
return col.alias;
|
|
5523
5649
|
case "WILDCARD":
|
|
5524
5650
|
case "PARENT_WILDCARD":
|
|
5525
5651
|
throw new Error("internal: computeOutputKey received a wildcard column");
|
|
@@ -5634,6 +5760,7 @@ function runFullScan(input) {
|
|
|
5634
5760
|
rows = applyGroupBy(rows, stmt.groupBy, stmt.columns, aggregateSortKindResolver);
|
|
5635
5761
|
}
|
|
5636
5762
|
rows = applyHaving(rows, stmt.having, havingFieldTypeResolver);
|
|
5763
|
+
rows = applyWindow(rows, stmt.columns, optionOrders, sortKinds);
|
|
5637
5764
|
if (stmt.distinct) {
|
|
5638
5765
|
rows = applyDistinct(rows, stmt.columns);
|
|
5639
5766
|
}
|
|
@@ -6578,6 +6705,11 @@ function validateNoFromColumns(stmt) {
|
|
|
6578
6705
|
throw new Error("ArgumentError: field reference is not allowed without FROM.");
|
|
6579
6706
|
}
|
|
6580
6707
|
break;
|
|
6708
|
+
case "WINDOW_COL":
|
|
6709
|
+
if (col.partitionBy.length > 0 || col.orderBy.length > 0) {
|
|
6710
|
+
throw new Error("ArgumentError: field reference is not allowed without FROM.");
|
|
6711
|
+
}
|
|
6712
|
+
break;
|
|
6581
6713
|
default:
|
|
6582
6714
|
throw new Error(`ArgumentError: ${col.type} is not supported without FROM.`);
|
|
6583
6715
|
}
|
|
@@ -6588,7 +6720,8 @@ function executeNoFromSelect(stmt) {
|
|
|
6588
6720
|
throw new Error("ArgumentError: JOIN/WHERE/GROUP BY/HAVING/ORDER BY/DISTINCT are not supported without FROM.");
|
|
6589
6721
|
}
|
|
6590
6722
|
validateNoFromColumns(stmt);
|
|
6591
|
-
const
|
|
6723
|
+
const windowed = applyWindow([{}], stmt.columns);
|
|
6724
|
+
const { rows: projected, columns } = project(windowed, stmt.columns);
|
|
6592
6725
|
const rows = applyLimit(projected, stmt.limit, stmt.offset);
|
|
6593
6726
|
return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [] };
|
|
6594
6727
|
}
|
|
@@ -7012,6 +7145,8 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
|
|
|
7012
7145
|
meta = { sortKind: "number" };
|
|
7013
7146
|
} else if (column.type === "LITERAL_COL") {
|
|
7014
7147
|
meta = { sortKind: "string" };
|
|
7148
|
+
} else if (column.type === "WINDOW_COL") {
|
|
7149
|
+
meta = { sortKind: "number" };
|
|
7015
7150
|
}
|
|
7016
7151
|
if (meta) inferred.set(output, meta);
|
|
7017
7152
|
});
|
|
@@ -7597,7 +7732,10 @@ async function getSortKindMapByApp(appId, client, cacheContext) {
|
|
|
7597
7732
|
return map;
|
|
7598
7733
|
}
|
|
7599
7734
|
async function buildOrderByMetaForSelect(stmt, client, cacheContext) {
|
|
7600
|
-
|
|
7735
|
+
const hasWindowOrderBy = stmt.columns.some(
|
|
7736
|
+
(column) => column.type === "WINDOW_COL" && column.orderBy.length > 0
|
|
7737
|
+
);
|
|
7738
|
+
if (stmt.orderBy.length === 0 && !hasWindowOrderBy) {
|
|
7601
7739
|
return { optionOrders: /* @__PURE__ */ new Map(), sortKinds: /* @__PURE__ */ new Map() };
|
|
7602
7740
|
}
|
|
7603
7741
|
const [optionOrders, sortKinds] = await Promise.all([
|
|
@@ -9059,6 +9197,8 @@ function collectFullScanReasons(stmt) {
|
|
|
9059
9197
|
r.push("DISTINCT \u3042\u308A");
|
|
9060
9198
|
if (stmt.columns.some((c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL"))
|
|
9061
9199
|
r.push("\u96C6\u8A08\u95A2\u6570\uFF08COUNT / SUM \u7B49\uFF09\u3042\u308A");
|
|
9200
|
+
if (stmt.columns.some((c) => c.type === "WINDOW_COL"))
|
|
9201
|
+
r.push("\u30A6\u30A3\u30F3\u30C9\u30A6\u95A2\u6570\u3042\u308A");
|
|
9062
9202
|
if (stmt.columns.some((c) => c.type === "SCALAR_SUBQUERY_COL"))
|
|
9063
9203
|
r.push("SELECT \u5217\u306B\u30B9\u30AB\u30E9\u30FC\u30B5\u30D6\u30AF\u30A8\u30EA");
|
|
9064
9204
|
if (whereRequiresJsEval(stmt.where))
|
package/dist-mcp/ksql-mcp.js
CHANGED
|
@@ -31000,6 +31000,9 @@ var KEYWORDS = /* @__PURE__ */ new Map([
|
|
|
31000
31000
|
["MAX", "MAX" /* MAX */],
|
|
31001
31001
|
["MIN", "MIN" /* MIN */],
|
|
31002
31002
|
["GROUP_CONCAT", "GROUP_CONCAT" /* GROUP_CONCAT */],
|
|
31003
|
+
["ROW_NUMBER", "ROW_NUMBER" /* ROW_NUMBER */],
|
|
31004
|
+
["RANK", "RANK" /* RANK */],
|
|
31005
|
+
["DENSE_RANK", "DENSE_RANK" /* DENSE_RANK */],
|
|
31003
31006
|
["ASSERT", "ASSERT" /* ASSERT */],
|
|
31004
31007
|
["AND", "AND" /* AND */],
|
|
31005
31008
|
["OR", "OR" /* OR */],
|
|
@@ -31376,6 +31379,9 @@ var FUNC_CALL_PREFIX_KINDS = /* @__PURE__ */ new Set([
|
|
|
31376
31379
|
"AVG" /* AVG */,
|
|
31377
31380
|
"MAX" /* MAX */,
|
|
31378
31381
|
"MIN" /* MIN */,
|
|
31382
|
+
"ROW_NUMBER" /* ROW_NUMBER */,
|
|
31383
|
+
"RANK" /* RANK */,
|
|
31384
|
+
"DENSE_RANK" /* DENSE_RANK */,
|
|
31379
31385
|
"TODAY" /* TODAY */,
|
|
31380
31386
|
"NOW" /* NOW */,
|
|
31381
31387
|
"LOGINUSER" /* LOGINUSER */,
|
|
@@ -31894,6 +31900,11 @@ var Parser = class {
|
|
|
31894
31900
|
const orderBy = this.consume("ORDER" /* ORDER */) ? (this.expect("BY" /* BY */), this.parseOrderBy()) : [];
|
|
31895
31901
|
const limit = this.consume("LIMIT" /* LIMIT */) ? this.parseUnsignedInt() : null;
|
|
31896
31902
|
const offset = this.consume("OFFSET" /* OFFSET */) ? this.parseUnsignedInt() : null;
|
|
31903
|
+
const hasWindow = columns.some((column) => column.type === "WINDOW_COL");
|
|
31904
|
+
const hasAggregate = columns.some((column) => this.selectColumnHasAggregate(column));
|
|
31905
|
+
if (hasWindow && (groupBy.length > 0 || hasAggregate)) {
|
|
31906
|
+
throw new ParseError("\u30A6\u30A3\u30F3\u30C9\u30A6\u95A2\u6570\u306F GROUP BY / \u96C6\u8A08\u95A2\u6570\u3068\u540C\u3058 SELECT \u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", this.peek());
|
|
31907
|
+
}
|
|
31897
31908
|
return {
|
|
31898
31909
|
type: "SELECT",
|
|
31899
31910
|
distinct,
|
|
@@ -31958,6 +31969,10 @@ var Parser = class {
|
|
|
31958
31969
|
if (this.consume("*" /* STAR */)) {
|
|
31959
31970
|
return { type: "WILDCARD" };
|
|
31960
31971
|
}
|
|
31972
|
+
const windowFunc = this.tryWindowFunc();
|
|
31973
|
+
if (windowFunc !== null) {
|
|
31974
|
+
return this.parseWindowColumn(windowFunc);
|
|
31975
|
+
}
|
|
31961
31976
|
if (this.peek().kind === "CASE" /* CASE */) {
|
|
31962
31977
|
const expr = this.parseCaseWhenExpr();
|
|
31963
31978
|
const alias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
|
|
@@ -32029,6 +32044,56 @@ var Parser = class {
|
|
|
32029
32044
|
const alias = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
|
|
32030
32045
|
return { type: "FIELD", field, alias };
|
|
32031
32046
|
}
|
|
32047
|
+
tryWindowFunc() {
|
|
32048
|
+
switch (this.peek().kind) {
|
|
32049
|
+
case "ROW_NUMBER" /* ROW_NUMBER */:
|
|
32050
|
+
return "ROW_NUMBER";
|
|
32051
|
+
case "RANK" /* RANK */:
|
|
32052
|
+
return "RANK";
|
|
32053
|
+
case "DENSE_RANK" /* DENSE_RANK */:
|
|
32054
|
+
return "DENSE_RANK";
|
|
32055
|
+
default:
|
|
32056
|
+
return null;
|
|
32057
|
+
}
|
|
32058
|
+
}
|
|
32059
|
+
parseWindowColumn(func) {
|
|
32060
|
+
this.advance();
|
|
32061
|
+
this.expect("(" /* LPAREN */);
|
|
32062
|
+
if (this.peek().kind !== ")" /* RPAREN */) {
|
|
32063
|
+
throw new ParseError(`${func} \u306F\u5F15\u6570\u3092\u53D7\u3051\u4ED8\u3051\u307E\u305B\u3093`, this.peek());
|
|
32064
|
+
}
|
|
32065
|
+
this.expect(")" /* RPAREN */);
|
|
32066
|
+
this.expectSoftKeyword("OVER", `${func} \u306B\u306F OVER (...) \u304C\u5FC5\u8981\u3067\u3059`);
|
|
32067
|
+
this.expect("(" /* LPAREN */);
|
|
32068
|
+
const partitionBy = [];
|
|
32069
|
+
if (this.isSoftKeyword("PARTITION")) {
|
|
32070
|
+
this.advance();
|
|
32071
|
+
this.expect("BY" /* BY */, "PARTITION \u306E\u5F8C\u306B\u306F BY \u304C\u5FC5\u8981\u3067\u3059");
|
|
32072
|
+
do {
|
|
32073
|
+
const ref = this.parseQualifiedIdent();
|
|
32074
|
+
partitionBy.push({ type: "FIELD", tableAlias: ref.tableAlias, field: ref.field });
|
|
32075
|
+
} while (this.consume("," /* COMMA */));
|
|
32076
|
+
}
|
|
32077
|
+
const orderBy = this.consume("ORDER" /* ORDER */) ? (this.expect("BY" /* BY */), this.parseOrderBy()) : [];
|
|
32078
|
+
this.expect(")" /* RPAREN */);
|
|
32079
|
+
if (!this.consume("AS" /* AS */)) {
|
|
32080
|
+
throw new ParseError("\u30A6\u30A3\u30F3\u30C9\u30A6\u95A2\u6570\u306B\u306F AS alias \u304C\u5FC5\u8981\u3067\u3059", this.peek());
|
|
32081
|
+
}
|
|
32082
|
+
const alias = this.parseAliasName();
|
|
32083
|
+
return { type: "WINDOW_COL", func, partitionBy, orderBy, alias };
|
|
32084
|
+
}
|
|
32085
|
+
selectColumnHasAggregate(column) {
|
|
32086
|
+
if (column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL") return true;
|
|
32087
|
+
if (column.type !== "STRFUNC_COL") return false;
|
|
32088
|
+
return column.expr.args.some((arg) => this.stringFuncArgHasAggregate(arg));
|
|
32089
|
+
}
|
|
32090
|
+
stringFuncArgHasAggregate(arg) {
|
|
32091
|
+
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
|
|
32092
|
+
if (arg.type === "STRING_FUNC") {
|
|
32093
|
+
return arg.args.some((nested) => this.stringFuncArgHasAggregate(nested));
|
|
32094
|
+
}
|
|
32095
|
+
return false;
|
|
32096
|
+
}
|
|
32032
32097
|
isArithOp(kind) {
|
|
32033
32098
|
return kind === "+" /* PLUS */ || kind === "-" /* MINUS */ || kind === "*" /* STAR */ || kind === "/" /* SLASH */ || kind === "%" /* PERCENT */;
|
|
32034
32099
|
}
|
|
@@ -33798,12 +33863,16 @@ var KintoneQueryError = class extends Error {
|
|
|
33798
33863
|
};
|
|
33799
33864
|
|
|
33800
33865
|
// src/converter/selectToKintone.ts
|
|
33866
|
+
function hasWindowColumns(columns) {
|
|
33867
|
+
return columns.some((column) => column.type === "WINDOW_COL");
|
|
33868
|
+
}
|
|
33801
33869
|
function resolveSelectMode(stmt) {
|
|
33802
33870
|
if (stmt.from.subtableCode) return "FULL_SCAN";
|
|
33803
33871
|
if (stmt.joins.some((j) => j.table.subtableCode)) return "FULL_SCAN";
|
|
33804
33872
|
if (stmt.joins.length > 0) return "FULL_SCAN";
|
|
33805
33873
|
if (stmt.groupBy.length > 0) return "FULL_SCAN";
|
|
33806
33874
|
if (stmt.distinct) return "FULL_SCAN";
|
|
33875
|
+
if (hasWindowColumns(stmt.columns)) return "FULL_SCAN";
|
|
33807
33876
|
if (stmt.columns.some(
|
|
33808
33877
|
(c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "SCALAR_SUBQUERY_COL" || c.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr(c.expr)
|
|
33809
33878
|
)) return "FULL_SCAN";
|
|
@@ -34175,16 +34244,16 @@ function collectRequiredFieldsByTable(stmt) {
|
|
|
34175
34244
|
}
|
|
34176
34245
|
walkStringFunc(k.expr, "groupBy");
|
|
34177
34246
|
};
|
|
34178
|
-
const walkOrderByKey = (k) => {
|
|
34247
|
+
const walkOrderByKey = (k, phase = "orderBy") => {
|
|
34179
34248
|
if (k.type === "FIELD_NAME") {
|
|
34180
|
-
addFieldName(k.name,
|
|
34249
|
+
addFieldName(k.name, phase);
|
|
34181
34250
|
return;
|
|
34182
34251
|
}
|
|
34183
34252
|
if (k.type === "ARITH_KEY") {
|
|
34184
|
-
walkArith(k.expr,
|
|
34253
|
+
walkArith(k.expr, phase);
|
|
34185
34254
|
return;
|
|
34186
34255
|
}
|
|
34187
|
-
walkStringFunc(k.expr,
|
|
34256
|
+
walkStringFunc(k.expr, phase);
|
|
34188
34257
|
};
|
|
34189
34258
|
for (const col of stmt.columns) {
|
|
34190
34259
|
switch (col.type) {
|
|
@@ -34216,6 +34285,10 @@ function collectRequiredFieldsByTable(stmt) {
|
|
|
34216
34285
|
break;
|
|
34217
34286
|
case "SCALAR_SUBQUERY_COL":
|
|
34218
34287
|
break;
|
|
34288
|
+
case "WINDOW_COL":
|
|
34289
|
+
for (const ref of col.partitionBy) addFieldRef(ref.field, ref.tableAlias, "select");
|
|
34290
|
+
for (const item of col.orderBy) walkOrderByKey(item.key, "select");
|
|
34291
|
+
break;
|
|
34219
34292
|
}
|
|
34220
34293
|
}
|
|
34221
34294
|
for (const join of stmt.joins) {
|
|
@@ -34262,6 +34335,10 @@ function collectSelectOutputNames(columns) {
|
|
|
34262
34335
|
}
|
|
34263
34336
|
if (col.type === "SCALAR_SUBQUERY_COL") {
|
|
34264
34337
|
names.add(col.alias ?? "(subquery)");
|
|
34338
|
+
continue;
|
|
34339
|
+
}
|
|
34340
|
+
if (col.type === "WINDOW_COL") {
|
|
34341
|
+
names.add(col.alias);
|
|
34265
34342
|
}
|
|
34266
34343
|
}
|
|
34267
34344
|
return names;
|
|
@@ -36209,6 +36286,10 @@ function buildDistinctKeyBuilder(rows, columns) {
|
|
|
36209
36286
|
values.push(row[col.field] ?? "");
|
|
36210
36287
|
continue;
|
|
36211
36288
|
}
|
|
36289
|
+
if (col.type === "WINDOW_COL") {
|
|
36290
|
+
values.push(row[col.alias] ?? "");
|
|
36291
|
+
continue;
|
|
36292
|
+
}
|
|
36212
36293
|
if (col.type === "PARENT_WILDCARD") {
|
|
36213
36294
|
for (const k of sortedParentKeys) {
|
|
36214
36295
|
values.push(row[k] !== void 0 ? row[k] : null);
|
|
@@ -36220,6 +36301,9 @@ function buildDistinctKeyBuilder(rows, columns) {
|
|
|
36220
36301
|
}
|
|
36221
36302
|
function applyOrderBy(rows, orderBy, optionOrders, sortKinds) {
|
|
36222
36303
|
if (orderBy.length === 0) return rows;
|
|
36304
|
+
return sortDecoratedRows(rows, orderBy, optionOrders, sortKinds).rows.map((item) => item.row);
|
|
36305
|
+
}
|
|
36306
|
+
function sortDecoratedRows(rows, orderBy, optionOrders, sortKinds) {
|
|
36223
36307
|
const keyMeta = orderBy.map(({ key }) => ({
|
|
36224
36308
|
orderMap: key.type === "FIELD_NAME" ? optionOrders?.get(key.name) : void 0,
|
|
36225
36309
|
sortKind: key.type === "FIELD_NAME" ? sortKinds?.get(key.name) : void 0
|
|
@@ -36238,14 +36322,16 @@ function applyOrderBy(rows, orderBy, optionOrders, sortKinds) {
|
|
|
36238
36322
|
};
|
|
36239
36323
|
})
|
|
36240
36324
|
}));
|
|
36241
|
-
|
|
36242
|
-
|
|
36243
|
-
|
|
36244
|
-
|
|
36245
|
-
|
|
36246
|
-
|
|
36247
|
-
|
|
36248
|
-
|
|
36325
|
+
const compare = (a, b) => compareDecoratedRows(a, b, orderBy, keyMeta);
|
|
36326
|
+
decorated.sort(compare);
|
|
36327
|
+
return { rows: decorated, compare };
|
|
36328
|
+
}
|
|
36329
|
+
function compareDecoratedRows(a, b, orderBy, keyMeta) {
|
|
36330
|
+
for (let i = 0; i < orderBy.length; i++) {
|
|
36331
|
+
const cmp = compareSortKeys(a.keys[i], b.keys[i], keyMeta[i]);
|
|
36332
|
+
if (cmp !== 0) return orderBy[i].direction === "ASC" ? cmp : -cmp;
|
|
36333
|
+
}
|
|
36334
|
+
return 0;
|
|
36249
36335
|
}
|
|
36250
36336
|
function compareSortKeys(a, b, meta3) {
|
|
36251
36337
|
if (meta3.orderMap) {
|
|
@@ -36290,6 +36376,38 @@ function minChoiceIndex(values, orderMap) {
|
|
|
36290
36376
|
}
|
|
36291
36377
|
return min;
|
|
36292
36378
|
}
|
|
36379
|
+
function applyWindow(rows, columns, optionOrders, sortKinds) {
|
|
36380
|
+
const windows = columns.filter((column) => column.type === "WINDOW_COL");
|
|
36381
|
+
if (rows.length === 0 || windows.length === 0) return rows;
|
|
36382
|
+
for (const window of windows) {
|
|
36383
|
+
const partitions = /* @__PURE__ */ new Map();
|
|
36384
|
+
for (const row of rows) {
|
|
36385
|
+
const key = JSON.stringify(window.partitionBy.map((ref) => resolveWindowField(row, ref)));
|
|
36386
|
+
const partition = partitions.get(key);
|
|
36387
|
+
if (partition) partition.push(row);
|
|
36388
|
+
else partitions.set(key, [row]);
|
|
36389
|
+
}
|
|
36390
|
+
for (const partition of partitions.values()) {
|
|
36391
|
+
const sortedResult = sortDecoratedRows(partition, window.orderBy, optionOrders, sortKinds);
|
|
36392
|
+
const sorted = sortedResult.rows;
|
|
36393
|
+
let rank = 1;
|
|
36394
|
+
let denseRank = 1;
|
|
36395
|
+
for (let index = 0; index < sorted.length; index++) {
|
|
36396
|
+
if (index > 0 && sortedResult.compare(sorted[index - 1], sorted[index]) !== 0) {
|
|
36397
|
+
rank = index + 1;
|
|
36398
|
+
denseRank++;
|
|
36399
|
+
}
|
|
36400
|
+
const value = window.func === "ROW_NUMBER" ? index + 1 : window.func === "RANK" ? rank : denseRank;
|
|
36401
|
+
sorted[index].row[window.alias] = String(value);
|
|
36402
|
+
}
|
|
36403
|
+
}
|
|
36404
|
+
}
|
|
36405
|
+
return rows;
|
|
36406
|
+
}
|
|
36407
|
+
function resolveWindowField(row, ref) {
|
|
36408
|
+
const name = ref.tableAlias ? `${ref.tableAlias}.${ref.field}` : ref.field;
|
|
36409
|
+
return resolveFieldRef(row, name);
|
|
36410
|
+
}
|
|
36293
36411
|
function applyLimit(rows, limit, offset) {
|
|
36294
36412
|
const start = offset ?? 0;
|
|
36295
36413
|
if (limit === null) return rows.slice(start);
|
|
@@ -36380,6 +36498,12 @@ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns) {
|
|
|
36380
36498
|
if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
|
|
36381
36499
|
break;
|
|
36382
36500
|
}
|
|
36501
|
+
case "WINDOW_COL": {
|
|
36502
|
+
const key = outputKeys?.[colIdx] ?? col.alias;
|
|
36503
|
+
out[key] = row[col.alias] ?? "";
|
|
36504
|
+
if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
|
|
36505
|
+
break;
|
|
36506
|
+
}
|
|
36383
36507
|
}
|
|
36384
36508
|
}
|
|
36385
36509
|
return out;
|
|
@@ -36420,6 +36544,8 @@ function computeOutputKey(col, colIdx, defaultFieldKeys) {
|
|
|
36420
36544
|
return col.alias ?? stringFuncDefaultKey(col.expr);
|
|
36421
36545
|
case "SCALAR_SUBQUERY_COL":
|
|
36422
36546
|
return col.alias ?? "(subquery)";
|
|
36547
|
+
case "WINDOW_COL":
|
|
36548
|
+
return col.alias;
|
|
36423
36549
|
case "WILDCARD":
|
|
36424
36550
|
case "PARENT_WILDCARD":
|
|
36425
36551
|
throw new Error("internal: computeOutputKey received a wildcard column");
|
|
@@ -36534,6 +36660,7 @@ function runFullScan(input) {
|
|
|
36534
36660
|
rows = applyGroupBy(rows, stmt.groupBy, stmt.columns, aggregateSortKindResolver);
|
|
36535
36661
|
}
|
|
36536
36662
|
rows = applyHaving(rows, stmt.having, havingFieldTypeResolver);
|
|
36663
|
+
rows = applyWindow(rows, stmt.columns, optionOrders, sortKinds);
|
|
36537
36664
|
if (stmt.distinct) {
|
|
36538
36665
|
rows = applyDistinct(rows, stmt.columns);
|
|
36539
36666
|
}
|
|
@@ -37478,6 +37605,11 @@ function validateNoFromColumns(stmt) {
|
|
|
37478
37605
|
throw new Error("ArgumentError: field reference is not allowed without FROM.");
|
|
37479
37606
|
}
|
|
37480
37607
|
break;
|
|
37608
|
+
case "WINDOW_COL":
|
|
37609
|
+
if (col.partitionBy.length > 0 || col.orderBy.length > 0) {
|
|
37610
|
+
throw new Error("ArgumentError: field reference is not allowed without FROM.");
|
|
37611
|
+
}
|
|
37612
|
+
break;
|
|
37481
37613
|
default:
|
|
37482
37614
|
throw new Error(`ArgumentError: ${col.type} is not supported without FROM.`);
|
|
37483
37615
|
}
|
|
@@ -37488,7 +37620,8 @@ function executeNoFromSelect(stmt) {
|
|
|
37488
37620
|
throw new Error("ArgumentError: JOIN/WHERE/GROUP BY/HAVING/ORDER BY/DISTINCT are not supported without FROM.");
|
|
37489
37621
|
}
|
|
37490
37622
|
validateNoFromColumns(stmt);
|
|
37491
|
-
const
|
|
37623
|
+
const windowed = applyWindow([{}], stmt.columns);
|
|
37624
|
+
const { rows: projected, columns } = project(windowed, stmt.columns);
|
|
37492
37625
|
const rows = applyLimit(projected, stmt.limit, stmt.offset);
|
|
37493
37626
|
return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [] };
|
|
37494
37627
|
}
|
|
@@ -37912,6 +38045,8 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
|
|
|
37912
38045
|
meta3 = { sortKind: "number" };
|
|
37913
38046
|
} else if (column.type === "LITERAL_COL") {
|
|
37914
38047
|
meta3 = { sortKind: "string" };
|
|
38048
|
+
} else if (column.type === "WINDOW_COL") {
|
|
38049
|
+
meta3 = { sortKind: "number" };
|
|
37915
38050
|
}
|
|
37916
38051
|
if (meta3) inferred.set(output, meta3);
|
|
37917
38052
|
});
|
|
@@ -38497,7 +38632,10 @@ async function getSortKindMapByApp(appId, client, cacheContext) {
|
|
|
38497
38632
|
return map2;
|
|
38498
38633
|
}
|
|
38499
38634
|
async function buildOrderByMetaForSelect(stmt, client, cacheContext) {
|
|
38500
|
-
|
|
38635
|
+
const hasWindowOrderBy = stmt.columns.some(
|
|
38636
|
+
(column) => column.type === "WINDOW_COL" && column.orderBy.length > 0
|
|
38637
|
+
);
|
|
38638
|
+
if (stmt.orderBy.length === 0 && !hasWindowOrderBy) {
|
|
38501
38639
|
return { optionOrders: /* @__PURE__ */ new Map(), sortKinds: /* @__PURE__ */ new Map() };
|
|
38502
38640
|
}
|
|
38503
38641
|
const [optionOrders, sortKinds] = await Promise.all([
|
|
@@ -39959,6 +40097,8 @@ function collectFullScanReasons(stmt) {
|
|
|
39959
40097
|
r.push("DISTINCT \u3042\u308A");
|
|
39960
40098
|
if (stmt.columns.some((c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL"))
|
|
39961
40099
|
r.push("\u96C6\u8A08\u95A2\u6570\uFF08COUNT / SUM \u7B49\uFF09\u3042\u308A");
|
|
40100
|
+
if (stmt.columns.some((c) => c.type === "WINDOW_COL"))
|
|
40101
|
+
r.push("\u30A6\u30A3\u30F3\u30C9\u30A6\u95A2\u6570\u3042\u308A");
|
|
39962
40102
|
if (stmt.columns.some((c) => c.type === "SCALAR_SUBQUERY_COL"))
|
|
39963
40103
|
r.push("SELECT \u5217\u306B\u30B9\u30AB\u30E9\u30FC\u30B5\u30D6\u30AF\u30A8\u30EA");
|
|
39964
40104
|
if (whereRequiresJsEval(stmt.where))
|
|
@@ -42414,7 +42554,7 @@ Options:
|
|
|
42414
42554
|
-h, --help Show help
|
|
42415
42555
|
`);
|
|
42416
42556
|
}
|
|
42417
|
-
var SERVER_VERSION = true ? "2.
|
|
42557
|
+
var SERVER_VERSION = true ? "2.16.0" : "0.0.0-dev";
|
|
42418
42558
|
function createServer(args) {
|
|
42419
42559
|
const server = new McpServer({
|
|
42420
42560
|
name: "ksql-mcp",
|
package/dist-mcpb/ksql-mcp.mcpb
CHANGED
|
Binary file
|