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:
parent
c90e63ec0f
commit
057274094d
2 changed files with 163 additions and 12 deletions
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue