Add typed Filter builder for collection filtering#6
Merged
Conversation
Replace raw filter strings with a Filter value object: one static factory per e-conomic operator (eq/ne/gt/gte/lt/lte/like/in/nin), ->and()/->or() combinators with safe parenthesization, automatic $-escaping of special characters, DateTimeInterface-to-UTC rendering, and Filter::raw() as the verbatim escape hatch. CollectionRequestOptions::withFilter() and the constructor now accept only ?Filter (pre-1.0 break; latest tag is v1.0.0-alpha).
__toString() delegates to it, and call sites use the nullsafe-friendly ?->toString() (CollectionRequestOptions::toArray(), tests). Also drops the .env ignore block again.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces hand-rolled filter strings like
with a typed builder:
Setono\Economic\Request\Filter(final readonly,\Stringable, Identifier-style private constructor): static factorieseq/ne/gt/gte/lt/lte(string|int|float|bool|\DateTimeInterface|null),like(*wildcard preserved),in/nin(non-empty list, max 200 elements per e-conomic's cap,nullelements render as$null:), andraw()as the verbatim escape hatch for anything the factories can't express.$ ( ) * , [ ]) are$-escaped automatically via single-passstrtr;nullrenders as$null:; anyDateTimeInterfaceis converted to UTC and formattedY-m-d\TH:i:s\Zwithout mutating the input; non-finite floats are rejected.->and()/->or()parenthesize every composite operand (receiver included) since e-conomic doesn't document$and:/$or:precedence;raw()filters are treated as composite when combined.CollectionRequestOptionsnarrows to?Filter(constructor andwithFilter()) — raw strings are no longer accepted. Pre-1.0 break (latest tag isv1.0.0-alpha); hand-written expressions go throughFilter::raw().openspec/specs/endpoint-api/spec.md, andCLAUDE.mdupdated to the new API.Test plan
composer phpunit— 232 tests, 785 assertions, including a new end-to-end test proving the unencoded-expression + RFC 3986 query-encoding layering throughScriptedHttpClientcomposer analyse— PHPStan level max, cleancomposer check-style— cleanvendor/bin/rector --dry-run— cleanvendor/bin/infection— MSI 17 points above the configured minimum