Skip to content

feat(searchy): send filter values as parameters and sort on any type - #64

Merged
AhmadRAbuhussein merged 1 commit into
mainfrom
muhannad/searchy-parameters
Oct 20, 2026
Merged

AhmadRAbuhussein merged 1 commit into
mainfrom
muhannad/searchy-parameters

Conversation

@mmalkhatib

Copy link
Copy Markdown
Contributor

Why

Searchy embedded every filter value in the expression tree as a constant. EF Core then compiled, cached and sent a new SQL text per distinct value: a search screen where users type different numbers fills EF's query cache, and the database's statement statistics, with one entry per value, and every new value pays a full query compilation.

Measured with EF Core 10 / Npgsql 10 against PostgreSQL 17: 20 searches with 20 different values → 20 compilations with constants, 1 with captured values.

What changes

  • Values are parameters. They are captured the way closure variables are, so EF Core sends @p instead of a literal. Lists become one array parameter (= ANY (@p) on PostgreSQL) whatever their length.
  • Invariant-culture conversion. "100.5" means the same on every server. The conversion now also covers Guid (it used to throw), enums by name or number, booleans written as 1/0, DateTimeOffset, DateOnly and TimeSpan. A value ending in Z stays UTC, as before.
  • Sort on any type and path. bool, long, enums, Guid, nullable numbers and dotted paths such as Customer.Address.City. Previously: seven types, top-level properties only, anything else threw.
  • Clear errors. An unknown filter or sort field throws an SWException naming it, not a NullReferenceException.
  • One copy of Searchy. The source is shared by both packages (SW.EfCoreExtensions/Searchy/, linked into PgSql). Each package keeps only its text rule: string methods in core, escaped ILIKE in PgSql.

No public API changes. The SQL changes from literals to parameters, and lists from IN (...) to = ANY (@p), hence 10.1.x (minor-version: '1').

Tests

  • New SW.EfCoreExtensions.PgSql.IntegrationTests: PostgreSQL 17 through Testcontainers, a small orders/customers domain, asserting on the SQL text and EF Core's compilation count. 17/17 pass; against 10.0.2, 13 of them fail.
  • Existing unit tests: 24/24.
  • New tests.yml runs both projects on every pull request; the publish workflow still has run-tests: false.
  • Checked against a real consumer: an application's 24 search integration tests (projections, date-range rewriting, OR conditions) pass unchanged on a local build of this branch.

Filter values were embedded in the expression tree as constants. EF Core
then compiled, cached and sent a new SQL text for every distinct value,
so a search screen typing different numbers filled the query cache and
the database's statement statistics with one entry per value. Values are
now captured the way closure variables are, so EF Core sends them as
parameters: a query shape compiles once, whatever the values, and lists
go as a single array parameter (= ANY (@p) on PostgreSQL).

Also:
- Values convert with the invariant culture, so "100.5" means the same on
  every server, and the conversion now covers Guid, enums by name or
  number, booleans written as 1/0, DateTimeOffset, DateOnly and TimeSpan.
- Sorting accepts any property type (bool, long, enums, Guid, nullable
  numbers...) and dotted paths, not just seven types on top-level
  properties.
- An unknown filter or sort field throws an SWException naming it,
  instead of a NullReferenceException.
- Searchy's source is shared by both packages; each keeps only its text
  rule (string methods in the core package, escaped ILIKE in PgSql).

Adds SW.EfCoreExtensions.PgSql.IntegrationTests (PostgreSQL 17 through
Testcontainers) and a pull-request workflow running both test projects.
13 of its 17 cases fail against 10.0.2. Publishes as 10.1.x.
@coderabbitai

coderabbitai Bot commented Oct 19, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Repository: simplify9/coderabbit/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: f43567f9-b6a8-4186-acf3-59030aba4c89
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@AhmadRAbuhussein
AhmadRAbuhussein merged commit fb29ead into main Oct 20, 2026
6 checks passed
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.

2 participants