Skip to content

Add SQL Server full-text search provider#37

Open
mhelleborg wants to merge 2 commits into
mainfrom
claude/provider-sqlserver-k9u9fc
Open

Add SQL Server full-text search provider#37
mhelleborg wants to merge 2 commits into
mainfrom
claude/provider-sqlserver-k9u9fc

Conversation

@mhelleborg

Copy link
Copy Markdown
Owner

Implements the SQL Server provider — issue #24, part of the multi-provider epic #23. Mirrors the existing Postgres/SQLite providers and plugs into the shared SearchLite.Conformance suite.

What's here

  • Source/SearchLite.SqlServerSearchManager + SearchIndex<T> on Microsoft.Data.SqlClient. Each index is a table (id NVARCHAR(450) PK, document NVARCHAR(MAX) JSON, search_text NVARCHAR(MAX), last_updated DATETIME2). Full implementation of the ISearchIndex<T> surface with MERGE upserts, JSON_VALUE ordering, and OFFSET/FETCH paging.
  • Full-text: a full-text catalog + index over search_text, queried via FREETEXTTABLE using its RANK as the relevance score.
  • WhereClauseBuilder<T> translates every FilterNode<T> Operator into JSON_VALUE / OPENJSON predicates (collection membership via OPENJSON … EXISTS, case-sensitive matching via a CS_AS collation), mirroring SQLite's json_extract/json_each idiom.
  • Tests/SearchLite.SqlServer.Tests — concrete subclass of the shared conformance suite via a Testcontainers.MsSql fixture, plus TableNameTests and WhereClauseTests.
  • Added Microsoft.Data.SqlClient, Testcontainers.MsSql, and Microsoft.Extensions.DependencyInjection.Abstractions to Directory.Packages.props (the DI abstractions aren't transitively provided by Microsoft.Data.SqlClient, unlike Npgsql).

Verification

  • Both projects build clean in Release across net8.0/net9.0/net10.0.
  • The 26 infrastructure-free unit tests (WhereClauseTests + TableNameTests) pass.
  • The parallel CI matrix auto-discovers SearchLite.SqlServer.Tests and runs it on its own runner.

⚠️ Known limitation — full-text image

The standard mcr.microsoft.com/mssql/server image does not ship the SQL Server Full-Text Search component, so CREATE FULLTEXT CATALOG/INDEX in EnsureTableExistsAsync is best-effort (wrapped in try/catch) and FREETEXTTABLE queries will fail on the stock Testcontainers.MsSql image. Running the full conformance suite needs a full-text-enabled image (a custom image FROM the base server with the full-text feature). The FREETEXTTABLE RANK scoring and the MinScore thresholds in the shared suite are therefore not yet validated end-to-end against a live server — that's the main follow-up before this is production-ready.

🤖 Generated with Claude Code


Generated by Claude Code

claude added 2 commits June 27, 2026 22:53
Implement SearchLite.SqlServer mirroring the Postgres/Sqlite providers:

- SearchIndex<T>: full ISearchIndex<T> surface backed by Microsoft.Data.SqlClient,
  storing each index as a table (id, document NVARCHAR(MAX) JSON, search_text, last_updated).
  Full-text search via a full-text catalog + index over search_text, queried with
  FREETEXTTABLE and using its RANK as the relevance score. MERGE-based upserts, JSON_VALUE
  ordering, OFFSET/FETCH paging.
- WhereClauseBuilder<T>: translates every FilterNode<T> Operator case to JSON_VALUE / OPENJSON
  predicates (CollectionContains via OPENJSON, ordering via JSON_VALUE), mirroring the SQLite
  json_extract/json_each approach.
- SearchManager + ServiceCollectionExtensions matching the existing providers.
- Tests/SearchLite.SqlServer.Tests: Testcontainers.MsSql fixture, concrete IndexTests subclass
  of the shared abstract suite, plus TableNameTests and WhereClauseTests.
- Central package management: Microsoft.Data.SqlClient, Testcontainers.MsSql and
  Microsoft.Extensions.DependencyInjection.Abstractions added to Directory.Packages.props.
- Both projects registered in SearchLite.sln.

Note: the stock mcr.microsoft.com/mssql/server image does not ship Full-Text Search, so
catalog/index creation is best-effort and full-text integration tests need a full-text-enabled
image.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AHZB8AqzqRcBEuzRurzJFf
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