Skip to content

feat(graphql): add literal case-insensitive text filters - #240

Open
patrickleet wants to merge 2 commits into
fix/private-live-snapshotsfrom
feat/literal-text-filter
Open

feat(graphql): add literal case-insensitive text filters#240
patrickleet wants to merge 2 commits into
fix/private-live-snapshotsfrom
feat/literal-text-filter

Conversation

@patrickleet

@patrickleet patrickleet commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Why

Stacked on #239 (fix/private-live-snapshots, itself targeting v5). This keeps the review diff focused on literal filters while CI exercises both changes together. Merge #239 first, then retarget this PR to v5.

A search box should pass the user's text to GraphQL. Today _ilike requires the caller to construct and escape a SQL pattern. That duplicates database-specific work across SSR, URL bindings and browser queries—and a missed escape turns a search for % or _ into a wildcard query.

This adds _icontains to String comparison inputs. The query engine owns the escaping and parameter binding; applications can use a normal URL-bound variable.

Before / after

Before, callers construct an escaped %...% pattern before running:

todos(where: { title: { _ilike: $pattern } }, limit: 20) { id title }

After, a colocated island takes literal search text directly:

query SearchTodos($q: String! = "") @load {
  todos(where: { title: { _icontains: $q } }, limit: 20) { id title }
}
export default defineGraphqlIslandBindings({ q: searchParam('q') });

Contract

  • %, _, backslash, quotes and the escape character are literal characters. SQL uses a bound escaped pattern and explicit ESCAPE on both PostgreSQL and SQLite.
  • Empty text matches non-null strings. Keep search queries bounded; result display remains an application choice.
  • Case folding follows the database: PostgreSQL ILIKE and SQLite's default ASCII case-insensitive LIKE. This does not promise identical Unicode collation.
  • Client codecs and generated filter plans recognize the operator. Local replica evaluation stays uncertain rather than guessing database collation or inventing optimistic matches.
  • _ilike retains intentional pattern semantics; _contains remains JSON containment. Numeric columns do not expose the new operator.

The generated schema fingerprint changes, so regenerate the application coherently with distributed build / distributed dev.

Validation

  • Real PostgreSQL + SQLite: 2 new integration tests pass, including wildcard/escape/quote literals, mixed case, empty/null values, paging, denied rows, invalid operands and unchanged _ilike behavior.
  • Existing GraphQL hardening: 49 pass; SQLite integration: 8 pass.
  • CLI integration: 12 pass, including typed @load generation, read-only drift checking and invalid-operand rejection.
  • Client compiler: 113 pass.
  • JavaScript: 375 pass on the combined fix!: keep authorized snapshot live queries subscribed #239 + feat(graphql): add literal case-insensitive text filters #240 revision; TypeScript and generated-fixture checks pass.
  • Formatting and diff checks pass.
  • After refreshing exact schema-fingerprint goldens for the new operator: 1,019 library tests pass (2 existing ignored), 26 manifest tests pass, and all 6 CLI manifest tests pass including explicit fixture exports. Exact runtime/SDL/manifest and generated-command comparisons remain enforced.
  • PostgreSQL CI explicitly runs the new test target with the real service database.

No user-facing UI copy is added. README examples document the API; no application pages or controls change in this PR.

@coderabbitai

coderabbitai Bot commented Sep 9, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 4508b4f7-17e9-484d-96cc-a900cf05a106

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@patrickleet
patrickleet force-pushed the feat/literal-text-filter branch from ab201a8 to c83252f Compare September 9, 2026 09:17
@patrickleet
patrickleet changed the base branch from v5 to fix/private-live-snapshots September 9, 2026 09:17
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