feat(job-array-one-based-index): selection predicate builder (task 7.2)

BuildSelectionPredicates converts each job_id/job_name filter entry
containing a bracketed value into one row predicate (values OR'ed,
entries AND'ed with each other and the plain conditions), removing only
that entry. Operators are honoured instead of dropped (bug-1898):
eq/in/between select, notin excludes, name pattern operators reuse
today's condition semantics on the name part, and ne / comparison /
null operators keep today's rejection. Element selections match only
array elements in range; bare identities match the whole array and any
ordinary job; an empty name under exact operators matches nothing.
Bare written keys are normalised to decimal on every path. Not yet
wired into the handlers.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Rongsong Shen 2026-10-01 12:09:47 +00:00
parent 2a8490bc92
commit 675d7d7f6c
Signed by untrusted user: rshen
GPG key ID: 80533536B0EB651C
3 changed files with 744 additions and 1 deletions

View file

@ -147,7 +147,7 @@
- _Boundary: ApiSel_
- _Depends: 5.1_
- [ ] 7.2 Build selection predicates
- [x] 7.2 Build selection predicates
- Turn each filter entry containing a bracketed value into one composed predicate (values OR'ed within the entry, entries AND'ed with each other and with plain conditions), converting the whole entry and only that entry
- Honour the operator: `eq`/`in` (and `between` on job identities) select, `notin` excludes, name pattern operators reuse today's condition semantics on the name part, `ne` and comparison/null operators keep today's "operator doesn't support" error, operators outside the field's table keep today's error
- Match identity elements only among array-marked rows, match empty names under exact operators to no row, and normalise written bare keys to decimal on both the plain and converted paths
@ -247,3 +247,4 @@
- 5.4: handler fixture in `controllers/jobs_handler_test.go` (`newHandlerFixture`, `seedJob`/`seedOrdinaryJob`/`seedArrayElements`/`seedQueue`, `submit`, `controlByID`, `controlByFilter`, `dispatchedIDs`, `submissions`); submit bodies must be client-style JSON maps (marshalled `models.JobSubmitRequest` breaks on zero CustomTime). Handlers are registered without `RequirePermission`; in-handler RBAC/queue/status checks still run.
- 6.1: the design's "saturate oversized numbers" rule alone loses the order of two oversized numbers; `ParseSubmitIndexExpr` compares leading-zero-stripped digit strings for 2.6. Use the same approach for the selection parsers' reversed-range check (7.1, 8.1) if they saturate. Rule tags are strings "2.1".."2.8" on `*ArrayExprError`.
- 7.1: `ParseNameSelection` on a value without `[`/`]` returns `SelBare` with `Name` = the raw untrimmed value (`Raw` is trimmed); 7.2 must match bare names on `Name` and must not treat a bare result as validated. Rule tags on `*SelError` are "5.16", "5.14", "5.17", "5.8", "5.7", "5.5"; decimal keys above uint64 are 5.14.
- 7.2: `BuildSelectionPredicates(filters []utils.FilterCondition) (plain []utils.FilterCondition, preds []func(utils.OrderMap) bool, err error)` in `controllers/jobmatch.go`; parser rejections come back as `*SelError`, other rejections with today's texts. Accepted consequence of the one-rule decision: bare `job_id` values under identity operators now go through `ParseIdentitySelection`, so `job_id:eq:+5` / `-1` (previously accepted) are rejected under 5.16. For 7.3: keep the `array_stats` bracket rejection before the builder, and run the builder in the validate-all-first pass before the `exec_hosts` store lookup.