Skip to content

Commit 7f5f753

Browse files
fix: use bare exists json tag on v3 FilterString, not $exists (#4678)
1 parent 479e431 commit 7f5f753

3 files changed

Lines changed: 6 additions & 4 deletions

File tree

.agents/skills/api-filters/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ Operator constants live in `api/v3/filters/parse.go` as `OpEq`, `OpNeq`, `OpGt`,
9191
| `FilterLabel` | `Eq`, `Neq`, `Contains`, `Oeq`, `Ocontains` (label map value predicates) |
9292
| `FilterLabels` | type alias: `map[string]FilterLabel` |
9393

94-
The `Exists` field is serialized under the JSON key `$exists` so it does not collide with a literal `exists` operator in flattened encodings.
94+
The wire operator for `Exists` is plain `exists` (see `OpExists` in `api/v3/filters/parse.go`), matching its `json:"exists,omitempty"` tag — don't confuse it with the unrelated `$`-prefixed Mongo-style tags used by the v1 API (`api/api.gen.go`).
9595

9696
**Important:** the API-layer types do NOT have `Validate()` methods. Validation (mutual exclusivity, complexity bounds, format checks) happens on the internal `pkg/filter.*` predicates — typically from the service input struct's own `Validate()`, calling `f.Validate()` on each non-nil filter.
9797

.agents/skills/api/rules/aip-160-filtering.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,13 @@ The authoritative operator surface for each Common type is defined in `api/spec/
4848

4949
The Go types in `api/v3/filters/filter.go` deliberately expose a **superset** of operators beyond what the matching OAS `Common.*FieldFilter` advertises, so a single Go struct can back several endpoints with different narrow OAS surfaces:
5050

51-
- `filters.FilterString` adds `gt`/`gte`/`lt`/`lte` and an `$exists` check on top of `Common.StringFieldFilter`'s operators
51+
- `filters.FilterString` adds `gt`/`gte`/`lt`/`lte` and an `exists` check on top of `Common.StringFieldFilter`'s operators
5252
- `filters.FilterNumeric` adds `neq` and `oeq`
5353
- `filters.FilterDateTime` matches its Common type exactly (`eq`/`gt`/`gte`/`lt`/`lte`)
5454

55-
The existence check (`$exists`) and `nexists` are AIP-160 operators, but they are not currently modeled in any `Common.*FieldFilter` `oneOf` shape, so picking e.g. `Common.StringFieldFilter` in TypeSpec does not advertise them. Do not rely on `gt`/`gte`/`lt`/`lte` on string fields as a stable contract — the Common type is the public surface.
55+
The existence check (`exists`) and `nexists` are AIP-160 operators, but they are not currently modeled in any `Common.*FieldFilter` `oneOf` shape, so picking e.g. `Common.StringFieldFilter` in TypeSpec does not advertise them. Do not rely on `gt`/`gte`/`lt`/`lte` on string fields as a stable contract — the Common type is the public surface.
56+
57+
Note: the v3 `exists` operator is unrelated to the `$`-prefixed Mongo-style tags (`$eq`, `$in`, ...) used by the v1 API (`api/api.gen.go`) — don't conflate the two.
5658

5759
## Operators
5860

api/v3/filters/filter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ type FilterString struct {
8080
Ocontains []string `json:"ocontains,omitempty"`
8181

8282
// Exists requires the field to be present (true) or absent (false).
83-
Exists *bool `json:"$exists,omitempty"`
83+
Exists *bool `json:"exists,omitempty"`
8484
}
8585

8686
// FilterULID represents a filter operation on a string field that satisfies ULID format.

0 commit comments

Comments
 (0)