@rex0220/kintone-sql-tools 2.4.0 → 2.5.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 +316 -77
- package/dist-mcp/ksql-mcp.js +317 -78
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +1 -1
package/dist-cli/ksql.js
CHANGED
|
@@ -3508,52 +3508,91 @@ 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
return parsed.some((item) => values.has(item));
|
|
3585
|
+
}
|
|
3586
|
+
if (OBJECT_ARRAY_FIELD_TYPES.has(fieldType)) {
|
|
3587
|
+
if (!Array.isArray(parsed) || !parsed.every(hasStringCode)) return fallback();
|
|
3588
|
+
return parsed.some((item) => values.has(item.code));
|
|
3589
|
+
}
|
|
3590
|
+
if (!hasStringCode(parsed)) return fallback();
|
|
3591
|
+
return values.has(parsed.code);
|
|
3592
|
+
}
|
|
3593
|
+
function hasStringCode(value) {
|
|
3594
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) && typeof value.code === "string";
|
|
3595
|
+
}
|
|
3557
3596
|
function assertResolvedInListValues2(values) {
|
|
3558
3597
|
const unresolved = values.find((item) => item.type === "VARIABLE");
|
|
3559
3598
|
if (unresolved?.type === "VARIABLE") {
|
|
@@ -3564,20 +3603,20 @@ function evalNullCheck(expr, row) {
|
|
|
3564
3603
|
const val = resolveField(expr.field, row);
|
|
3565
3604
|
return expr.not ? val !== "" : val === "";
|
|
3566
3605
|
}
|
|
3567
|
-
function evalLogical(expr, row) {
|
|
3606
|
+
function evalLogical(expr, row, resolveFieldType) {
|
|
3568
3607
|
if (expr.op === "AND") {
|
|
3569
|
-
return evalWhere(expr.left, row) && evalWhere(expr.right, row);
|
|
3608
|
+
return evalWhere(expr.left, row, resolveFieldType) && evalWhere(expr.right, row, resolveFieldType);
|
|
3570
3609
|
}
|
|
3571
|
-
return evalWhere(expr.left, row) || evalWhere(expr.right, row);
|
|
3610
|
+
return evalWhere(expr.left, row, resolveFieldType) || evalWhere(expr.right, row, resolveFieldType);
|
|
3572
3611
|
}
|
|
3573
|
-
function resolveField(field, row) {
|
|
3612
|
+
function resolveField(field, row, resolveFieldType) {
|
|
3574
3613
|
if (field.type === "FUNC_FIELD") return evalStringFunc(field.expr, row);
|
|
3575
3614
|
if (field.type === "ARITH_FIELD") return String(evalArithExpr(field.expr, row));
|
|
3576
|
-
if (field.type === "CASE_FIELD") return evalCaseWhen(field.expr, row);
|
|
3615
|
+
if (field.type === "CASE_FIELD") return evalCaseWhen(field.expr, row, resolveFieldType);
|
|
3577
3616
|
const key = field.tableAlias ? `${field.tableAlias}.${field.field}` : field.field;
|
|
3578
3617
|
return resolveFieldRef(row, key);
|
|
3579
3618
|
}
|
|
3580
|
-
function resolveValue(value, row) {
|
|
3619
|
+
function resolveValue(value, row, resolveFieldType) {
|
|
3581
3620
|
switch (value.type) {
|
|
3582
3621
|
case "VARIABLE":
|
|
3583
3622
|
throw new Error(`ParseError: unresolved batch variable @${value.name}.`);
|
|
@@ -3600,14 +3639,14 @@ function resolveValue(value, row) {
|
|
|
3600
3639
|
if (value.expr.type === "STRING_FUNC") return evalStringFunc(value.expr, row);
|
|
3601
3640
|
return String(evalArithExpr(value.expr, row));
|
|
3602
3641
|
case "CASE_VALUE":
|
|
3603
|
-
return evalCaseWhen(value.expr, row);
|
|
3642
|
+
return evalCaseWhen(value.expr, row, resolveFieldType);
|
|
3604
3643
|
case "ARRAY":
|
|
3605
3644
|
return value.elements.map((e) => e.value).join(",");
|
|
3606
3645
|
}
|
|
3607
3646
|
}
|
|
3608
|
-
function evalCaseWhen(expr, row) {
|
|
3647
|
+
function evalCaseWhen(expr, row, resolveFieldType) {
|
|
3609
3648
|
for (const branch of expr.branches) {
|
|
3610
|
-
if (evalWhere(branch.condition, row)) {
|
|
3649
|
+
if (evalWhere(branch.condition, row, resolveFieldType)) {
|
|
3611
3650
|
return evalCaseResult(branch.result, row);
|
|
3612
3651
|
}
|
|
3613
3652
|
}
|
|
@@ -4274,9 +4313,9 @@ function applyJoin(leftRows, rightRows, join2) {
|
|
|
4274
4313
|
}
|
|
4275
4314
|
return result;
|
|
4276
4315
|
}
|
|
4277
|
-
function applyFilter(rows, where) {
|
|
4316
|
+
function applyFilter(rows, where, resolveFieldType) {
|
|
4278
4317
|
if (where === null) return rows;
|
|
4279
|
-
return rows.filter((row) => evalWhere(where, row));
|
|
4318
|
+
return rows.filter((row) => evalWhere(where, row, resolveFieldType));
|
|
4280
4319
|
}
|
|
4281
4320
|
function hasAggregateColumns(columns) {
|
|
4282
4321
|
return columns.some(
|
|
@@ -4402,9 +4441,9 @@ function aggregateSyntheticName2(func, distinct, arg) {
|
|
|
4402
4441
|
const argStr = aggregateArgLabel(arg);
|
|
4403
4442
|
return distinct ? `${func}(DISTINCT ${argStr})` : `${func}(${argStr})`;
|
|
4404
4443
|
}
|
|
4405
|
-
function applyHaving(rows, having) {
|
|
4444
|
+
function applyHaving(rows, having, resolveFieldType) {
|
|
4406
4445
|
if (having === null) return rows;
|
|
4407
|
-
return rows.filter((row) => evalWhere(having, row));
|
|
4446
|
+
return rows.filter((row) => evalWhere(having, row, resolveFieldType));
|
|
4408
4447
|
}
|
|
4409
4448
|
function applyDistinct(rows, columns) {
|
|
4410
4449
|
if (rows.length === 0) return rows;
|
|
@@ -4529,7 +4568,7 @@ function applyLimit(rows, limit, offset) {
|
|
|
4529
4568
|
if (limit === null) return rows.slice(start);
|
|
4530
4569
|
return rows.slice(start, start + limit);
|
|
4531
4570
|
}
|
|
4532
|
-
function project(rows, columns, scalarCache) {
|
|
4571
|
+
function project(rows, columns, scalarCache, resolveFieldType) {
|
|
4533
4572
|
if (columns.length === 1 && columns[0].type === "WILDCARD") {
|
|
4534
4573
|
const projected2 = rows.map((row) => stripParentShortcutColumns(row));
|
|
4535
4574
|
const cols = projected2.length > 0 ? Object.keys(projected2[0]) : [];
|
|
@@ -4590,7 +4629,7 @@ function project(rows, columns, scalarCache) {
|
|
|
4590
4629
|
}
|
|
4591
4630
|
case "CASE_COL": {
|
|
4592
4631
|
const key = outputKeys?.[colIdx] ?? col.alias ?? "case";
|
|
4593
|
-
out[key] = evalCaseWhen(col.expr, row);
|
|
4632
|
+
out[key] = evalCaseWhen(col.expr, row, resolveFieldType);
|
|
4594
4633
|
if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
|
|
4595
4634
|
break;
|
|
4596
4635
|
}
|
|
@@ -4726,7 +4765,15 @@ function resolveAggInStringFuncExpr(expr, rows) {
|
|
|
4726
4765
|
};
|
|
4727
4766
|
}
|
|
4728
4767
|
function runFullScan(input) {
|
|
4729
|
-
const {
|
|
4768
|
+
const {
|
|
4769
|
+
stmt,
|
|
4770
|
+
tables,
|
|
4771
|
+
scalarCache,
|
|
4772
|
+
optionOrders,
|
|
4773
|
+
sortKinds,
|
|
4774
|
+
fieldTypeResolver,
|
|
4775
|
+
havingFieldTypeResolver
|
|
4776
|
+
} = input;
|
|
4730
4777
|
let rows = [];
|
|
4731
4778
|
const mainAlias = stmt.from.alias;
|
|
4732
4779
|
const mainRecords = tables.get(mainAlias) ?? tables.get(null) ?? [];
|
|
@@ -4737,17 +4784,17 @@ function runFullScan(input) {
|
|
|
4737
4784
|
const rightRows = rightRecords.map((r) => flatten(r, rightAlias));
|
|
4738
4785
|
rows = applyJoin(rows, rightRows, join2);
|
|
4739
4786
|
}
|
|
4740
|
-
rows = applyFilter(rows, stmt.where);
|
|
4787
|
+
rows = applyFilter(rows, stmt.where, fieldTypeResolver);
|
|
4741
4788
|
if (stmt.groupBy.length > 0 || hasAggregateColumns(stmt.columns)) {
|
|
4742
4789
|
rows = applyGroupBy(rows, stmt.groupBy, stmt.columns);
|
|
4743
4790
|
}
|
|
4744
|
-
rows = applyHaving(rows, stmt.having);
|
|
4791
|
+
rows = applyHaving(rows, stmt.having, havingFieldTypeResolver);
|
|
4745
4792
|
if (stmt.distinct) {
|
|
4746
4793
|
rows = applyDistinct(rows, stmt.columns);
|
|
4747
4794
|
}
|
|
4748
4795
|
rows = applyOrderBy(rows, stmt.orderBy, optionOrders, sortKinds);
|
|
4749
4796
|
rows = applyLimit(rows, stmt.limit, stmt.offset);
|
|
4750
|
-
return project(rows, stmt.columns, scalarCache);
|
|
4797
|
+
return project(rows, stmt.columns, scalarCache, fieldTypeResolver);
|
|
4751
4798
|
}
|
|
4752
4799
|
|
|
4753
4800
|
// src/converter/subtableAdapter.ts
|
|
@@ -5280,6 +5327,7 @@ async function executeSelect(stmt, client, options, cacheContext, cteCache) {
|
|
|
5280
5327
|
if (isNoFromSelect(stmt)) {
|
|
5281
5328
|
return executeNoFromSelect(stmt);
|
|
5282
5329
|
}
|
|
5330
|
+
await resolveSelectCaseSubqueries(stmt, client, options, cacheContext, cteCache);
|
|
5283
5331
|
const mode = resolveSelectMode(stmt);
|
|
5284
5332
|
await validateSelectFieldCodes(stmt, mode, client, cacheContext);
|
|
5285
5333
|
if (mode === "SIMPLE") {
|
|
@@ -5338,6 +5386,8 @@ function executeNoFromSelect(stmt) {
|
|
|
5338
5386
|
}
|
|
5339
5387
|
async function executeSimpleSelect(stmt, client, options, cacheContext) {
|
|
5340
5388
|
const params = selectToKintoneParams(stmt);
|
|
5389
|
+
const typedInFieldTypes = await loadTypedInFieldTypes(stmt, client, cacheContext);
|
|
5390
|
+
const fieldTypeResolvers = buildSelectFieldTypeResolvers(stmt, typedInFieldTypes);
|
|
5341
5391
|
const maxRecords = options.maxRecords ?? 1e4;
|
|
5342
5392
|
const warnings = /* @__PURE__ */ new Set();
|
|
5343
5393
|
const onLimit = options.onLimitReached ?? "error";
|
|
@@ -5374,7 +5424,12 @@ async function executeSimpleSelect(stmt, client, options, cacheContext) {
|
|
|
5374
5424
|
rows = applyOrderBy(rows, stmt.orderBy, optionOrders, sortKinds);
|
|
5375
5425
|
rows = applyLimit(rows, stmt.limit, stmt.offset);
|
|
5376
5426
|
}
|
|
5377
|
-
const { rows: projected, columns } = project(
|
|
5427
|
+
const { rows: projected, columns } = project(
|
|
5428
|
+
rows,
|
|
5429
|
+
stmt.columns,
|
|
5430
|
+
void 0,
|
|
5431
|
+
fieldTypeResolvers.row
|
|
5432
|
+
);
|
|
5378
5433
|
return { type: "SELECT", rows: projected, columns, rowCount: projected.length, warnings: [...warnings] };
|
|
5379
5434
|
}
|
|
5380
5435
|
async function validateSelectFieldCodes(stmt, mode, client, cacheContext) {
|
|
@@ -5447,6 +5502,108 @@ async function loadNumericPushdownFieldTypes(stmt, client, cacheContext) {
|
|
|
5447
5502
|
const entries = await Promise.all([...appIds].map(async (appId) => [appId, await getFieldTypeMap(appId, client, cacheContext)]));
|
|
5448
5503
|
return new Map(entries);
|
|
5449
5504
|
}
|
|
5505
|
+
function collectTypedInFieldRefs(expr, out) {
|
|
5506
|
+
if (expr === null) return;
|
|
5507
|
+
switch (expr.type) {
|
|
5508
|
+
case "BINARY":
|
|
5509
|
+
if ((expr.op === "IN" || expr.op === "NOT_IN") && expr.left.type === "FIELD") {
|
|
5510
|
+
out.push(expr.left);
|
|
5511
|
+
}
|
|
5512
|
+
if (expr.left.type === "CASE_FIELD") collectCaseTypedInFieldRefs(expr.left.expr, out);
|
|
5513
|
+
if (expr.right.type === "CASE_VALUE") collectCaseTypedInFieldRefs(expr.right.expr, out);
|
|
5514
|
+
return;
|
|
5515
|
+
case "LOGICAL":
|
|
5516
|
+
collectTypedInFieldRefs(expr.left, out);
|
|
5517
|
+
collectTypedInFieldRefs(expr.right, out);
|
|
5518
|
+
return;
|
|
5519
|
+
case "NOT":
|
|
5520
|
+
case "GROUP":
|
|
5521
|
+
collectTypedInFieldRefs(expr.expr, out);
|
|
5522
|
+
return;
|
|
5523
|
+
case "NULL_CHECK":
|
|
5524
|
+
case "EXISTS":
|
|
5525
|
+
return;
|
|
5526
|
+
}
|
|
5527
|
+
}
|
|
5528
|
+
function collectCaseTypedInFieldRefs(expr, out) {
|
|
5529
|
+
for (const branch of expr.branches) collectTypedInFieldRefs(branch.condition, out);
|
|
5530
|
+
}
|
|
5531
|
+
function collectSelectTypedInFieldRefs(stmt) {
|
|
5532
|
+
const refs = [];
|
|
5533
|
+
collectTypedInFieldRefs(stmt.where, refs);
|
|
5534
|
+
collectTypedInFieldRefs(stmt.having, refs);
|
|
5535
|
+
for (const column of stmt.columns) {
|
|
5536
|
+
if (column.type === "CASE_COL") collectCaseTypedInFieldRefs(column.expr, refs);
|
|
5537
|
+
}
|
|
5538
|
+
return refs;
|
|
5539
|
+
}
|
|
5540
|
+
function findTableForAlias(stmt, alias) {
|
|
5541
|
+
return [stmt.from, ...stmt.joins.map((join2) => join2.table)].find((table) => table.alias === alias);
|
|
5542
|
+
}
|
|
5543
|
+
function physicalSelectTables(stmt) {
|
|
5544
|
+
return [stmt.from, ...stmt.joins.map((join2) => join2.table)].filter((table) => table.cteName === null);
|
|
5545
|
+
}
|
|
5546
|
+
async function loadTypedInFieldTypes(stmt, client, cacheContext) {
|
|
5547
|
+
const refs = collectSelectTypedInFieldRefs(stmt);
|
|
5548
|
+
if (refs.length === 0) return /* @__PURE__ */ new Map();
|
|
5549
|
+
const appIds = /* @__PURE__ */ new Set();
|
|
5550
|
+
const physicalTables = physicalSelectTables(stmt);
|
|
5551
|
+
for (const ref of refs) {
|
|
5552
|
+
if (ref.tableAlias !== null) {
|
|
5553
|
+
if (ref.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
|
|
5554
|
+
appIds.add(stmt.from.appId);
|
|
5555
|
+
continue;
|
|
5556
|
+
}
|
|
5557
|
+
const table = findTableForAlias(stmt, ref.tableAlias);
|
|
5558
|
+
if (table && table.cteName === null) appIds.add(table.appId);
|
|
5559
|
+
continue;
|
|
5560
|
+
}
|
|
5561
|
+
if (stmt.joins.length === 0) {
|
|
5562
|
+
if (stmt.from.cteName === null) appIds.add(stmt.from.appId);
|
|
5563
|
+
continue;
|
|
5564
|
+
}
|
|
5565
|
+
for (const table of physicalTables) appIds.add(table.appId);
|
|
5566
|
+
}
|
|
5567
|
+
const entries = await Promise.all([...appIds].map(async (appId) => [appId, await getFieldTypeMap(appId, client, cacheContext)]));
|
|
5568
|
+
return new Map(entries);
|
|
5569
|
+
}
|
|
5570
|
+
function fieldCodeForTypeLookup(table, field) {
|
|
5571
|
+
if (table.subtableCode && field.startsWith("_p.")) return field.slice(3);
|
|
5572
|
+
return field;
|
|
5573
|
+
}
|
|
5574
|
+
function buildSelectFieldTypeResolvers(stmt, fieldTypesByApp) {
|
|
5575
|
+
const tables = [stmt.from, ...stmt.joins.map((join2) => join2.table)];
|
|
5576
|
+
const physicalTables = tables.filter((table) => table.cteName === null);
|
|
5577
|
+
const outputAliases = new Set(
|
|
5578
|
+
stmt.columns.map((column) => "alias" in column ? column.alias : null).filter((alias) => alias !== null)
|
|
5579
|
+
);
|
|
5580
|
+
const row = (field) => {
|
|
5581
|
+
if (field.tableAlias !== null) {
|
|
5582
|
+
if (field.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
|
|
5583
|
+
return fieldTypesByApp.get(stmt.from.appId)?.get(field.field);
|
|
5584
|
+
}
|
|
5585
|
+
const table2 = tables.find((candidate) => candidate.alias === field.tableAlias);
|
|
5586
|
+
if (!table2 || table2.cteName !== null) return void 0;
|
|
5587
|
+
return fieldTypesByApp.get(table2.appId)?.get(fieldCodeForTypeLookup(table2, field.field));
|
|
5588
|
+
}
|
|
5589
|
+
if (stmt.joins.length === 0) {
|
|
5590
|
+
if (stmt.from.cteName !== null) return void 0;
|
|
5591
|
+
return fieldTypesByApp.get(stmt.from.appId)?.get(fieldCodeForTypeLookup(stmt.from, field.field));
|
|
5592
|
+
}
|
|
5593
|
+
if (tables.some((table2) => table2.cteName !== null)) return void 0;
|
|
5594
|
+
const matches = physicalTables.filter(
|
|
5595
|
+
(table2) => fieldTypesByApp.get(table2.appId)?.has(fieldCodeForTypeLookup(table2, field.field))
|
|
5596
|
+
);
|
|
5597
|
+
if (matches.length !== 1) return void 0;
|
|
5598
|
+
const table = matches[0];
|
|
5599
|
+
return fieldTypesByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, field.field));
|
|
5600
|
+
};
|
|
5601
|
+
const having = (field) => {
|
|
5602
|
+
if (field.tableAlias === null && outputAliases.has(field.field)) return void 0;
|
|
5603
|
+
return row(field);
|
|
5604
|
+
};
|
|
5605
|
+
return { row, having };
|
|
5606
|
+
}
|
|
5450
5607
|
async function executeFullScanSelect(stmt, client, options, cacheContext, cteCache) {
|
|
5451
5608
|
const maxRecords = options.maxRecords ?? 1e4;
|
|
5452
5609
|
const warnings = /* @__PURE__ */ new Set();
|
|
@@ -5455,7 +5612,11 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
|
|
|
5455
5612
|
resolveSubqueries(stmt.where, client, options, cacheContext, cteCache),
|
|
5456
5613
|
resolveSubqueries(stmt.having, client, options, cacheContext, cteCache)
|
|
5457
5614
|
]);
|
|
5458
|
-
const pushdownFieldTypes = await
|
|
5615
|
+
const [pushdownFieldTypes, typedInFieldTypes] = await Promise.all([
|
|
5616
|
+
loadNumericPushdownFieldTypes(stmt, client, cacheContext),
|
|
5617
|
+
loadTypedInFieldTypes(stmt, client, cacheContext)
|
|
5618
|
+
]);
|
|
5619
|
+
const fieldTypeResolvers = buildSelectFieldTypeResolvers(stmt, typedInFieldTypes);
|
|
5459
5620
|
const mainPushDown = extractMainSafePushdown(
|
|
5460
5621
|
stmt,
|
|
5461
5622
|
pushdownFieldTypes.get(stmt.from.appId)
|
|
@@ -5544,7 +5705,15 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
|
|
|
5544
5705
|
}));
|
|
5545
5706
|
const scalarCache = await scalarCachePromise;
|
|
5546
5707
|
const { optionOrders, sortKinds } = await orderByMetaPromise;
|
|
5547
|
-
const { rows, columns } = runFullScan({
|
|
5708
|
+
const { rows, columns } = runFullScan({
|
|
5709
|
+
tables,
|
|
5710
|
+
stmt,
|
|
5711
|
+
scalarCache,
|
|
5712
|
+
optionOrders,
|
|
5713
|
+
sortKinds,
|
|
5714
|
+
fieldTypeResolver: fieldTypeResolvers.row,
|
|
5715
|
+
havingFieldTypeResolver: fieldTypeResolvers.having
|
|
5716
|
+
});
|
|
5548
5717
|
return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [...warnings] };
|
|
5549
5718
|
}
|
|
5550
5719
|
async function executeUnion(stmt, client, options, cacheContext) {
|
|
@@ -5700,8 +5869,11 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
|
|
|
5700
5869
|
const parallel = options.fetchParallel ?? 1;
|
|
5701
5870
|
await Promise.all([
|
|
5702
5871
|
resolveSubqueries(stmt.where, client, options, cacheContext, cteCache),
|
|
5703
|
-
resolveSubqueries(stmt.having, client, options, cacheContext, cteCache)
|
|
5872
|
+
resolveSubqueries(stmt.having, client, options, cacheContext, cteCache),
|
|
5873
|
+
resolveSelectCaseSubqueries(stmt, client, options, cacheContext, cteCache)
|
|
5704
5874
|
]);
|
|
5875
|
+
const typedInFieldTypes = await loadTypedInFieldTypes(stmt, client, cacheContext);
|
|
5876
|
+
const fieldTypeResolvers = buildSelectFieldTypeResolvers(stmt, typedInFieldTypes);
|
|
5705
5877
|
const scalarCachePromise = resolveScalarColumns(stmt.columns, client, options, cacheContext, cteCache);
|
|
5706
5878
|
const orderByMetaPromise = buildOrderByMetaForSelect(stmt, client, cacheContext);
|
|
5707
5879
|
scalarCachePromise.catch(() => {
|
|
@@ -5756,7 +5928,15 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
|
|
|
5756
5928
|
await Promise.all(joinFetches);
|
|
5757
5929
|
const scalarCache = await scalarCachePromise;
|
|
5758
5930
|
const { optionOrders, sortKinds } = await orderByMetaPromise;
|
|
5759
|
-
const { rows, columns } = runFullScan({
|
|
5931
|
+
const { rows, columns } = runFullScan({
|
|
5932
|
+
tables,
|
|
5933
|
+
stmt,
|
|
5934
|
+
scalarCache,
|
|
5935
|
+
optionOrders,
|
|
5936
|
+
sortKinds,
|
|
5937
|
+
fieldTypeResolver: fieldTypeResolvers.row,
|
|
5938
|
+
havingFieldTypeResolver: fieldTypeResolvers.having
|
|
5939
|
+
});
|
|
5760
5940
|
return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [...warnings] };
|
|
5761
5941
|
}
|
|
5762
5942
|
function processRowToKintoneRecord(row) {
|
|
@@ -6253,6 +6433,16 @@ async function executeUpsert(stmt, client, options, cacheContext) {
|
|
|
6253
6433
|
updatedCount: toUpdate.length
|
|
6254
6434
|
};
|
|
6255
6435
|
}
|
|
6436
|
+
async function buildSubtableFieldTypeResolver(appId, typedInRefs, client, cacheContext) {
|
|
6437
|
+
if (typedInRefs.length === 0) return void 0;
|
|
6438
|
+
const fieldTypes = await getFieldTypeMap(appId, client, cacheContext);
|
|
6439
|
+
return (field) => {
|
|
6440
|
+
if (field.tableAlias !== null && field.tableAlias !== "_p") return void 0;
|
|
6441
|
+
if (field.tableAlias === "_p") return fieldTypes.get(field.field);
|
|
6442
|
+
const code = field.field.startsWith("_p.") ? field.field.slice(3) : field.field;
|
|
6443
|
+
return fieldTypes.get(code);
|
|
6444
|
+
};
|
|
6445
|
+
}
|
|
6256
6446
|
async function executeInsertSubtable(stmt, client, options, _cacheContext) {
|
|
6257
6447
|
const subtableCode = stmt.subtableCode;
|
|
6258
6448
|
const pidIndex = stmt.fields.indexOf("_pid");
|
|
@@ -6293,11 +6483,24 @@ async function executeInsertSubtable(stmt, client, options, _cacheContext) {
|
|
|
6293
6483
|
}
|
|
6294
6484
|
return { type: "INSERT", createdIds: [], insertedCount: stmt.values.length };
|
|
6295
6485
|
}
|
|
6296
|
-
async function executeUpdateSubtable(stmt, client, options,
|
|
6486
|
+
async function executeUpdateSubtable(stmt, client, options, cacheContext) {
|
|
6297
6487
|
const subtableCode = stmt.subtableCode;
|
|
6298
6488
|
if (!hasRidCondition(stmt.where)) {
|
|
6299
6489
|
throw new Error("\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB UPDATE \u306B\u306F _rid \u6761\u4EF6\u304C\u5FC5\u9808\u3067\u3059");
|
|
6300
6490
|
}
|
|
6491
|
+
const typedInRefs = [];
|
|
6492
|
+
collectTypedInFieldRefs(stmt.where, typedInRefs);
|
|
6493
|
+
for (const assignment of stmt.assignments) {
|
|
6494
|
+
if (assignment.value.type === "CASE_VALUE") {
|
|
6495
|
+
collectCaseTypedInFieldRefs(assignment.value.expr, typedInRefs);
|
|
6496
|
+
}
|
|
6497
|
+
}
|
|
6498
|
+
const resolveFieldType = await buildSubtableFieldTypeResolver(
|
|
6499
|
+
stmt.appId,
|
|
6500
|
+
typedInRefs,
|
|
6501
|
+
client,
|
|
6502
|
+
cacheContext
|
|
6503
|
+
);
|
|
6301
6504
|
const parents = await fetchAll(
|
|
6302
6505
|
client.getRecords,
|
|
6303
6506
|
stmt.appId,
|
|
@@ -6306,7 +6509,7 @@ async function executeUpdateSubtable(stmt, client, options, _cacheContext) {
|
|
|
6306
6509
|
{ maxRecords: options.maxRecords ?? 1e4, parallel: options.fetchParallel ?? 1 }
|
|
6307
6510
|
);
|
|
6308
6511
|
const expanded = expandRowsForSubtableDml(parents, subtableCode);
|
|
6309
|
-
const targets = expanded.filter((r) => evalWhere(stmt.where, r.flat));
|
|
6512
|
+
const targets = expanded.filter((r) => evalWhere(stmt.where, r.flat, resolveFieldType));
|
|
6310
6513
|
if (options.confirm) {
|
|
6311
6514
|
const ok = await options.confirm(targets.length, "UPDATE");
|
|
6312
6515
|
if (!ok) throw new OperationCancelledError("UPDATE", targets.length);
|
|
@@ -6326,7 +6529,7 @@ async function executeUpdateSubtable(stmt, client, options, _cacheContext) {
|
|
|
6326
6529
|
if (a.field.startsWith("_")) {
|
|
6327
6530
|
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
6531
|
}
|
|
6329
|
-
updates[a.field] = { value: evalAssignmentValueForSubtable(a.value, t.flat) };
|
|
6532
|
+
updates[a.field] = { value: evalAssignmentValueForSubtable(a.value, t.flat, resolveFieldType) };
|
|
6330
6533
|
}
|
|
6331
6534
|
byRid.set(t.rowId, updates);
|
|
6332
6535
|
}
|
|
@@ -6348,11 +6551,19 @@ async function executeUpdateSubtable(stmt, client, options, _cacheContext) {
|
|
|
6348
6551
|
}
|
|
6349
6552
|
return { type: "UPDATE", updatedCount: targets.length };
|
|
6350
6553
|
}
|
|
6351
|
-
async function executeDeleteSubtable(stmt, client, options,
|
|
6554
|
+
async function executeDeleteSubtable(stmt, client, options, cacheContext) {
|
|
6352
6555
|
const subtableCode = stmt.subtableCode;
|
|
6353
6556
|
if (!hasRidCondition(stmt.where)) {
|
|
6354
6557
|
throw new Error("\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB DELETE \u306B\u306F _rid \u6761\u4EF6\u304C\u5FC5\u9808\u3067\u3059");
|
|
6355
6558
|
}
|
|
6559
|
+
const typedInRefs = [];
|
|
6560
|
+
collectTypedInFieldRefs(stmt.where, typedInRefs);
|
|
6561
|
+
const resolveFieldType = await buildSubtableFieldTypeResolver(
|
|
6562
|
+
stmt.appId,
|
|
6563
|
+
typedInRefs,
|
|
6564
|
+
client,
|
|
6565
|
+
cacheContext
|
|
6566
|
+
);
|
|
6356
6567
|
const parents = await fetchAll(
|
|
6357
6568
|
client.getRecords,
|
|
6358
6569
|
stmt.appId,
|
|
@@ -6361,7 +6572,7 @@ async function executeDeleteSubtable(stmt, client, options, _cacheContext) {
|
|
|
6361
6572
|
{ maxRecords: options.maxRecords ?? 1e4, parallel: options.fetchParallel ?? 1 }
|
|
6362
6573
|
);
|
|
6363
6574
|
const expanded = expandRowsForSubtableDml(parents, subtableCode);
|
|
6364
|
-
const targets = expanded.filter((r) => evalWhere(stmt.where, r.flat));
|
|
6575
|
+
const targets = expanded.filter((r) => evalWhere(stmt.where, r.flat, resolveFieldType));
|
|
6365
6576
|
if (options.confirm) {
|
|
6366
6577
|
const ok = await options.confirm(targets.length, "DELETE");
|
|
6367
6578
|
if (!ok) throw new OperationCancelledError("DELETE", targets.length);
|
|
@@ -6476,11 +6687,11 @@ function buildSubtableReorderPutParams(appId, parentId, revision, subtableCode,
|
|
|
6476
6687
|
]
|
|
6477
6688
|
};
|
|
6478
6689
|
}
|
|
6479
|
-
function evalAssignmentValueForSubtable(value, row) {
|
|
6690
|
+
function evalAssignmentValueForSubtable(value, row, resolveFieldType) {
|
|
6480
6691
|
if (value.type === "STRING") return value.value;
|
|
6481
6692
|
if (value.type === "NUMBER") return String(value.value);
|
|
6482
6693
|
if (value.type === "ARITH") return String(evalArithExpr(value, row));
|
|
6483
|
-
if (value.type === "CASE_VALUE") return evalCaseWhen(value.expr, row);
|
|
6694
|
+
if (value.type === "CASE_VALUE") return evalCaseWhen(value.expr, row, resolveFieldType);
|
|
6484
6695
|
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
6696
|
}
|
|
6486
6697
|
function valueToString(value) {
|
|
@@ -6512,7 +6723,15 @@ function hasRidCondition(where) {
|
|
|
6512
6723
|
return false;
|
|
6513
6724
|
}
|
|
6514
6725
|
}
|
|
6515
|
-
async function executeReorder(stmt, client, options,
|
|
6726
|
+
async function executeReorder(stmt, client, options, cacheContext) {
|
|
6727
|
+
const typedInRefs = [];
|
|
6728
|
+
collectTypedInFieldRefs(stmt.where, typedInRefs);
|
|
6729
|
+
const resolveFieldType = await buildSubtableFieldTypeResolver(
|
|
6730
|
+
stmt.appId,
|
|
6731
|
+
typedInRefs,
|
|
6732
|
+
client,
|
|
6733
|
+
cacheContext
|
|
6734
|
+
);
|
|
6516
6735
|
const parents = await fetchAll(
|
|
6517
6736
|
client.getRecords,
|
|
6518
6737
|
stmt.appId,
|
|
@@ -6521,7 +6740,7 @@ async function executeReorder(stmt, client, options, _cacheContext) {
|
|
|
6521
6740
|
{ maxRecords: options.maxRecords ?? 1e4, parallel: options.fetchParallel ?? 1 }
|
|
6522
6741
|
);
|
|
6523
6742
|
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));
|
|
6743
|
+
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
6744
|
if (options.confirm) {
|
|
6526
6745
|
const ok = await options.confirm(targetParentIds.size, "UPDATE");
|
|
6527
6746
|
if (!ok) throw new OperationCancelledError("UPDATE", targetParentIds.size);
|
|
@@ -6666,6 +6885,16 @@ async function resolveSubqueries(where, client, options, cacheContext, cteCache)
|
|
|
6666
6885
|
collectSubqueryTasks(where, client, options, cacheContext, tasks, cteCache);
|
|
6667
6886
|
await Promise.all(tasks);
|
|
6668
6887
|
}
|
|
6888
|
+
async function resolveSelectCaseSubqueries(stmt, client, options, cacheContext, cteCache) {
|
|
6889
|
+
const tasks = [];
|
|
6890
|
+
for (const column of stmt.columns) {
|
|
6891
|
+
if (column.type !== "CASE_COL") continue;
|
|
6892
|
+
for (const branch of column.expr.branches) {
|
|
6893
|
+
tasks.push(resolveSubqueries(branch.condition, client, options, cacheContext, cteCache));
|
|
6894
|
+
}
|
|
6895
|
+
}
|
|
6896
|
+
await Promise.all(tasks);
|
|
6897
|
+
}
|
|
6669
6898
|
function runSubquery(query, client, options, cacheContext, cteCache) {
|
|
6670
6899
|
if (cteCache !== void 0 && cteCache.size > 0) {
|
|
6671
6900
|
return executeQueryWithCte(query, client, options, cteCache, cacheContext);
|
|
@@ -7595,6 +7824,42 @@ function clampInt(v, min, max) {
|
|
|
7595
7824
|
return Math.max(min, Math.min(max, Math.trunc(v)));
|
|
7596
7825
|
}
|
|
7597
7826
|
|
|
7827
|
+
// src/core/formFieldInfo.ts
|
|
7828
|
+
function flattenFormFieldProperties(properties) {
|
|
7829
|
+
const out = [];
|
|
7830
|
+
for (const field of Object.values(properties)) {
|
|
7831
|
+
out.push({
|
|
7832
|
+
code: field.code,
|
|
7833
|
+
label: field.label,
|
|
7834
|
+
fieldType: field.type,
|
|
7835
|
+
optionOrder: toOptionOrderMap(field.options),
|
|
7836
|
+
sortKind: detectSortKind(field.type, field.format)
|
|
7837
|
+
});
|
|
7838
|
+
if (field.fields) out.push(...flattenFormFieldProperties(field.fields));
|
|
7839
|
+
}
|
|
7840
|
+
return out;
|
|
7841
|
+
}
|
|
7842
|
+
function toOptionOrderMap(options) {
|
|
7843
|
+
if (!options || typeof options !== "object") return void 0;
|
|
7844
|
+
const order = {};
|
|
7845
|
+
let hasAny = false;
|
|
7846
|
+
for (const [label, meta] of Object.entries(options)) {
|
|
7847
|
+
const n = Number(meta?.index);
|
|
7848
|
+
if (!Number.isFinite(n)) continue;
|
|
7849
|
+
order[label] = n;
|
|
7850
|
+
hasAny = true;
|
|
7851
|
+
}
|
|
7852
|
+
return hasAny ? order : void 0;
|
|
7853
|
+
}
|
|
7854
|
+
function detectSortKind(fieldType, calcFormat) {
|
|
7855
|
+
if (fieldType === "NUMBER" || fieldType === "RECORD_NUMBER") return "number";
|
|
7856
|
+
if (fieldType === "CALC") {
|
|
7857
|
+
if (calcFormat === "NUMBER" || calcFormat === "NUMBER_DIGIT") return "number";
|
|
7858
|
+
return "string";
|
|
7859
|
+
}
|
|
7860
|
+
return void 0;
|
|
7861
|
+
}
|
|
7862
|
+
|
|
7598
7863
|
// src/cli/nodeKintoneClient.ts
|
|
7599
7864
|
function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
7600
7865
|
const normalizedBaseUrl = baseUrl.replace(/\/+$/, "");
|
|
@@ -7773,36 +8038,10 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
|
7773
8038
|
{ method: "GET" },
|
|
7774
8039
|
appId
|
|
7775
8040
|
);
|
|
7776
|
-
return
|
|
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
|
-
}));
|
|
8041
|
+
return flattenFormFieldProperties(res.properties);
|
|
7783
8042
|
}
|
|
7784
8043
|
};
|
|
7785
8044
|
}
|
|
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
8045
|
|
|
7807
8046
|
// src/node/appProfiles.ts
|
|
7808
8047
|
var import_fs = require("fs");
|
package/dist-mcp/ksql-mcp.js
CHANGED
|
@@ -34409,52 +34409,91 @@ 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
return parsed.some((item) => values.has(item));
|
|
34486
|
+
}
|
|
34487
|
+
if (OBJECT_ARRAY_FIELD_TYPES.has(fieldType)) {
|
|
34488
|
+
if (!Array.isArray(parsed) || !parsed.every(hasStringCode)) return fallback();
|
|
34489
|
+
return parsed.some((item) => values.has(item.code));
|
|
34490
|
+
}
|
|
34491
|
+
if (!hasStringCode(parsed)) return fallback();
|
|
34492
|
+
return values.has(parsed.code);
|
|
34493
|
+
}
|
|
34494
|
+
function hasStringCode(value) {
|
|
34495
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) && typeof value.code === "string";
|
|
34496
|
+
}
|
|
34458
34497
|
function assertResolvedInListValues2(values) {
|
|
34459
34498
|
const unresolved = values.find((item) => item.type === "VARIABLE");
|
|
34460
34499
|
if (unresolved?.type === "VARIABLE") {
|
|
@@ -34465,20 +34504,20 @@ function evalNullCheck(expr, row) {
|
|
|
34465
34504
|
const val = resolveField(expr.field, row);
|
|
34466
34505
|
return expr.not ? val !== "" : val === "";
|
|
34467
34506
|
}
|
|
34468
|
-
function evalLogical(expr, row) {
|
|
34507
|
+
function evalLogical(expr, row, resolveFieldType) {
|
|
34469
34508
|
if (expr.op === "AND") {
|
|
34470
|
-
return evalWhere(expr.left, row) && evalWhere(expr.right, row);
|
|
34509
|
+
return evalWhere(expr.left, row, resolveFieldType) && evalWhere(expr.right, row, resolveFieldType);
|
|
34471
34510
|
}
|
|
34472
|
-
return evalWhere(expr.left, row) || evalWhere(expr.right, row);
|
|
34511
|
+
return evalWhere(expr.left, row, resolveFieldType) || evalWhere(expr.right, row, resolveFieldType);
|
|
34473
34512
|
}
|
|
34474
|
-
function resolveField(field, row) {
|
|
34513
|
+
function resolveField(field, row, resolveFieldType) {
|
|
34475
34514
|
if (field.type === "FUNC_FIELD") return evalStringFunc(field.expr, row);
|
|
34476
34515
|
if (field.type === "ARITH_FIELD") return String(evalArithExpr(field.expr, row));
|
|
34477
|
-
if (field.type === "CASE_FIELD") return evalCaseWhen(field.expr, row);
|
|
34516
|
+
if (field.type === "CASE_FIELD") return evalCaseWhen(field.expr, row, resolveFieldType);
|
|
34478
34517
|
const key = field.tableAlias ? `${field.tableAlias}.${field.field}` : field.field;
|
|
34479
34518
|
return resolveFieldRef(row, key);
|
|
34480
34519
|
}
|
|
34481
|
-
function resolveValue(value, row) {
|
|
34520
|
+
function resolveValue(value, row, resolveFieldType) {
|
|
34482
34521
|
switch (value.type) {
|
|
34483
34522
|
case "VARIABLE":
|
|
34484
34523
|
throw new Error(`ParseError: unresolved batch variable @${value.name}.`);
|
|
@@ -34501,14 +34540,14 @@ function resolveValue(value, row) {
|
|
|
34501
34540
|
if (value.expr.type === "STRING_FUNC") return evalStringFunc(value.expr, row);
|
|
34502
34541
|
return String(evalArithExpr(value.expr, row));
|
|
34503
34542
|
case "CASE_VALUE":
|
|
34504
|
-
return evalCaseWhen(value.expr, row);
|
|
34543
|
+
return evalCaseWhen(value.expr, row, resolveFieldType);
|
|
34505
34544
|
case "ARRAY":
|
|
34506
34545
|
return value.elements.map((e) => e.value).join(",");
|
|
34507
34546
|
}
|
|
34508
34547
|
}
|
|
34509
|
-
function evalCaseWhen(expr, row) {
|
|
34548
|
+
function evalCaseWhen(expr, row, resolveFieldType) {
|
|
34510
34549
|
for (const branch of expr.branches) {
|
|
34511
|
-
if (evalWhere(branch.condition, row)) {
|
|
34550
|
+
if (evalWhere(branch.condition, row, resolveFieldType)) {
|
|
34512
34551
|
return evalCaseResult(branch.result, row);
|
|
34513
34552
|
}
|
|
34514
34553
|
}
|
|
@@ -35175,9 +35214,9 @@ function applyJoin(leftRows, rightRows, join) {
|
|
|
35175
35214
|
}
|
|
35176
35215
|
return result;
|
|
35177
35216
|
}
|
|
35178
|
-
function applyFilter(rows, where) {
|
|
35217
|
+
function applyFilter(rows, where, resolveFieldType) {
|
|
35179
35218
|
if (where === null) return rows;
|
|
35180
|
-
return rows.filter((row) => evalWhere(where, row));
|
|
35219
|
+
return rows.filter((row) => evalWhere(where, row, resolveFieldType));
|
|
35181
35220
|
}
|
|
35182
35221
|
function hasAggregateColumns(columns) {
|
|
35183
35222
|
return columns.some(
|
|
@@ -35303,9 +35342,9 @@ function aggregateSyntheticName2(func, distinct, arg) {
|
|
|
35303
35342
|
const argStr = aggregateArgLabel(arg);
|
|
35304
35343
|
return distinct ? `${func}(DISTINCT ${argStr})` : `${func}(${argStr})`;
|
|
35305
35344
|
}
|
|
35306
|
-
function applyHaving(rows, having) {
|
|
35345
|
+
function applyHaving(rows, having, resolveFieldType) {
|
|
35307
35346
|
if (having === null) return rows;
|
|
35308
|
-
return rows.filter((row) => evalWhere(having, row));
|
|
35347
|
+
return rows.filter((row) => evalWhere(having, row, resolveFieldType));
|
|
35309
35348
|
}
|
|
35310
35349
|
function applyDistinct(rows, columns) {
|
|
35311
35350
|
if (rows.length === 0) return rows;
|
|
@@ -35430,7 +35469,7 @@ function applyLimit(rows, limit, offset) {
|
|
|
35430
35469
|
if (limit === null) return rows.slice(start);
|
|
35431
35470
|
return rows.slice(start, start + limit);
|
|
35432
35471
|
}
|
|
35433
|
-
function project(rows, columns, scalarCache) {
|
|
35472
|
+
function project(rows, columns, scalarCache, resolveFieldType) {
|
|
35434
35473
|
if (columns.length === 1 && columns[0].type === "WILDCARD") {
|
|
35435
35474
|
const projected2 = rows.map((row) => stripParentShortcutColumns(row));
|
|
35436
35475
|
const cols = projected2.length > 0 ? Object.keys(projected2[0]) : [];
|
|
@@ -35491,7 +35530,7 @@ function project(rows, columns, scalarCache) {
|
|
|
35491
35530
|
}
|
|
35492
35531
|
case "CASE_COL": {
|
|
35493
35532
|
const key = outputKeys?.[colIdx] ?? col.alias ?? "case";
|
|
35494
|
-
out[key] = evalCaseWhen(col.expr, row);
|
|
35533
|
+
out[key] = evalCaseWhen(col.expr, row, resolveFieldType);
|
|
35495
35534
|
if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
|
|
35496
35535
|
break;
|
|
35497
35536
|
}
|
|
@@ -35627,7 +35666,15 @@ function resolveAggInStringFuncExpr(expr, rows) {
|
|
|
35627
35666
|
};
|
|
35628
35667
|
}
|
|
35629
35668
|
function runFullScan(input) {
|
|
35630
|
-
const {
|
|
35669
|
+
const {
|
|
35670
|
+
stmt,
|
|
35671
|
+
tables,
|
|
35672
|
+
scalarCache,
|
|
35673
|
+
optionOrders,
|
|
35674
|
+
sortKinds,
|
|
35675
|
+
fieldTypeResolver,
|
|
35676
|
+
havingFieldTypeResolver
|
|
35677
|
+
} = input;
|
|
35631
35678
|
let rows = [];
|
|
35632
35679
|
const mainAlias = stmt.from.alias;
|
|
35633
35680
|
const mainRecords = tables.get(mainAlias) ?? tables.get(null) ?? [];
|
|
@@ -35638,17 +35685,17 @@ function runFullScan(input) {
|
|
|
35638
35685
|
const rightRows = rightRecords.map((r) => flatten(r, rightAlias));
|
|
35639
35686
|
rows = applyJoin(rows, rightRows, join);
|
|
35640
35687
|
}
|
|
35641
|
-
rows = applyFilter(rows, stmt.where);
|
|
35688
|
+
rows = applyFilter(rows, stmt.where, fieldTypeResolver);
|
|
35642
35689
|
if (stmt.groupBy.length > 0 || hasAggregateColumns(stmt.columns)) {
|
|
35643
35690
|
rows = applyGroupBy(rows, stmt.groupBy, stmt.columns);
|
|
35644
35691
|
}
|
|
35645
|
-
rows = applyHaving(rows, stmt.having);
|
|
35692
|
+
rows = applyHaving(rows, stmt.having, havingFieldTypeResolver);
|
|
35646
35693
|
if (stmt.distinct) {
|
|
35647
35694
|
rows = applyDistinct(rows, stmt.columns);
|
|
35648
35695
|
}
|
|
35649
35696
|
rows = applyOrderBy(rows, stmt.orderBy, optionOrders, sortKinds);
|
|
35650
35697
|
rows = applyLimit(rows, stmt.limit, stmt.offset);
|
|
35651
|
-
return project(rows, stmt.columns, scalarCache);
|
|
35698
|
+
return project(rows, stmt.columns, scalarCache, fieldTypeResolver);
|
|
35652
35699
|
}
|
|
35653
35700
|
|
|
35654
35701
|
// src/converter/subtableAdapter.ts
|
|
@@ -36181,6 +36228,7 @@ async function executeSelect(stmt, client, options, cacheContext, cteCache) {
|
|
|
36181
36228
|
if (isNoFromSelect(stmt)) {
|
|
36182
36229
|
return executeNoFromSelect(stmt);
|
|
36183
36230
|
}
|
|
36231
|
+
await resolveSelectCaseSubqueries(stmt, client, options, cacheContext, cteCache);
|
|
36184
36232
|
const mode = resolveSelectMode(stmt);
|
|
36185
36233
|
await validateSelectFieldCodes(stmt, mode, client, cacheContext);
|
|
36186
36234
|
if (mode === "SIMPLE") {
|
|
@@ -36239,6 +36287,8 @@ function executeNoFromSelect(stmt) {
|
|
|
36239
36287
|
}
|
|
36240
36288
|
async function executeSimpleSelect(stmt, client, options, cacheContext) {
|
|
36241
36289
|
const params = selectToKintoneParams(stmt);
|
|
36290
|
+
const typedInFieldTypes = await loadTypedInFieldTypes(stmt, client, cacheContext);
|
|
36291
|
+
const fieldTypeResolvers = buildSelectFieldTypeResolvers(stmt, typedInFieldTypes);
|
|
36242
36292
|
const maxRecords2 = options.maxRecords ?? 1e4;
|
|
36243
36293
|
const warnings = /* @__PURE__ */ new Set();
|
|
36244
36294
|
const onLimit2 = options.onLimitReached ?? "error";
|
|
@@ -36275,7 +36325,12 @@ async function executeSimpleSelect(stmt, client, options, cacheContext) {
|
|
|
36275
36325
|
rows = applyOrderBy(rows, stmt.orderBy, optionOrders, sortKinds);
|
|
36276
36326
|
rows = applyLimit(rows, stmt.limit, stmt.offset);
|
|
36277
36327
|
}
|
|
36278
|
-
const { rows: projected, columns } = project(
|
|
36328
|
+
const { rows: projected, columns } = project(
|
|
36329
|
+
rows,
|
|
36330
|
+
stmt.columns,
|
|
36331
|
+
void 0,
|
|
36332
|
+
fieldTypeResolvers.row
|
|
36333
|
+
);
|
|
36279
36334
|
return { type: "SELECT", rows: projected, columns, rowCount: projected.length, warnings: [...warnings] };
|
|
36280
36335
|
}
|
|
36281
36336
|
async function validateSelectFieldCodes(stmt, mode, client, cacheContext) {
|
|
@@ -36348,6 +36403,108 @@ async function loadNumericPushdownFieldTypes(stmt, client, cacheContext) {
|
|
|
36348
36403
|
const entries = await Promise.all([...appIds].map(async (appId) => [appId, await getFieldTypeMap(appId, client, cacheContext)]));
|
|
36349
36404
|
return new Map(entries);
|
|
36350
36405
|
}
|
|
36406
|
+
function collectTypedInFieldRefs(expr, out) {
|
|
36407
|
+
if (expr === null) return;
|
|
36408
|
+
switch (expr.type) {
|
|
36409
|
+
case "BINARY":
|
|
36410
|
+
if ((expr.op === "IN" || expr.op === "NOT_IN") && expr.left.type === "FIELD") {
|
|
36411
|
+
out.push(expr.left);
|
|
36412
|
+
}
|
|
36413
|
+
if (expr.left.type === "CASE_FIELD") collectCaseTypedInFieldRefs(expr.left.expr, out);
|
|
36414
|
+
if (expr.right.type === "CASE_VALUE") collectCaseTypedInFieldRefs(expr.right.expr, out);
|
|
36415
|
+
return;
|
|
36416
|
+
case "LOGICAL":
|
|
36417
|
+
collectTypedInFieldRefs(expr.left, out);
|
|
36418
|
+
collectTypedInFieldRefs(expr.right, out);
|
|
36419
|
+
return;
|
|
36420
|
+
case "NOT":
|
|
36421
|
+
case "GROUP":
|
|
36422
|
+
collectTypedInFieldRefs(expr.expr, out);
|
|
36423
|
+
return;
|
|
36424
|
+
case "NULL_CHECK":
|
|
36425
|
+
case "EXISTS":
|
|
36426
|
+
return;
|
|
36427
|
+
}
|
|
36428
|
+
}
|
|
36429
|
+
function collectCaseTypedInFieldRefs(expr, out) {
|
|
36430
|
+
for (const branch of expr.branches) collectTypedInFieldRefs(branch.condition, out);
|
|
36431
|
+
}
|
|
36432
|
+
function collectSelectTypedInFieldRefs(stmt) {
|
|
36433
|
+
const refs = [];
|
|
36434
|
+
collectTypedInFieldRefs(stmt.where, refs);
|
|
36435
|
+
collectTypedInFieldRefs(stmt.having, refs);
|
|
36436
|
+
for (const column of stmt.columns) {
|
|
36437
|
+
if (column.type === "CASE_COL") collectCaseTypedInFieldRefs(column.expr, refs);
|
|
36438
|
+
}
|
|
36439
|
+
return refs;
|
|
36440
|
+
}
|
|
36441
|
+
function findTableForAlias(stmt, alias) {
|
|
36442
|
+
return [stmt.from, ...stmt.joins.map((join) => join.table)].find((table) => table.alias === alias);
|
|
36443
|
+
}
|
|
36444
|
+
function physicalSelectTables(stmt) {
|
|
36445
|
+
return [stmt.from, ...stmt.joins.map((join) => join.table)].filter((table) => table.cteName === null);
|
|
36446
|
+
}
|
|
36447
|
+
async function loadTypedInFieldTypes(stmt, client, cacheContext) {
|
|
36448
|
+
const refs = collectSelectTypedInFieldRefs(stmt);
|
|
36449
|
+
if (refs.length === 0) return /* @__PURE__ */ new Map();
|
|
36450
|
+
const appIds = /* @__PURE__ */ new Set();
|
|
36451
|
+
const physicalTables = physicalSelectTables(stmt);
|
|
36452
|
+
for (const ref of refs) {
|
|
36453
|
+
if (ref.tableAlias !== null) {
|
|
36454
|
+
if (ref.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
|
|
36455
|
+
appIds.add(stmt.from.appId);
|
|
36456
|
+
continue;
|
|
36457
|
+
}
|
|
36458
|
+
const table = findTableForAlias(stmt, ref.tableAlias);
|
|
36459
|
+
if (table && table.cteName === null) appIds.add(table.appId);
|
|
36460
|
+
continue;
|
|
36461
|
+
}
|
|
36462
|
+
if (stmt.joins.length === 0) {
|
|
36463
|
+
if (stmt.from.cteName === null) appIds.add(stmt.from.appId);
|
|
36464
|
+
continue;
|
|
36465
|
+
}
|
|
36466
|
+
for (const table of physicalTables) appIds.add(table.appId);
|
|
36467
|
+
}
|
|
36468
|
+
const entries = await Promise.all([...appIds].map(async (appId) => [appId, await getFieldTypeMap(appId, client, cacheContext)]));
|
|
36469
|
+
return new Map(entries);
|
|
36470
|
+
}
|
|
36471
|
+
function fieldCodeForTypeLookup(table, field) {
|
|
36472
|
+
if (table.subtableCode && field.startsWith("_p.")) return field.slice(3);
|
|
36473
|
+
return field;
|
|
36474
|
+
}
|
|
36475
|
+
function buildSelectFieldTypeResolvers(stmt, fieldTypesByApp) {
|
|
36476
|
+
const tables = [stmt.from, ...stmt.joins.map((join) => join.table)];
|
|
36477
|
+
const physicalTables = tables.filter((table) => table.cteName === null);
|
|
36478
|
+
const outputAliases = new Set(
|
|
36479
|
+
stmt.columns.map((column) => "alias" in column ? column.alias : null).filter((alias) => alias !== null)
|
|
36480
|
+
);
|
|
36481
|
+
const row = (field) => {
|
|
36482
|
+
if (field.tableAlias !== null) {
|
|
36483
|
+
if (field.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
|
|
36484
|
+
return fieldTypesByApp.get(stmt.from.appId)?.get(field.field);
|
|
36485
|
+
}
|
|
36486
|
+
const table2 = tables.find((candidate) => candidate.alias === field.tableAlias);
|
|
36487
|
+
if (!table2 || table2.cteName !== null) return void 0;
|
|
36488
|
+
return fieldTypesByApp.get(table2.appId)?.get(fieldCodeForTypeLookup(table2, field.field));
|
|
36489
|
+
}
|
|
36490
|
+
if (stmt.joins.length === 0) {
|
|
36491
|
+
if (stmt.from.cteName !== null) return void 0;
|
|
36492
|
+
return fieldTypesByApp.get(stmt.from.appId)?.get(fieldCodeForTypeLookup(stmt.from, field.field));
|
|
36493
|
+
}
|
|
36494
|
+
if (tables.some((table2) => table2.cteName !== null)) return void 0;
|
|
36495
|
+
const matches = physicalTables.filter(
|
|
36496
|
+
(table2) => fieldTypesByApp.get(table2.appId)?.has(fieldCodeForTypeLookup(table2, field.field))
|
|
36497
|
+
);
|
|
36498
|
+
if (matches.length !== 1) return void 0;
|
|
36499
|
+
const table = matches[0];
|
|
36500
|
+
return fieldTypesByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, field.field));
|
|
36501
|
+
};
|
|
36502
|
+
const having = (field) => {
|
|
36503
|
+
if (field.tableAlias === null && outputAliases.has(field.field)) return void 0;
|
|
36504
|
+
return row(field);
|
|
36505
|
+
};
|
|
36506
|
+
return { row, having };
|
|
36507
|
+
}
|
|
36351
36508
|
async function executeFullScanSelect(stmt, client, options, cacheContext, cteCache) {
|
|
36352
36509
|
const maxRecords2 = options.maxRecords ?? 1e4;
|
|
36353
36510
|
const warnings = /* @__PURE__ */ new Set();
|
|
@@ -36356,7 +36513,11 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
|
|
|
36356
36513
|
resolveSubqueries(stmt.where, client, options, cacheContext, cteCache),
|
|
36357
36514
|
resolveSubqueries(stmt.having, client, options, cacheContext, cteCache)
|
|
36358
36515
|
]);
|
|
36359
|
-
const pushdownFieldTypes = await
|
|
36516
|
+
const [pushdownFieldTypes, typedInFieldTypes] = await Promise.all([
|
|
36517
|
+
loadNumericPushdownFieldTypes(stmt, client, cacheContext),
|
|
36518
|
+
loadTypedInFieldTypes(stmt, client, cacheContext)
|
|
36519
|
+
]);
|
|
36520
|
+
const fieldTypeResolvers = buildSelectFieldTypeResolvers(stmt, typedInFieldTypes);
|
|
36360
36521
|
const mainPushDown = extractMainSafePushdown(
|
|
36361
36522
|
stmt,
|
|
36362
36523
|
pushdownFieldTypes.get(stmt.from.appId)
|
|
@@ -36445,7 +36606,15 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
|
|
|
36445
36606
|
}));
|
|
36446
36607
|
const scalarCache = await scalarCachePromise;
|
|
36447
36608
|
const { optionOrders, sortKinds } = await orderByMetaPromise;
|
|
36448
|
-
const { rows, columns } = runFullScan({
|
|
36609
|
+
const { rows, columns } = runFullScan({
|
|
36610
|
+
tables,
|
|
36611
|
+
stmt,
|
|
36612
|
+
scalarCache,
|
|
36613
|
+
optionOrders,
|
|
36614
|
+
sortKinds,
|
|
36615
|
+
fieldTypeResolver: fieldTypeResolvers.row,
|
|
36616
|
+
havingFieldTypeResolver: fieldTypeResolvers.having
|
|
36617
|
+
});
|
|
36449
36618
|
return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [...warnings] };
|
|
36450
36619
|
}
|
|
36451
36620
|
async function executeUnion(stmt, client, options, cacheContext) {
|
|
@@ -36601,8 +36770,11 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
|
|
|
36601
36770
|
const parallel = options.fetchParallel ?? 1;
|
|
36602
36771
|
await Promise.all([
|
|
36603
36772
|
resolveSubqueries(stmt.where, client, options, cacheContext, cteCache),
|
|
36604
|
-
resolveSubqueries(stmt.having, client, options, cacheContext, cteCache)
|
|
36773
|
+
resolveSubqueries(stmt.having, client, options, cacheContext, cteCache),
|
|
36774
|
+
resolveSelectCaseSubqueries(stmt, client, options, cacheContext, cteCache)
|
|
36605
36775
|
]);
|
|
36776
|
+
const typedInFieldTypes = await loadTypedInFieldTypes(stmt, client, cacheContext);
|
|
36777
|
+
const fieldTypeResolvers = buildSelectFieldTypeResolvers(stmt, typedInFieldTypes);
|
|
36606
36778
|
const scalarCachePromise = resolveScalarColumns(stmt.columns, client, options, cacheContext, cteCache);
|
|
36607
36779
|
const orderByMetaPromise = buildOrderByMetaForSelect(stmt, client, cacheContext);
|
|
36608
36780
|
scalarCachePromise.catch(() => {
|
|
@@ -36657,7 +36829,15 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
|
|
|
36657
36829
|
await Promise.all(joinFetches);
|
|
36658
36830
|
const scalarCache = await scalarCachePromise;
|
|
36659
36831
|
const { optionOrders, sortKinds } = await orderByMetaPromise;
|
|
36660
|
-
const { rows, columns } = runFullScan({
|
|
36832
|
+
const { rows, columns } = runFullScan({
|
|
36833
|
+
tables,
|
|
36834
|
+
stmt,
|
|
36835
|
+
scalarCache,
|
|
36836
|
+
optionOrders,
|
|
36837
|
+
sortKinds,
|
|
36838
|
+
fieldTypeResolver: fieldTypeResolvers.row,
|
|
36839
|
+
havingFieldTypeResolver: fieldTypeResolvers.having
|
|
36840
|
+
});
|
|
36661
36841
|
return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [...warnings] };
|
|
36662
36842
|
}
|
|
36663
36843
|
function processRowToKintoneRecord(row) {
|
|
@@ -37154,6 +37334,16 @@ async function executeUpsert(stmt, client, options, cacheContext) {
|
|
|
37154
37334
|
updatedCount: toUpdate.length
|
|
37155
37335
|
};
|
|
37156
37336
|
}
|
|
37337
|
+
async function buildSubtableFieldTypeResolver(appId, typedInRefs, client, cacheContext) {
|
|
37338
|
+
if (typedInRefs.length === 0) return void 0;
|
|
37339
|
+
const fieldTypes = await getFieldTypeMap(appId, client, cacheContext);
|
|
37340
|
+
return (field) => {
|
|
37341
|
+
if (field.tableAlias !== null && field.tableAlias !== "_p") return void 0;
|
|
37342
|
+
if (field.tableAlias === "_p") return fieldTypes.get(field.field);
|
|
37343
|
+
const code = field.field.startsWith("_p.") ? field.field.slice(3) : field.field;
|
|
37344
|
+
return fieldTypes.get(code);
|
|
37345
|
+
};
|
|
37346
|
+
}
|
|
37157
37347
|
async function executeInsertSubtable(stmt, client, options, _cacheContext) {
|
|
37158
37348
|
const subtableCode = stmt.subtableCode;
|
|
37159
37349
|
const pidIndex = stmt.fields.indexOf("_pid");
|
|
@@ -37194,11 +37384,24 @@ async function executeInsertSubtable(stmt, client, options, _cacheContext) {
|
|
|
37194
37384
|
}
|
|
37195
37385
|
return { type: "INSERT", createdIds: [], insertedCount: stmt.values.length };
|
|
37196
37386
|
}
|
|
37197
|
-
async function executeUpdateSubtable(stmt, client, options,
|
|
37387
|
+
async function executeUpdateSubtable(stmt, client, options, cacheContext) {
|
|
37198
37388
|
const subtableCode = stmt.subtableCode;
|
|
37199
37389
|
if (!hasRidCondition(stmt.where)) {
|
|
37200
37390
|
throw new Error("\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB UPDATE \u306B\u306F _rid \u6761\u4EF6\u304C\u5FC5\u9808\u3067\u3059");
|
|
37201
37391
|
}
|
|
37392
|
+
const typedInRefs = [];
|
|
37393
|
+
collectTypedInFieldRefs(stmt.where, typedInRefs);
|
|
37394
|
+
for (const assignment of stmt.assignments) {
|
|
37395
|
+
if (assignment.value.type === "CASE_VALUE") {
|
|
37396
|
+
collectCaseTypedInFieldRefs(assignment.value.expr, typedInRefs);
|
|
37397
|
+
}
|
|
37398
|
+
}
|
|
37399
|
+
const resolveFieldType = await buildSubtableFieldTypeResolver(
|
|
37400
|
+
stmt.appId,
|
|
37401
|
+
typedInRefs,
|
|
37402
|
+
client,
|
|
37403
|
+
cacheContext
|
|
37404
|
+
);
|
|
37202
37405
|
const parents = await fetchAll(
|
|
37203
37406
|
client.getRecords,
|
|
37204
37407
|
stmt.appId,
|
|
@@ -37207,7 +37410,7 @@ async function executeUpdateSubtable(stmt, client, options, _cacheContext) {
|
|
|
37207
37410
|
{ maxRecords: options.maxRecords ?? 1e4, parallel: options.fetchParallel ?? 1 }
|
|
37208
37411
|
);
|
|
37209
37412
|
const expanded = expandRowsForSubtableDml(parents, subtableCode);
|
|
37210
|
-
const targets = expanded.filter((r) => evalWhere(stmt.where, r.flat));
|
|
37413
|
+
const targets = expanded.filter((r) => evalWhere(stmt.where, r.flat, resolveFieldType));
|
|
37211
37414
|
if (options.confirm) {
|
|
37212
37415
|
const ok = await options.confirm(targets.length, "UPDATE");
|
|
37213
37416
|
if (!ok) throw new OperationCancelledError("UPDATE", targets.length);
|
|
@@ -37227,7 +37430,7 @@ async function executeUpdateSubtable(stmt, client, options, _cacheContext) {
|
|
|
37227
37430
|
if (a.field.startsWith("_")) {
|
|
37228
37431
|
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
37432
|
}
|
|
37230
|
-
updates[a.field] = { value: evalAssignmentValueForSubtable(a.value, t.flat) };
|
|
37433
|
+
updates[a.field] = { value: evalAssignmentValueForSubtable(a.value, t.flat, resolveFieldType) };
|
|
37231
37434
|
}
|
|
37232
37435
|
byRid.set(t.rowId, updates);
|
|
37233
37436
|
}
|
|
@@ -37249,11 +37452,19 @@ async function executeUpdateSubtable(stmt, client, options, _cacheContext) {
|
|
|
37249
37452
|
}
|
|
37250
37453
|
return { type: "UPDATE", updatedCount: targets.length };
|
|
37251
37454
|
}
|
|
37252
|
-
async function executeDeleteSubtable(stmt, client, options,
|
|
37455
|
+
async function executeDeleteSubtable(stmt, client, options, cacheContext) {
|
|
37253
37456
|
const subtableCode = stmt.subtableCode;
|
|
37254
37457
|
if (!hasRidCondition(stmt.where)) {
|
|
37255
37458
|
throw new Error("\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB DELETE \u306B\u306F _rid \u6761\u4EF6\u304C\u5FC5\u9808\u3067\u3059");
|
|
37256
37459
|
}
|
|
37460
|
+
const typedInRefs = [];
|
|
37461
|
+
collectTypedInFieldRefs(stmt.where, typedInRefs);
|
|
37462
|
+
const resolveFieldType = await buildSubtableFieldTypeResolver(
|
|
37463
|
+
stmt.appId,
|
|
37464
|
+
typedInRefs,
|
|
37465
|
+
client,
|
|
37466
|
+
cacheContext
|
|
37467
|
+
);
|
|
37257
37468
|
const parents = await fetchAll(
|
|
37258
37469
|
client.getRecords,
|
|
37259
37470
|
stmt.appId,
|
|
@@ -37262,7 +37473,7 @@ async function executeDeleteSubtable(stmt, client, options, _cacheContext) {
|
|
|
37262
37473
|
{ maxRecords: options.maxRecords ?? 1e4, parallel: options.fetchParallel ?? 1 }
|
|
37263
37474
|
);
|
|
37264
37475
|
const expanded = expandRowsForSubtableDml(parents, subtableCode);
|
|
37265
|
-
const targets = expanded.filter((r) => evalWhere(stmt.where, r.flat));
|
|
37476
|
+
const targets = expanded.filter((r) => evalWhere(stmt.where, r.flat, resolveFieldType));
|
|
37266
37477
|
if (options.confirm) {
|
|
37267
37478
|
const ok = await options.confirm(targets.length, "DELETE");
|
|
37268
37479
|
if (!ok) throw new OperationCancelledError("DELETE", targets.length);
|
|
@@ -37377,11 +37588,11 @@ function buildSubtableReorderPutParams(appId, parentId, revision, subtableCode,
|
|
|
37377
37588
|
]
|
|
37378
37589
|
};
|
|
37379
37590
|
}
|
|
37380
|
-
function evalAssignmentValueForSubtable(value, row) {
|
|
37591
|
+
function evalAssignmentValueForSubtable(value, row, resolveFieldType) {
|
|
37381
37592
|
if (value.type === "STRING") return value.value;
|
|
37382
37593
|
if (value.type === "NUMBER") return String(value.value);
|
|
37383
37594
|
if (value.type === "ARITH") return String(evalArithExpr(value, row));
|
|
37384
|
-
if (value.type === "CASE_VALUE") return evalCaseWhen(value.expr, row);
|
|
37595
|
+
if (value.type === "CASE_VALUE") return evalCaseWhen(value.expr, row, resolveFieldType);
|
|
37385
37596
|
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
37597
|
}
|
|
37387
37598
|
function valueToString(value) {
|
|
@@ -37413,7 +37624,15 @@ function hasRidCondition(where) {
|
|
|
37413
37624
|
return false;
|
|
37414
37625
|
}
|
|
37415
37626
|
}
|
|
37416
|
-
async function executeReorder(stmt, client, options,
|
|
37627
|
+
async function executeReorder(stmt, client, options, cacheContext) {
|
|
37628
|
+
const typedInRefs = [];
|
|
37629
|
+
collectTypedInFieldRefs(stmt.where, typedInRefs);
|
|
37630
|
+
const resolveFieldType = await buildSubtableFieldTypeResolver(
|
|
37631
|
+
stmt.appId,
|
|
37632
|
+
typedInRefs,
|
|
37633
|
+
client,
|
|
37634
|
+
cacheContext
|
|
37635
|
+
);
|
|
37417
37636
|
const parents = await fetchAll(
|
|
37418
37637
|
client.getRecords,
|
|
37419
37638
|
stmt.appId,
|
|
@@ -37422,7 +37641,7 @@ async function executeReorder(stmt, client, options, _cacheContext) {
|
|
|
37422
37641
|
{ maxRecords: options.maxRecords ?? 1e4, parallel: options.fetchParallel ?? 1 }
|
|
37423
37642
|
);
|
|
37424
37643
|
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));
|
|
37644
|
+
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
37645
|
if (options.confirm) {
|
|
37427
37646
|
const ok = await options.confirm(targetParentIds.size, "UPDATE");
|
|
37428
37647
|
if (!ok) throw new OperationCancelledError("UPDATE", targetParentIds.size);
|
|
@@ -37567,6 +37786,16 @@ async function resolveSubqueries(where, client, options, cacheContext, cteCache)
|
|
|
37567
37786
|
collectSubqueryTasks(where, client, options, cacheContext, tasks, cteCache);
|
|
37568
37787
|
await Promise.all(tasks);
|
|
37569
37788
|
}
|
|
37789
|
+
async function resolveSelectCaseSubqueries(stmt, client, options, cacheContext, cteCache) {
|
|
37790
|
+
const tasks = [];
|
|
37791
|
+
for (const column of stmt.columns) {
|
|
37792
|
+
if (column.type !== "CASE_COL") continue;
|
|
37793
|
+
for (const branch of column.expr.branches) {
|
|
37794
|
+
tasks.push(resolveSubqueries(branch.condition, client, options, cacheContext, cteCache));
|
|
37795
|
+
}
|
|
37796
|
+
}
|
|
37797
|
+
await Promise.all(tasks);
|
|
37798
|
+
}
|
|
37570
37799
|
function runSubquery(query, client, options, cacheContext, cteCache) {
|
|
37571
37800
|
if (cteCache !== void 0 && cteCache.size > 0) {
|
|
37572
37801
|
return executeQueryWithCte(query, client, options, cteCache, cacheContext);
|
|
@@ -38489,6 +38718,42 @@ function clampInt(v, min, max) {
|
|
|
38489
38718
|
return Math.max(min, Math.min(max, Math.trunc(v)));
|
|
38490
38719
|
}
|
|
38491
38720
|
|
|
38721
|
+
// src/core/formFieldInfo.ts
|
|
38722
|
+
function flattenFormFieldProperties(properties) {
|
|
38723
|
+
const out = [];
|
|
38724
|
+
for (const field of Object.values(properties)) {
|
|
38725
|
+
out.push({
|
|
38726
|
+
code: field.code,
|
|
38727
|
+
label: field.label,
|
|
38728
|
+
fieldType: field.type,
|
|
38729
|
+
optionOrder: toOptionOrderMap(field.options),
|
|
38730
|
+
sortKind: detectSortKind(field.type, field.format)
|
|
38731
|
+
});
|
|
38732
|
+
if (field.fields) out.push(...flattenFormFieldProperties(field.fields));
|
|
38733
|
+
}
|
|
38734
|
+
return out;
|
|
38735
|
+
}
|
|
38736
|
+
function toOptionOrderMap(options) {
|
|
38737
|
+
if (!options || typeof options !== "object") return void 0;
|
|
38738
|
+
const order = {};
|
|
38739
|
+
let hasAny = false;
|
|
38740
|
+
for (const [label, meta3] of Object.entries(options)) {
|
|
38741
|
+
const n = Number(meta3?.index);
|
|
38742
|
+
if (!Number.isFinite(n)) continue;
|
|
38743
|
+
order[label] = n;
|
|
38744
|
+
hasAny = true;
|
|
38745
|
+
}
|
|
38746
|
+
return hasAny ? order : void 0;
|
|
38747
|
+
}
|
|
38748
|
+
function detectSortKind(fieldType, calcFormat) {
|
|
38749
|
+
if (fieldType === "NUMBER" || fieldType === "RECORD_NUMBER") return "number";
|
|
38750
|
+
if (fieldType === "CALC") {
|
|
38751
|
+
if (calcFormat === "NUMBER" || calcFormat === "NUMBER_DIGIT") return "number";
|
|
38752
|
+
return "string";
|
|
38753
|
+
}
|
|
38754
|
+
return void 0;
|
|
38755
|
+
}
|
|
38756
|
+
|
|
38492
38757
|
// src/cli/nodeKintoneClient.ts
|
|
38493
38758
|
function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
38494
38759
|
const normalizedBaseUrl = baseUrl.replace(/\/+$/, "");
|
|
@@ -38667,36 +38932,10 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
|
38667
38932
|
{ method: "GET" },
|
|
38668
38933
|
appId
|
|
38669
38934
|
);
|
|
38670
|
-
return
|
|
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
|
-
}));
|
|
38935
|
+
return flattenFormFieldProperties(res.properties);
|
|
38677
38936
|
}
|
|
38678
38937
|
};
|
|
38679
38938
|
}
|
|
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
38939
|
|
|
38701
38940
|
// src/node/appProfiles.ts
|
|
38702
38941
|
function parseTokenMap(raw) {
|
|
@@ -40156,7 +40395,7 @@ Options:
|
|
|
40156
40395
|
-h, --help Show help
|
|
40157
40396
|
`);
|
|
40158
40397
|
}
|
|
40159
|
-
var SERVER_VERSION = true ? "2.
|
|
40398
|
+
var SERVER_VERSION = true ? "2.5.0" : "0.0.0-dev";
|
|
40160
40399
|
function createServer(args) {
|
|
40161
40400
|
const server = new McpServer({
|
|
40162
40401
|
name: "ksql-mcp",
|
package/dist-mcpb/ksql-mcp.mcpb
CHANGED
|
Binary file
|