@rex0220/kintone-sql-tools 2.10.0 → 2.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
@@ -4514,6 +4514,11 @@ async function fetchAll(fetcher, app, query, fields, options = {}) {
4514
4514
  const parallel = Math.max(1, options.parallel ?? PARALLEL_DEFAULT);
4515
4515
  const maxRecords = options.maxRecords ?? MAX_RECORDS_DEFAULT;
4516
4516
  const onLimit = options.onLimit ?? "error";
4517
+ const stopAfter = options.stopAfter;
4518
+ if (stopAfter !== void 0 && (!Number.isSafeInteger(stopAfter) || stopAfter <= 0 || stopAfter > maxRecords)) {
4519
+ throw new RangeError("stopAfter must be a positive safe integer <= maxRecords");
4520
+ }
4521
+ const fetchCap = stopAfter ?? maxRecords;
4517
4522
  const fetchFields = fields.length > 0 && !fields.includes("$id") ? [...fields, "$id"] : fields;
4518
4523
  const allRecords = [];
4519
4524
  let notified = false;
@@ -4524,6 +4529,9 @@ async function fetchAll(fetcher, app, query, fields, options = {}) {
4524
4529
  const first = await fetchPage(fetcher, app, cursorQuery0, fetchFields, pageSize, windowOffset);
4525
4530
  notifySearchAborted(first, options);
4526
4531
  allRecords.push(...first.records);
4532
+ if (stopAfter !== void 0 && allRecords.length >= stopAfter) {
4533
+ return allRecords.slice(0, stopAfter);
4534
+ }
4527
4535
  if (allRecords.length > maxRecords) {
4528
4536
  if (onLimit === "truncate") {
4529
4537
  if (!notified && options.onTruncate) {
@@ -4541,6 +4549,9 @@ async function fetchAll(fetcher, app, query, fields, options = {}) {
4541
4549
  windowOffset = 0;
4542
4550
  }
4543
4551
  while (true) {
4552
+ if (stopAfter !== void 0 && allRecords.length >= stopAfter) {
4553
+ return allRecords.slice(0, stopAfter);
4554
+ }
4544
4555
  if (allRecords.length >= maxRecords) {
4545
4556
  if (onLimit === "truncate") {
4546
4557
  if (!notified && options.onTruncate) {
@@ -4551,7 +4562,7 @@ async function fetchAll(fetcher, app, query, fields, options = {}) {
4551
4562
  }
4552
4563
  throw new FetchAllLimitError(limitMessage);
4553
4564
  }
4554
- const remaining = maxRecords - allRecords.length;
4565
+ const remaining = fetchCap - allRecords.length;
4555
4566
  const maxPagesByLimit = Math.ceil(remaining / pageSize);
4556
4567
  const batchParallel = Math.max(1, Math.min(parallel, maxPagesByLimit));
4557
4568
  const batchOffsets = [];
@@ -4570,6 +4581,9 @@ async function fetchAll(fetcher, app, query, fields, options = {}) {
4570
4581
  let done = false;
4571
4582
  for (const res of responses) {
4572
4583
  allRecords.push(...res.records);
4584
+ if (stopAfter !== void 0 && allRecords.length >= stopAfter) {
4585
+ return allRecords.slice(0, stopAfter);
4586
+ }
4573
4587
  if (allRecords.length > maxRecords) {
4574
4588
  if (onLimit === "truncate") {
4575
4589
  if (!notified && options.onTruncate) {
@@ -4995,10 +5009,10 @@ function applyLimit(rows, limit, offset) {
4995
5009
  if (limit === null) return rows.slice(start);
4996
5010
  return rows.slice(start, start + limit);
4997
5011
  }
4998
- function project(rows, columns, scalarCache, resolveFieldType) {
5012
+ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns) {
4999
5013
  if (columns.length === 1 && columns[0].type === "WILDCARD") {
5000
5014
  const projected2 = rows.map((row) => stripParentShortcutColumns(row));
5001
- const cols = projected2.length > 0 ? Object.keys(projected2[0]) : [];
5015
+ const cols = projected2.length > 0 ? Object.keys(projected2[0]) : [...sourceColumns ?? []];
5002
5016
  return { rows: projected2, columns: cols };
5003
5017
  }
5004
5018
  const defaultFieldKeys = buildDefaultFieldOutputKeys(columns);
@@ -5007,6 +5021,9 @@ function project(rows, columns, scalarCache, resolveFieldType) {
5007
5021
  );
5008
5022
  const outputKeys = hasWildcard ? null : computeOutputKeys(columns, defaultFieldKeys);
5009
5023
  const orderedKeys = outputKeys ?? [];
5024
+ if (hasWildcard && rows.length === 0) {
5025
+ return { rows: [], columns: computeExplicitOutputKeys(columns, defaultFieldKeys) };
5026
+ }
5010
5027
  const projected = rows.map((row, rowIdx) => {
5011
5028
  const out = {};
5012
5029
  for (const [colIdx, col] of columns.entries()) {
@@ -5084,29 +5101,43 @@ function project(rows, columns, scalarCache, resolveFieldType) {
5084
5101
  return { rows: projected, columns: orderedKeys };
5085
5102
  }
5086
5103
  function computeOutputKeys(columns, defaultFieldKeys) {
5087
- return columns.map((col, colIdx) => {
5088
- switch (col.type) {
5089
- case "FIELD":
5090
- return col.alias ?? defaultFieldKeys.get(colIdx) ?? col.field;
5091
- case "LITERAL_COL":
5092
- return col.alias ?? `'${col.value}'`;
5093
- case "AGGREGATE":
5094
- return col.alias ?? aggregateSyntheticName2(col.func, col.distinct, col.arg);
5095
- case "ARITH_AGG_COL":
5096
- return col.alias ?? aggArithDefaultKey(col.expr);
5097
- case "ARITH_COL":
5098
- return col.alias ?? arithColDefaultKey(col.expr);
5099
- case "CASE_COL":
5100
- return col.alias ?? "case";
5101
- case "STRFUNC_COL":
5102
- return col.alias ?? stringFuncDefaultKey(col.expr);
5103
- case "SCALAR_SUBQUERY_COL":
5104
- return col.alias ?? "(subquery)";
5105
- case "WILDCARD":
5106
- case "PARENT_WILDCARD":
5107
- throw new Error("internal: computeOutputKeys received a wildcard column");
5104
+ return columns.map((col, colIdx) => computeOutputKey(col, colIdx, defaultFieldKeys));
5105
+ }
5106
+ function computeExplicitOutputKeys(columns, defaultFieldKeys) {
5107
+ const keys = [];
5108
+ const seen = /* @__PURE__ */ new Set();
5109
+ for (const [colIdx, col] of columns.entries()) {
5110
+ if (col.type === "WILDCARD" || col.type === "PARENT_WILDCARD") continue;
5111
+ const key = computeOutputKey(col, colIdx, defaultFieldKeys);
5112
+ if (!seen.has(key)) {
5113
+ seen.add(key);
5114
+ keys.push(key);
5108
5115
  }
5109
- });
5116
+ }
5117
+ return keys;
5118
+ }
5119
+ function computeOutputKey(col, colIdx, defaultFieldKeys) {
5120
+ switch (col.type) {
5121
+ case "FIELD":
5122
+ return col.alias ?? defaultFieldKeys.get(colIdx) ?? col.field;
5123
+ case "LITERAL_COL":
5124
+ return col.alias ?? `'${col.value}'`;
5125
+ case "AGGREGATE":
5126
+ return col.alias ?? aggregateSyntheticName2(col.func, col.distinct, col.arg);
5127
+ case "ARITH_AGG_COL":
5128
+ return col.alias ?? aggArithDefaultKey(col.expr);
5129
+ case "ARITH_COL":
5130
+ return col.alias ?? arithColDefaultKey(col.expr);
5131
+ case "CASE_COL":
5132
+ return col.alias ?? "case";
5133
+ case "STRFUNC_COL":
5134
+ return col.alias ?? stringFuncDefaultKey(col.expr);
5135
+ case "SCALAR_SUBQUERY_COL":
5136
+ return col.alias ?? "(subquery)";
5137
+ case "WILDCARD":
5138
+ case "PARENT_WILDCARD":
5139
+ throw new Error("internal: computeOutputKey received a wildcard column");
5140
+ }
5110
5141
  }
5111
5142
  function buildDefaultFieldOutputKeys(columns) {
5112
5143
  const qualifierCollisionCount = /* @__PURE__ */ new Map();
@@ -5200,7 +5231,8 @@ function runFullScan(input) {
5200
5231
  sortKinds,
5201
5232
  fieldTypeResolver,
5202
5233
  havingFieldTypeResolver,
5203
- appliedKlikes
5234
+ appliedKlikes,
5235
+ sourceColumns
5204
5236
  } = input;
5205
5237
  let rows = [];
5206
5238
  const mainAlias = stmt.from.alias;
@@ -5222,7 +5254,7 @@ function runFullScan(input) {
5222
5254
  }
5223
5255
  rows = applyOrderBy(rows, stmt.orderBy, optionOrders, sortKinds);
5224
5256
  rows = applyLimit(rows, stmt.limit, stmt.offset);
5225
- return project(rows, stmt.columns, scalarCache, fieldTypeResolver);
5257
+ return project(rows, stmt.columns, scalarCache, fieldTypeResolver, sourceColumns);
5226
5258
  }
5227
5259
 
5228
5260
  // src/converter/subtableAdapter.ts
@@ -5556,7 +5588,7 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
5556
5588
  onLimitReached: "error"
5557
5589
  };
5558
5590
  const result = await runSelectLike(resolvedStmt.query, client, materializeOptions, cacheContext, tempTables);
5559
- tempTables.set(resolvedStmt.name, result.rows);
5591
+ tempTables.set(resolvedStmt.name, { rows: result.rows, columns: result.columns });
5560
5592
  return { tempTable: resolvedStmt.name, rowCount: result.rows.length };
5561
5593
  }
5562
5594
  if (stmt.type === "DROP_TEMP_TABLE") {
@@ -5873,7 +5905,9 @@ async function executeSimpleSelect(stmt, client, options, cacheContext) {
5873
5905
  const warnings = /* @__PURE__ */ new Set();
5874
5906
  const onLimit = options.onLimitReached ?? "error";
5875
5907
  const parallel = options.fetchParallel ?? 1;
5876
- const useSingleGet = params.query.includes("limit") || stmt.limit !== null && stmt.limit <= 500;
5908
+ const useSingleGet = stmt.limit !== null && stmt.limit <= 500;
5909
+ const needed = stmt.limit === null ? null : (stmt.offset ?? 0) + stmt.limit;
5910
+ const stopAfter = stmt.orderBy.length === 0 && needed !== null && needed <= maxRecords && !whereHasKlike(stmt.where) ? needed : void 0;
5877
5911
  let records;
5878
5912
  if (useSingleGet) {
5879
5913
  const res = await client.getRecords({
@@ -5892,6 +5926,7 @@ async function executeSimpleSelect(stmt, client, options, cacheContext) {
5892
5926
  {
5893
5927
  parallel,
5894
5928
  maxRecords,
5929
+ stopAfter,
5895
5930
  onLimit,
5896
5931
  onTruncate: (max) => {
5897
5932
  warnings.add(`\u53D6\u5F97\u4E0A\u9650\uFF08${max} \u4EF6\uFF09\u306B\u9054\u3057\u305F\u305F\u3081\u3001${max} \u4EF6\u3067\u6253\u3061\u5207\u3063\u3066\u8868\u793A\u3057\u3066\u3044\u307E\u3059\u3002`);
@@ -6256,7 +6291,7 @@ async function executeWith(stmt, client, options, cacheContext, seed) {
6256
6291
  } else {
6257
6292
  result = await executeQueryWithCte(cte.query, client, options, cteCache, cacheContext);
6258
6293
  }
6259
- cteCache.set(cte.name, result.rows);
6294
+ cteCache.set(cte.name, { rows: result.rows, columns: result.columns });
6260
6295
  }
6261
6296
  return executeQueryWithCte(stmt.query, client, options, cteCache, cacheContext);
6262
6297
  }
@@ -6309,8 +6344,8 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
6309
6344
  });
6310
6345
  const tables = /* @__PURE__ */ new Map();
6311
6346
  if (stmt.from.cteName != null) {
6312
- const rows2 = cteCache.get(stmt.from.cteName) ?? [];
6313
- tables.set(stmt.from.alias, rows2.map(processRowToKintoneRecord));
6347
+ const table = cteCache.get(stmt.from.cteName);
6348
+ tables.set(stmt.from.alias, (table?.rows ?? []).map(processRowToKintoneRecord));
6314
6349
  } else {
6315
6350
  const mainRecords = await fetchTableRecordsForFullScan(
6316
6351
  stmt,
@@ -6327,8 +6362,8 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
6327
6362
  }
6328
6363
  const joinFetches = stmt.joins.map(async (join2) => {
6329
6364
  if (join2.table.cteName != null) {
6330
- const rows2 = cteCache.get(join2.table.cteName) ?? [];
6331
- tables.set(join2.table.alias, rows2.map(processRowToKintoneRecord));
6365
+ const table = cteCache.get(join2.table.cteName);
6366
+ tables.set(join2.table.alias, (table?.rows ?? []).map(processRowToKintoneRecord));
6332
6367
  } else {
6333
6368
  const pushDownCond = join2.table.alias ? pushdownPlan.joinConditions.get(join2.table.alias) ?? null : null;
6334
6369
  const optimized = await tryFetchJoinRecordsBySourceKeys(
@@ -6359,6 +6394,7 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
6359
6394
  await Promise.all(joinFetches);
6360
6395
  const scalarCache = await scalarCachePromise;
6361
6396
  const { optionOrders, sortKinds } = await orderByMetaPromise;
6397
+ const sourceColumns = stmt.joins.length === 0 && stmt.from.cteName != null ? cteCache.get(stmt.from.cteName)?.columns : void 0;
6362
6398
  const { rows, columns } = runFullScan({
6363
6399
  tables,
6364
6400
  stmt,
@@ -6367,7 +6403,8 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
6367
6403
  sortKinds,
6368
6404
  fieldTypeResolver: fieldTypeResolvers.row,
6369
6405
  havingFieldTypeResolver: fieldTypeResolvers.having,
6370
- appliedKlikes: pushdownPlan.appliedKlikes
6406
+ appliedKlikes: pushdownPlan.appliedKlikes,
6407
+ sourceColumns
6371
6408
  });
6372
6409
  return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [...warnings] };
6373
6410
  }
@@ -10333,6 +10370,11 @@ async function run() {
10333
10370
  const yes = args.yes || envBool("KSQL_YES") === true || Boolean(profile.dml?.yes);
10334
10371
  const allowWithoutWhere = args.allowWithoutWhere || envBool("KSQL_ALLOW_WITHOUT_WHERE") === true || Boolean(profile.dml?.allowWithoutWhere);
10335
10372
  const dmlMaxRows = args.dmlMaxRows ?? envInt2("KSQL_DML_MAX_ROWS") ?? profile.dml?.maxRows ?? 100;
10373
+ const dmlForcesOnLimitError = isDmlStatement || batchContainsDml;
10374
+ const effectiveOnLimit = dmlForcesOnLimitError ? "error" : onLimit;
10375
+ if (dmlForcesOnLimitError && onLimit === "truncate" && !quiet && !args.dryRun) {
10376
+ process.stderr.write("note: onLimit=truncate is ignored for DML (forced to error)\n");
10377
+ }
10336
10378
  if (format === "markdown" && noHeader) {
10337
10379
  process.stderr.write("ArgumentError: --no-header cannot be used with --format markdown|md.\n");
10338
10380
  return 2;
@@ -10684,7 +10726,7 @@ query=${label}`);
10684
10726
  const batchResult = await executeBatch(sql, client, {
10685
10727
  maxRecords,
10686
10728
  fetchParallel,
10687
- onLimitReached: onLimit,
10729
+ onLimitReached: effectiveOnLimit,
10688
10730
  cacheContext,
10689
10731
  continueOnError: args.continueOnError,
10690
10732
  tempTableMaxRows,
@@ -10702,7 +10744,7 @@ query=${label}`);
10702
10744
  let result = args.dryRun ? await execute(`EXPLAIN ${sql}`, client, { maxRecords, onLimitReached: onLimit, cacheContext }) : await execute(sql, client, {
10703
10745
  maxRecords,
10704
10746
  fetchParallel,
10705
- onLimitReached: onLimit,
10747
+ onLimitReached: effectiveOnLimit,
10706
10748
  confirm: isDmlStatement ? confirm : void 0,
10707
10749
  cacheContext
10708
10750
  });
@@ -35415,6 +35415,11 @@ async function fetchAll(fetcher, app, query, fields, options = {}) {
35415
35415
  const parallel = Math.max(1, options.parallel ?? PARALLEL_DEFAULT);
35416
35416
  const maxRecords2 = options.maxRecords ?? MAX_RECORDS_DEFAULT;
35417
35417
  const onLimit2 = options.onLimit ?? "error";
35418
+ const stopAfter = options.stopAfter;
35419
+ if (stopAfter !== void 0 && (!Number.isSafeInteger(stopAfter) || stopAfter <= 0 || stopAfter > maxRecords2)) {
35420
+ throw new RangeError("stopAfter must be a positive safe integer <= maxRecords");
35421
+ }
35422
+ const fetchCap = stopAfter ?? maxRecords2;
35418
35423
  const fetchFields = fields.length > 0 && !fields.includes("$id") ? [...fields, "$id"] : fields;
35419
35424
  const allRecords = [];
35420
35425
  let notified = false;
@@ -35425,6 +35430,9 @@ async function fetchAll(fetcher, app, query, fields, options = {}) {
35425
35430
  const first = await fetchPage(fetcher, app, cursorQuery0, fetchFields, pageSize, windowOffset);
35426
35431
  notifySearchAborted(first, options);
35427
35432
  allRecords.push(...first.records);
35433
+ if (stopAfter !== void 0 && allRecords.length >= stopAfter) {
35434
+ return allRecords.slice(0, stopAfter);
35435
+ }
35428
35436
  if (allRecords.length > maxRecords2) {
35429
35437
  if (onLimit2 === "truncate") {
35430
35438
  if (!notified && options.onTruncate) {
@@ -35442,6 +35450,9 @@ async function fetchAll(fetcher, app, query, fields, options = {}) {
35442
35450
  windowOffset = 0;
35443
35451
  }
35444
35452
  while (true) {
35453
+ if (stopAfter !== void 0 && allRecords.length >= stopAfter) {
35454
+ return allRecords.slice(0, stopAfter);
35455
+ }
35445
35456
  if (allRecords.length >= maxRecords2) {
35446
35457
  if (onLimit2 === "truncate") {
35447
35458
  if (!notified && options.onTruncate) {
@@ -35452,7 +35463,7 @@ async function fetchAll(fetcher, app, query, fields, options = {}) {
35452
35463
  }
35453
35464
  throw new FetchAllLimitError(limitMessage);
35454
35465
  }
35455
- const remaining = maxRecords2 - allRecords.length;
35466
+ const remaining = fetchCap - allRecords.length;
35456
35467
  const maxPagesByLimit = Math.ceil(remaining / pageSize);
35457
35468
  const batchParallel = Math.max(1, Math.min(parallel, maxPagesByLimit));
35458
35469
  const batchOffsets = [];
@@ -35471,6 +35482,9 @@ async function fetchAll(fetcher, app, query, fields, options = {}) {
35471
35482
  let done = false;
35472
35483
  for (const res of responses) {
35473
35484
  allRecords.push(...res.records);
35485
+ if (stopAfter !== void 0 && allRecords.length >= stopAfter) {
35486
+ return allRecords.slice(0, stopAfter);
35487
+ }
35474
35488
  if (allRecords.length > maxRecords2) {
35475
35489
  if (onLimit2 === "truncate") {
35476
35490
  if (!notified && options.onTruncate) {
@@ -35896,10 +35910,10 @@ function applyLimit(rows, limit, offset) {
35896
35910
  if (limit === null) return rows.slice(start);
35897
35911
  return rows.slice(start, start + limit);
35898
35912
  }
35899
- function project(rows, columns, scalarCache, resolveFieldType) {
35913
+ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns) {
35900
35914
  if (columns.length === 1 && columns[0].type === "WILDCARD") {
35901
35915
  const projected2 = rows.map((row) => stripParentShortcutColumns(row));
35902
- const cols = projected2.length > 0 ? Object.keys(projected2[0]) : [];
35916
+ const cols = projected2.length > 0 ? Object.keys(projected2[0]) : [...sourceColumns ?? []];
35903
35917
  return { rows: projected2, columns: cols };
35904
35918
  }
35905
35919
  const defaultFieldKeys = buildDefaultFieldOutputKeys(columns);
@@ -35908,6 +35922,9 @@ function project(rows, columns, scalarCache, resolveFieldType) {
35908
35922
  );
35909
35923
  const outputKeys = hasWildcard ? null : computeOutputKeys(columns, defaultFieldKeys);
35910
35924
  const orderedKeys = outputKeys ?? [];
35925
+ if (hasWildcard && rows.length === 0) {
35926
+ return { rows: [], columns: computeExplicitOutputKeys(columns, defaultFieldKeys) };
35927
+ }
35911
35928
  const projected = rows.map((row, rowIdx) => {
35912
35929
  const out = {};
35913
35930
  for (const [colIdx, col] of columns.entries()) {
@@ -35985,29 +36002,43 @@ function project(rows, columns, scalarCache, resolveFieldType) {
35985
36002
  return { rows: projected, columns: orderedKeys };
35986
36003
  }
35987
36004
  function computeOutputKeys(columns, defaultFieldKeys) {
35988
- return columns.map((col, colIdx) => {
35989
- switch (col.type) {
35990
- case "FIELD":
35991
- return col.alias ?? defaultFieldKeys.get(colIdx) ?? col.field;
35992
- case "LITERAL_COL":
35993
- return col.alias ?? `'${col.value}'`;
35994
- case "AGGREGATE":
35995
- return col.alias ?? aggregateSyntheticName2(col.func, col.distinct, col.arg);
35996
- case "ARITH_AGG_COL":
35997
- return col.alias ?? aggArithDefaultKey(col.expr);
35998
- case "ARITH_COL":
35999
- return col.alias ?? arithColDefaultKey(col.expr);
36000
- case "CASE_COL":
36001
- return col.alias ?? "case";
36002
- case "STRFUNC_COL":
36003
- return col.alias ?? stringFuncDefaultKey(col.expr);
36004
- case "SCALAR_SUBQUERY_COL":
36005
- return col.alias ?? "(subquery)";
36006
- case "WILDCARD":
36007
- case "PARENT_WILDCARD":
36008
- throw new Error("internal: computeOutputKeys received a wildcard column");
36005
+ return columns.map((col, colIdx) => computeOutputKey(col, colIdx, defaultFieldKeys));
36006
+ }
36007
+ function computeExplicitOutputKeys(columns, defaultFieldKeys) {
36008
+ const keys = [];
36009
+ const seen = /* @__PURE__ */ new Set();
36010
+ for (const [colIdx, col] of columns.entries()) {
36011
+ if (col.type === "WILDCARD" || col.type === "PARENT_WILDCARD") continue;
36012
+ const key = computeOutputKey(col, colIdx, defaultFieldKeys);
36013
+ if (!seen.has(key)) {
36014
+ seen.add(key);
36015
+ keys.push(key);
36009
36016
  }
36010
- });
36017
+ }
36018
+ return keys;
36019
+ }
36020
+ function computeOutputKey(col, colIdx, defaultFieldKeys) {
36021
+ switch (col.type) {
36022
+ case "FIELD":
36023
+ return col.alias ?? defaultFieldKeys.get(colIdx) ?? col.field;
36024
+ case "LITERAL_COL":
36025
+ return col.alias ?? `'${col.value}'`;
36026
+ case "AGGREGATE":
36027
+ return col.alias ?? aggregateSyntheticName2(col.func, col.distinct, col.arg);
36028
+ case "ARITH_AGG_COL":
36029
+ return col.alias ?? aggArithDefaultKey(col.expr);
36030
+ case "ARITH_COL":
36031
+ return col.alias ?? arithColDefaultKey(col.expr);
36032
+ case "CASE_COL":
36033
+ return col.alias ?? "case";
36034
+ case "STRFUNC_COL":
36035
+ return col.alias ?? stringFuncDefaultKey(col.expr);
36036
+ case "SCALAR_SUBQUERY_COL":
36037
+ return col.alias ?? "(subquery)";
36038
+ case "WILDCARD":
36039
+ case "PARENT_WILDCARD":
36040
+ throw new Error("internal: computeOutputKey received a wildcard column");
36041
+ }
36011
36042
  }
36012
36043
  function buildDefaultFieldOutputKeys(columns) {
36013
36044
  const qualifierCollisionCount = /* @__PURE__ */ new Map();
@@ -36101,7 +36132,8 @@ function runFullScan(input) {
36101
36132
  sortKinds,
36102
36133
  fieldTypeResolver,
36103
36134
  havingFieldTypeResolver,
36104
- appliedKlikes
36135
+ appliedKlikes,
36136
+ sourceColumns
36105
36137
  } = input;
36106
36138
  let rows = [];
36107
36139
  const mainAlias = stmt.from.alias;
@@ -36123,7 +36155,7 @@ function runFullScan(input) {
36123
36155
  }
36124
36156
  rows = applyOrderBy(rows, stmt.orderBy, optionOrders, sortKinds);
36125
36157
  rows = applyLimit(rows, stmt.limit, stmt.offset);
36126
- return project(rows, stmt.columns, scalarCache, fieldTypeResolver);
36158
+ return project(rows, stmt.columns, scalarCache, fieldTypeResolver, sourceColumns);
36127
36159
  }
36128
36160
 
36129
36161
  // src/converter/subtableAdapter.ts
@@ -36457,7 +36489,7 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
36457
36489
  onLimitReached: "error"
36458
36490
  };
36459
36491
  const result = await runSelectLike(resolvedStmt.query, client, materializeOptions, cacheContext, tempTables);
36460
- tempTables.set(resolvedStmt.name, result.rows);
36492
+ tempTables.set(resolvedStmt.name, { rows: result.rows, columns: result.columns });
36461
36493
  return { tempTable: resolvedStmt.name, rowCount: result.rows.length };
36462
36494
  }
36463
36495
  if (stmt.type === "DROP_TEMP_TABLE") {
@@ -36774,7 +36806,9 @@ async function executeSimpleSelect(stmt, client, options, cacheContext) {
36774
36806
  const warnings = /* @__PURE__ */ new Set();
36775
36807
  const onLimit2 = options.onLimitReached ?? "error";
36776
36808
  const parallel = options.fetchParallel ?? 1;
36777
- const useSingleGet = params.query.includes("limit") || stmt.limit !== null && stmt.limit <= 500;
36809
+ const useSingleGet = stmt.limit !== null && stmt.limit <= 500;
36810
+ const needed = stmt.limit === null ? null : (stmt.offset ?? 0) + stmt.limit;
36811
+ const stopAfter = stmt.orderBy.length === 0 && needed !== null && needed <= maxRecords2 && !whereHasKlike(stmt.where) ? needed : void 0;
36778
36812
  let records;
36779
36813
  if (useSingleGet) {
36780
36814
  const res = await client.getRecords({
@@ -36793,6 +36827,7 @@ async function executeSimpleSelect(stmt, client, options, cacheContext) {
36793
36827
  {
36794
36828
  parallel,
36795
36829
  maxRecords: maxRecords2,
36830
+ stopAfter,
36796
36831
  onLimit: onLimit2,
36797
36832
  onTruncate: (max) => {
36798
36833
  warnings.add(`\u53D6\u5F97\u4E0A\u9650\uFF08${max} \u4EF6\uFF09\u306B\u9054\u3057\u305F\u305F\u3081\u3001${max} \u4EF6\u3067\u6253\u3061\u5207\u3063\u3066\u8868\u793A\u3057\u3066\u3044\u307E\u3059\u3002`);
@@ -37157,7 +37192,7 @@ async function executeWith(stmt, client, options, cacheContext, seed) {
37157
37192
  } else {
37158
37193
  result = await executeQueryWithCte(cte.query, client, options, cteCache, cacheContext);
37159
37194
  }
37160
- cteCache.set(cte.name, result.rows);
37195
+ cteCache.set(cte.name, { rows: result.rows, columns: result.columns });
37161
37196
  }
37162
37197
  return executeQueryWithCte(stmt.query, client, options, cteCache, cacheContext);
37163
37198
  }
@@ -37210,8 +37245,8 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
37210
37245
  });
37211
37246
  const tables = /* @__PURE__ */ new Map();
37212
37247
  if (stmt.from.cteName != null) {
37213
- const rows2 = cteCache.get(stmt.from.cteName) ?? [];
37214
- tables.set(stmt.from.alias, rows2.map(processRowToKintoneRecord));
37248
+ const table = cteCache.get(stmt.from.cteName);
37249
+ tables.set(stmt.from.alias, (table?.rows ?? []).map(processRowToKintoneRecord));
37215
37250
  } else {
37216
37251
  const mainRecords = await fetchTableRecordsForFullScan(
37217
37252
  stmt,
@@ -37228,8 +37263,8 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
37228
37263
  }
37229
37264
  const joinFetches = stmt.joins.map(async (join) => {
37230
37265
  if (join.table.cteName != null) {
37231
- const rows2 = cteCache.get(join.table.cteName) ?? [];
37232
- tables.set(join.table.alias, rows2.map(processRowToKintoneRecord));
37266
+ const table = cteCache.get(join.table.cteName);
37267
+ tables.set(join.table.alias, (table?.rows ?? []).map(processRowToKintoneRecord));
37233
37268
  } else {
37234
37269
  const pushDownCond = join.table.alias ? pushdownPlan.joinConditions.get(join.table.alias) ?? null : null;
37235
37270
  const optimized = await tryFetchJoinRecordsBySourceKeys(
@@ -37260,6 +37295,7 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
37260
37295
  await Promise.all(joinFetches);
37261
37296
  const scalarCache = await scalarCachePromise;
37262
37297
  const { optionOrders, sortKinds } = await orderByMetaPromise;
37298
+ const sourceColumns = stmt.joins.length === 0 && stmt.from.cteName != null ? cteCache.get(stmt.from.cteName)?.columns : void 0;
37263
37299
  const { rows, columns } = runFullScan({
37264
37300
  tables,
37265
37301
  stmt,
@@ -37268,7 +37304,8 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
37268
37304
  sortKinds,
37269
37305
  fieldTypeResolver: fieldTypeResolvers.row,
37270
37306
  havingFieldTypeResolver: fieldTypeResolvers.having,
37271
- appliedKlikes: pushdownPlan.appliedKlikes
37307
+ appliedKlikes: pushdownPlan.appliedKlikes,
37308
+ sourceColumns
37272
37309
  });
37273
37310
  return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [...warnings] };
37274
37311
  }
@@ -40886,7 +40923,7 @@ Options:
40886
40923
  -h, --help Show help
40887
40924
  `);
40888
40925
  }
40889
- var SERVER_VERSION = true ? "2.10.0" : "0.0.0-dev";
40926
+ var SERVER_VERSION = true ? "2.11.0" : "0.0.0-dev";
40890
40927
  function createServer(args) {
40891
40928
  const server = new McpServer({
40892
40929
  name: "ksql-mcp",
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rex0220/kintone-sql-tools",
3
- "version": "2.10.0",
3
+ "version": "2.11.0",
4
4
  "description": "kintone SQL plugin, CLI, and MCP tools (ksql)",
5
5
  "publishConfig": {
6
6
  "access": "public"