10 Commits

Author SHA1 Message Date
Mike Dalessio 0d138df952 Guard search indexing with searchable? check
Only index cards and comments if their card is `published?`, using a
new method `searchable?` that is implemented on both Card and Comment.
This prevents draft cards and their comments from being indexed.

When drafts are published, the existing `update_in_search_index`
callback creates the record via `upsert!`, or else ensures unpublished
records are removed from the index.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 12:13:08 -05:00
Mike Dalessio bb2d3a59b5 prefactor: update search to use published cards
We're about to make a change to assert that draft cards are not added
to the search index, and so let's make the intention behind these
tests clear first.
2026-01-23 11:07:43 -05:00
Donal McBreen b571303385 Don't use Current.account for search records
It doesn't actually work, and even if we could make it work reliably
we are better off if the records always know to go to the right shard.

It does make the interface a bit more complicated as we need to select
the right shard class with `for(account_id)`.
2025-11-25 11:34:41 +00:00
Donal McBreen 525e53a2f7 Add FTS ActiveRecord model
Needs some special handling for the FTS virtual table format. Set the
primary key to rowid and manually specify the columns.
2025-11-21 15:21:11 +00:00
Donal McBreen 01d16f96d4 Remove Search::Record.for_account
Instead we'll compute the table name dynamically based on
Current.account where needed. Also we'll prevent searchable records
from being saved if Current.account is not set, otherwise the after
commit callbacks will fail.
2025-11-21 12:09:21 +00:00
Donal McBreen 28efe28f24 Replace Search::Index with Search::Records
Lean on ActiveRecord models for searching and strip out the raw SQL.
Replaces the search_index_* tables with sharded search_records_* tables
as that allows us to use a Search::Record model name.

A Class is dynamically created for each record table shard so that we
and we can access it via the Search::Record.for_account(account_id)
method.
2025-11-17 09:12:40 -05:00
Donal McBreen fc56ad9d7c Combine uuid-old and uuid branch changes
- Switch to binary 16 for UUID keys
- Remove AccountScopedRecord base class, all model use binary uuids now
- Fix the search sql to serialize uuids properly
- Patch the MySQL schema dumper to output binary lengths
2025-11-17 09:12:34 -05:00
Donal McBreen 05a7ec84e2 Make search tables work with UUID references 2025-11-17 09:12:31 -05:00
Donal McBreen 3aa4a1a562 Shard the search index into 16 tables
Create search_index_0 to search_index_15 tables and shard each index by
account id. MySQL has no ability to pre-filter fulltext indexes by
another field so this is the best bet for improving performance.

Each fulltest index internally creates 11 sub tables (see
https://dev.mysql.com/doc/refman/8.4/en/innodb-fulltext-index.html) so
actually we have 192 tables in total here.

The search_index table name is generated dynamically based on the
account_id.
2025-11-17 09:12:17 -05:00
Donal McBreen 996140e053 Add non transactional search tests
MySQL fulltext indexes are only updated on commit. Use a single test in
each file to avoid repeated setup.
2025-11-17 09:12:17 -05:00