Skip to content

v3: Multi-database driver, anchor support, crawl progress tracking - #51

Merged
freekmurze merged 44 commits into
mainfrom
sqlite
Mar 2, 2026
Merged

v3: Multi-database driver, anchor support, crawl progress tracking#51
freekmurze merged 44 commits into
mainfrom
sqlite

Conversation

@timvandijck

@timvandijck timvandijck commented Feb 16, 2026

Copy link
Copy Markdown
Member

Summary

This is a new major version of laravel-site-search. The biggest change is that the package no longer requires Meilisearch by default. Instead, it ships with a unified DatabaseDriver that uses your application's database for full-text search, supporting SQLite, MySQL, and PostgreSQL out of the box with zero external dependencies.

New features

  • DatabaseDriver (now the default): full-text search using your existing database connection. Supports SQLite (FTS5), MySQL (FULLTEXT), and PostgreSQL (tsvector) through a Grammar abstraction pattern. Features include porter stemming, prefix matching, highlighted results, and relevance ranking
  • Deep linking with anchors: search results include anchor links to specific page sections. Headings with id attributes are extracted during indexing, and Hit::urlWithAnchor() returns URLs like https://example.com/page#installation
  • Crawl progress tracking: site-search:list now shows URLs found, URLs failed, finish reason, and latest crawl time. New CrawlFinishedEvent with FinishReason and CrawlProgress
  • Meta description indexing: the DefaultIndexer now extracts <meta name="description"> content and includes it in search results

Breaking changes

  • PHP 8.4+ required (was 8.3)
  • Laravel 12+ required (Laravel 10 and 11 dropped)
  • Crawler v9: UriInterface parameters become string, ResponseInterface becomes CrawlResponse in all interfaces (SearchProfile, Indexer, events)
  • Indexer::entries() now returns array<array{text: string, anchor: ?string}> instead of string[]
  • Driver interface has new required methods: finalizeIndex(), documentCount(): int
  • New database columns: urls_found, urls_failed, finish_reason on site_search_configs table (migration required)
  • New migration: create_site_search_documents_table for the unified DatabaseDriver
  • Default driver changed from MeiliSearchDriver to DatabaseDriver
  • SqliteDriver removed: replaced by DatabaseDriver which uses Laravel's DB layer. If you used SqliteDriver with a custom storage_path, configure a dedicated SQLite database connection instead

Bug fixes and code quality improvements

  • Fixed ArrayDriver::search() passing arguments in wrong order to SearchResults constructor
  • Fixed ListCommand hard-importing Meilisearch\Exceptions\ApiException (breaks when meilisearch package isn't installed)
  • Removed broken SiteSearchFacade alias from composer.json (class didn't exist)
  • Removed unused IndexNameNotSet exception
  • Fixed misplaced docblock on Indexer interface
  • Fixed overly aggressive content filter that rejected any text starting with / or .
  • Added missing return types (void, self, mixed, array) across all commands, jobs, and interfaces
  • Changed model $guarded/$casts from public properties to protected/casts() method
  • Fixed SiteSearchCrawlProfile::$baseUrl type from mixed to string
  • Fixed FQCNs in docblocks to use imported class names
  • Fixed "Lastest" typo in ListCommand

See UPGRADING.md for detailed migration instructions.

timvandijck and others added 16 commits February 16, 2026 16:26
The action class, contract, config key, and tests were never wired up —
anchor extraction is handled by DefaultIndexer::walkNodes().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Headings without an id attribute now reset the current anchor to null,
preventing content from being incorrectly linked to a previous section.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use strtok to strip any existing fragment before appending the anchor,
preventing invalid URLs like url#existing#anchor.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SQLite and Array drivers now return one result per URL (keeping the
best-ranked match), consistent with MeiliSearch's distinctAttribute
behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Anchor IDs like 'installation' were affecting search ranking. Default
searchableAttributes now excludes anchor while remaining overridable
via user settings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@freekmurze
freekmurze marked this pull request as ready for review February 28, 2026 23:53
@freekmurze freekmurze changed the title Add sqlite driver v3: SQLite driver, anchor support, crawl progress tracking Mar 1, 2026
freekmurze and others added 7 commits March 1, 2026 02:47
These are no longer supported in v3 (requires PHP 8.4+ and Laravel 12+).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
MySQL: Remove required (+) prefix from boolean query terms so stop
words like "with" don't prevent matches.

PostgreSQL: Create custom text search config (site_search) that uses
English stemmer without stop word filtering. Build tsquery manually
with :* prefix for prefix matching support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The english_stem dictionary includes stop word filtering which removes
common words like "here" and "with" from the index. Create a custom
Snowball dictionary (site_search_stem) that only does stemming without
stop word removal.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@freekmurze freekmurze changed the title v3: SQLite driver, anchor support, crawl progress tracking v3: Multi-database driver, anchor support, crawl progress tracking Mar 1, 2026
freekmurze and others added 9 commits March 1, 2026 11:46
Instead of creating one row per text fragment extracted from a page,
consolidate all entries for the same URL into a single row with
concatenated entry text. This reduces document count from ~80x the
number of pages to 1x.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
With consolidated entries per URL, the entry column can exceed MySQL's
TEXT limit (64KB) on content-heavy pages like archives.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove URL deduplication so all drivers return every matching section
with its anchor. This lets users see multiple relevant sections from
the same page in search results.
@freekmurze
freekmurze merged commit 9ff4aa2 into main Mar 2, 2026
12 checks passed
@freekmurze
freekmurze deleted the sqlite branch March 2, 2026 13:58
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