@rex0220/kintone-sql-tools 2.4.0 → 2.6.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.
@@ -34409,52 +34409,93 @@ function resolveFieldRef(row, field) {
34409
34409
  }
34410
34410
 
34411
34411
  // src/engine/evalWhere.ts
34412
- function evalWhere(expr, row) {
34412
+ function evalWhere(expr, row, resolveFieldType) {
34413
34413
  switch (expr.type) {
34414
34414
  case "BINARY":
34415
- return evalBinary(expr, row);
34415
+ return evalBinary(expr, row, resolveFieldType);
34416
34416
  case "NULL_CHECK":
34417
34417
  return evalNullCheck(expr, row);
34418
34418
  case "LOGICAL":
34419
- return evalLogical(expr, row);
34419
+ return evalLogical(expr, row, resolveFieldType);
34420
34420
  case "NOT":
34421
- return !evalWhere(expr.expr, row);
34421
+ return !evalWhere(expr.expr, row, resolveFieldType);
34422
34422
  case "GROUP":
34423
- return evalWhere(expr.expr, row);
34423
+ return evalWhere(expr.expr, row, resolveFieldType);
34424
34424
  case "EXISTS": {
34425
34425
  const exists = expr.resolved;
34426
34426
  return expr.not ? !exists : exists;
34427
34427
  }
34428
34428
  }
34429
34429
  }
34430
- function evalBinary(expr, row) {
34431
- const left = resolveField(expr.left, row);
34432
- return evalOp(expr.op, left, expr.right, row);
34430
+ function evalBinary(expr, row, resolveFieldType) {
34431
+ const left = resolveField(expr.left, row, resolveFieldType);
34432
+ const fieldType = expr.left.type === "FIELD" ? resolveFieldType?.(expr.left) : void 0;
34433
+ return evalOp(expr.op, left, expr.right, row, fieldType, resolveFieldType);
34433
34434
  }
34434
- function evalOp(op, leftStr, right, row) {
34435
+ function evalOp(op, leftStr, right, row, fieldType, resolveFieldType) {
34435
34436
  if (op === "IN" || op === "NOT_IN") {
34437
+ let values = null;
34436
34438
  if (right.type === "IN_LIST") {
34437
34439
  assertResolvedInListValues2(right.values);
34438
- const contains = right.values.some((v) => leftStr === String(v.value));
34439
- return op === "IN" ? contains : !contains;
34440
+ values = new Set(right.values.map((v) => String(v.value)));
34440
34441
  }
34441
34442
  if (right.type === "SUBQUERY_IN_LIST") {
34442
- const contains = right.resolved.has(leftStr);
34443
- return op === "IN" ? contains : !contains;
34443
+ values = right.resolved;
34444
34444
  }
34445
- return op === "NOT_IN";
34445
+ if (values === null) return op === "NOT_IN";
34446
+ const contains = typedInContains(leftStr, values, fieldType);
34447
+ return op === "IN" ? contains : !contains;
34446
34448
  }
34447
34449
  if (op === "LIKE") {
34448
- const pattern = resolveValue(right, row);
34450
+ const pattern = resolveValue(right, row, resolveFieldType);
34449
34451
  return matchLike(leftStr, pattern);
34450
34452
  }
34451
34453
  if (op === "NOT_LIKE") {
34452
- const pattern = resolveValue(right, row);
34454
+ const pattern = resolveValue(right, row, resolveFieldType);
34453
34455
  return !matchLike(leftStr, pattern);
34454
34456
  }
34455
- const rightStr = resolveValue(right, row);
34457
+ const rightStr = resolveValue(right, row, resolveFieldType);
34456
34458
  return compareScalarValues(op, leftStr, rightStr);
34457
34459
  }
34460
+ var STRING_ARRAY_FIELD_TYPES = /* @__PURE__ */ new Set(["CHECK_BOX", "MULTI_SELECT"]);
34461
+ var OBJECT_ARRAY_FIELD_TYPES = /* @__PURE__ */ new Set([
34462
+ "USER_SELECT",
34463
+ "ORGANIZATION_SELECT",
34464
+ "GROUP_SELECT",
34465
+ "STATUS_ASSIGNEE"
34466
+ ]);
34467
+ var SINGLE_OBJECT_FIELD_TYPES = /* @__PURE__ */ new Set(["CREATOR", "MODIFIER"]);
34468
+ function typedInContains(leftStr, values, fieldType) {
34469
+ const fallback = () => values.has(leftStr);
34470
+ if (fieldType === void 0) return fallback();
34471
+ let parsed;
34472
+ if (STRING_ARRAY_FIELD_TYPES.has(fieldType) || OBJECT_ARRAY_FIELD_TYPES.has(fieldType) || SINGLE_OBJECT_FIELD_TYPES.has(fieldType)) {
34473
+ try {
34474
+ parsed = JSON.parse(leftStr);
34475
+ } catch {
34476
+ return fallback();
34477
+ }
34478
+ } else {
34479
+ return fallback();
34480
+ }
34481
+ if (STRING_ARRAY_FIELD_TYPES.has(fieldType)) {
34482
+ if (!Array.isArray(parsed) || !parsed.every((item) => typeof item === "string")) {
34483
+ return fallback();
34484
+ }
34485
+ if (parsed.length === 0 && values.has("")) return true;
34486
+ return parsed.some((item) => values.has(item));
34487
+ }
34488
+ if (OBJECT_ARRAY_FIELD_TYPES.has(fieldType)) {
34489
+ if (!Array.isArray(parsed) || !parsed.every(hasStringCode)) return fallback();
34490
+ if (parsed.length === 0 && values.has("")) return true;
34491
+ return parsed.some((item) => values.has(item.code));
34492
+ }
34493
+ if (!hasStringCode(parsed)) return fallback();
34494
+ return values.has(parsed.code);
34495
+ }
34496
+ function hasStringCode(value) {
34497
+ return value !== null && typeof value === "object" && !Array.isArray(value) && typeof value.code === "string";
34498
+ }
34458
34499
  function assertResolvedInListValues2(values) {
34459
34500
  const unresolved = values.find((item) => item.type === "VARIABLE");
34460
34501
  if (unresolved?.type === "VARIABLE") {
@@ -34465,20 +34506,20 @@ function evalNullCheck(expr, row) {
34465
34506
  const val = resolveField(expr.field, row);
34466
34507
  return expr.not ? val !== "" : val === "";
34467
34508
  }
34468
- function evalLogical(expr, row) {
34509
+ function evalLogical(expr, row, resolveFieldType) {
34469
34510
  if (expr.op === "AND") {
34470
- return evalWhere(expr.left, row) && evalWhere(expr.right, row);
34511
+ return evalWhere(expr.left, row, resolveFieldType) && evalWhere(expr.right, row, resolveFieldType);
34471
34512
  }
34472
- return evalWhere(expr.left, row) || evalWhere(expr.right, row);
34513
+ return evalWhere(expr.left, row, resolveFieldType) || evalWhere(expr.right, row, resolveFieldType);
34473
34514
  }
34474
- function resolveField(field, row) {
34515
+ function resolveField(field, row, resolveFieldType) {
34475
34516
  if (field.type === "FUNC_FIELD") return evalStringFunc(field.expr, row);
34476
34517
  if (field.type === "ARITH_FIELD") return String(evalArithExpr(field.expr, row));
34477
- if (field.type === "CASE_FIELD") return evalCaseWhen(field.expr, row);
34518
+ if (field.type === "CASE_FIELD") return evalCaseWhen(field.expr, row, resolveFieldType);
34478
34519
  const key = field.tableAlias ? `${field.tableAlias}.${field.field}` : field.field;
34479
34520
  return resolveFieldRef(row, key);
34480
34521
  }
34481
- function resolveValue(value, row) {
34522
+ function resolveValue(value, row, resolveFieldType) {
34482
34523
  switch (value.type) {
34483
34524
  case "VARIABLE":
34484
34525
  throw new Error(`ParseError: unresolved batch variable @${value.name}.`);
@@ -34501,14 +34542,14 @@ function resolveValue(value, row) {
34501
34542
  if (value.expr.type === "STRING_FUNC") return evalStringFunc(value.expr, row);
34502
34543
  return String(evalArithExpr(value.expr, row));
34503
34544
  case "CASE_VALUE":
34504
- return evalCaseWhen(value.expr, row);
34545
+ return evalCaseWhen(value.expr, row, resolveFieldType);
34505
34546
  case "ARRAY":
34506
34547
  return value.elements.map((e) => e.value).join(",");
34507
34548
  }
34508
34549
  }
34509
- function evalCaseWhen(expr, row) {
34550
+ function evalCaseWhen(expr, row, resolveFieldType) {
34510
34551
  for (const branch of expr.branches) {
34511
- if (evalWhere(branch.condition, row)) {
34552
+ if (evalWhere(branch.condition, row, resolveFieldType)) {
34512
34553
  return evalCaseResult(branch.result, row);
34513
34554
  }
34514
34555
  }
@@ -35059,8 +35100,11 @@ async function resolveDmlTargetIds(getRecords, app, query, options) {
35059
35100
  function extractSafePushdownLeaves(where, options = {}) {
35060
35101
  return extractAndLeaves(where, (expr) => isSafeComparison(expr, options));
35061
35102
  }
35062
- function extractNumericPushdownCandidates(where, options = {}) {
35063
- return extractAndLeaves(where, (expr) => isNumericCandidate(expr, options));
35103
+ function extractTypedPushdownCandidates(where, options = {}) {
35104
+ return extractAndLeaves(
35105
+ where,
35106
+ (expr) => isNumericCandidate(expr, options) || isSelectionInCandidate(expr, options)
35107
+ );
35064
35108
  }
35065
35109
  function extractAndLeaves(where, accept) {
35066
35110
  switch (where.type) {
@@ -35084,8 +35128,27 @@ function extractAndLeaves(where, accept) {
35084
35128
  }
35085
35129
  function isSafeComparison(expr, options) {
35086
35130
  if (isSafeIdComparison(expr, options)) return true;
35087
- if (!isNumericCandidate(expr, options)) return false;
35088
- return options.fieldTypes?.get(expr.left.field) === "NUMBER";
35131
+ if (isNumericCandidate(expr, options)) {
35132
+ return options.fieldTypes?.get(expr.left.field) === "NUMBER";
35133
+ }
35134
+ return isSelectionInComparison(expr, options);
35135
+ }
35136
+ var SELECTION_IN_FIELD_TYPES = /* @__PURE__ */ new Set([
35137
+ "DROP_DOWN",
35138
+ "RADIO_BUTTON",
35139
+ "CHECK_BOX",
35140
+ "MULTI_SELECT"
35141
+ ]);
35142
+ function isSelectionInComparison(expr, options) {
35143
+ if (!isSelectionInCandidate(expr, options)) return false;
35144
+ if (expr.left.type !== "FIELD" || expr.right.type !== "IN_LIST") return false;
35145
+ const fieldType = options.fieldTypes?.get(expr.left.field);
35146
+ if (fieldType === void 0 || !SELECTION_IN_FIELD_TYPES.has(fieldType)) return false;
35147
+ const validOptions = options.fieldOptions?.get(expr.left.field);
35148
+ if (validOptions === void 0) return false;
35149
+ return expr.right.values.every(
35150
+ (value) => value.type === "STRING" && value.value !== "" && validOptions.has(value.value)
35151
+ );
35089
35152
  }
35090
35153
  function isSafeIdComparison(expr, options) {
35091
35154
  if (!isTargetIdField(expr.left, options)) return false;
@@ -35105,6 +35168,13 @@ function isNumericCandidate(expr, options) {
35105
35168
  if (expr.op === "=") return true;
35106
35169
  return (expr.op === "<" || expr.op === ">") && Number.isSafeInteger(expr.right.value);
35107
35170
  }
35171
+ function isSelectionInCandidate(expr, options) {
35172
+ if (expr.left.type !== "FIELD" || expr.left.field === "$id") return false;
35173
+ if (!isTargetField(expr.left, options)) return false;
35174
+ if (expr.op !== "IN" && expr.op !== "NOT_IN") return false;
35175
+ if (expr.right.type !== "IN_LIST" || expr.right.values.length === 0) return false;
35176
+ return expr.right.values.every((value) => value.type === "STRING" && value.value !== "");
35177
+ }
35108
35178
  function isTargetField(field, options) {
35109
35179
  const targetAlias = options.tableAlias ?? null;
35110
35180
  if (field.tableAlias === targetAlias) return true;
@@ -35116,7 +35186,7 @@ function flatten(record2, alias) {
35116
35186
  const row = {};
35117
35187
  for (const [field, fv] of Object.entries(record2)) {
35118
35188
  const val = fv.value;
35119
- const strVal = typeof val === "string" ? val : JSON.stringify(val ?? "");
35189
+ const strVal = val == null ? "" : typeof val === "string" ? val : JSON.stringify(val);
35120
35190
  if (alias) {
35121
35191
  row[`${alias}.${field}`] = strVal;
35122
35192
  row[field] = strVal;
@@ -35175,9 +35245,9 @@ function applyJoin(leftRows, rightRows, join) {
35175
35245
  }
35176
35246
  return result;
35177
35247
  }
35178
- function applyFilter(rows, where) {
35248
+ function applyFilter(rows, where, resolveFieldType) {
35179
35249
  if (where === null) return rows;
35180
- return rows.filter((row) => evalWhere(where, row));
35250
+ return rows.filter((row) => evalWhere(where, row, resolveFieldType));
35181
35251
  }
35182
35252
  function hasAggregateColumns(columns) {
35183
35253
  return columns.some(
@@ -35303,9 +35373,9 @@ function aggregateSyntheticName2(func, distinct, arg) {
35303
35373
  const argStr = aggregateArgLabel(arg);
35304
35374
  return distinct ? `${func}(DISTINCT ${argStr})` : `${func}(${argStr})`;
35305
35375
  }
35306
- function applyHaving(rows, having) {
35376
+ function applyHaving(rows, having, resolveFieldType) {
35307
35377
  if (having === null) return rows;
35308
- return rows.filter((row) => evalWhere(having, row));
35378
+ return rows.filter((row) => evalWhere(having, row, resolveFieldType));
35309
35379
  }
35310
35380
  function applyDistinct(rows, columns) {
35311
35381
  if (rows.length === 0) return rows;
@@ -35430,7 +35500,7 @@ function applyLimit(rows, limit, offset) {
35430
35500
  if (limit === null) return rows.slice(start);
35431
35501
  return rows.slice(start, start + limit);
35432
35502
  }
35433
- function project(rows, columns, scalarCache) {
35503
+ function project(rows, columns, scalarCache, resolveFieldType) {
35434
35504
  if (columns.length === 1 && columns[0].type === "WILDCARD") {
35435
35505
  const projected2 = rows.map((row) => stripParentShortcutColumns(row));
35436
35506
  const cols = projected2.length > 0 ? Object.keys(projected2[0]) : [];
@@ -35491,7 +35561,7 @@ function project(rows, columns, scalarCache) {
35491
35561
  }
35492
35562
  case "CASE_COL": {
35493
35563
  const key = outputKeys?.[colIdx] ?? col.alias ?? "case";
35494
- out[key] = evalCaseWhen(col.expr, row);
35564
+ out[key] = evalCaseWhen(col.expr, row, resolveFieldType);
35495
35565
  if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
35496
35566
  break;
35497
35567
  }
@@ -35627,7 +35697,15 @@ function resolveAggInStringFuncExpr(expr, rows) {
35627
35697
  };
35628
35698
  }
35629
35699
  function runFullScan(input) {
35630
- const { stmt, tables, scalarCache, optionOrders, sortKinds } = input;
35700
+ const {
35701
+ stmt,
35702
+ tables,
35703
+ scalarCache,
35704
+ optionOrders,
35705
+ sortKinds,
35706
+ fieldTypeResolver,
35707
+ havingFieldTypeResolver
35708
+ } = input;
35631
35709
  let rows = [];
35632
35710
  const mainAlias = stmt.from.alias;
35633
35711
  const mainRecords = tables.get(mainAlias) ?? tables.get(null) ?? [];
@@ -35638,17 +35716,17 @@ function runFullScan(input) {
35638
35716
  const rightRows = rightRecords.map((r) => flatten(r, rightAlias));
35639
35717
  rows = applyJoin(rows, rightRows, join);
35640
35718
  }
35641
- rows = applyFilter(rows, stmt.where);
35719
+ rows = applyFilter(rows, stmt.where, fieldTypeResolver);
35642
35720
  if (stmt.groupBy.length > 0 || hasAggregateColumns(stmt.columns)) {
35643
35721
  rows = applyGroupBy(rows, stmt.groupBy, stmt.columns);
35644
35722
  }
35645
- rows = applyHaving(rows, stmt.having);
35723
+ rows = applyHaving(rows, stmt.having, havingFieldTypeResolver);
35646
35724
  if (stmt.distinct) {
35647
35725
  rows = applyDistinct(rows, stmt.columns);
35648
35726
  }
35649
35727
  rows = applyOrderBy(rows, stmt.orderBy, optionOrders, sortKinds);
35650
35728
  rows = applyLimit(rows, stmt.limit, stmt.offset);
35651
- return project(rows, stmt.columns, scalarCache);
35729
+ return project(rows, stmt.columns, scalarCache, fieldTypeResolver);
35652
35730
  }
35653
35731
 
35654
35732
  // src/converter/subtableAdapter.ts
@@ -36181,6 +36259,7 @@ async function executeSelect(stmt, client, options, cacheContext, cteCache) {
36181
36259
  if (isNoFromSelect(stmt)) {
36182
36260
  return executeNoFromSelect(stmt);
36183
36261
  }
36262
+ await resolveSelectCaseSubqueries(stmt, client, options, cacheContext, cteCache);
36184
36263
  const mode = resolveSelectMode(stmt);
36185
36264
  await validateSelectFieldCodes(stmt, mode, client, cacheContext);
36186
36265
  if (mode === "SIMPLE") {
@@ -36239,6 +36318,8 @@ function executeNoFromSelect(stmt) {
36239
36318
  }
36240
36319
  async function executeSimpleSelect(stmt, client, options, cacheContext) {
36241
36320
  const params = selectToKintoneParams(stmt);
36321
+ const typedInFieldTypes = await loadTypedInFieldTypes(stmt, client, cacheContext);
36322
+ const fieldTypeResolvers = buildSelectFieldTypeResolvers(stmt, typedInFieldTypes);
36242
36323
  const maxRecords2 = options.maxRecords ?? 1e4;
36243
36324
  const warnings = /* @__PURE__ */ new Set();
36244
36325
  const onLimit2 = options.onLimitReached ?? "error";
@@ -36275,7 +36356,12 @@ async function executeSimpleSelect(stmt, client, options, cacheContext) {
36275
36356
  rows = applyOrderBy(rows, stmt.orderBy, optionOrders, sortKinds);
36276
36357
  rows = applyLimit(rows, stmt.limit, stmt.offset);
36277
36358
  }
36278
- const { rows: projected, columns } = project(rows, stmt.columns);
36359
+ const { rows: projected, columns } = project(
36360
+ rows,
36361
+ stmt.columns,
36362
+ void 0,
36363
+ fieldTypeResolvers.row
36364
+ );
36279
36365
  return { type: "SELECT", rows: projected, columns, rowCount: projected.length, warnings: [...warnings] };
36280
36366
  }
36281
36367
  async function validateSelectFieldCodes(stmt, mode, client, cacheContext) {
@@ -36310,44 +36396,160 @@ async function validateSelectFieldCodes(stmt, mode, client, cacheContext) {
36310
36396
  }
36311
36397
  }
36312
36398
  }
36313
- function extractMainSafePushdown(stmt, fieldTypes) {
36399
+ function extractMainSafePushdown(stmt, fieldTypes, fieldOptions) {
36314
36400
  if (stmt.where === null || stmt.from.subtableCode || stmt.from.cteName !== null) return null;
36315
36401
  if (stmt.joins.length === 0) {
36316
36402
  return extractSafePushdownLeaves(stmt.where, {
36317
36403
  tableAlias: stmt.from.alias ?? void 0,
36318
36404
  allowUnqualifiedFields: true,
36319
- fieldTypes
36405
+ fieldTypes,
36406
+ fieldOptions
36320
36407
  });
36321
36408
  }
36322
36409
  if (!stmt.from.alias) return null;
36323
- return extractSafePushdownLeaves(stmt.where, { tableAlias: stmt.from.alias, fieldTypes });
36410
+ return extractSafePushdownLeaves(stmt.where, {
36411
+ tableAlias: stmt.from.alias,
36412
+ fieldTypes,
36413
+ fieldOptions
36414
+ });
36324
36415
  }
36325
- function extractMainNumericPushdownCandidate(stmt) {
36416
+ function extractMainTypedPushdownCandidate(stmt) {
36326
36417
  if (stmt.where === null || stmt.from.subtableCode || stmt.from.cteName !== null) return null;
36327
36418
  if (stmt.joins.length === 0) {
36328
- return extractNumericPushdownCandidates(stmt.where, {
36419
+ return extractTypedPushdownCandidates(stmt.where, {
36329
36420
  tableAlias: stmt.from.alias ?? void 0,
36330
36421
  allowUnqualifiedFields: true
36331
36422
  });
36332
36423
  }
36333
36424
  if (!stmt.from.alias) return null;
36334
- return extractNumericPushdownCandidates(stmt.where, { tableAlias: stmt.from.alias });
36425
+ return extractTypedPushdownCandidates(stmt.where, { tableAlias: stmt.from.alias });
36335
36426
  }
36336
- async function loadNumericPushdownFieldTypes(stmt, client, cacheContext) {
36427
+ async function loadTypedPushdownMeta(stmt, client, cacheContext) {
36337
36428
  const appIds = /* @__PURE__ */ new Set();
36338
- if (extractMainNumericPushdownCandidate(stmt) !== null) appIds.add(stmt.from.appId);
36429
+ if (extractMainTypedPushdownCandidate(stmt) !== null) appIds.add(stmt.from.appId);
36339
36430
  if (stmt.where !== null) {
36340
36431
  for (const join of stmt.joins) {
36341
36432
  if (!join.table.alias || join.table.subtableCode || join.table.cteName !== null) continue;
36342
- const candidate = extractNumericPushdownCandidates(stmt.where, {
36433
+ const candidate = extractTypedPushdownCandidates(stmt.where, {
36343
36434
  tableAlias: join.table.alias
36344
36435
  });
36345
36436
  if (candidate !== null) appIds.add(join.table.appId);
36346
36437
  }
36347
36438
  }
36439
+ const entries = await Promise.all([...appIds].map(async (appId) => {
36440
+ const [fieldTypes, fieldOptions] = await Promise.all([
36441
+ getFieldTypeMap(appId, client, cacheContext),
36442
+ getFieldOptionSetMapByApp(appId, client, cacheContext)
36443
+ ]);
36444
+ return [appId, fieldTypes, fieldOptions];
36445
+ }));
36446
+ return {
36447
+ fieldTypesByApp: new Map(entries.map(([appId, fieldTypes]) => [appId, fieldTypes])),
36448
+ fieldOptionsByApp: new Map(entries.map(([appId, , fieldOptions]) => [appId, fieldOptions]))
36449
+ };
36450
+ }
36451
+ function collectTypedInFieldRefs(expr, out) {
36452
+ if (expr === null) return;
36453
+ switch (expr.type) {
36454
+ case "BINARY":
36455
+ if ((expr.op === "IN" || expr.op === "NOT_IN") && expr.left.type === "FIELD") {
36456
+ out.push(expr.left);
36457
+ }
36458
+ if (expr.left.type === "CASE_FIELD") collectCaseTypedInFieldRefs(expr.left.expr, out);
36459
+ if (expr.right.type === "CASE_VALUE") collectCaseTypedInFieldRefs(expr.right.expr, out);
36460
+ return;
36461
+ case "LOGICAL":
36462
+ collectTypedInFieldRefs(expr.left, out);
36463
+ collectTypedInFieldRefs(expr.right, out);
36464
+ return;
36465
+ case "NOT":
36466
+ case "GROUP":
36467
+ collectTypedInFieldRefs(expr.expr, out);
36468
+ return;
36469
+ case "NULL_CHECK":
36470
+ case "EXISTS":
36471
+ return;
36472
+ }
36473
+ }
36474
+ function collectCaseTypedInFieldRefs(expr, out) {
36475
+ for (const branch of expr.branches) collectTypedInFieldRefs(branch.condition, out);
36476
+ }
36477
+ function collectSelectTypedInFieldRefs(stmt) {
36478
+ const refs = [];
36479
+ collectTypedInFieldRefs(stmt.where, refs);
36480
+ collectTypedInFieldRefs(stmt.having, refs);
36481
+ for (const column of stmt.columns) {
36482
+ if (column.type === "CASE_COL") collectCaseTypedInFieldRefs(column.expr, refs);
36483
+ }
36484
+ return refs;
36485
+ }
36486
+ function findTableForAlias(stmt, alias) {
36487
+ return [stmt.from, ...stmt.joins.map((join) => join.table)].find((table) => table.alias === alias);
36488
+ }
36489
+ function physicalSelectTables(stmt) {
36490
+ return [stmt.from, ...stmt.joins.map((join) => join.table)].filter((table) => table.cteName === null);
36491
+ }
36492
+ async function loadTypedInFieldTypes(stmt, client, cacheContext) {
36493
+ const refs = collectSelectTypedInFieldRefs(stmt);
36494
+ if (refs.length === 0) return /* @__PURE__ */ new Map();
36495
+ const appIds = /* @__PURE__ */ new Set();
36496
+ const physicalTables = physicalSelectTables(stmt);
36497
+ for (const ref of refs) {
36498
+ if (ref.tableAlias !== null) {
36499
+ if (ref.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
36500
+ appIds.add(stmt.from.appId);
36501
+ continue;
36502
+ }
36503
+ const table = findTableForAlias(stmt, ref.tableAlias);
36504
+ if (table && table.cteName === null) appIds.add(table.appId);
36505
+ continue;
36506
+ }
36507
+ if (stmt.joins.length === 0) {
36508
+ if (stmt.from.cteName === null) appIds.add(stmt.from.appId);
36509
+ continue;
36510
+ }
36511
+ for (const table of physicalTables) appIds.add(table.appId);
36512
+ }
36348
36513
  const entries = await Promise.all([...appIds].map(async (appId) => [appId, await getFieldTypeMap(appId, client, cacheContext)]));
36349
36514
  return new Map(entries);
36350
36515
  }
36516
+ function fieldCodeForTypeLookup(table, field) {
36517
+ if (table.subtableCode && field.startsWith("_p.")) return field.slice(3);
36518
+ return field;
36519
+ }
36520
+ function buildSelectFieldTypeResolvers(stmt, fieldTypesByApp) {
36521
+ const tables = [stmt.from, ...stmt.joins.map((join) => join.table)];
36522
+ const physicalTables = tables.filter((table) => table.cteName === null);
36523
+ const outputAliases = new Set(
36524
+ stmt.columns.map((column) => "alias" in column ? column.alias : null).filter((alias) => alias !== null)
36525
+ );
36526
+ const row = (field) => {
36527
+ if (field.tableAlias !== null) {
36528
+ if (field.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
36529
+ return fieldTypesByApp.get(stmt.from.appId)?.get(field.field);
36530
+ }
36531
+ const table2 = tables.find((candidate) => candidate.alias === field.tableAlias);
36532
+ if (!table2 || table2.cteName !== null) return void 0;
36533
+ return fieldTypesByApp.get(table2.appId)?.get(fieldCodeForTypeLookup(table2, field.field));
36534
+ }
36535
+ if (stmt.joins.length === 0) {
36536
+ if (stmt.from.cteName !== null) return void 0;
36537
+ return fieldTypesByApp.get(stmt.from.appId)?.get(fieldCodeForTypeLookup(stmt.from, field.field));
36538
+ }
36539
+ if (tables.some((table2) => table2.cteName !== null)) return void 0;
36540
+ const matches = physicalTables.filter(
36541
+ (table2) => fieldTypesByApp.get(table2.appId)?.has(fieldCodeForTypeLookup(table2, field.field))
36542
+ );
36543
+ if (matches.length !== 1) return void 0;
36544
+ const table = matches[0];
36545
+ return fieldTypesByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, field.field));
36546
+ };
36547
+ const having = (field) => {
36548
+ if (field.tableAlias === null && outputAliases.has(field.field)) return void 0;
36549
+ return row(field);
36550
+ };
36551
+ return { row, having };
36552
+ }
36351
36553
  async function executeFullScanSelect(stmt, client, options, cacheContext, cteCache) {
36352
36554
  const maxRecords2 = options.maxRecords ?? 1e4;
36353
36555
  const warnings = /* @__PURE__ */ new Set();
@@ -36356,10 +36558,15 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
36356
36558
  resolveSubqueries(stmt.where, client, options, cacheContext, cteCache),
36357
36559
  resolveSubqueries(stmt.having, client, options, cacheContext, cteCache)
36358
36560
  ]);
36359
- const pushdownFieldTypes = await loadNumericPushdownFieldTypes(stmt, client, cacheContext);
36561
+ const [pushdownMeta, typedInFieldTypes] = await Promise.all([
36562
+ loadTypedPushdownMeta(stmt, client, cacheContext),
36563
+ loadTypedInFieldTypes(stmt, client, cacheContext)
36564
+ ]);
36565
+ const fieldTypeResolvers = buildSelectFieldTypeResolvers(stmt, typedInFieldTypes);
36360
36566
  const mainPushDown = extractMainSafePushdown(
36361
36567
  stmt,
36362
- pushdownFieldTypes.get(stmt.from.appId)
36568
+ pushdownMeta.fieldTypesByApp.get(stmt.from.appId),
36569
+ pushdownMeta.fieldOptionsByApp.get(stmt.from.appId)
36363
36570
  );
36364
36571
  const tableConditions = /* @__PURE__ */ new Map();
36365
36572
  if (stmt.where !== null) {
@@ -36367,7 +36574,8 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
36367
36574
  if (!join.table.alias || join.table.subtableCode || join.table.cteName !== null) continue;
36368
36575
  const cond = extractSafePushdownLeaves(stmt.where, {
36369
36576
  tableAlias: join.table.alias,
36370
- fieldTypes: pushdownFieldTypes.get(join.table.appId)
36577
+ fieldTypes: pushdownMeta.fieldTypesByApp.get(join.table.appId),
36578
+ fieldOptions: pushdownMeta.fieldOptionsByApp.get(join.table.appId)
36371
36579
  });
36372
36580
  if (cond) tableConditions.set(join.table.alias, cond);
36373
36581
  }
@@ -36445,7 +36653,15 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
36445
36653
  }));
36446
36654
  const scalarCache = await scalarCachePromise;
36447
36655
  const { optionOrders, sortKinds } = await orderByMetaPromise;
36448
- const { rows, columns } = runFullScan({ tables, stmt, scalarCache, optionOrders, sortKinds });
36656
+ const { rows, columns } = runFullScan({
36657
+ tables,
36658
+ stmt,
36659
+ scalarCache,
36660
+ optionOrders,
36661
+ sortKinds,
36662
+ fieldTypeResolver: fieldTypeResolvers.row,
36663
+ havingFieldTypeResolver: fieldTypeResolvers.having
36664
+ });
36449
36665
  return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [...warnings] };
36450
36666
  }
36451
36667
  async function executeUnion(stmt, client, options, cacheContext) {
@@ -36601,8 +36817,11 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
36601
36817
  const parallel = options.fetchParallel ?? 1;
36602
36818
  await Promise.all([
36603
36819
  resolveSubqueries(stmt.where, client, options, cacheContext, cteCache),
36604
- resolveSubqueries(stmt.having, client, options, cacheContext, cteCache)
36820
+ resolveSubqueries(stmt.having, client, options, cacheContext, cteCache),
36821
+ resolveSelectCaseSubqueries(stmt, client, options, cacheContext, cteCache)
36605
36822
  ]);
36823
+ const typedInFieldTypes = await loadTypedInFieldTypes(stmt, client, cacheContext);
36824
+ const fieldTypeResolvers = buildSelectFieldTypeResolvers(stmt, typedInFieldTypes);
36606
36825
  const scalarCachePromise = resolveScalarColumns(stmt.columns, client, options, cacheContext, cteCache);
36607
36826
  const orderByMetaPromise = buildOrderByMetaForSelect(stmt, client, cacheContext);
36608
36827
  scalarCachePromise.catch(() => {
@@ -36657,7 +36876,15 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
36657
36876
  await Promise.all(joinFetches);
36658
36877
  const scalarCache = await scalarCachePromise;
36659
36878
  const { optionOrders, sortKinds } = await orderByMetaPromise;
36660
- const { rows, columns } = runFullScan({ tables, stmt, scalarCache, optionOrders, sortKinds });
36879
+ const { rows, columns } = runFullScan({
36880
+ tables,
36881
+ stmt,
36882
+ scalarCache,
36883
+ optionOrders,
36884
+ sortKinds,
36885
+ fieldTypeResolver: fieldTypeResolvers.row,
36886
+ havingFieldTypeResolver: fieldTypeResolvers.having
36887
+ });
36661
36888
  return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [...warnings] };
36662
36889
  }
36663
36890
  function processRowToKintoneRecord(row) {
@@ -36889,6 +37116,15 @@ async function getOptionOrderMapByApp(appId, client, cacheContext) {
36889
37116
  setScopedCacheValue(optionOrderCache, cacheContext, appId, map2);
36890
37117
  return map2;
36891
37118
  }
37119
+ async function getFieldOptionSetMapByApp(appId, client, cacheContext) {
37120
+ const optionOrders = await getOptionOrderMapByApp(appId, client, cacheContext);
37121
+ return new Map(
37122
+ [...optionOrders.entries()].map(([fieldCode, order]) => [
37123
+ fieldCode,
37124
+ new Set(order.keys())
37125
+ ])
37126
+ );
37127
+ }
36892
37128
  async function getSortKindMapByApp(appId, client, cacheContext) {
36893
37129
  const cached2 = getScopedCacheValue(sortKindCache, cacheContext, appId);
36894
37130
  if (cached2) return cached2;
@@ -37154,6 +37390,16 @@ async function executeUpsert(stmt, client, options, cacheContext) {
37154
37390
  updatedCount: toUpdate.length
37155
37391
  };
37156
37392
  }
37393
+ async function buildSubtableFieldTypeResolver(appId, typedInRefs, client, cacheContext) {
37394
+ if (typedInRefs.length === 0) return void 0;
37395
+ const fieldTypes = await getFieldTypeMap(appId, client, cacheContext);
37396
+ return (field) => {
37397
+ if (field.tableAlias !== null && field.tableAlias !== "_p") return void 0;
37398
+ if (field.tableAlias === "_p") return fieldTypes.get(field.field);
37399
+ const code = field.field.startsWith("_p.") ? field.field.slice(3) : field.field;
37400
+ return fieldTypes.get(code);
37401
+ };
37402
+ }
37157
37403
  async function executeInsertSubtable(stmt, client, options, _cacheContext) {
37158
37404
  const subtableCode = stmt.subtableCode;
37159
37405
  const pidIndex = stmt.fields.indexOf("_pid");
@@ -37194,11 +37440,24 @@ async function executeInsertSubtable(stmt, client, options, _cacheContext) {
37194
37440
  }
37195
37441
  return { type: "INSERT", createdIds: [], insertedCount: stmt.values.length };
37196
37442
  }
37197
- async function executeUpdateSubtable(stmt, client, options, _cacheContext) {
37443
+ async function executeUpdateSubtable(stmt, client, options, cacheContext) {
37198
37444
  const subtableCode = stmt.subtableCode;
37199
37445
  if (!hasRidCondition(stmt.where)) {
37200
37446
  throw new Error("\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB UPDATE \u306B\u306F _rid \u6761\u4EF6\u304C\u5FC5\u9808\u3067\u3059");
37201
37447
  }
37448
+ const typedInRefs = [];
37449
+ collectTypedInFieldRefs(stmt.where, typedInRefs);
37450
+ for (const assignment of stmt.assignments) {
37451
+ if (assignment.value.type === "CASE_VALUE") {
37452
+ collectCaseTypedInFieldRefs(assignment.value.expr, typedInRefs);
37453
+ }
37454
+ }
37455
+ const resolveFieldType = await buildSubtableFieldTypeResolver(
37456
+ stmt.appId,
37457
+ typedInRefs,
37458
+ client,
37459
+ cacheContext
37460
+ );
37202
37461
  const parents = await fetchAll(
37203
37462
  client.getRecords,
37204
37463
  stmt.appId,
@@ -37207,7 +37466,7 @@ async function executeUpdateSubtable(stmt, client, options, _cacheContext) {
37207
37466
  { maxRecords: options.maxRecords ?? 1e4, parallel: options.fetchParallel ?? 1 }
37208
37467
  );
37209
37468
  const expanded = expandRowsForSubtableDml(parents, subtableCode);
37210
- const targets = expanded.filter((r) => evalWhere(stmt.where, r.flat));
37469
+ const targets = expanded.filter((r) => evalWhere(stmt.where, r.flat, resolveFieldType));
37211
37470
  if (options.confirm) {
37212
37471
  const ok = await options.confirm(targets.length, "UPDATE");
37213
37472
  if (!ok) throw new OperationCancelledError("UPDATE", targets.length);
@@ -37227,7 +37486,7 @@ async function executeUpdateSubtable(stmt, client, options, _cacheContext) {
37227
37486
  if (a.field.startsWith("_")) {
37228
37487
  throw new Error(`\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB UPDATE \u3067\u30B7\u30B9\u30C6\u30E0\u5217\u300C${a.field}\u300D\u306F\u66F4\u65B0\u3067\u304D\u307E\u305B\u3093`);
37229
37488
  }
37230
- updates[a.field] = { value: evalAssignmentValueForSubtable(a.value, t.flat) };
37489
+ updates[a.field] = { value: evalAssignmentValueForSubtable(a.value, t.flat, resolveFieldType) };
37231
37490
  }
37232
37491
  byRid.set(t.rowId, updates);
37233
37492
  }
@@ -37249,11 +37508,19 @@ async function executeUpdateSubtable(stmt, client, options, _cacheContext) {
37249
37508
  }
37250
37509
  return { type: "UPDATE", updatedCount: targets.length };
37251
37510
  }
37252
- async function executeDeleteSubtable(stmt, client, options, _cacheContext) {
37511
+ async function executeDeleteSubtable(stmt, client, options, cacheContext) {
37253
37512
  const subtableCode = stmt.subtableCode;
37254
37513
  if (!hasRidCondition(stmt.where)) {
37255
37514
  throw new Error("\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB DELETE \u306B\u306F _rid \u6761\u4EF6\u304C\u5FC5\u9808\u3067\u3059");
37256
37515
  }
37516
+ const typedInRefs = [];
37517
+ collectTypedInFieldRefs(stmt.where, typedInRefs);
37518
+ const resolveFieldType = await buildSubtableFieldTypeResolver(
37519
+ stmt.appId,
37520
+ typedInRefs,
37521
+ client,
37522
+ cacheContext
37523
+ );
37257
37524
  const parents = await fetchAll(
37258
37525
  client.getRecords,
37259
37526
  stmt.appId,
@@ -37262,7 +37529,7 @@ async function executeDeleteSubtable(stmt, client, options, _cacheContext) {
37262
37529
  { maxRecords: options.maxRecords ?? 1e4, parallel: options.fetchParallel ?? 1 }
37263
37530
  );
37264
37531
  const expanded = expandRowsForSubtableDml(parents, subtableCode);
37265
- const targets = expanded.filter((r) => evalWhere(stmt.where, r.flat));
37532
+ const targets = expanded.filter((r) => evalWhere(stmt.where, r.flat, resolveFieldType));
37266
37533
  if (options.confirm) {
37267
37534
  const ok = await options.confirm(targets.length, "DELETE");
37268
37535
  if (!ok) throw new OperationCancelledError("DELETE", targets.length);
@@ -37377,11 +37644,11 @@ function buildSubtableReorderPutParams(appId, parentId, revision, subtableCode,
37377
37644
  ]
37378
37645
  };
37379
37646
  }
37380
- function evalAssignmentValueForSubtable(value, row) {
37647
+ function evalAssignmentValueForSubtable(value, row, resolveFieldType) {
37381
37648
  if (value.type === "STRING") return value.value;
37382
37649
  if (value.type === "NUMBER") return String(value.value);
37383
37650
  if (value.type === "ARITH") return String(evalArithExpr(value, row));
37384
- if (value.type === "CASE_VALUE") return evalCaseWhen(value.expr, row);
37651
+ if (value.type === "CASE_VALUE") return evalCaseWhen(value.expr, row, resolveFieldType);
37385
37652
  throw new Error(`${value.type} \u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB UPDATE \u306E\u5024\u3068\u3057\u3066\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`);
37386
37653
  }
37387
37654
  function valueToString(value) {
@@ -37413,7 +37680,15 @@ function hasRidCondition(where) {
37413
37680
  return false;
37414
37681
  }
37415
37682
  }
37416
- async function executeReorder(stmt, client, options, _cacheContext) {
37683
+ async function executeReorder(stmt, client, options, cacheContext) {
37684
+ const typedInRefs = [];
37685
+ collectTypedInFieldRefs(stmt.where, typedInRefs);
37686
+ const resolveFieldType = await buildSubtableFieldTypeResolver(
37687
+ stmt.appId,
37688
+ typedInRefs,
37689
+ client,
37690
+ cacheContext
37691
+ );
37417
37692
  const parents = await fetchAll(
37418
37693
  client.getRecords,
37419
37694
  stmt.appId,
@@ -37422,7 +37697,7 @@ async function executeReorder(stmt, client, options, _cacheContext) {
37422
37697
  { maxRecords: options.maxRecords ?? 1e4, parallel: options.fetchParallel ?? 1 }
37423
37698
  );
37424
37699
  const expanded = expandRowsForSubtableDml(parents, stmt.subtableCode);
37425
- const targetParentIds = stmt.all ? new Set(parents.map((p) => String(p["$id"]?.value ?? "")).filter((id) => id !== "")) : new Set(expanded.filter((r) => stmt.where && evalWhere(stmt.where, r.flat)).map((r) => r.parentId));
37700
+ const targetParentIds = stmt.all ? new Set(parents.map((p) => String(p["$id"]?.value ?? "")).filter((id) => id !== "")) : new Set(expanded.filter((r) => stmt.where && evalWhere(stmt.where, r.flat, resolveFieldType)).map((r) => r.parentId));
37426
37701
  if (options.confirm) {
37427
37702
  const ok = await options.confirm(targetParentIds.size, "UPDATE");
37428
37703
  if (!ok) throw new OperationCancelledError("UPDATE", targetParentIds.size);
@@ -37567,6 +37842,16 @@ async function resolveSubqueries(where, client, options, cacheContext, cteCache)
37567
37842
  collectSubqueryTasks(where, client, options, cacheContext, tasks, cteCache);
37568
37843
  await Promise.all(tasks);
37569
37844
  }
37845
+ async function resolveSelectCaseSubqueries(stmt, client, options, cacheContext, cteCache) {
37846
+ const tasks = [];
37847
+ for (const column of stmt.columns) {
37848
+ if (column.type !== "CASE_COL") continue;
37849
+ for (const branch of column.expr.branches) {
37850
+ tasks.push(resolveSubqueries(branch.condition, client, options, cacheContext, cteCache));
37851
+ }
37852
+ }
37853
+ await Promise.all(tasks);
37854
+ }
37570
37855
  function runSubquery(query, client, options, cacheContext, cteCache) {
37571
37856
  if (cteCache !== void 0 && cteCache.size > 0) {
37572
37857
  return executeQueryWithCte(query, client, options, cteCache, cacheContext);
@@ -37799,12 +38084,12 @@ function buildSelectPlan(stmt, label) {
37799
38084
  const mainFields = selectToFetchAllFields(stmt, stmt.from);
37800
38085
  const mainAliasStr = stmt.from.alias ? ` AS ${stmt.from.alias}` : "";
37801
38086
  const mainPushDown = extractMainSafePushdown(stmt);
37802
- const mainCandidate = extractMainNumericPushdownCandidate(stmt);
38087
+ const mainCandidate = extractMainTypedPushdownCandidate(stmt);
37803
38088
  const mainQ = mainPushDown !== null ? whereToKintone(mainPushDown) : "(\u5168\u4EF6\u53D6\u5F97)";
37804
38089
  lines.push(` app: APP${stmt.from.appId}${mainAliasStr} (${stmt.from.appId})`);
37805
38090
  lines.push(` kintone query: ${mainQ}`);
37806
38091
  if (mainCandidate !== null) {
37807
- lines.push(` pushdown candidate: ${whereToKintone(mainCandidate)}\uFF08\u5B9F\u884C\u6642\u306E\u578B\u78BA\u8A8D\u5F85\u3061\uFF09`);
38092
+ lines.push(` pushdown candidate: ${whereToKintone(mainCandidate)}\uFF08\u5B9F\u884C\u6642\u306E\u578B\u30FB\u5B9F\u5728\u78BA\u8A8D\u5F85\u3061\uFF09`);
37808
38093
  }
37809
38094
  lines.push(` fields: ${mainFields.length === 0 ? "(\u5168\u30D5\u30A3\u30FC\u30EB\u30C9)" : mainFields.join(", ")}`);
37810
38095
  for (const join of stmt.joins) {
@@ -37812,12 +38097,12 @@ function buildSelectPlan(stmt, label) {
37812
38097
  const joinAliasStr = join.table.alias ? ` AS ${join.table.alias}` : "";
37813
38098
  const joinType = join.type === "INNER" ? "JOIN" : `${join.type} JOIN`;
37814
38099
  const joinPushDown = join.table.alias && !join.table.subtableCode && join.table.cteName === null && stmt.where ? extractSafePushdownLeaves(stmt.where, { tableAlias: join.table.alias }) : null;
37815
- const joinCandidate = join.table.alias && !join.table.subtableCode && join.table.cteName === null && stmt.where ? extractNumericPushdownCandidates(stmt.where, { tableAlias: join.table.alias }) : null;
38100
+ const joinCandidate = join.table.alias && !join.table.subtableCode && join.table.cteName === null && stmt.where ? extractTypedPushdownCandidates(stmt.where, { tableAlias: join.table.alias }) : null;
37816
38101
  const joinQ = joinPushDown !== null ? whereToKintone(joinPushDown) : "(\u5168\u4EF6\u53D6\u5F97)";
37817
38102
  lines.push(` ${joinType}: APP${join.table.appId}${joinAliasStr} (${join.table.appId})`);
37818
38103
  lines.push(` kintone query: ${joinQ}`);
37819
38104
  if (joinCandidate !== null) {
37820
- lines.push(` pushdown candidate: ${whereToKintone(joinCandidate)}\uFF08\u5B9F\u884C\u6642\u306E\u578B\u78BA\u8A8D\u5F85\u3061\uFF09`);
38105
+ lines.push(` pushdown candidate: ${whereToKintone(joinCandidate)}\uFF08\u5B9F\u884C\u6642\u306E\u578B\u30FB\u5B9F\u5728\u78BA\u8A8D\u5F85\u3061\uFF09`);
37821
38106
  }
37822
38107
  lines.push(` fields: ${joinFields.length === 0 ? "(\u5168\u30D5\u30A3\u30FC\u30EB\u30C9)" : joinFields.join(", ")}`);
37823
38108
  }
@@ -38489,6 +38774,42 @@ function clampInt(v, min, max) {
38489
38774
  return Math.max(min, Math.min(max, Math.trunc(v)));
38490
38775
  }
38491
38776
 
38777
+ // src/core/formFieldInfo.ts
38778
+ function flattenFormFieldProperties(properties) {
38779
+ const out = [];
38780
+ for (const field of Object.values(properties)) {
38781
+ out.push({
38782
+ code: field.code,
38783
+ label: field.label,
38784
+ fieldType: field.type,
38785
+ optionOrder: toOptionOrderMap(field.options),
38786
+ sortKind: detectSortKind(field.type, field.format)
38787
+ });
38788
+ if (field.fields) out.push(...flattenFormFieldProperties(field.fields));
38789
+ }
38790
+ return out;
38791
+ }
38792
+ function toOptionOrderMap(options) {
38793
+ if (!options || typeof options !== "object") return void 0;
38794
+ const order = {};
38795
+ let hasAny = false;
38796
+ for (const [label, meta3] of Object.entries(options)) {
38797
+ const n = Number(meta3?.index);
38798
+ if (!Number.isFinite(n)) continue;
38799
+ order[label] = n;
38800
+ hasAny = true;
38801
+ }
38802
+ return hasAny ? order : void 0;
38803
+ }
38804
+ function detectSortKind(fieldType, calcFormat) {
38805
+ if (fieldType === "NUMBER" || fieldType === "RECORD_NUMBER") return "number";
38806
+ if (fieldType === "CALC") {
38807
+ if (calcFormat === "NUMBER" || calcFormat === "NUMBER_DIGIT") return "number";
38808
+ return "string";
38809
+ }
38810
+ return void 0;
38811
+ }
38812
+
38492
38813
  // src/cli/nodeKintoneClient.ts
38493
38814
  function createNodeKintoneClient(baseUrl, tokenResolver) {
38494
38815
  const normalizedBaseUrl = baseUrl.replace(/\/+$/, "");
@@ -38667,36 +38988,10 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
38667
38988
  { method: "GET" },
38668
38989
  appId
38669
38990
  );
38670
- return Object.values(res.properties).map((f) => ({
38671
- code: f.code,
38672
- label: f.label,
38673
- fieldType: f.type,
38674
- optionOrder: toOptionOrderMap(f.options),
38675
- sortKind: detectSortKind(f.type, f.format)
38676
- }));
38991
+ return flattenFormFieldProperties(res.properties);
38677
38992
  }
38678
38993
  };
38679
38994
  }
38680
- function toOptionOrderMap(options) {
38681
- if (!options || typeof options !== "object") return void 0;
38682
- const order = {};
38683
- let hasAny = false;
38684
- for (const [label, meta3] of Object.entries(options)) {
38685
- const n = Number(meta3?.index);
38686
- if (!Number.isFinite(n)) continue;
38687
- order[label] = n;
38688
- hasAny = true;
38689
- }
38690
- return hasAny ? order : void 0;
38691
- }
38692
- function detectSortKind(fieldType, calcFormat) {
38693
- if (fieldType === "NUMBER" || fieldType === "RECORD_NUMBER") return "number";
38694
- if (fieldType === "CALC") {
38695
- if (calcFormat === "NUMBER" || calcFormat === "NUMBER_DIGIT") return "number";
38696
- return "string";
38697
- }
38698
- return void 0;
38699
- }
38700
38995
 
38701
38996
  // src/node/appProfiles.ts
38702
38997
  function parseTokenMap(raw) {
@@ -40156,7 +40451,7 @@ Options:
40156
40451
  -h, --help Show help
40157
40452
  `);
40158
40453
  }
40159
- var SERVER_VERSION = true ? "2.4.0" : "0.0.0-dev";
40454
+ var SERVER_VERSION = true ? "2.6.0" : "0.0.0-dev";
40160
40455
  function createServer(args) {
40161
40456
  const server = new McpServer({
40162
40457
  name: "ksql-mcp",