@rex0220/kintone-sql-tools 3.55.0 → 3.56.1
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 +88 -5
- package/dist-engine/index.cjs +11 -11
- package/dist-engine/index.mjs +11 -11
- package/dist-engine/ksql-engine.umd.js +11 -11
- package/dist-engine/meta/bundle-baseline.json +7 -7
- package/dist-engine/meta/cjs.json +3 -3
- package/dist-engine/meta/esm.json +3 -3
- package/dist-engine/meta/umd.json +3 -3
- package/dist-mcp/ksql-mcp.js +90 -7
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +1 -1
package/dist-cli/ksql.js
CHANGED
|
@@ -17931,7 +17931,7 @@ async function executeSelect(stmt, client, options, cacheContext, cteCache, capt
|
|
|
17931
17931
|
maxRecords: options.maxRecords ?? 1e4,
|
|
17932
17932
|
hasKlike: whereHasKlike(stmt.where)
|
|
17933
17933
|
}) : null;
|
|
17934
|
-
await validateSelectFieldCodes(
|
|
17934
|
+
const subtableFieldWarnings = await validateSelectFieldCodes(
|
|
17935
17935
|
stmt,
|
|
17936
17936
|
orderPlan?.kind === "CANONICAL_LOCAL" ? "FULL_SCAN" : mode,
|
|
17937
17937
|
client,
|
|
@@ -17976,11 +17976,31 @@ async function executeSelect(stmt, client, options, cacheContext, cteCache, capt
|
|
|
17976
17976
|
await inferSelectColumnMeta(stmt, result.columns, client, cacheContext, cteCache, forLibraryCapture)
|
|
17977
17977
|
);
|
|
17978
17978
|
}
|
|
17979
|
-
return mergeSelectWarnings(result, defaultRangeWarnings);
|
|
17979
|
+
return mergeSelectWarnings(result, [...defaultRangeWarnings, ...subtableFieldWarnings]);
|
|
17980
|
+
}
|
|
17981
|
+
function subtableGroupingAdvice(fieldName, owners) {
|
|
17982
|
+
if (owners.length === 1) {
|
|
17983
|
+
const { appId, owner } = owners[0];
|
|
17984
|
+
return `ArgumentError: ${fieldName} \u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB\u300C${owner}\u300D\uFF08APP${appId}\uFF09\u306E\u4E2D\u306E\u9805\u76EE\u3067\u3059\u3002\u89AA\u30C6\u30FC\u30D6\u30EB\u306E GROUP BY \u306B\u306F\u6307\u5B9A\u3067\u304D\u307E\u305B\u3093\u3002APP${appId}$${owner} \u304B\u3089\u96C6\u8A08\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u89AA\u306E\u30EC\u30B3\u30FC\u30C9 ID \u306F _pid\u3001\u89AA\u9805\u76EE\u306F _p.<\u30D5\u30A3\u30FC\u30EB\u30C9\u30B3\u30FC\u30C9> \u306B\u306A\u308A\u307E\u3059\uFF09\u3002`;
|
|
17985
|
+
}
|
|
17986
|
+
const list = owners.map(({ appId, owner }) => `APP${appId}$${owner}`).join(" / ");
|
|
17987
|
+
return `ArgumentError: ${fieldName} \u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB\u306E\u4E2D\u306E\u9805\u76EE\u3067\u3059\uFF08${list}\uFF09\u3002\u89AA\u30C6\u30FC\u30D6\u30EB\u306E GROUP BY \u306B\u306F\u6307\u5B9A\u3067\u304D\u307E\u305B\u3093\u3002\u3069\u306E\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB\u304B\u3089\u96C6\u8A08\u3059\u308B\u304B\u3092 FROM \u3067\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002`;
|
|
17988
|
+
}
|
|
17989
|
+
function dedupeSubtableOwners(owners) {
|
|
17990
|
+
const seen = /* @__PURE__ */ new Set();
|
|
17991
|
+
const result = [];
|
|
17992
|
+
for (const entry of owners) {
|
|
17993
|
+
const key = `${entry.appId}\0${entry.owner}`;
|
|
17994
|
+
if (seen.has(key)) continue;
|
|
17995
|
+
seen.add(key);
|
|
17996
|
+
result.push(entry);
|
|
17997
|
+
}
|
|
17998
|
+
return result;
|
|
17980
17999
|
}
|
|
17981
18000
|
async function buildRuntimePlainGroupByPlan(stmt, client, cacheContext, materializedTables) {
|
|
17982
18001
|
if (stmt.groupBy.length === 0) return void 0;
|
|
17983
18002
|
const sources = [stmt.from, ...stmt.joins.map((join2) => join2.table)];
|
|
18003
|
+
const subtableOwners = /* @__PURE__ */ new Map();
|
|
17984
18004
|
const inputs = await Promise.all(sources.map(async (source) => {
|
|
17985
18005
|
if (source.cteName !== null) {
|
|
17986
18006
|
const materialized = materializedTables?.get(source.cteName);
|
|
@@ -17991,6 +18011,12 @@ async function buildRuntimePlainGroupByPlan(stmt, client, cacheContext, material
|
|
|
17991
18011
|
}
|
|
17992
18012
|
const fields = await getFieldsCached(source.appId, client, cacheContext);
|
|
17993
18013
|
if (!source.subtableCode) {
|
|
18014
|
+
for (const field of fields) {
|
|
18015
|
+
if (field.inSubtable !== true || !field.subtableCode) continue;
|
|
18016
|
+
const entries = subtableOwners.get(field.code) ?? [];
|
|
18017
|
+
entries.push({ appId: source.appId, owner: field.subtableCode });
|
|
18018
|
+
subtableOwners.set(field.code, dedupeSubtableOwners(entries));
|
|
18019
|
+
}
|
|
17994
18020
|
return {
|
|
17995
18021
|
kind: "APP",
|
|
17996
18022
|
fieldCodes: fields.filter((field) => !field.inSubtable).map((field) => field.code)
|
|
@@ -18012,10 +18038,10 @@ async function buildRuntimePlainGroupByPlan(stmt, client, cacheContext, material
|
|
|
18012
18038
|
);
|
|
18013
18039
|
const groupBy = stmt.groupBy;
|
|
18014
18040
|
const plan = planPlainGroupByResolution(groupBy, stmt.columns, schemas);
|
|
18015
|
-
assertRuntimePlainGroupByPlan(stmt, groupBy, plan);
|
|
18041
|
+
assertRuntimePlainGroupByPlan(stmt, groupBy, plan, subtableOwners);
|
|
18016
18042
|
return plan;
|
|
18017
18043
|
}
|
|
18018
|
-
function assertRuntimePlainGroupByPlan(stmt, groupBy, plan) {
|
|
18044
|
+
function assertRuntimePlainGroupByPlan(stmt, groupBy, plan, subtableOwners) {
|
|
18019
18045
|
const physicalAppIds = [
|
|
18020
18046
|
stmt.from,
|
|
18021
18047
|
...stmt.joins.map((join2) => join2.table)
|
|
@@ -18028,6 +18054,12 @@ function assertRuntimePlainGroupByPlan(stmt, groupBy, plan) {
|
|
|
18028
18054
|
const name = key?.type === "FIELD_NAME" ? key.name : "(expression)";
|
|
18029
18055
|
if (item.kind === "UNKNOWN") {
|
|
18030
18056
|
const appSuffix = primaryPhysicalAppId === null ? "" : ` (APP${primaryPhysicalAppId})`;
|
|
18057
|
+
const dot = item.name.indexOf(".");
|
|
18058
|
+
const bare = dot >= 0 ? item.name.slice(dot + 1) : item.name;
|
|
18059
|
+
const owners = subtableOwners.get(item.name) ?? subtableOwners.get(bare) ?? [];
|
|
18060
|
+
if (owners.length > 0) {
|
|
18061
|
+
throw new Error(subtableGroupingAdvice(item.name, owners));
|
|
18062
|
+
}
|
|
18031
18063
|
throw new Error(`ArgumentError: unknown field code(s): ${item.name}${appSuffix}`);
|
|
18032
18064
|
}
|
|
18033
18065
|
if (item.kind === "ALIAS_REJECT") {
|
|
@@ -18078,9 +18110,15 @@ async function buildGroupingFieldResolver(stmt, client, cacheContext, materializ
|
|
|
18078
18110
|
return [appId, new Map(infos.map((info) => [info.code, info]))];
|
|
18079
18111
|
}))
|
|
18080
18112
|
);
|
|
18113
|
+
const subtableFieldOf = (table, code) => {
|
|
18114
|
+
if (table.subtableCode) return null;
|
|
18115
|
+
const info = infosByApp.get(table.appId)?.get(code);
|
|
18116
|
+
return info?.inSubtable === true ? info.subtableCode ?? "" : null;
|
|
18117
|
+
};
|
|
18081
18118
|
const physicalMatch = (table, field) => {
|
|
18082
18119
|
if (field === "$id") return "$id";
|
|
18083
18120
|
const code = fieldCodeForTypeLookup(table, field);
|
|
18121
|
+
if (subtableFieldOf(table, code) !== null) return null;
|
|
18084
18122
|
return infosByApp.get(table.appId)?.has(code) ? code : null;
|
|
18085
18123
|
};
|
|
18086
18124
|
const materializedHas = (table, field) => {
|
|
@@ -18115,6 +18153,10 @@ async function buildGroupingFieldResolver(stmt, client, cacheContext, materializ
|
|
|
18115
18153
|
}
|
|
18116
18154
|
const code = physicalMatch(table, field.field);
|
|
18117
18155
|
if (code === null) {
|
|
18156
|
+
const owner = subtableFieldOf(table, fieldCodeForTypeLookup(table, field.field));
|
|
18157
|
+
if (owner !== null && owner !== "") {
|
|
18158
|
+
throw new Error(subtableGroupingAdvice(field.field, [{ appId: table.appId, owner }]));
|
|
18159
|
+
}
|
|
18118
18160
|
throw new Error(`ArgumentError: B65 field ${field.tableAlias}.${field.field} does not exist in APP${table.appId}.`);
|
|
18119
18161
|
}
|
|
18120
18162
|
return resolved(table, tableIndex, field, code);
|
|
@@ -18137,6 +18179,15 @@ async function buildGroupingFieldResolver(stmt, client, cacheContext, materializ
|
|
|
18137
18179
|
`ArgumentError: B65 field ${field.field} resolves to a materialized CTE/temp column; physical APP fields are required.`
|
|
18138
18180
|
);
|
|
18139
18181
|
}
|
|
18182
|
+
const owners = tables.flatMap((table) => {
|
|
18183
|
+
if (table.cteName !== null) return [];
|
|
18184
|
+
const owner = subtableFieldOf(table, fieldCodeForTypeLookup(table, field.field));
|
|
18185
|
+
return owner === null || owner === "" ? [] : [{ appId: table.appId, owner }];
|
|
18186
|
+
});
|
|
18187
|
+
const uniqueOwners = dedupeSubtableOwners(owners);
|
|
18188
|
+
if (uniqueOwners.length > 0) {
|
|
18189
|
+
throw new Error(subtableGroupingAdvice(field.field, uniqueOwners));
|
|
18190
|
+
}
|
|
18140
18191
|
throw new Error(`ArgumentError: B65 field ${field.field} does not exist in a physical APP source.`);
|
|
18141
18192
|
};
|
|
18142
18193
|
}
|
|
@@ -18369,6 +18420,7 @@ async function executeSimpleSelect(stmt, client, options, cacheContext, orderPla
|
|
|
18369
18420
|
return { type: "SELECT", rows: projected, columns, rowCount: projected.length, warnings: [...warnings] };
|
|
18370
18421
|
}
|
|
18371
18422
|
async function validateSelectFieldCodes(stmt, mode, client, cacheContext) {
|
|
18423
|
+
const warnings = [];
|
|
18372
18424
|
const appToFields = /* @__PURE__ */ new Map();
|
|
18373
18425
|
const addFields = (appId, fields) => {
|
|
18374
18426
|
if (fields.length === 0) return;
|
|
@@ -18379,13 +18431,25 @@ async function validateSelectFieldCodes(stmt, mode, client, cacheContext) {
|
|
|
18379
18431
|
}
|
|
18380
18432
|
for (const f of fields) target.add(f);
|
|
18381
18433
|
};
|
|
18434
|
+
const parentTableFields = /* @__PURE__ */ new Map();
|
|
18435
|
+
const addParentFields = (appId, fields) => {
|
|
18436
|
+
let target = parentTableFields.get(appId);
|
|
18437
|
+
if (!target) {
|
|
18438
|
+
target = /* @__PURE__ */ new Set();
|
|
18439
|
+
parentTableFields.set(appId, target);
|
|
18440
|
+
}
|
|
18441
|
+
for (const f of fields) target.add(f);
|
|
18442
|
+
};
|
|
18382
18443
|
if (mode === "SIMPLE") {
|
|
18383
18444
|
const params = selectToKintoneParams(stmt);
|
|
18384
18445
|
addFields(params.app, params.fields);
|
|
18446
|
+
if (!stmt.from.subtableCode) addParentFields(params.app, params.fields);
|
|
18385
18447
|
} else {
|
|
18386
18448
|
const tables = [stmt.from, ...stmt.joins.map((j) => j.table)].filter((t) => t.cteName === null);
|
|
18387
18449
|
for (const table of tables) {
|
|
18388
|
-
|
|
18450
|
+
const fields = selectToFetchAllFields(stmt, table);
|
|
18451
|
+
addFields(table.appId, fields);
|
|
18452
|
+
if (!table.subtableCode) addParentFields(table.appId, fields);
|
|
18389
18453
|
}
|
|
18390
18454
|
}
|
|
18391
18455
|
for (const [appId, fields] of appToFields.entries()) {
|
|
@@ -18398,7 +18462,21 @@ async function validateSelectFieldCodes(stmt, mode, client, cacheContext) {
|
|
|
18398
18462
|
if (unknown.length > 0) {
|
|
18399
18463
|
throw new Error(`ArgumentError: unknown field code(s): ${unknown.join(", ")} (APP${appId})`);
|
|
18400
18464
|
}
|
|
18465
|
+
const referenced = parentTableFields.get(appId);
|
|
18466
|
+
if (referenced) {
|
|
18467
|
+
const subtableFields = defs.filter(
|
|
18468
|
+
(d) => d.inSubtable === true && referenced.has(d.code)
|
|
18469
|
+
);
|
|
18470
|
+
for (const field of subtableFields) {
|
|
18471
|
+
const owner = field.subtableCode ?? "";
|
|
18472
|
+
const source = owner ? `\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB\u300C${owner}\u300D` : "\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB";
|
|
18473
|
+
warnings.push(
|
|
18474
|
+
`${field.code} \u306F${source}\u306E\u4E2D\u306E\u9805\u76EE\u3067\u3059\u3002APP${appId} \u304B\u3089\u9078\u3076\u3068\u3001\u30A8\u30E9\u30FC\u306B\u306A\u3089\u305A\u5168\u884C\u304C\u7A7A\u306B\u306A\u308A\u307E\u3059\u3002` + (owner ? `APP${appId}$${owner} \u304B\u3089\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u89AA\u306E\u30EC\u30B3\u30FC\u30C9 ID \u306F _pid\u3001\u89AA\u9805\u76EE\u306F _p.<\u30D5\u30A3\u30FC\u30EB\u30C9\u30B3\u30FC\u30C9> \u306B\u306A\u308A\u307E\u3059\uFF09\u3002` : "")
|
|
18475
|
+
);
|
|
18476
|
+
}
|
|
18477
|
+
}
|
|
18401
18478
|
}
|
|
18479
|
+
return warnings;
|
|
18402
18480
|
}
|
|
18403
18481
|
function b86SourceLabel(table) {
|
|
18404
18482
|
return table.cteName ?? `APP${table.appId}`;
|
|
@@ -23130,9 +23208,12 @@ var SHOW_APPS_COLUMNS = Object.freeze([
|
|
|
23130
23208
|
"\u8AAC\u660E"
|
|
23131
23209
|
]);
|
|
23132
23210
|
var DESCRIBE_COLUMNS = Object.freeze([
|
|
23211
|
+
// B145: サブテーブル列は「その項目がどの表にあるか」を示す。無いと明細項目を
|
|
23212
|
+
// 親項目と取り違え、親から SELECT して全行空という結果になる(エラーも警告も出ない)。
|
|
23133
23213
|
"\u30D5\u30A3\u30FC\u30EB\u30C9\u30B3\u30FC\u30C9",
|
|
23134
23214
|
"\u30E9\u30D9\u30EB",
|
|
23135
23215
|
"\u30BF\u30A4\u30D7",
|
|
23216
|
+
"\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB",
|
|
23136
23217
|
"\u30EB\u30C3\u30AF\u30A2\u30C3\u30D7",
|
|
23137
23218
|
"\u30B3\u30D4\u30FC\u5143",
|
|
23138
23219
|
"\u91CD\u8907\u7981\u6B62",
|
|
@@ -23155,6 +23236,8 @@ async function executeDescribe(stmt, client, cacheContext) {
|
|
|
23155
23236
|
"\u30D5\u30A3\u30FC\u30EB\u30C9\u30B3\u30FC\u30C9": f.code,
|
|
23156
23237
|
"\u30E9\u30D9\u30EB": f.label,
|
|
23157
23238
|
"\u30BF\u30A4\u30D7": f.fieldType,
|
|
23239
|
+
// 明細項目はサブテーブルのフィールドコード、親項目は空文字。
|
|
23240
|
+
"\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB": f.inSubtable === true ? f.subtableCode ?? "" : "",
|
|
23158
23241
|
"\u30EB\u30C3\u30AF\u30A2\u30C3\u30D7": f.hasLookup === true ? "YES" : "",
|
|
23159
23242
|
"\u30B3\u30D4\u30FC\u5143": f.isLookupCopyTarget === true ? "YES" : "",
|
|
23160
23243
|
"\u91CD\u8907\u7981\u6B62": f.isUnique === true ? "YES" : "",
|