Skip to content

query: Negative contains/glob filters are false when the field is absent, contrary to intuition #4

@PaluMacil

Description

@PaluMacil

This requires a decision.

In filter.go, filterOpNegContains and filterOpNegGlob both return false when the field is absent:
goif seg.filterOp == filterOpNegContains {
    fv := fieldValue(v, seg.name)
    if fv == nil {
        return false  // <-- surprising
    }
Semantically, [Tags!~devops] reads as "Tags does not contain devops". If the element doesn't have a Tags field at all, most users would expect that to be true (it certainly doesn't contain devops). Today it's treated as false — absent fields fail negative filters.
This matters for mixed-type slices where some element types have the field and others don't. ..[Status!=retired] on a slice of heterogeneous records silently drops records that don't even have a Status field.
Before changing anything, write tests for:

[Tags!~devops] with an element missing the Tags field — should match (absence means no devops tag)
[Status!=retired] with an element missing Status — should match
Corresponding positive cases: [Tags~devops] with absent Tags — should NOT match (already correct)
[Status=active] with absent Status — should NOT match (already correct)

Confirm the negative cases fail today. Decide and document: does "absent = negative filter passes" apply to ALL negative forms (!!, !=, !~)? Currently !! does match-on-absence. Make != and !~ consistent with !!. Update the README to state this invariant explicitly: "negative filters (!!, !=, !~) treat missing fields as matching; positive filters treat missing fields as non-matching."

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions