Skip to content

feat: support querying fields containing the literal string, "null"#2233

Open
jcrossley3 wants to merge 2 commits intoguacsec:mainfrom
jcrossley3:2230
Open

feat: support querying fields containing the literal string, "null"#2233
jcrossley3 wants to merge 2 commits intoguacsec:mainfrom
jcrossley3:2230

Conversation

@jcrossley3
Copy link
Contributor

@jcrossley3 jcrossley3 commented Feb 4, 2026

Relates #2230

BREAKING-CHANGE: Querying for NULL fields is now achieved using an ASCII NUL value, percent-encoded as %00, instead of the literal string "null".

Summary by Sourcery

Document and implement a new convention for querying unset (NULL) fields using an ASCII NUL value instead of the literal string "null", and update tests accordingly.

Enhancements:

  • Change query parsing so that an ASCII NUL value (\x00) in [Not]Equal filters represents NULL/NOT NULL checks instead of the literal string "null".

Documentation:

  • Update OpenAPI documentation to describe using ASCII NUL percent-encoded as %00 for querying fields that are NULL, replacing the previous 'null' sentinel examples.

Tests:

  • Adjust database and endpoint tests to use the ASCII NUL (\x00) sentinel in query parameters when asserting NULL/NOT NULL filtering semantics.

Relates guacsec#2230

BREAKING-CHANGE: Querying for NULL fields is now achieved using an
ASCII NUL value, percent-encoded as %00, instead of the literal string
"null".
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Feb 4, 2026

Reviewer's Guide

This PR changes how NULL values are represented in query filters, switching from the literal string "null" to the ASCII NUL byte (percent-encoded as %00) for both API docs and implementation, and updates tests accordingly so that fields containing the literal string "null" can now be queried normally.

Sequence diagram for handling NULL vs literal null in query filters

sequenceDiagram
    actor Client
    participant APIServer
    participant QueryParser
    participant Columns
    participant Database

    Client->>APIServer: GET /resources?name=%00
    APIServer->>QueryParser: parse_query("name=%00")
    QueryParser->>Columns: build_filter(field name, operator Equal, value "\x00")
    Columns-->>QueryParser: SimpleExpr lhs.is_null()
    QueryParser->>Database: SELECT ... WHERE NAME IS NULL
    Database-->>QueryParser: rows with name IS NULL
    QueryParser-->>APIServer: filtered results
    APIServer-->>Client: 200 OK (resources with name NOT SET)

    Client->>APIServer: GET /resources?name=null
    APIServer->>QueryParser: parse_query("name=null")
    QueryParser->>Columns: build_filter(field name, operator Equal, value "null")
    Columns-->>QueryParser: SimpleExpr lhs.eq("null")
    QueryParser->>Database: SELECT ... WHERE NAME = 'null'
    Database-->>QueryParser: rows with name = literal "null"
    QueryParser-->>APIServer: filtered results
    APIServer-->>Client: 200 OK (resources with name "null")
Loading

Flow diagram for mapping filter values to SQL NULL handling

graph TD
    A[Start: receive filter field, operator, value] --> B{Value equals ASCII NUL?}
    B -- Yes --> C{Operator Equal or NotEqual?}
    C -- Equal --> D[Return SQL expression lhs IS NULL]
    C -- NotEqual --> E[Return SQL expression lhs IS NOT NULL]
    C -- Other --> F[Apply normal operator handling]
    B -- No --> G[Treat value as normal string]
    G --> F[Apply normal operator handling]
    D --> H[End]
    E --> H[End]
    F --> H[End]
Loading

File-Level Changes

Change Details Files
Switch NULL-filter semantics from the string "null" to ASCII NUL (\x00 / %00) across API docs and implementation.
  • Update OpenAPI filter documentation to describe using ASCII NUL (%00) to represent NULL and adjust examples from name=null to name=%00 across all affected endpoints.
  • Update Rust query help text (Query struct docs) to explain the new %00 / NUL convention and example WHERE clauses.
  • Change query column matching logic to map an input value of \x00 with == / != operators to IS NULL / IS NOT NULL instead of using the string "null".
  • Update query/filter and endpoint tests to assert the new \x00-based behavior for NULL comparisons and adjust helper code that previously emitted "null" to emit \x00 instead.
openapi.yaml
common/src/db/query.rs
common/src/db/query/columns.rs
common/src/db/query/filter.rs
modules/fundamental/src/advisory/endpoints/test.rs
modules/fundamental/src/sbom_group/endpoints/test.rs

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • The OpenAPI description block explaining the NUL/%00 handling is repeated verbatim for many paths; consider centralizing this text via a shared component/description to avoid duplication and reduce the risk of future inconsistencies.
  • In Columns::filter, you still allocate a lowercase String and then match on the literal "\x00"; since case-folding is irrelevant for this sentinel value, you could special-case "\x00" before to_lowercase() (or avoid the allocation entirely) to make this branch cheaper and more explicit.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The OpenAPI description block explaining the `NUL`/`%00` handling is repeated verbatim for many paths; consider centralizing this text via a shared component/description to avoid duplication and reduce the risk of future inconsistencies.
- In `Columns::filter`, you still allocate a lowercase String and then match on the literal `"\x00"`; since case-folding is irrelevant for this sentinel value, you could special-case `"\x00"` before `to_lowercase()` (or avoid the allocation entirely) to make this branch cheaper and more explicit.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@codecov
Copy link

codecov bot commented Feb 4, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 69.24%. Comparing base (bc3f83a) to head (99993f2).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2233      +/-   ##
==========================================
+ Coverage   69.21%   69.24%   +0.02%     
==========================================
  Files         405      405              
  Lines       23038    23044       +6     
  Branches    23038    23044       +6     
==========================================
+ Hits        15946    15957      +11     
+ Misses       6188     6177      -11     
- Partials      904      910       +6     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@ctron ctron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of adding more magic characters. Especially 0x00.

Technically that is fine, but I can't make the decision if we break the API or not. I also guess UI should take a look at this.

Consider this a +1, but someone other than me should approve/merge this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants