@rex0220/kintone-sql-tools 3.10.0 → 3.11.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
@@ -4930,6 +4930,9 @@ function canInlineSingleCte(stmt) {
4930
4930
  if (stmt.ctes.length !== 1) return false;
4931
4931
  const cteDef = stmt.ctes[0];
4932
4932
  if (cteDef.query.type !== "SELECT" || resolveSelectMode(cteDef.query) !== "SIMPLE") return false;
4933
+ if (!cteDef.query.columns.every(
4934
+ (column) => column.type === "WILDCARD" || column.type === "FIELD" && (column.alias === null || column.alias === column.field)
4935
+ )) return false;
4933
4936
  const finalQuery = stmt.query;
4934
4937
  if (finalQuery.type !== "SELECT") return false;
4935
4938
  if (finalQuery.from.cteName !== cteDef.name || finalQuery.joins.length > 0) return false;
@@ -9700,10 +9703,12 @@ function flatten(record, alias) {
9700
9703
  }
9701
9704
  return row;
9702
9705
  }
9703
- function applyJoin(leftRows, rightRows, join2) {
9706
+ function applyJoin(leftRows, rightRows, join2, columns = {}) {
9704
9707
  const { on, type: joinType } = join2;
9705
9708
  const leftKey = on.left.tableAlias ? `${on.left.tableAlias}.${on.left.field}` : on.left.field;
9706
9709
  const rightKey = on.right.tableAlias ? `${on.right.tableAlias}.${on.right.field}` : on.right.field;
9710
+ assertJoinKeyAvailable(leftRows, leftKey, columns.leftColumns);
9711
+ assertJoinKeyAvailable(rightRows, rightKey, columns.rightColumns);
9707
9712
  if (joinType === "RIGHT") {
9708
9713
  const leftIndex = /* @__PURE__ */ new Map();
9709
9714
  for (const lRow of leftRows) {
@@ -9713,7 +9718,7 @@ function applyJoin(leftRows, rightRows, join2) {
9713
9718
  else leftIndex.set(k, [lRow]);
9714
9719
  }
9715
9720
  const emptyLeft = {};
9716
- for (const key of Object.keys(leftRows[0] ?? {})) emptyLeft[key] = "";
9721
+ for (const key of columns.leftColumns ?? Object.keys(leftRows[0] ?? {})) emptyLeft[key] = "";
9717
9722
  const result2 = [];
9718
9723
  for (const rRow of rightRows) {
9719
9724
  const k = rRow[rightKey] ?? "";
@@ -9735,7 +9740,7 @@ function applyJoin(leftRows, rightRows, join2) {
9735
9740
  }
9736
9741
  const result = [];
9737
9742
  const emptyRight = {};
9738
- for (const key of Object.keys(rightRows[0] ?? {})) emptyRight[key] = "";
9743
+ for (const key of columns.rightColumns ?? Object.keys(rightRows[0] ?? {})) emptyRight[key] = "";
9739
9744
  for (const lRow of leftRows) {
9740
9745
  const k = lRow[leftKey] ?? "";
9741
9746
  const matched = rightIndex.get(k) ?? [];
@@ -9749,6 +9754,12 @@ function applyJoin(leftRows, rightRows, join2) {
9749
9754
  }
9750
9755
  return result;
9751
9756
  }
9757
+ function assertJoinKeyAvailable(rows, key, savedColumns) {
9758
+ const missing = rows.length > 0 ? rows.some((row) => !Object.prototype.hasOwnProperty.call(row, key)) : savedColumns !== void 0 && !savedColumns.includes(key);
9759
+ if (missing) {
9760
+ throw new Error(`ArgumentError: JOIN key ${key} is not available in the materialized table.`);
9761
+ }
9762
+ }
9752
9763
  function applyFilter(rows, where, resolveFieldType, appliedKlikes, resolveFieldSemantics2) {
9753
9764
  if (where === null) return rows;
9754
9765
  return rows.filter((row) => evalWhere(where, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2));
@@ -10047,9 +10058,12 @@ function applyLimit(rows, limit, offset) {
10047
10058
  if (limit === null) return rows.slice(start);
10048
10059
  return rows.slice(start, start + limit);
10049
10060
  }
10050
- function project(rows, columns, scalarCache, resolveFieldType, sourceColumns, resolveFieldSemantics2) {
10061
+ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns, resolveFieldSemantics2, hiddenQualifiedAliases) {
10051
10062
  if (columns.length === 1 && columns[0].type === "WILDCARD") {
10052
- const projected2 = rows.map((row) => stripParentShortcutColumns(row));
10063
+ const projected2 = rows.map((row) => stripHiddenQualifiedColumns(
10064
+ stripParentShortcutColumns(row),
10065
+ hiddenQualifiedAliases
10066
+ ));
10053
10067
  const cols = projected2.length > 0 ? Object.keys(projected2[0]) : [...sourceColumns ?? []];
10054
10068
  return { rows: projected2, columns: cols };
10055
10069
  }
@@ -10069,7 +10083,10 @@ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns, re
10069
10083
  case "VARIABLE_COL":
10070
10084
  throw new Error(`internal error: unresolved SELECT variable @${col.name}`);
10071
10085
  case "WILDCARD":
10072
- Object.assign(out, stripParentShortcutColumns(row));
10086
+ Object.assign(out, stripHiddenQualifiedColumns(
10087
+ stripParentShortcutColumns(row),
10088
+ hiddenQualifiedAliases
10089
+ ));
10073
10090
  break;
10074
10091
  case "PARENT_WILDCARD": {
10075
10092
  const parentKeys = Object.keys(row).filter((k) => k.startsWith("_p.")).sort();
@@ -10322,6 +10339,27 @@ function resolveAggInStringFuncExpr(expr, rows, resolveAggSortKind) {
10322
10339
  args: expr.args.map((arg) => resolveAggInStringFuncArg(arg, rows, resolveAggSortKind))
10323
10340
  };
10324
10341
  }
10342
+ function stripHiddenQualifiedColumns(row, hiddenQualifiedAliases) {
10343
+ if (!hiddenQualifiedAliases || hiddenQualifiedAliases.size === 0) return row;
10344
+ const out = {};
10345
+ for (const [key, value] of Object.entries(row)) {
10346
+ if ([...hiddenQualifiedAliases].some((alias) => key.startsWith(`${alias}.`))) continue;
10347
+ out[key] = value;
10348
+ }
10349
+ return out;
10350
+ }
10351
+ function flattenedColumns(columns, alias) {
10352
+ if (columns === void 0) return void 0;
10353
+ return alias ? columns.flatMap((column) => [`${alias}.${column}`, column]) : [...columns];
10354
+ }
10355
+ function mergeKnownColumns(left, right, rows) {
10356
+ if (left === void 0 && right === void 0 && rows.length === 0) return void 0;
10357
+ return [.../* @__PURE__ */ new Set([
10358
+ ...left ?? [],
10359
+ ...right ?? [],
10360
+ ...Object.keys(rows[0] ?? {})
10361
+ ])];
10362
+ }
10325
10363
  function deriveOutputOrderSemantics(columns) {
10326
10364
  const result = /* @__PURE__ */ new Map();
10327
10365
  for (const column of columns) {
@@ -10356,7 +10394,9 @@ function runFullScan(input) {
10356
10394
  havingFieldSemanticsResolver,
10357
10395
  aggregateSortKindResolver,
10358
10396
  appliedKlikes,
10359
- sourceColumns
10397
+ sourceColumns,
10398
+ tableColumns,
10399
+ hiddenQualifiedAliases
10360
10400
  } = input;
10361
10401
  const effectiveOrderSemantics = deriveOutputOrderSemantics(stmt.columns);
10362
10402
  for (const [key, value] of orderSemantics ?? []) effectiveOrderSemantics.set(key, value);
@@ -10364,11 +10404,25 @@ function runFullScan(input) {
10364
10404
  const mainAlias = stmt.from.alias;
10365
10405
  const mainRecords = tables.get(mainAlias) ?? tables.get(null) ?? [];
10366
10406
  rows = mainRecords.map((r) => flatten(r, mainAlias));
10407
+ let knownColumns = mergeKnownColumns(
10408
+ flattenedColumns(tableColumns?.get(mainAlias), mainAlias),
10409
+ void 0,
10410
+ rows
10411
+ );
10367
10412
  for (const join2 of stmt.joins) {
10368
10413
  const rightAlias = join2.table.alias;
10369
10414
  const rightRecords = tables.get(rightAlias) ?? [];
10370
10415
  const rightRows = rightRecords.map((r) => flatten(r, rightAlias));
10371
- rows = applyJoin(rows, rightRows, join2);
10416
+ const rightColumns = mergeKnownColumns(
10417
+ flattenedColumns(tableColumns?.get(rightAlias), rightAlias),
10418
+ void 0,
10419
+ rightRows
10420
+ );
10421
+ rows = applyJoin(rows, rightRows, join2, {
10422
+ leftColumns: knownColumns,
10423
+ rightColumns
10424
+ });
10425
+ knownColumns = mergeKnownColumns(knownColumns, rightColumns, rows);
10372
10426
  }
10373
10427
  rows = applyFilter(rows, stmt.where, fieldTypeResolver, appliedKlikes, fieldSemanticsResolver);
10374
10428
  if (stmt.groupBy.length > 0 || hasAggregateColumns(stmt.columns)) {
@@ -10381,7 +10435,15 @@ function runFullScan(input) {
10381
10435
  }
10382
10436
  rows = applyOrderBy(rows, stmt.orderBy, optionOrders, sortKinds, effectiveOrderSemantics);
10383
10437
  rows = applyLimit(rows, stmt.limit, stmt.offset);
10384
- return project(rows, stmt.columns, scalarCache, fieldTypeResolver, sourceColumns, fieldSemanticsResolver);
10438
+ return project(
10439
+ rows,
10440
+ stmt.columns,
10441
+ scalarCache,
10442
+ fieldTypeResolver,
10443
+ sourceColumns,
10444
+ fieldSemanticsResolver,
10445
+ hiddenQualifiedAliases
10446
+ );
10385
10447
  }
10386
10448
 
10387
10449
  // src/converter/subtableAdapter.ts
@@ -12693,7 +12755,7 @@ async function buildWhereFieldSemanticsResolver(stmt, client, cacheContext, mate
12693
12755
  if (field.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
12694
12756
  return fromPhysical(stmt.from, field.field, false);
12695
12757
  }
12696
- const table = tables.find((candidate) => candidate.alias === field.tableAlias);
12758
+ const table = tables.find((candidate) => effectiveTableAlias(candidate) === field.tableAlias);
12697
12759
  if (!table) return void 0;
12698
12760
  if (table.cteName !== null) {
12699
12761
  return materializedTables?.get(table.cteName)?.columnMeta?.get(field.field)?.semantics ?? syntheticSemantics("string");
@@ -13127,8 +13189,11 @@ function collectSelectTypedInFieldRefs(stmt) {
13127
13189
  }
13128
13190
  return refs;
13129
13191
  }
13192
+ function effectiveTableAlias(table) {
13193
+ return table.alias ?? table.cteName;
13194
+ }
13130
13195
  function findTableForAlias(stmt, alias) {
13131
- return [stmt.from, ...stmt.joins.map((join2) => join2.table)].find((table) => table.alias === alias);
13196
+ return [stmt.from, ...stmt.joins.map((join2) => join2.table)].find((table) => effectiveTableAlias(table) === alias);
13132
13197
  }
13133
13198
  function physicalSelectTables(stmt) {
13134
13199
  return [stmt.from, ...stmt.joins.map((join2) => join2.table)].filter((table) => table.cteName === null);
@@ -13280,7 +13345,7 @@ async function loadAggregateSortKindResolver(stmt, client, cacheContext, materia
13280
13345
  if (ref.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
13281
13346
  info = fieldInfosByApp.get(stmt.from.appId)?.get(ref.field);
13282
13347
  } else {
13283
- const table = tables.find((candidate) => candidate.alias === ref.tableAlias);
13348
+ const table = tables.find((candidate) => effectiveTableAlias(candidate) === ref.tableAlias);
13284
13349
  if (!table) return void 0;
13285
13350
  if (table.cteName !== null) {
13286
13351
  return materializedTables?.get(table.cteName)?.columnMeta?.get(ref.field)?.semantics ?? syntheticSemantics("string");
@@ -13305,7 +13370,7 @@ async function loadAggregateSortKindResolver(stmt, client, cacheContext, materia
13305
13370
  return matches[0];
13306
13371
  }
13307
13372
  if (!info) return void 0;
13308
- const sourceTable = ref.tableAlias !== null ? tables.find((table) => table.alias === ref.tableAlias) : stmt.joins.length === 0 ? stmt.from : void 0;
13373
+ const sourceTable = ref.tableAlias !== null ? tables.find((table) => effectiveTableAlias(table) === ref.tableAlias) : stmt.joins.length === 0 ? stmt.from : void 0;
13309
13374
  return semanticsForInfo(info, sourceTable?.appId ?? stmt.from.appId);
13310
13375
  };
13311
13376
  }
@@ -13435,7 +13500,7 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
13435
13500
  const info2 = physicalInfos.get(stmt.from.appId)?.get(ref.field);
13436
13501
  return info2 ? materializedMetaFromFieldInfo(info2, stmt.from.appId) : void 0;
13437
13502
  }
13438
- const table = tables.find((candidate) => candidate.alias === ref.tableAlias);
13503
+ const table = tables.find((candidate) => effectiveTableAlias(candidate) === ref.tableAlias);
13439
13504
  if (!table) return void 0;
13440
13505
  if (table.cteName !== null) return materializedTables?.get(table.cteName)?.columnMeta?.get(ref.field);
13441
13506
  const info = physicalInfos.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
@@ -13540,7 +13605,7 @@ function buildSelectFieldTypeResolvers(stmt, fieldTypesByApp) {
13540
13605
  if (field.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
13541
13606
  return fieldTypesByApp.get(stmt.from.appId)?.get(field.field);
13542
13607
  }
13543
- const table = tables.find((candidate) => candidate.alias === field.tableAlias);
13608
+ const table = tables.find((candidate) => effectiveTableAlias(candidate) === field.tableAlias);
13544
13609
  if (!table || table.cteName !== null) return void 0;
13545
13610
  return subtableSystemFieldType(table, field.field) ?? fieldTypesByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, field.field));
13546
13611
  }
@@ -13765,6 +13830,37 @@ async function executeQueryWithCte(query, client, options, cteCache, cacheContex
13765
13830
  return result;
13766
13831
  }
13767
13832
  async function executeFullScanWithCte(stmt, client, options, cteCache, cacheContext) {
13833
+ const hiddenQualifiedAliases = /* @__PURE__ */ new Set();
13834
+ const withEffectiveAlias = (table) => {
13835
+ if (table.alias !== null || table.cteName === null) return table;
13836
+ const alias = effectiveTableAlias(table);
13837
+ hiddenQualifiedAliases.add(alias);
13838
+ return { ...table, alias };
13839
+ };
13840
+ stmt = {
13841
+ ...stmt,
13842
+ from: withEffectiveAlias(stmt.from),
13843
+ joins: stmt.joins.map((join2) => ({ ...join2, table: withEffectiveAlias(join2.table) }))
13844
+ };
13845
+ const aliases = /* @__PURE__ */ new Set();
13846
+ for (const table of [stmt.from, ...stmt.joins.map((join2) => join2.table)]) {
13847
+ const alias = effectiveTableAlias(table);
13848
+ if (alias === null) continue;
13849
+ if (aliases.has(alias)) {
13850
+ throw new Error(`ArgumentError: effective alias ${alias} is used by multiple tables.`);
13851
+ }
13852
+ aliases.add(alias);
13853
+ }
13854
+ const requireMaterializedTable = (name) => {
13855
+ const table = cteCache.get(name);
13856
+ if (!table) {
13857
+ throw new Error(`ArgumentError: materialized source ${name} is not available.`);
13858
+ }
13859
+ return table;
13860
+ };
13861
+ for (const table of [stmt.from, ...stmt.joins.map((join2) => join2.table)]) {
13862
+ if (table.cteName !== null) requireMaterializedTable(table.cteName);
13863
+ }
13768
13864
  const maxRecords = options.maxRecords ?? 1e4;
13769
13865
  const warnings = /* @__PURE__ */ new Set();
13770
13866
  const parallel = options.fetchParallel ?? 1;
@@ -13811,9 +13907,11 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
13811
13907
  orderByMetaPromise.catch(() => {
13812
13908
  });
13813
13909
  const tables = /* @__PURE__ */ new Map();
13910
+ const tableColumns = /* @__PURE__ */ new Map();
13814
13911
  if (stmt.from.cteName != null) {
13815
- const table = cteCache.get(stmt.from.cteName);
13816
- tables.set(stmt.from.alias, (table?.rows ?? []).map(processRowToKintoneRecord));
13912
+ const table = requireMaterializedTable(stmt.from.cteName);
13913
+ tables.set(stmt.from.alias, table.rows.map(processRowToKintoneRecord));
13914
+ tableColumns.set(stmt.from.alias, table.columns);
13817
13915
  } else {
13818
13916
  const mainRecords = await fetchTableRecordsForFullScan(
13819
13917
  stmt,
@@ -13831,8 +13929,9 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
13831
13929
  }
13832
13930
  const joinFetches = stmt.joins.map(async (join2) => {
13833
13931
  if (join2.table.cteName != null) {
13834
- const table = cteCache.get(join2.table.cteName);
13835
- tables.set(join2.table.alias, (table?.rows ?? []).map(processRowToKintoneRecord));
13932
+ const table = requireMaterializedTable(join2.table.cteName);
13933
+ tables.set(join2.table.alias, table.rows.map(processRowToKintoneRecord));
13934
+ tableColumns.set(join2.table.alias, table.columns);
13836
13935
  } else {
13837
13936
  const pushDownCond = join2.table.alias ? pushdownPlan.joinConditions.get(join2.table.alias) ?? null : null;
13838
13937
  const optimized = await tryFetchJoinRecordsBySourceKeys(
@@ -13863,7 +13962,7 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
13863
13962
  await Promise.all(joinFetches);
13864
13963
  const scalarCache = await scalarCachePromise;
13865
13964
  const { optionOrders, sortKinds, semantics } = await orderByMetaPromise;
13866
- const sourceColumns = stmt.joins.length === 0 && stmt.from.cteName != null ? cteCache.get(stmt.from.cteName)?.columns : void 0;
13965
+ const sourceColumns = stmt.joins.length === 0 && stmt.from.cteName != null ? requireMaterializedTable(stmt.from.cteName).columns : void 0;
13867
13966
  const { rows, columns } = runFullScan({
13868
13967
  tables,
13869
13968
  stmt,
@@ -13877,7 +13976,9 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
13877
13976
  havingFieldSemanticsResolver,
13878
13977
  aggregateSortKindResolver,
13879
13978
  appliedKlikes: pushdownPlan.appliedKlikes,
13880
- sourceColumns
13979
+ sourceColumns,
13980
+ tableColumns,
13981
+ hiddenQualifiedAliases
13881
13982
  });
13882
13983
  return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [...warnings] };
13883
13984
  }
@@ -14179,7 +14280,7 @@ async function buildOrderSemanticsForSelect(stmt, client, cacheContext, material
14179
14280
  const info2 = infosByApp.get(stmt.from.appId)?.get(ref.field);
14180
14281
  return info2 ? materializedMetaFromFieldInfo(info2, stmt.from.appId) : void 0;
14181
14282
  }
14182
- const table = tables.find((candidate) => candidate.alias === ref.tableAlias);
14283
+ const table = tables.find((candidate) => effectiveTableAlias(candidate) === ref.tableAlias);
14183
14284
  if (!table) return void 0;
14184
14285
  if (table.cteName !== null) return materializedTables?.get(table.cteName)?.columnMeta?.get(ref.field);
14185
14286
  const info = infosByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
@@ -36603,6 +36603,9 @@ function canInlineSingleCte(stmt) {
36603
36603
  if (stmt.ctes.length !== 1) return false;
36604
36604
  const cteDef = stmt.ctes[0];
36605
36605
  if (cteDef.query.type !== "SELECT" || resolveSelectMode(cteDef.query) !== "SIMPLE") return false;
36606
+ if (!cteDef.query.columns.every(
36607
+ (column) => column.type === "WILDCARD" || column.type === "FIELD" && (column.alias === null || column.alias === column.field)
36608
+ )) return false;
36606
36609
  const finalQuery = stmt.query;
36607
36610
  if (finalQuery.type !== "SELECT") return false;
36608
36611
  if (finalQuery.from.cteName !== cteDef.name || finalQuery.joins.length > 0) return false;
@@ -41433,10 +41436,12 @@ function flatten(record2, alias) {
41433
41436
  }
41434
41437
  return row;
41435
41438
  }
41436
- function applyJoin(leftRows, rightRows, join) {
41439
+ function applyJoin(leftRows, rightRows, join, columns = {}) {
41437
41440
  const { on, type: joinType } = join;
41438
41441
  const leftKey = on.left.tableAlias ? `${on.left.tableAlias}.${on.left.field}` : on.left.field;
41439
41442
  const rightKey = on.right.tableAlias ? `${on.right.tableAlias}.${on.right.field}` : on.right.field;
41443
+ assertJoinKeyAvailable(leftRows, leftKey, columns.leftColumns);
41444
+ assertJoinKeyAvailable(rightRows, rightKey, columns.rightColumns);
41440
41445
  if (joinType === "RIGHT") {
41441
41446
  const leftIndex = /* @__PURE__ */ new Map();
41442
41447
  for (const lRow of leftRows) {
@@ -41446,7 +41451,7 @@ function applyJoin(leftRows, rightRows, join) {
41446
41451
  else leftIndex.set(k, [lRow]);
41447
41452
  }
41448
41453
  const emptyLeft = {};
41449
- for (const key of Object.keys(leftRows[0] ?? {})) emptyLeft[key] = "";
41454
+ for (const key of columns.leftColumns ?? Object.keys(leftRows[0] ?? {})) emptyLeft[key] = "";
41450
41455
  const result2 = [];
41451
41456
  for (const rRow of rightRows) {
41452
41457
  const k = rRow[rightKey] ?? "";
@@ -41468,7 +41473,7 @@ function applyJoin(leftRows, rightRows, join) {
41468
41473
  }
41469
41474
  const result = [];
41470
41475
  const emptyRight = {};
41471
- for (const key of Object.keys(rightRows[0] ?? {})) emptyRight[key] = "";
41476
+ for (const key of columns.rightColumns ?? Object.keys(rightRows[0] ?? {})) emptyRight[key] = "";
41472
41477
  for (const lRow of leftRows) {
41473
41478
  const k = lRow[leftKey] ?? "";
41474
41479
  const matched = rightIndex.get(k) ?? [];
@@ -41482,6 +41487,12 @@ function applyJoin(leftRows, rightRows, join) {
41482
41487
  }
41483
41488
  return result;
41484
41489
  }
41490
+ function assertJoinKeyAvailable(rows, key, savedColumns) {
41491
+ const missing = rows.length > 0 ? rows.some((row) => !Object.prototype.hasOwnProperty.call(row, key)) : savedColumns !== void 0 && !savedColumns.includes(key);
41492
+ if (missing) {
41493
+ throw new Error(`ArgumentError: JOIN key ${key} is not available in the materialized table.`);
41494
+ }
41495
+ }
41485
41496
  function applyFilter(rows, where, resolveFieldType, appliedKlikes, resolveFieldSemantics2) {
41486
41497
  if (where === null) return rows;
41487
41498
  return rows.filter((row) => evalWhere(where, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2));
@@ -41780,9 +41791,12 @@ function applyLimit(rows, limit, offset) {
41780
41791
  if (limit === null) return rows.slice(start);
41781
41792
  return rows.slice(start, start + limit);
41782
41793
  }
41783
- function project(rows, columns, scalarCache, resolveFieldType, sourceColumns, resolveFieldSemantics2) {
41794
+ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns, resolveFieldSemantics2, hiddenQualifiedAliases) {
41784
41795
  if (columns.length === 1 && columns[0].type === "WILDCARD") {
41785
- const projected2 = rows.map((row) => stripParentShortcutColumns(row));
41796
+ const projected2 = rows.map((row) => stripHiddenQualifiedColumns(
41797
+ stripParentShortcutColumns(row),
41798
+ hiddenQualifiedAliases
41799
+ ));
41786
41800
  const cols = projected2.length > 0 ? Object.keys(projected2[0]) : [...sourceColumns ?? []];
41787
41801
  return { rows: projected2, columns: cols };
41788
41802
  }
@@ -41802,7 +41816,10 @@ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns, re
41802
41816
  case "VARIABLE_COL":
41803
41817
  throw new Error(`internal error: unresolved SELECT variable @${col.name}`);
41804
41818
  case "WILDCARD":
41805
- Object.assign(out, stripParentShortcutColumns(row));
41819
+ Object.assign(out, stripHiddenQualifiedColumns(
41820
+ stripParentShortcutColumns(row),
41821
+ hiddenQualifiedAliases
41822
+ ));
41806
41823
  break;
41807
41824
  case "PARENT_WILDCARD": {
41808
41825
  const parentKeys = Object.keys(row).filter((k) => k.startsWith("_p.")).sort();
@@ -42055,6 +42072,27 @@ function resolveAggInStringFuncExpr(expr, rows, resolveAggSortKind) {
42055
42072
  args: expr.args.map((arg) => resolveAggInStringFuncArg(arg, rows, resolveAggSortKind))
42056
42073
  };
42057
42074
  }
42075
+ function stripHiddenQualifiedColumns(row, hiddenQualifiedAliases) {
42076
+ if (!hiddenQualifiedAliases || hiddenQualifiedAliases.size === 0) return row;
42077
+ const out = {};
42078
+ for (const [key, value] of Object.entries(row)) {
42079
+ if ([...hiddenQualifiedAliases].some((alias) => key.startsWith(`${alias}.`))) continue;
42080
+ out[key] = value;
42081
+ }
42082
+ return out;
42083
+ }
42084
+ function flattenedColumns(columns, alias) {
42085
+ if (columns === void 0) return void 0;
42086
+ return alias ? columns.flatMap((column) => [`${alias}.${column}`, column]) : [...columns];
42087
+ }
42088
+ function mergeKnownColumns(left, right, rows) {
42089
+ if (left === void 0 && right === void 0 && rows.length === 0) return void 0;
42090
+ return [.../* @__PURE__ */ new Set([
42091
+ ...left ?? [],
42092
+ ...right ?? [],
42093
+ ...Object.keys(rows[0] ?? {})
42094
+ ])];
42095
+ }
42058
42096
  function deriveOutputOrderSemantics(columns) {
42059
42097
  const result = /* @__PURE__ */ new Map();
42060
42098
  for (const column of columns) {
@@ -42089,7 +42127,9 @@ function runFullScan(input) {
42089
42127
  havingFieldSemanticsResolver,
42090
42128
  aggregateSortKindResolver,
42091
42129
  appliedKlikes,
42092
- sourceColumns
42130
+ sourceColumns,
42131
+ tableColumns,
42132
+ hiddenQualifiedAliases
42093
42133
  } = input;
42094
42134
  const effectiveOrderSemantics = deriveOutputOrderSemantics(stmt.columns);
42095
42135
  for (const [key, value] of orderSemantics ?? []) effectiveOrderSemantics.set(key, value);
@@ -42097,11 +42137,25 @@ function runFullScan(input) {
42097
42137
  const mainAlias = stmt.from.alias;
42098
42138
  const mainRecords = tables.get(mainAlias) ?? tables.get(null) ?? [];
42099
42139
  rows = mainRecords.map((r) => flatten(r, mainAlias));
42140
+ let knownColumns = mergeKnownColumns(
42141
+ flattenedColumns(tableColumns?.get(mainAlias), mainAlias),
42142
+ void 0,
42143
+ rows
42144
+ );
42100
42145
  for (const join of stmt.joins) {
42101
42146
  const rightAlias = join.table.alias;
42102
42147
  const rightRecords = tables.get(rightAlias) ?? [];
42103
42148
  const rightRows = rightRecords.map((r) => flatten(r, rightAlias));
42104
- rows = applyJoin(rows, rightRows, join);
42149
+ const rightColumns = mergeKnownColumns(
42150
+ flattenedColumns(tableColumns?.get(rightAlias), rightAlias),
42151
+ void 0,
42152
+ rightRows
42153
+ );
42154
+ rows = applyJoin(rows, rightRows, join, {
42155
+ leftColumns: knownColumns,
42156
+ rightColumns
42157
+ });
42158
+ knownColumns = mergeKnownColumns(knownColumns, rightColumns, rows);
42105
42159
  }
42106
42160
  rows = applyFilter(rows, stmt.where, fieldTypeResolver, appliedKlikes, fieldSemanticsResolver);
42107
42161
  if (stmt.groupBy.length > 0 || hasAggregateColumns(stmt.columns)) {
@@ -42114,7 +42168,15 @@ function runFullScan(input) {
42114
42168
  }
42115
42169
  rows = applyOrderBy(rows, stmt.orderBy, optionOrders, sortKinds, effectiveOrderSemantics);
42116
42170
  rows = applyLimit(rows, stmt.limit, stmt.offset);
42117
- return project(rows, stmt.columns, scalarCache, fieldTypeResolver, sourceColumns, fieldSemanticsResolver);
42171
+ return project(
42172
+ rows,
42173
+ stmt.columns,
42174
+ scalarCache,
42175
+ fieldTypeResolver,
42176
+ sourceColumns,
42177
+ fieldSemanticsResolver,
42178
+ hiddenQualifiedAliases
42179
+ );
42118
42180
  }
42119
42181
 
42120
42182
  // src/converter/subtableAdapter.ts
@@ -44450,7 +44512,7 @@ async function buildWhereFieldSemanticsResolver(stmt, client, cacheContext, mate
44450
44512
  if (field.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
44451
44513
  return fromPhysical(stmt.from, field.field, false);
44452
44514
  }
44453
- const table = tables.find((candidate) => candidate.alias === field.tableAlias);
44515
+ const table = tables.find((candidate) => effectiveTableAlias(candidate) === field.tableAlias);
44454
44516
  if (!table) return void 0;
44455
44517
  if (table.cteName !== null) {
44456
44518
  return materializedTables?.get(table.cteName)?.columnMeta?.get(field.field)?.semantics ?? syntheticSemantics("string");
@@ -44884,8 +44946,11 @@ function collectSelectTypedInFieldRefs(stmt) {
44884
44946
  }
44885
44947
  return refs;
44886
44948
  }
44949
+ function effectiveTableAlias(table) {
44950
+ return table.alias ?? table.cteName;
44951
+ }
44887
44952
  function findTableForAlias(stmt, alias) {
44888
- return [stmt.from, ...stmt.joins.map((join) => join.table)].find((table) => table.alias === alias);
44953
+ return [stmt.from, ...stmt.joins.map((join) => join.table)].find((table) => effectiveTableAlias(table) === alias);
44889
44954
  }
44890
44955
  function physicalSelectTables(stmt) {
44891
44956
  return [stmt.from, ...stmt.joins.map((join) => join.table)].filter((table) => table.cteName === null);
@@ -45037,7 +45102,7 @@ async function loadAggregateSortKindResolver(stmt, client, cacheContext, materia
45037
45102
  if (ref.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
45038
45103
  info = fieldInfosByApp.get(stmt.from.appId)?.get(ref.field);
45039
45104
  } else {
45040
- const table = tables.find((candidate) => candidate.alias === ref.tableAlias);
45105
+ const table = tables.find((candidate) => effectiveTableAlias(candidate) === ref.tableAlias);
45041
45106
  if (!table) return void 0;
45042
45107
  if (table.cteName !== null) {
45043
45108
  return materializedTables?.get(table.cteName)?.columnMeta?.get(ref.field)?.semantics ?? syntheticSemantics("string");
@@ -45062,7 +45127,7 @@ async function loadAggregateSortKindResolver(stmt, client, cacheContext, materia
45062
45127
  return matches[0];
45063
45128
  }
45064
45129
  if (!info) return void 0;
45065
- const sourceTable = ref.tableAlias !== null ? tables.find((table) => table.alias === ref.tableAlias) : stmt.joins.length === 0 ? stmt.from : void 0;
45130
+ const sourceTable = ref.tableAlias !== null ? tables.find((table) => effectiveTableAlias(table) === ref.tableAlias) : stmt.joins.length === 0 ? stmt.from : void 0;
45066
45131
  return semanticsForInfo(info, sourceTable?.appId ?? stmt.from.appId);
45067
45132
  };
45068
45133
  }
@@ -45192,7 +45257,7 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
45192
45257
  const info2 = physicalInfos.get(stmt.from.appId)?.get(ref.field);
45193
45258
  return info2 ? materializedMetaFromFieldInfo(info2, stmt.from.appId) : void 0;
45194
45259
  }
45195
- const table = tables.find((candidate) => candidate.alias === ref.tableAlias);
45260
+ const table = tables.find((candidate) => effectiveTableAlias(candidate) === ref.tableAlias);
45196
45261
  if (!table) return void 0;
45197
45262
  if (table.cteName !== null) return materializedTables?.get(table.cteName)?.columnMeta?.get(ref.field);
45198
45263
  const info = physicalInfos.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
@@ -45297,7 +45362,7 @@ function buildSelectFieldTypeResolvers(stmt, fieldTypesByApp) {
45297
45362
  if (field.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
45298
45363
  return fieldTypesByApp.get(stmt.from.appId)?.get(field.field);
45299
45364
  }
45300
- const table = tables.find((candidate) => candidate.alias === field.tableAlias);
45365
+ const table = tables.find((candidate) => effectiveTableAlias(candidate) === field.tableAlias);
45301
45366
  if (!table || table.cteName !== null) return void 0;
45302
45367
  return subtableSystemFieldType(table, field.field) ?? fieldTypesByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, field.field));
45303
45368
  }
@@ -45522,6 +45587,37 @@ async function executeQueryWithCte(query, client, options, cteCache, cacheContex
45522
45587
  return result;
45523
45588
  }
45524
45589
  async function executeFullScanWithCte(stmt, client, options, cteCache, cacheContext) {
45590
+ const hiddenQualifiedAliases = /* @__PURE__ */ new Set();
45591
+ const withEffectiveAlias = (table) => {
45592
+ if (table.alias !== null || table.cteName === null) return table;
45593
+ const alias = effectiveTableAlias(table);
45594
+ hiddenQualifiedAliases.add(alias);
45595
+ return { ...table, alias };
45596
+ };
45597
+ stmt = {
45598
+ ...stmt,
45599
+ from: withEffectiveAlias(stmt.from),
45600
+ joins: stmt.joins.map((join) => ({ ...join, table: withEffectiveAlias(join.table) }))
45601
+ };
45602
+ const aliases = /* @__PURE__ */ new Set();
45603
+ for (const table of [stmt.from, ...stmt.joins.map((join) => join.table)]) {
45604
+ const alias = effectiveTableAlias(table);
45605
+ if (alias === null) continue;
45606
+ if (aliases.has(alias)) {
45607
+ throw new Error(`ArgumentError: effective alias ${alias} is used by multiple tables.`);
45608
+ }
45609
+ aliases.add(alias);
45610
+ }
45611
+ const requireMaterializedTable = (name) => {
45612
+ const table = cteCache.get(name);
45613
+ if (!table) {
45614
+ throw new Error(`ArgumentError: materialized source ${name} is not available.`);
45615
+ }
45616
+ return table;
45617
+ };
45618
+ for (const table of [stmt.from, ...stmt.joins.map((join) => join.table)]) {
45619
+ if (table.cteName !== null) requireMaterializedTable(table.cteName);
45620
+ }
45525
45621
  const maxRecords2 = options.maxRecords ?? 1e4;
45526
45622
  const warnings = /* @__PURE__ */ new Set();
45527
45623
  const parallel = options.fetchParallel ?? 1;
@@ -45568,9 +45664,11 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
45568
45664
  orderByMetaPromise.catch(() => {
45569
45665
  });
45570
45666
  const tables = /* @__PURE__ */ new Map();
45667
+ const tableColumns = /* @__PURE__ */ new Map();
45571
45668
  if (stmt.from.cteName != null) {
45572
- const table = cteCache.get(stmt.from.cteName);
45573
- tables.set(stmt.from.alias, (table?.rows ?? []).map(processRowToKintoneRecord));
45669
+ const table = requireMaterializedTable(stmt.from.cteName);
45670
+ tables.set(stmt.from.alias, table.rows.map(processRowToKintoneRecord));
45671
+ tableColumns.set(stmt.from.alias, table.columns);
45574
45672
  } else {
45575
45673
  const mainRecords = await fetchTableRecordsForFullScan(
45576
45674
  stmt,
@@ -45588,8 +45686,9 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
45588
45686
  }
45589
45687
  const joinFetches = stmt.joins.map(async (join) => {
45590
45688
  if (join.table.cteName != null) {
45591
- const table = cteCache.get(join.table.cteName);
45592
- tables.set(join.table.alias, (table?.rows ?? []).map(processRowToKintoneRecord));
45689
+ const table = requireMaterializedTable(join.table.cteName);
45690
+ tables.set(join.table.alias, table.rows.map(processRowToKintoneRecord));
45691
+ tableColumns.set(join.table.alias, table.columns);
45593
45692
  } else {
45594
45693
  const pushDownCond = join.table.alias ? pushdownPlan.joinConditions.get(join.table.alias) ?? null : null;
45595
45694
  const optimized = await tryFetchJoinRecordsBySourceKeys(
@@ -45620,7 +45719,7 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
45620
45719
  await Promise.all(joinFetches);
45621
45720
  const scalarCache = await scalarCachePromise;
45622
45721
  const { optionOrders, sortKinds, semantics } = await orderByMetaPromise;
45623
- const sourceColumns = stmt.joins.length === 0 && stmt.from.cteName != null ? cteCache.get(stmt.from.cteName)?.columns : void 0;
45722
+ const sourceColumns = stmt.joins.length === 0 && stmt.from.cteName != null ? requireMaterializedTable(stmt.from.cteName).columns : void 0;
45624
45723
  const { rows, columns } = runFullScan({
45625
45724
  tables,
45626
45725
  stmt,
@@ -45634,7 +45733,9 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
45634
45733
  havingFieldSemanticsResolver,
45635
45734
  aggregateSortKindResolver,
45636
45735
  appliedKlikes: pushdownPlan.appliedKlikes,
45637
- sourceColumns
45736
+ sourceColumns,
45737
+ tableColumns,
45738
+ hiddenQualifiedAliases
45638
45739
  });
45639
45740
  return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [...warnings] };
45640
45741
  }
@@ -45936,7 +46037,7 @@ async function buildOrderSemanticsForSelect(stmt, client, cacheContext, material
45936
46037
  const info2 = infosByApp.get(stmt.from.appId)?.get(ref.field);
45937
46038
  return info2 ? materializedMetaFromFieldInfo(info2, stmt.from.appId) : void 0;
45938
46039
  }
45939
- const table = tables.find((candidate) => candidate.alias === ref.tableAlias);
46040
+ const table = tables.find((candidate) => effectiveTableAlias(candidate) === ref.tableAlias);
45940
46041
  if (!table) return void 0;
45941
46042
  if (table.cteName !== null) return materializedTables?.get(table.cteName)?.columnMeta?.get(ref.field);
45942
46043
  const info = infosByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
@@ -53200,7 +53301,7 @@ Nested JSON/CSV subtable mutation is fail-closed on MCP: use VALIDATE ONLY/EXPLA
53200
53301
  JSON child IDs are rejected and replacement renumbers all rows.
53201
53302
  `);
53202
53303
  }
53203
- var SERVER_VERSION = true ? "3.10.0" : "0.0.0-dev";
53304
+ var SERVER_VERSION = true ? "3.11.0" : "0.0.0-dev";
53204
53305
  var KSQL_MCP_INSTRUCTIONS = `kSQL is a SQL-like dialect for kintone, not generic SQL. It supports SELECT,
53205
53306
  JOIN, aggregates, CTEs, UNION, ROW_NUMBER/RANK/DENSE_RANK, GROUP_CONCAT,
53206
53307
  INSERT/UPDATE/UPSERT/DELETE, UPDATE ... FROM, subtable virtual tables
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rex0220/kintone-sql-tools",
3
- "version": "3.10.0",
3
+ "version": "3.11.0",
4
4
  "description": "kintone SQL plugin, CLI, and MCP tools (ksql)",
5
5
  "publishConfig": {
6
6
  "access": "public"