Value shapes
PostgreSQL answers a value of the wrong type with an error rather than “no match”, so filter[project]=garbage on a uuid column is a request-triggerable 500. (MySQL and SQLite coerce instead — a non-numeric string becomes 0 and quietly matches row zero.) Declare a FilterValueShape on any typed column and values the column cannot hold never reach the driver:
| Case | Value | Accepts |
|---|---|---|
FilterValueShape::Text | text | Any string — the default; guards nothing. |
FilterValueShape::Uuid | uuid | A valid UUID. |
FilterValueShape::Id | id | A non-negative integer up to PHP_INT_MAX (a bigint’s maximum). |
FilterValueShape::Boolean | boolean | true/false/1/0 in any case, handed to the query as a real boolean. |
use RoundlyConsulting\QueryBuilder\Enums\FilterValueShape;
use RoundlyConsulting\QueryBuilder\Enums\RequestedOperator;
->allowedFilters(
AllowedFilter::operators('author', [RequestedOperator::Not], 'author_id', shape: FilterValueShape::Id),
AllowedFilter::nullable('project', 'project_id', FilterValueShape::Uuid),
AllowedFilter::relation('label', 'labels', 'labels.id', FilterValueShape::Uuid),
)
// ?filter[author]=garbage → empty result, no driver error
// ?filter[author]=not:garbage → excludes nothing
// ?filter[project]=12345 → empty resultBoolean also hands the query a real boolean — the text 'false' is not false to any engine. Combined with operators() it gives a flag column a negation:
->allowedFilters(
AllowedFilter::operators('active', [RequestedOperator::Not], shape: FilterValueShape::Boolean), // not:true
)How it behaves
- Accepted by operators(), nullable() and relation(); AllowedFilter::boolean() is operators() with the Boolean shape. The default Text guards nothing, so no existing filter changes.
- Values of the wrong shape are dropped before the query is built. If none survive, a match returns an empty result — never the unfiltered list — and a negation excludes nothing, since no row could have matched.
- Id rejects out-of-range numbers too: PostgreSQL fails on an out-of-range bigint exactly as on a malformed uuid.
- A typed shape cannot be combined with a LIKE-family operator (contains, ncontains, starts) or partialByDefault — the declaration throws UnsupportedOperator instead of failing on the first request.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.