Skip to content

Allow an empty string as an is filter value - #95

Merged
jstayton merged 1 commit into
developmentfrom
fix-empty-is-filter-value
Aug 27, 2026
Merged

jstayton merged 1 commit into
developmentfrom
fix-empty-is-filter-value

Conversation

@jstayton

Copy link
Copy Markdown
Contributor

KnexAdapter declares filter:is and filter:is not as .empty(['null', '']), so an empty string was always meant to coerce to null. The filter
parser rejected it first, though, because Joi's string() disallows an empty
string by default — making that half of the adapter rule unreachable and
erroring on ?filter[x][is]=, which is a natural way for a client to ask for
is null. Only the 'null' string worked.

Deferring the decision to the adapter costs nothing elsewhere, because every
other operator rejects an empty string through its own schema. Measured across
all seventeen:

Operators Before After
is, is not rejected is null / is not null
= != <> > >= < <= like not like ilike not ilike "is not allowed to be empty" identical message, raised one layer later
in not in between not between "is not allowed to be empty" "must be an array", as for every other scalar

The existing permits an empty string value tests in the adapter suite passed
against the broken pipeline because they call validateValue directly and
skip the parser, so the regression tests here are an end-to-end assertion
through run() plus a parser-level one.

🤖 Generated with Claude Code

`KnexAdapter` declares `filter:is` and `filter:is not` as
`.empty(['null', ''])`, so an empty string was always meant to coerce to
`null`. The filter parser rejected it first, though, because Joi's
`string()` disallows an empty string by default — making that half of the
adapter rule unreachable and erroring on `?filter[x][is]=`, which is a
natural way for a client to ask for `is null`.

Deferring to the adapter costs nothing elsewhere, since every other
operator rejects an empty string through its own schema. The eleven
comparison and `like` operators return a byte-identical message one
layer later, and the four array operators now say "must be an array",
which is already what they say for every other scalar.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jstayton
jstayton merged commit c7eed4c into development Aug 27, 2026
4 checks passed
@jstayton
jstayton deleted the fix-empty-is-filter-value branch August 27, 2026 13:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant