fix(apiserver): apply CompConditions in ExecuteQuery so job-by-id actually filters (bug-1490 adjacent)

GetJobByIDs (GET /xce/v1/jobs/:jobids) built its job_id filter via
ConvertToNewFilterArray into QueryOptions.CompConditions, but ExecuteQuery
only ever applied opts.Conditions and silently dropped CompConditions. Every
per-id job query therefore returned the ENTIRE job table, and the MCP
scheduler_get_job tool returned the first job in the store regardless of the
requested id (observed: get_job(73930445842022400) -> "post-clean").

Fix: add FilterCompConditions (per-field AND, OR across ConditionArrays,
main-condition AND OR(sub-conditions) within an array) and run it in
ExecuteQuery after the flat filter; extract the bitmask-aware per-row match
into rowMatchesCondition shared by FilterRows and FilterCompConditions.

Verified via the MCP server: scheduler_get_job now returns the requested job
(mcp-e2e, EXIT), and the full submit->hold->release->cancel->get cycle still
works.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
lei.chen 2026-08-07 08:40:50 +00:00
parent c90e63ec0f
commit 057274094d
2 changed files with 163 additions and 12 deletions

View file

@ -17,10 +17,16 @@ func ExecuteQuery(rows []utils.OrderMap, opts *utils.QueryOptions, fields []stri
return SelectFields(rows, fields), ""
}
// 1. Filter
// 1. Filter — both the flat AND-conditions AND the compound (per-field OR,
// array-aware) conditions. bug-1490-adjacent: CompConditions used to be
// silently dropped here, so GET /xce/v1/jobs/:jobids returned the whole
// job table (the mcp scheduler_get_job tool never saw the requested job).
if len(opts.Conditions) > 0 {
rows = FilterRows(rows, opts.Conditions)
}
if len(opts.CompConditions) > 0 {
rows = FilterCompConditions(rows, opts.CompConditions)
}
// 2. Sort
if len(opts.Orders) > 0 {
@ -105,28 +111,76 @@ func IsBitmaskField(field string) bool {
return field == "job_status" || field == "host_status"
}
// rowMatchesCondition evaluates a single condition against a row, dispatching
// bitmask fields (job_status/host_status) to MatchesBitmaskCondition and all
// others to MatchesCondition.
func rowMatchesCondition(row utils.OrderMap, cond utils.Condition) bool {
if IsBitmaskField(cond.Column) {
bitmask, ok := cond.Value.Value.(int64)
if !ok {
return false
}
return MatchesBitmaskCondition(row, cond.Column, bitmask, cond.Operator)
}
return MatchesCondition(row, cond)
}
// FilterRows applies all conditions (AND logic) to rows.
func FilterRows(rows []utils.OrderMap, conditions []utils.Condition) []utils.OrderMap {
result := make([]utils.OrderMap, 0, len(rows))
for _, row := range rows {
match := true
for _, cond := range conditions {
if IsBitmaskField(cond.Column) {
bitmask, ok := cond.Value.Value.(int64)
if !ok {
match = false
if !rowMatchesCondition(row, cond) {
match = false
break
}
}
if match {
result = append(result, row)
}
}
return result
}
// FilterCompConditions applies compound conditions — the per-field OR structure
// built by ConvertToNewFilterArray for array-aware queries (e.g. job_id with
// array_idx sub-ranges in GET /xce/v1/jobs/:jobids, or job_name filters in
// GET /xce/v1/jobs). A row must match EVERY field key present (AND across
// fields); within a field, the row matches if ANY of its ConditionArrays
// matches. A ConditionArray matches when its MainCondition holds AND either it
// has no SubORConditions or any sub-condition holds.
func FilterCompConditions(rows []utils.OrderMap, comp utils.CompCondition) []utils.OrderMap {
if len(comp) == 0 {
return rows
}
result := make([]utils.OrderMap, 0, len(rows))
for _, row := range rows {
match := true
for _, arrays := range comp {
fieldMatch := false
for _, arr := range arrays {
if !rowMatchesCondition(row, arr.MainCondition) {
continue
}
if len(arr.SubORConditions) == 0 {
fieldMatch = true
break
}
if !MatchesBitmaskCondition(row, cond.Column, bitmask, cond.Operator) {
match = false
break
}
} else {
if !MatchesCondition(row, cond) {
match = false
for _, sub := range arr.SubORConditions {
if rowMatchesCondition(row, sub) {
fieldMatch = true
break
}
}
if fieldMatch {
break
}
}
if !fieldMatch {
match = false
break
}
}
if match {
result = append(result, row)