@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.
package/dist-cli/ksql.js CHANGED
@@ -3508,52 +3508,93 @@ function resolveFieldRef(row, field) {
3508
3508
  }
3509
3509
 
3510
3510
  // src/engine/evalWhere.ts
3511
- function evalWhere(expr, row) {
3511
+ function evalWhere(expr, row, resolveFieldType) {
3512
3512
  switch (expr.type) {
3513
3513
  case "BINARY":
3514
- return evalBinary(expr, row);
3514
+ return evalBinary(expr, row, resolveFieldType);
3515
3515
  case "NULL_CHECK":
3516
3516
  return evalNullCheck(expr, row);
3517
3517
  case "LOGICAL":
3518
- return evalLogical(expr, row);
3518
+ return evalLogical(expr, row, resolveFieldType);
3519
3519
  case "NOT":
3520
- return !evalWhere(expr.expr, row);
3520
+ return !evalWhere(expr.expr, row, resolveFieldType);
3521
3521
  case "GROUP":
3522
- return evalWhere(expr.expr, row);
3522
+ return evalWhere(expr.expr, row, resolveFieldType);
3523
3523
  case "EXISTS": {
3524
3524
  const exists = expr.resolved;
3525
3525
  return expr.not ? !exists : exists;
3526
3526
  }
3527
3527
  }
3528
3528
  }
3529
- function evalBinary(expr, row) {
3530
- const left = resolveField(expr.left, row);
3531
- return evalOp(expr.op, left, expr.right, row);
3529
+ function evalBinary(expr, row, resolveFieldType) {
3530
+ const left = resolveField(expr.left, row, resolveFieldType);
3531
+ const fieldType = expr.left.type === "FIELD" ? resolveFieldType?.(expr.left) : void 0;
3532
+ return evalOp(expr.op, left, expr.right, row, fieldType, resolveFieldType);
3532
3533
  }
3533
- function evalOp(op, leftStr, right, row) {
3534
+ function evalOp(op, leftStr, right, row, fieldType, resolveFieldType) {
3534
3535
  if (op === "IN" || op === "NOT_IN") {
3536
+ let values = null;
3535
3537
  if (right.type === "IN_LIST") {
3536
3538
  assertResolvedInListValues2(right.values);
3537
- const contains = right.values.some((v) => leftStr === String(v.value));
3538
- return op === "IN" ? contains : !contains;
3539
+ values = new Set(right.values.map((v) => String(v.value)));
3539
3540
  }
3540
3541
  if (right.type === "SUBQUERY_IN_LIST") {
3541
- const contains = right.resolved.has(leftStr);
3542
- return op === "IN" ? contains : !contains;
3542
+ values = right.resolved;
3543
3543
  }
3544
- return op === "NOT_IN";
3544
+ if (values === null) return op === "NOT_IN";
3545
+ const contains = typedInContains(leftStr, values, fieldType);
3546
+ return op === "IN" ? contains : !contains;
3545
3547
  }
3546
3548
  if (op === "LIKE") {
3547
- const pattern = resolveValue(right, row);
3549
+ const pattern = resolveValue(right, row, resolveFieldType);
3548
3550
  return matchLike(leftStr, pattern);
3549
3551
  }
3550
3552
  if (op === "NOT_LIKE") {
3551
- const pattern = resolveValue(right, row);
3553
+ const pattern = resolveValue(right, row, resolveFieldType);
3552
3554
  return !matchLike(leftStr, pattern);
3553
3555
  }
3554
- const rightStr = resolveValue(right, row);
3556
+ const rightStr = resolveValue(right, row, resolveFieldType);
3555
3557
  return compareScalarValues(op, leftStr, rightStr);
3556
3558
  }
3559
+ var STRING_ARRAY_FIELD_TYPES = /* @__PURE__ */ new Set(["CHECK_BOX", "MULTI_SELECT"]);
3560
+ var OBJECT_ARRAY_FIELD_TYPES = /* @__PURE__ */ new Set([
3561
+ "USER_SELECT",
3562
+ "ORGANIZATION_SELECT",
3563
+ "GROUP_SELECT",
3564
+ "STATUS_ASSIGNEE"
3565
+ ]);
3566
+ var SINGLE_OBJECT_FIELD_TYPES = /* @__PURE__ */ new Set(["CREATOR", "MODIFIER"]);
3567
+ function typedInContains(leftStr, values, fieldType) {
3568
+ const fallback = () => values.has(leftStr);
3569
+ if (fieldType === void 0) return fallback();
3570
+ let parsed;
3571
+ if (STRING_ARRAY_FIELD_TYPES.has(fieldType) || OBJECT_ARRAY_FIELD_TYPES.has(fieldType) || SINGLE_OBJECT_FIELD_TYPES.has(fieldType)) {
3572
+ try {
3573
+ parsed = JSON.parse(leftStr);
3574
+ } catch {
3575
+ return fallback();
3576
+ }
3577
+ } else {
3578
+ return fallback();
3579
+ }
3580
+ if (STRING_ARRAY_FIELD_TYPES.has(fieldType)) {
3581
+ if (!Array.isArray(parsed) || !parsed.every((item) => typeof item === "string")) {
3582
+ return fallback();
3583
+ }
3584
+ if (parsed.length === 0 && values.has("")) return true;
3585
+ return parsed.some((item) => values.has(item));
3586
+ }
3587
+ if (OBJECT_ARRAY_FIELD_TYPES.has(fieldType)) {
3588
+ if (!Array.isArray(parsed) || !parsed.every(hasStringCode)) return fallback();
3589
+ if (parsed.length === 0 && values.has("")) return true;
3590
+ return parsed.some((item) => values.has(item.code));
3591
+ }
3592
+ if (!hasStringCode(parsed)) return fallback();
3593
+ return values.has(parsed.code);
3594
+ }
3595
+ function hasStringCode(value) {
3596
+ return value !== null && typeof value === "object" && !Array.isArray(value) && typeof value.code === "string";
3597
+ }
3557
3598
  function assertResolvedInListValues2(values) {
3558
3599
  const unresolved = values.find((item) => item.type === "VARIABLE");
3559
3600
  if (unresolved?.type === "VARIABLE") {
@@ -3564,20 +3605,20 @@ function evalNullCheck(expr, row) {
3564
3605
  const val = resolveField(expr.field, row);
3565
3606
  return expr.not ? val !== "" : val === "";
3566
3607
  }
3567
- function evalLogical(expr, row) {
3608
+ function evalLogical(expr, row, resolveFieldType) {
3568
3609
  if (expr.op === "AND") {
3569
- return evalWhere(expr.left, row) && evalWhere(expr.right, row);
3610
+ return evalWhere(expr.left, row, resolveFieldType) && evalWhere(expr.right, row, resolveFieldType);
3570
3611
  }
3571
- return evalWhere(expr.left, row) || evalWhere(expr.right, row);
3612
+ return evalWhere(expr.left, row, resolveFieldType) || evalWhere(expr.right, row, resolveFieldType);
3572
3613
  }
3573
- function resolveField(field, row) {
3614
+ function resolveField(field, row, resolveFieldType) {
3574
3615
  if (field.type === "FUNC_FIELD") return evalStringFunc(field.expr, row);
3575
3616
  if (field.type === "ARITH_FIELD") return String(evalArithExpr(field.expr, row));
3576
- if (field.type === "CASE_FIELD") return evalCaseWhen(field.expr, row);
3617
+ if (field.type === "CASE_FIELD") return evalCaseWhen(field.expr, row, resolveFieldType);
3577
3618
  const key = field.tableAlias ? `${field.tableAlias}.${field.field}` : field.field;
3578
3619
  return resolveFieldRef(row, key);
3579
3620
  }
3580
- function resolveValue(value, row) {
3621
+ function resolveValue(value, row, resolveFieldType) {
3581
3622
  switch (value.type) {
3582
3623
  case "VARIABLE":
3583
3624
  throw new Error(`ParseError: unresolved batch variable @${value.name}.`);
@@ -3600,14 +3641,14 @@ function resolveValue(value, row) {
3600
3641
  if (value.expr.type === "STRING_FUNC") return evalStringFunc(value.expr, row);
3601
3642
  return String(evalArithExpr(value.expr, row));
3602
3643
  case "CASE_VALUE":
3603
- return evalCaseWhen(value.expr, row);
3644
+ return evalCaseWhen(value.expr, row, resolveFieldType);
3604
3645
  case "ARRAY":
3605
3646
  return value.elements.map((e) => e.value).join(",");
3606
3647
  }
3607
3648
  }
3608
- function evalCaseWhen(expr, row) {
3649
+ function evalCaseWhen(expr, row, resolveFieldType) {
3609
3650
  for (const branch of expr.branches) {
3610
- if (evalWhere(branch.condition, row)) {
3651
+ if (evalWhere(branch.condition, row, resolveFieldType)) {
3611
3652
  return evalCaseResult(branch.result, row);
3612
3653
  }
3613
3654
  }
@@ -4158,8 +4199,11 @@ async function resolveDmlTargetIds(getRecords, app, query, options) {
4158
4199
  function extractSafePushdownLeaves(where, options = {}) {
4159
4200
  return extractAndLeaves(where, (expr) => isSafeComparison(expr, options));
4160
4201
  }
4161
- function extractNumericPushdownCandidates(where, options = {}) {
4162
- return extractAndLeaves(where, (expr) => isNumericCandidate(expr, options));
4202
+ function extractTypedPushdownCandidates(where, options = {}) {
4203
+ return extractAndLeaves(
4204
+ where,
4205
+ (expr) => isNumericCandidate(expr, options) || isSelectionInCandidate(expr, options)
4206
+ );
4163
4207
  }
4164
4208
  function extractAndLeaves(where, accept) {
4165
4209
  switch (where.type) {
@@ -4183,8 +4227,27 @@ function extractAndLeaves(where, accept) {
4183
4227
  }
4184
4228
  function isSafeComparison(expr, options) {
4185
4229
  if (isSafeIdComparison(expr, options)) return true;
4186
- if (!isNumericCandidate(expr, options)) return false;
4187
- return options.fieldTypes?.get(expr.left.field) === "NUMBER";
4230
+ if (isNumericCandidate(expr, options)) {
4231
+ return options.fieldTypes?.get(expr.left.field) === "NUMBER";
4232
+ }
4233
+ return isSelectionInComparison(expr, options);
4234
+ }
4235
+ var SELECTION_IN_FIELD_TYPES = /* @__PURE__ */ new Set([
4236
+ "DROP_DOWN",
4237
+ "RADIO_BUTTON",
4238
+ "CHECK_BOX",
4239
+ "MULTI_SELECT"
4240
+ ]);
4241
+ function isSelectionInComparison(expr, options) {
4242
+ if (!isSelectionInCandidate(expr, options)) return false;
4243
+ if (expr.left.type !== "FIELD" || expr.right.type !== "IN_LIST") return false;
4244
+ const fieldType = options.fieldTypes?.get(expr.left.field);
4245
+ if (fieldType === void 0 || !SELECTION_IN_FIELD_TYPES.has(fieldType)) return false;
4246
+ const validOptions = options.fieldOptions?.get(expr.left.field);
4247
+ if (validOptions === void 0) return false;
4248
+ return expr.right.values.every(
4249
+ (value) => value.type === "STRING" && value.value !== "" && validOptions.has(value.value)
4250
+ );
4188
4251
  }
4189
4252
  function isSafeIdComparison(expr, options) {
4190
4253
  if (!isTargetIdField(expr.left, options)) return false;
@@ -4204,6 +4267,13 @@ function isNumericCandidate(expr, options) {
4204
4267
  if (expr.op === "=") return true;
4205
4268
  return (expr.op === "<" || expr.op === ">") && Number.isSafeInteger(expr.right.value);
4206
4269
  }
4270
+ function isSelectionInCandidate(expr, options) {
4271
+ if (expr.left.type !== "FIELD" || expr.left.field === "$id") return false;
4272
+ if (!isTargetField(expr.left, options)) return false;
4273
+ if (expr.op !== "IN" && expr.op !== "NOT_IN") return false;
4274
+ if (expr.right.type !== "IN_LIST" || expr.right.values.length === 0) return false;
4275
+ return expr.right.values.every((value) => value.type === "STRING" && value.value !== "");
4276
+ }
4207
4277
  function isTargetField(field, options) {
4208
4278
  const targetAlias = options.tableAlias ?? null;
4209
4279
  if (field.tableAlias === targetAlias) return true;
@@ -4215,7 +4285,7 @@ function flatten(record, alias) {
4215
4285
  const row = {};
4216
4286
  for (const [field, fv] of Object.entries(record)) {
4217
4287
  const val = fv.value;
4218
- const strVal = typeof val === "string" ? val : JSON.stringify(val ?? "");
4288
+ const strVal = val == null ? "" : typeof val === "string" ? val : JSON.stringify(val);
4219
4289
  if (alias) {
4220
4290
  row[`${alias}.${field}`] = strVal;
4221
4291
  row[field] = strVal;
@@ -4274,9 +4344,9 @@ function applyJoin(leftRows, rightRows, join2) {
4274
4344
  }
4275
4345
  return result;
4276
4346
  }
4277
- function applyFilter(rows, where) {
4347
+ function applyFilter(rows, where, resolveFieldType) {
4278
4348
  if (where === null) return rows;
4279
- return rows.filter((row) => evalWhere(where, row));
4349
+ return rows.filter((row) => evalWhere(where, row, resolveFieldType));
4280
4350
  }
4281
4351
  function hasAggregateColumns(columns) {
4282
4352
  return columns.some(
@@ -4402,9 +4472,9 @@ function aggregateSyntheticName2(func, distinct, arg) {
4402
4472
  const argStr = aggregateArgLabel(arg);
4403
4473
  return distinct ? `${func}(DISTINCT ${argStr})` : `${func}(${argStr})`;
4404
4474
  }
4405
- function applyHaving(rows, having) {
4475
+ function applyHaving(rows, having, resolveFieldType) {
4406
4476
  if (having === null) return rows;
4407
- return rows.filter((row) => evalWhere(having, row));
4477
+ return rows.filter((row) => evalWhere(having, row, resolveFieldType));
4408
4478
  }
4409
4479
  function applyDistinct(rows, columns) {
4410
4480
  if (rows.length === 0) return rows;
@@ -4529,7 +4599,7 @@ function applyLimit(rows, limit, offset) {
4529
4599
  if (limit === null) return rows.slice(start);
4530
4600
  return rows.slice(start, start + limit);
4531
4601
  }
4532
- function project(rows, columns, scalarCache) {
4602
+ function project(rows, columns, scalarCache, resolveFieldType) {
4533
4603
  if (columns.length === 1 && columns[0].type === "WILDCARD") {
4534
4604
  const projected2 = rows.map((row) => stripParentShortcutColumns(row));
4535
4605
  const cols = projected2.length > 0 ? Object.keys(projected2[0]) : [];
@@ -4590,7 +4660,7 @@ function project(rows, columns, scalarCache) {
4590
4660
  }
4591
4661
  case "CASE_COL": {
4592
4662
  const key = outputKeys?.[colIdx] ?? col.alias ?? "case";
4593
- out[key] = evalCaseWhen(col.expr, row);
4663
+ out[key] = evalCaseWhen(col.expr, row, resolveFieldType);
4594
4664
  if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
4595
4665
  break;
4596
4666
  }
@@ -4726,7 +4796,15 @@ function resolveAggInStringFuncExpr(expr, rows) {
4726
4796
  };
4727
4797
  }
4728
4798
  function runFullScan(input) {
4729
- const { stmt, tables, scalarCache, optionOrders, sortKinds } = input;
4799
+ const {
4800
+ stmt,
4801
+ tables,
4802
+ scalarCache,
4803
+ optionOrders,
4804
+ sortKinds,
4805
+ fieldTypeResolver,
4806
+ havingFieldTypeResolver
4807
+ } = input;
4730
4808
  let rows = [];
4731
4809
  const mainAlias = stmt.from.alias;
4732
4810
  const mainRecords = tables.get(mainAlias) ?? tables.get(null) ?? [];
@@ -4737,17 +4815,17 @@ function runFullScan(input) {
4737
4815
  const rightRows = rightRecords.map((r) => flatten(r, rightAlias));
4738
4816
  rows = applyJoin(rows, rightRows, join2);
4739
4817
  }
4740
- rows = applyFilter(rows, stmt.where);
4818
+ rows = applyFilter(rows, stmt.where, fieldTypeResolver);
4741
4819
  if (stmt.groupBy.length > 0 || hasAggregateColumns(stmt.columns)) {
4742
4820
  rows = applyGroupBy(rows, stmt.groupBy, stmt.columns);
4743
4821
  }
4744
- rows = applyHaving(rows, stmt.having);
4822
+ rows = applyHaving(rows, stmt.having, havingFieldTypeResolver);
4745
4823
  if (stmt.distinct) {
4746
4824
  rows = applyDistinct(rows, stmt.columns);
4747
4825
  }
4748
4826
  rows = applyOrderBy(rows, stmt.orderBy, optionOrders, sortKinds);
4749
4827
  rows = applyLimit(rows, stmt.limit, stmt.offset);
4750
- return project(rows, stmt.columns, scalarCache);
4828
+ return project(rows, stmt.columns, scalarCache, fieldTypeResolver);
4751
4829
  }
4752
4830
 
4753
4831
  // src/converter/subtableAdapter.ts
@@ -5280,6 +5358,7 @@ async function executeSelect(stmt, client, options, cacheContext, cteCache) {
5280
5358
  if (isNoFromSelect(stmt)) {
5281
5359
  return executeNoFromSelect(stmt);
5282
5360
  }
5361
+ await resolveSelectCaseSubqueries(stmt, client, options, cacheContext, cteCache);
5283
5362
  const mode = resolveSelectMode(stmt);
5284
5363
  await validateSelectFieldCodes(stmt, mode, client, cacheContext);
5285
5364
  if (mode === "SIMPLE") {
@@ -5338,6 +5417,8 @@ function executeNoFromSelect(stmt) {
5338
5417
  }
5339
5418
  async function executeSimpleSelect(stmt, client, options, cacheContext) {
5340
5419
  const params = selectToKintoneParams(stmt);
5420
+ const typedInFieldTypes = await loadTypedInFieldTypes(stmt, client, cacheContext);
5421
+ const fieldTypeResolvers = buildSelectFieldTypeResolvers(stmt, typedInFieldTypes);
5341
5422
  const maxRecords = options.maxRecords ?? 1e4;
5342
5423
  const warnings = /* @__PURE__ */ new Set();
5343
5424
  const onLimit = options.onLimitReached ?? "error";
@@ -5374,7 +5455,12 @@ async function executeSimpleSelect(stmt, client, options, cacheContext) {
5374
5455
  rows = applyOrderBy(rows, stmt.orderBy, optionOrders, sortKinds);
5375
5456
  rows = applyLimit(rows, stmt.limit, stmt.offset);
5376
5457
  }
5377
- const { rows: projected, columns } = project(rows, stmt.columns);
5458
+ const { rows: projected, columns } = project(
5459
+ rows,
5460
+ stmt.columns,
5461
+ void 0,
5462
+ fieldTypeResolvers.row
5463
+ );
5378
5464
  return { type: "SELECT", rows: projected, columns, rowCount: projected.length, warnings: [...warnings] };
5379
5465
  }
5380
5466
  async function validateSelectFieldCodes(stmt, mode, client, cacheContext) {
@@ -5409,44 +5495,160 @@ async function validateSelectFieldCodes(stmt, mode, client, cacheContext) {
5409
5495
  }
5410
5496
  }
5411
5497
  }
5412
- function extractMainSafePushdown(stmt, fieldTypes) {
5498
+ function extractMainSafePushdown(stmt, fieldTypes, fieldOptions) {
5413
5499
  if (stmt.where === null || stmt.from.subtableCode || stmt.from.cteName !== null) return null;
5414
5500
  if (stmt.joins.length === 0) {
5415
5501
  return extractSafePushdownLeaves(stmt.where, {
5416
5502
  tableAlias: stmt.from.alias ?? void 0,
5417
5503
  allowUnqualifiedFields: true,
5418
- fieldTypes
5504
+ fieldTypes,
5505
+ fieldOptions
5419
5506
  });
5420
5507
  }
5421
5508
  if (!stmt.from.alias) return null;
5422
- return extractSafePushdownLeaves(stmt.where, { tableAlias: stmt.from.alias, fieldTypes });
5509
+ return extractSafePushdownLeaves(stmt.where, {
5510
+ tableAlias: stmt.from.alias,
5511
+ fieldTypes,
5512
+ fieldOptions
5513
+ });
5423
5514
  }
5424
- function extractMainNumericPushdownCandidate(stmt) {
5515
+ function extractMainTypedPushdownCandidate(stmt) {
5425
5516
  if (stmt.where === null || stmt.from.subtableCode || stmt.from.cteName !== null) return null;
5426
5517
  if (stmt.joins.length === 0) {
5427
- return extractNumericPushdownCandidates(stmt.where, {
5518
+ return extractTypedPushdownCandidates(stmt.where, {
5428
5519
  tableAlias: stmt.from.alias ?? void 0,
5429
5520
  allowUnqualifiedFields: true
5430
5521
  });
5431
5522
  }
5432
5523
  if (!stmt.from.alias) return null;
5433
- return extractNumericPushdownCandidates(stmt.where, { tableAlias: stmt.from.alias });
5524
+ return extractTypedPushdownCandidates(stmt.where, { tableAlias: stmt.from.alias });
5434
5525
  }
5435
- async function loadNumericPushdownFieldTypes(stmt, client, cacheContext) {
5526
+ async function loadTypedPushdownMeta(stmt, client, cacheContext) {
5436
5527
  const appIds = /* @__PURE__ */ new Set();
5437
- if (extractMainNumericPushdownCandidate(stmt) !== null) appIds.add(stmt.from.appId);
5528
+ if (extractMainTypedPushdownCandidate(stmt) !== null) appIds.add(stmt.from.appId);
5438
5529
  if (stmt.where !== null) {
5439
5530
  for (const join2 of stmt.joins) {
5440
5531
  if (!join2.table.alias || join2.table.subtableCode || join2.table.cteName !== null) continue;
5441
- const candidate = extractNumericPushdownCandidates(stmt.where, {
5532
+ const candidate = extractTypedPushdownCandidates(stmt.where, {
5442
5533
  tableAlias: join2.table.alias
5443
5534
  });
5444
5535
  if (candidate !== null) appIds.add(join2.table.appId);
5445
5536
  }
5446
5537
  }
5538
+ const entries = await Promise.all([...appIds].map(async (appId) => {
5539
+ const [fieldTypes, fieldOptions] = await Promise.all([
5540
+ getFieldTypeMap(appId, client, cacheContext),
5541
+ getFieldOptionSetMapByApp(appId, client, cacheContext)
5542
+ ]);
5543
+ return [appId, fieldTypes, fieldOptions];
5544
+ }));
5545
+ return {
5546
+ fieldTypesByApp: new Map(entries.map(([appId, fieldTypes]) => [appId, fieldTypes])),
5547
+ fieldOptionsByApp: new Map(entries.map(([appId, , fieldOptions]) => [appId, fieldOptions]))
5548
+ };
5549
+ }
5550
+ function collectTypedInFieldRefs(expr, out) {
5551
+ if (expr === null) return;
5552
+ switch (expr.type) {
5553
+ case "BINARY":
5554
+ if ((expr.op === "IN" || expr.op === "NOT_IN") && expr.left.type === "FIELD") {
5555
+ out.push(expr.left);
5556
+ }
5557
+ if (expr.left.type === "CASE_FIELD") collectCaseTypedInFieldRefs(expr.left.expr, out);
5558
+ if (expr.right.type === "CASE_VALUE") collectCaseTypedInFieldRefs(expr.right.expr, out);
5559
+ return;
5560
+ case "LOGICAL":
5561
+ collectTypedInFieldRefs(expr.left, out);
5562
+ collectTypedInFieldRefs(expr.right, out);
5563
+ return;
5564
+ case "NOT":
5565
+ case "GROUP":
5566
+ collectTypedInFieldRefs(expr.expr, out);
5567
+ return;
5568
+ case "NULL_CHECK":
5569
+ case "EXISTS":
5570
+ return;
5571
+ }
5572
+ }
5573
+ function collectCaseTypedInFieldRefs(expr, out) {
5574
+ for (const branch of expr.branches) collectTypedInFieldRefs(branch.condition, out);
5575
+ }
5576
+ function collectSelectTypedInFieldRefs(stmt) {
5577
+ const refs = [];
5578
+ collectTypedInFieldRefs(stmt.where, refs);
5579
+ collectTypedInFieldRefs(stmt.having, refs);
5580
+ for (const column of stmt.columns) {
5581
+ if (column.type === "CASE_COL") collectCaseTypedInFieldRefs(column.expr, refs);
5582
+ }
5583
+ return refs;
5584
+ }
5585
+ function findTableForAlias(stmt, alias) {
5586
+ return [stmt.from, ...stmt.joins.map((join2) => join2.table)].find((table) => table.alias === alias);
5587
+ }
5588
+ function physicalSelectTables(stmt) {
5589
+ return [stmt.from, ...stmt.joins.map((join2) => join2.table)].filter((table) => table.cteName === null);
5590
+ }
5591
+ async function loadTypedInFieldTypes(stmt, client, cacheContext) {
5592
+ const refs = collectSelectTypedInFieldRefs(stmt);
5593
+ if (refs.length === 0) return /* @__PURE__ */ new Map();
5594
+ const appIds = /* @__PURE__ */ new Set();
5595
+ const physicalTables = physicalSelectTables(stmt);
5596
+ for (const ref of refs) {
5597
+ if (ref.tableAlias !== null) {
5598
+ if (ref.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
5599
+ appIds.add(stmt.from.appId);
5600
+ continue;
5601
+ }
5602
+ const table = findTableForAlias(stmt, ref.tableAlias);
5603
+ if (table && table.cteName === null) appIds.add(table.appId);
5604
+ continue;
5605
+ }
5606
+ if (stmt.joins.length === 0) {
5607
+ if (stmt.from.cteName === null) appIds.add(stmt.from.appId);
5608
+ continue;
5609
+ }
5610
+ for (const table of physicalTables) appIds.add(table.appId);
5611
+ }
5447
5612
  const entries = await Promise.all([...appIds].map(async (appId) => [appId, await getFieldTypeMap(appId, client, cacheContext)]));
5448
5613
  return new Map(entries);
5449
5614
  }
5615
+ function fieldCodeForTypeLookup(table, field) {
5616
+ if (table.subtableCode && field.startsWith("_p.")) return field.slice(3);
5617
+ return field;
5618
+ }
5619
+ function buildSelectFieldTypeResolvers(stmt, fieldTypesByApp) {
5620
+ const tables = [stmt.from, ...stmt.joins.map((join2) => join2.table)];
5621
+ const physicalTables = tables.filter((table) => table.cteName === null);
5622
+ const outputAliases = new Set(
5623
+ stmt.columns.map((column) => "alias" in column ? column.alias : null).filter((alias) => alias !== null)
5624
+ );
5625
+ const row = (field) => {
5626
+ if (field.tableAlias !== null) {
5627
+ if (field.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
5628
+ return fieldTypesByApp.get(stmt.from.appId)?.get(field.field);
5629
+ }
5630
+ const table2 = tables.find((candidate) => candidate.alias === field.tableAlias);
5631
+ if (!table2 || table2.cteName !== null) return void 0;
5632
+ return fieldTypesByApp.get(table2.appId)?.get(fieldCodeForTypeLookup(table2, field.field));
5633
+ }
5634
+ if (stmt.joins.length === 0) {
5635
+ if (stmt.from.cteName !== null) return void 0;
5636
+ return fieldTypesByApp.get(stmt.from.appId)?.get(fieldCodeForTypeLookup(stmt.from, field.field));
5637
+ }
5638
+ if (tables.some((table2) => table2.cteName !== null)) return void 0;
5639
+ const matches = physicalTables.filter(
5640
+ (table2) => fieldTypesByApp.get(table2.appId)?.has(fieldCodeForTypeLookup(table2, field.field))
5641
+ );
5642
+ if (matches.length !== 1) return void 0;
5643
+ const table = matches[0];
5644
+ return fieldTypesByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, field.field));
5645
+ };
5646
+ const having = (field) => {
5647
+ if (field.tableAlias === null && outputAliases.has(field.field)) return void 0;
5648
+ return row(field);
5649
+ };
5650
+ return { row, having };
5651
+ }
5450
5652
  async function executeFullScanSelect(stmt, client, options, cacheContext, cteCache) {
5451
5653
  const maxRecords = options.maxRecords ?? 1e4;
5452
5654
  const warnings = /* @__PURE__ */ new Set();
@@ -5455,10 +5657,15 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
5455
5657
  resolveSubqueries(stmt.where, client, options, cacheContext, cteCache),
5456
5658
  resolveSubqueries(stmt.having, client, options, cacheContext, cteCache)
5457
5659
  ]);
5458
- const pushdownFieldTypes = await loadNumericPushdownFieldTypes(stmt, client, cacheContext);
5660
+ const [pushdownMeta, typedInFieldTypes] = await Promise.all([
5661
+ loadTypedPushdownMeta(stmt, client, cacheContext),
5662
+ loadTypedInFieldTypes(stmt, client, cacheContext)
5663
+ ]);
5664
+ const fieldTypeResolvers = buildSelectFieldTypeResolvers(stmt, typedInFieldTypes);
5459
5665
  const mainPushDown = extractMainSafePushdown(
5460
5666
  stmt,
5461
- pushdownFieldTypes.get(stmt.from.appId)
5667
+ pushdownMeta.fieldTypesByApp.get(stmt.from.appId),
5668
+ pushdownMeta.fieldOptionsByApp.get(stmt.from.appId)
5462
5669
  );
5463
5670
  const tableConditions = /* @__PURE__ */ new Map();
5464
5671
  if (stmt.where !== null) {
@@ -5466,7 +5673,8 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
5466
5673
  if (!join2.table.alias || join2.table.subtableCode || join2.table.cteName !== null) continue;
5467
5674
  const cond = extractSafePushdownLeaves(stmt.where, {
5468
5675
  tableAlias: join2.table.alias,
5469
- fieldTypes: pushdownFieldTypes.get(join2.table.appId)
5676
+ fieldTypes: pushdownMeta.fieldTypesByApp.get(join2.table.appId),
5677
+ fieldOptions: pushdownMeta.fieldOptionsByApp.get(join2.table.appId)
5470
5678
  });
5471
5679
  if (cond) tableConditions.set(join2.table.alias, cond);
5472
5680
  }
@@ -5544,7 +5752,15 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
5544
5752
  }));
5545
5753
  const scalarCache = await scalarCachePromise;
5546
5754
  const { optionOrders, sortKinds } = await orderByMetaPromise;
5547
- const { rows, columns } = runFullScan({ tables, stmt, scalarCache, optionOrders, sortKinds });
5755
+ const { rows, columns } = runFullScan({
5756
+ tables,
5757
+ stmt,
5758
+ scalarCache,
5759
+ optionOrders,
5760
+ sortKinds,
5761
+ fieldTypeResolver: fieldTypeResolvers.row,
5762
+ havingFieldTypeResolver: fieldTypeResolvers.having
5763
+ });
5548
5764
  return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [...warnings] };
5549
5765
  }
5550
5766
  async function executeUnion(stmt, client, options, cacheContext) {
@@ -5700,8 +5916,11 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
5700
5916
  const parallel = options.fetchParallel ?? 1;
5701
5917
  await Promise.all([
5702
5918
  resolveSubqueries(stmt.where, client, options, cacheContext, cteCache),
5703
- resolveSubqueries(stmt.having, client, options, cacheContext, cteCache)
5919
+ resolveSubqueries(stmt.having, client, options, cacheContext, cteCache),
5920
+ resolveSelectCaseSubqueries(stmt, client, options, cacheContext, cteCache)
5704
5921
  ]);
5922
+ const typedInFieldTypes = await loadTypedInFieldTypes(stmt, client, cacheContext);
5923
+ const fieldTypeResolvers = buildSelectFieldTypeResolvers(stmt, typedInFieldTypes);
5705
5924
  const scalarCachePromise = resolveScalarColumns(stmt.columns, client, options, cacheContext, cteCache);
5706
5925
  const orderByMetaPromise = buildOrderByMetaForSelect(stmt, client, cacheContext);
5707
5926
  scalarCachePromise.catch(() => {
@@ -5756,7 +5975,15 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
5756
5975
  await Promise.all(joinFetches);
5757
5976
  const scalarCache = await scalarCachePromise;
5758
5977
  const { optionOrders, sortKinds } = await orderByMetaPromise;
5759
- const { rows, columns } = runFullScan({ tables, stmt, scalarCache, optionOrders, sortKinds });
5978
+ const { rows, columns } = runFullScan({
5979
+ tables,
5980
+ stmt,
5981
+ scalarCache,
5982
+ optionOrders,
5983
+ sortKinds,
5984
+ fieldTypeResolver: fieldTypeResolvers.row,
5985
+ havingFieldTypeResolver: fieldTypeResolvers.having
5986
+ });
5760
5987
  return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [...warnings] };
5761
5988
  }
5762
5989
  function processRowToKintoneRecord(row) {
@@ -5988,6 +6215,15 @@ async function getOptionOrderMapByApp(appId, client, cacheContext) {
5988
6215
  setScopedCacheValue(optionOrderCache, cacheContext, appId, map);
5989
6216
  return map;
5990
6217
  }
6218
+ async function getFieldOptionSetMapByApp(appId, client, cacheContext) {
6219
+ const optionOrders = await getOptionOrderMapByApp(appId, client, cacheContext);
6220
+ return new Map(
6221
+ [...optionOrders.entries()].map(([fieldCode, order]) => [
6222
+ fieldCode,
6223
+ new Set(order.keys())
6224
+ ])
6225
+ );
6226
+ }
5991
6227
  async function getSortKindMapByApp(appId, client, cacheContext) {
5992
6228
  const cached = getScopedCacheValue(sortKindCache, cacheContext, appId);
5993
6229
  if (cached) return cached;
@@ -6253,6 +6489,16 @@ async function executeUpsert(stmt, client, options, cacheContext) {
6253
6489
  updatedCount: toUpdate.length
6254
6490
  };
6255
6491
  }
6492
+ async function buildSubtableFieldTypeResolver(appId, typedInRefs, client, cacheContext) {
6493
+ if (typedInRefs.length === 0) return void 0;
6494
+ const fieldTypes = await getFieldTypeMap(appId, client, cacheContext);
6495
+ return (field) => {
6496
+ if (field.tableAlias !== null && field.tableAlias !== "_p") return void 0;
6497
+ if (field.tableAlias === "_p") return fieldTypes.get(field.field);
6498
+ const code = field.field.startsWith("_p.") ? field.field.slice(3) : field.field;
6499
+ return fieldTypes.get(code);
6500
+ };
6501
+ }
6256
6502
  async function executeInsertSubtable(stmt, client, options, _cacheContext) {
6257
6503
  const subtableCode = stmt.subtableCode;
6258
6504
  const pidIndex = stmt.fields.indexOf("_pid");
@@ -6293,11 +6539,24 @@ async function executeInsertSubtable(stmt, client, options, _cacheContext) {
6293
6539
  }
6294
6540
  return { type: "INSERT", createdIds: [], insertedCount: stmt.values.length };
6295
6541
  }
6296
- async function executeUpdateSubtable(stmt, client, options, _cacheContext) {
6542
+ async function executeUpdateSubtable(stmt, client, options, cacheContext) {
6297
6543
  const subtableCode = stmt.subtableCode;
6298
6544
  if (!hasRidCondition(stmt.where)) {
6299
6545
  throw new Error("\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB UPDATE \u306B\u306F _rid \u6761\u4EF6\u304C\u5FC5\u9808\u3067\u3059");
6300
6546
  }
6547
+ const typedInRefs = [];
6548
+ collectTypedInFieldRefs(stmt.where, typedInRefs);
6549
+ for (const assignment of stmt.assignments) {
6550
+ if (assignment.value.type === "CASE_VALUE") {
6551
+ collectCaseTypedInFieldRefs(assignment.value.expr, typedInRefs);
6552
+ }
6553
+ }
6554
+ const resolveFieldType = await buildSubtableFieldTypeResolver(
6555
+ stmt.appId,
6556
+ typedInRefs,
6557
+ client,
6558
+ cacheContext
6559
+ );
6301
6560
  const parents = await fetchAll(
6302
6561
  client.getRecords,
6303
6562
  stmt.appId,
@@ -6306,7 +6565,7 @@ async function executeUpdateSubtable(stmt, client, options, _cacheContext) {
6306
6565
  { maxRecords: options.maxRecords ?? 1e4, parallel: options.fetchParallel ?? 1 }
6307
6566
  );
6308
6567
  const expanded = expandRowsForSubtableDml(parents, subtableCode);
6309
- const targets = expanded.filter((r) => evalWhere(stmt.where, r.flat));
6568
+ const targets = expanded.filter((r) => evalWhere(stmt.where, r.flat, resolveFieldType));
6310
6569
  if (options.confirm) {
6311
6570
  const ok = await options.confirm(targets.length, "UPDATE");
6312
6571
  if (!ok) throw new OperationCancelledError("UPDATE", targets.length);
@@ -6326,7 +6585,7 @@ async function executeUpdateSubtable(stmt, client, options, _cacheContext) {
6326
6585
  if (a.field.startsWith("_")) {
6327
6586
  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`);
6328
6587
  }
6329
- updates[a.field] = { value: evalAssignmentValueForSubtable(a.value, t.flat) };
6588
+ updates[a.field] = { value: evalAssignmentValueForSubtable(a.value, t.flat, resolveFieldType) };
6330
6589
  }
6331
6590
  byRid.set(t.rowId, updates);
6332
6591
  }
@@ -6348,11 +6607,19 @@ async function executeUpdateSubtable(stmt, client, options, _cacheContext) {
6348
6607
  }
6349
6608
  return { type: "UPDATE", updatedCount: targets.length };
6350
6609
  }
6351
- async function executeDeleteSubtable(stmt, client, options, _cacheContext) {
6610
+ async function executeDeleteSubtable(stmt, client, options, cacheContext) {
6352
6611
  const subtableCode = stmt.subtableCode;
6353
6612
  if (!hasRidCondition(stmt.where)) {
6354
6613
  throw new Error("\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB DELETE \u306B\u306F _rid \u6761\u4EF6\u304C\u5FC5\u9808\u3067\u3059");
6355
6614
  }
6615
+ const typedInRefs = [];
6616
+ collectTypedInFieldRefs(stmt.where, typedInRefs);
6617
+ const resolveFieldType = await buildSubtableFieldTypeResolver(
6618
+ stmt.appId,
6619
+ typedInRefs,
6620
+ client,
6621
+ cacheContext
6622
+ );
6356
6623
  const parents = await fetchAll(
6357
6624
  client.getRecords,
6358
6625
  stmt.appId,
@@ -6361,7 +6628,7 @@ async function executeDeleteSubtable(stmt, client, options, _cacheContext) {
6361
6628
  { maxRecords: options.maxRecords ?? 1e4, parallel: options.fetchParallel ?? 1 }
6362
6629
  );
6363
6630
  const expanded = expandRowsForSubtableDml(parents, subtableCode);
6364
- const targets = expanded.filter((r) => evalWhere(stmt.where, r.flat));
6631
+ const targets = expanded.filter((r) => evalWhere(stmt.where, r.flat, resolveFieldType));
6365
6632
  if (options.confirm) {
6366
6633
  const ok = await options.confirm(targets.length, "DELETE");
6367
6634
  if (!ok) throw new OperationCancelledError("DELETE", targets.length);
@@ -6476,11 +6743,11 @@ function buildSubtableReorderPutParams(appId, parentId, revision, subtableCode,
6476
6743
  ]
6477
6744
  };
6478
6745
  }
6479
- function evalAssignmentValueForSubtable(value, row) {
6746
+ function evalAssignmentValueForSubtable(value, row, resolveFieldType) {
6480
6747
  if (value.type === "STRING") return value.value;
6481
6748
  if (value.type === "NUMBER") return String(value.value);
6482
6749
  if (value.type === "ARITH") return String(evalArithExpr(value, row));
6483
- if (value.type === "CASE_VALUE") return evalCaseWhen(value.expr, row);
6750
+ if (value.type === "CASE_VALUE") return evalCaseWhen(value.expr, row, resolveFieldType);
6484
6751
  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`);
6485
6752
  }
6486
6753
  function valueToString(value) {
@@ -6512,7 +6779,15 @@ function hasRidCondition(where) {
6512
6779
  return false;
6513
6780
  }
6514
6781
  }
6515
- async function executeReorder(stmt, client, options, _cacheContext) {
6782
+ async function executeReorder(stmt, client, options, cacheContext) {
6783
+ const typedInRefs = [];
6784
+ collectTypedInFieldRefs(stmt.where, typedInRefs);
6785
+ const resolveFieldType = await buildSubtableFieldTypeResolver(
6786
+ stmt.appId,
6787
+ typedInRefs,
6788
+ client,
6789
+ cacheContext
6790
+ );
6516
6791
  const parents = await fetchAll(
6517
6792
  client.getRecords,
6518
6793
  stmt.appId,
@@ -6521,7 +6796,7 @@ async function executeReorder(stmt, client, options, _cacheContext) {
6521
6796
  { maxRecords: options.maxRecords ?? 1e4, parallel: options.fetchParallel ?? 1 }
6522
6797
  );
6523
6798
  const expanded = expandRowsForSubtableDml(parents, stmt.subtableCode);
6524
- 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));
6799
+ 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));
6525
6800
  if (options.confirm) {
6526
6801
  const ok = await options.confirm(targetParentIds.size, "UPDATE");
6527
6802
  if (!ok) throw new OperationCancelledError("UPDATE", targetParentIds.size);
@@ -6666,6 +6941,16 @@ async function resolveSubqueries(where, client, options, cacheContext, cteCache)
6666
6941
  collectSubqueryTasks(where, client, options, cacheContext, tasks, cteCache);
6667
6942
  await Promise.all(tasks);
6668
6943
  }
6944
+ async function resolveSelectCaseSubqueries(stmt, client, options, cacheContext, cteCache) {
6945
+ const tasks = [];
6946
+ for (const column of stmt.columns) {
6947
+ if (column.type !== "CASE_COL") continue;
6948
+ for (const branch of column.expr.branches) {
6949
+ tasks.push(resolveSubqueries(branch.condition, client, options, cacheContext, cteCache));
6950
+ }
6951
+ }
6952
+ await Promise.all(tasks);
6953
+ }
6669
6954
  function runSubquery(query, client, options, cacheContext, cteCache) {
6670
6955
  if (cteCache !== void 0 && cteCache.size > 0) {
6671
6956
  return executeQueryWithCte(query, client, options, cteCache, cacheContext);
@@ -6898,12 +7183,12 @@ function buildSelectPlan(stmt, label) {
6898
7183
  const mainFields = selectToFetchAllFields(stmt, stmt.from);
6899
7184
  const mainAliasStr = stmt.from.alias ? ` AS ${stmt.from.alias}` : "";
6900
7185
  const mainPushDown = extractMainSafePushdown(stmt);
6901
- const mainCandidate = extractMainNumericPushdownCandidate(stmt);
7186
+ const mainCandidate = extractMainTypedPushdownCandidate(stmt);
6902
7187
  const mainQ = mainPushDown !== null ? whereToKintone(mainPushDown) : "(\u5168\u4EF6\u53D6\u5F97)";
6903
7188
  lines.push(` app: APP${stmt.from.appId}${mainAliasStr} (${stmt.from.appId})`);
6904
7189
  lines.push(` kintone query: ${mainQ}`);
6905
7190
  if (mainCandidate !== null) {
6906
- lines.push(` pushdown candidate: ${whereToKintone(mainCandidate)}\uFF08\u5B9F\u884C\u6642\u306E\u578B\u78BA\u8A8D\u5F85\u3061\uFF09`);
7191
+ lines.push(` pushdown candidate: ${whereToKintone(mainCandidate)}\uFF08\u5B9F\u884C\u6642\u306E\u578B\u30FB\u5B9F\u5728\u78BA\u8A8D\u5F85\u3061\uFF09`);
6907
7192
  }
6908
7193
  lines.push(` fields: ${mainFields.length === 0 ? "(\u5168\u30D5\u30A3\u30FC\u30EB\u30C9)" : mainFields.join(", ")}`);
6909
7194
  for (const join2 of stmt.joins) {
@@ -6911,12 +7196,12 @@ function buildSelectPlan(stmt, label) {
6911
7196
  const joinAliasStr = join2.table.alias ? ` AS ${join2.table.alias}` : "";
6912
7197
  const joinType = join2.type === "INNER" ? "JOIN" : `${join2.type} JOIN`;
6913
7198
  const joinPushDown = join2.table.alias && !join2.table.subtableCode && join2.table.cteName === null && stmt.where ? extractSafePushdownLeaves(stmt.where, { tableAlias: join2.table.alias }) : null;
6914
- const joinCandidate = join2.table.alias && !join2.table.subtableCode && join2.table.cteName === null && stmt.where ? extractNumericPushdownCandidates(stmt.where, { tableAlias: join2.table.alias }) : null;
7199
+ const joinCandidate = join2.table.alias && !join2.table.subtableCode && join2.table.cteName === null && stmt.where ? extractTypedPushdownCandidates(stmt.where, { tableAlias: join2.table.alias }) : null;
6915
7200
  const joinQ = joinPushDown !== null ? whereToKintone(joinPushDown) : "(\u5168\u4EF6\u53D6\u5F97)";
6916
7201
  lines.push(` ${joinType}: APP${join2.table.appId}${joinAliasStr} (${join2.table.appId})`);
6917
7202
  lines.push(` kintone query: ${joinQ}`);
6918
7203
  if (joinCandidate !== null) {
6919
- lines.push(` pushdown candidate: ${whereToKintone(joinCandidate)}\uFF08\u5B9F\u884C\u6642\u306E\u578B\u78BA\u8A8D\u5F85\u3061\uFF09`);
7204
+ lines.push(` pushdown candidate: ${whereToKintone(joinCandidate)}\uFF08\u5B9F\u884C\u6642\u306E\u578B\u30FB\u5B9F\u5728\u78BA\u8A8D\u5F85\u3061\uFF09`);
6920
7205
  }
6921
7206
  lines.push(` fields: ${joinFields.length === 0 ? "(\u5168\u30D5\u30A3\u30FC\u30EB\u30C9)" : joinFields.join(", ")}`);
6922
7207
  }
@@ -7595,6 +7880,42 @@ function clampInt(v, min, max) {
7595
7880
  return Math.max(min, Math.min(max, Math.trunc(v)));
7596
7881
  }
7597
7882
 
7883
+ // src/core/formFieldInfo.ts
7884
+ function flattenFormFieldProperties(properties) {
7885
+ const out = [];
7886
+ for (const field of Object.values(properties)) {
7887
+ out.push({
7888
+ code: field.code,
7889
+ label: field.label,
7890
+ fieldType: field.type,
7891
+ optionOrder: toOptionOrderMap(field.options),
7892
+ sortKind: detectSortKind(field.type, field.format)
7893
+ });
7894
+ if (field.fields) out.push(...flattenFormFieldProperties(field.fields));
7895
+ }
7896
+ return out;
7897
+ }
7898
+ function toOptionOrderMap(options) {
7899
+ if (!options || typeof options !== "object") return void 0;
7900
+ const order = {};
7901
+ let hasAny = false;
7902
+ for (const [label, meta] of Object.entries(options)) {
7903
+ const n = Number(meta?.index);
7904
+ if (!Number.isFinite(n)) continue;
7905
+ order[label] = n;
7906
+ hasAny = true;
7907
+ }
7908
+ return hasAny ? order : void 0;
7909
+ }
7910
+ function detectSortKind(fieldType, calcFormat) {
7911
+ if (fieldType === "NUMBER" || fieldType === "RECORD_NUMBER") return "number";
7912
+ if (fieldType === "CALC") {
7913
+ if (calcFormat === "NUMBER" || calcFormat === "NUMBER_DIGIT") return "number";
7914
+ return "string";
7915
+ }
7916
+ return void 0;
7917
+ }
7918
+
7598
7919
  // src/cli/nodeKintoneClient.ts
7599
7920
  function createNodeKintoneClient(baseUrl, tokenResolver) {
7600
7921
  const normalizedBaseUrl = baseUrl.replace(/\/+$/, "");
@@ -7773,36 +8094,10 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
7773
8094
  { method: "GET" },
7774
8095
  appId
7775
8096
  );
7776
- return Object.values(res.properties).map((f) => ({
7777
- code: f.code,
7778
- label: f.label,
7779
- fieldType: f.type,
7780
- optionOrder: toOptionOrderMap(f.options),
7781
- sortKind: detectSortKind(f.type, f.format)
7782
- }));
8097
+ return flattenFormFieldProperties(res.properties);
7783
8098
  }
7784
8099
  };
7785
8100
  }
7786
- function toOptionOrderMap(options) {
7787
- if (!options || typeof options !== "object") return void 0;
7788
- const order = {};
7789
- let hasAny = false;
7790
- for (const [label, meta] of Object.entries(options)) {
7791
- const n = Number(meta?.index);
7792
- if (!Number.isFinite(n)) continue;
7793
- order[label] = n;
7794
- hasAny = true;
7795
- }
7796
- return hasAny ? order : void 0;
7797
- }
7798
- function detectSortKind(fieldType, calcFormat) {
7799
- if (fieldType === "NUMBER" || fieldType === "RECORD_NUMBER") return "number";
7800
- if (fieldType === "CALC") {
7801
- if (calcFormat === "NUMBER" || calcFormat === "NUMBER_DIGIT") return "number";
7802
- return "string";
7803
- }
7804
- return void 0;
7805
- }
7806
8101
 
7807
8102
  // src/node/appProfiles.ts
7808
8103
  var import_fs = require("fs");