@rex0220/kintone-sql-tools 3.56.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 CHANGED
@@ -17978,9 +17978,29 @@ async function executeSelect(stmt, client, options, cacheContext, cteCache, capt
17978
17978
  }
17979
17979
  return mergeSelectWarnings(result, [...defaultRangeWarnings, ...subtableFieldWarnings]);
17980
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;
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
  }