Skip to content

Commit

Permalink
Use Fulltext matching to search by keyword
Browse files Browse the repository at this point in the history
This should be faster than using regular expressions. The tests don’t
work out of the box, because they’re run in transactions, so the indexes
don’t get built. To get around this, we need to disable transactions for
these tests and make sure DatabaseCleaner wipes that database after each
test run.
  • Loading branch information
pezholio committed Feb 21, 2025
1 parent 593df2c commit b4a8866
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 10 deletions.
3 changes: 3 additions & 0 deletions features/support/env.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,6 @@

# Require step definitions contained within engines
Dir.glob(Rails.root.join("lib/engines/**/features/step_definitions/*.rb")).each(&method(:require))

# Require support files contained within engines
Dir.glob(Rails.root.join("lib/engines/**/features/support/*.rb")).each(&method(:require))
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ module ContentBlock::Document::Scopes::SearchableByKeyword
extend ActiveSupport::Concern

SQL = <<-SQL.freeze
content_block_editions.title REGEXP :pattern OR#{' '}
content_block_editions.details REGEXP :pattern OR#{' '}
content_block_editions.instructions_to_publishers REGEXP :pattern
MATCH(
content_block_editions.title,#{' '}
content_block_editions.details_for_indexing,#{' '}
content_block_editions.instructions_to_publishers
) AGAINST (:pattern IN BOOLEAN MODE)
SQL

included do
Expand All @@ -14,8 +16,8 @@ module ContentBlock::Document::Scopes::SearchableByKeyword
split_keywords = keywords.split
pattern = split_keywords.map { |k|
escaped_word = Regexp.escape(k)
"(?=.*#{escaped_word})"
}.join
"+#{escaped_word}"
}.join(" ")
joins(:latest_edition)
.where(SQL, pattern:)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,23 @@ Feature: Search for a content object
And I click to view results
Then I should see the details for all documents from my organisation

@disable_transactions
Scenario: GDS Editor searches for a content object by keyword in instructions to publishers
When I visit the Content Block Manager home page
And I enter the keyword "GDS"
And I click to view results
Then I should see the content block with title "an address" returned
And "1" content blocks are returned in total

@disable_transactions
Scenario: GDS Editor searches for a content object by keyword in title
When I visit the Content Block Manager home page
And I enter the keyword "example search"
And I click to view results
Then I should see the content block with title "example search title" returned
And "1" content blocks are returned in total

@disable_transactions
Scenario: GDS Editor searches for a content object by keyword in details
When I visit the Content Block Manager home page
And I enter the keyword "ABC123"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Around("@disable_transactions") do |_scenario, block|
Cucumber::Rails::World.use_transactional_tests = false
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.start

block.call

DatabaseCleaner.clean
end
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,22 @@
class ContentBlockManager::SearchableByKeywordTest < ActiveSupport::TestCase
extend Minitest::Spec::DSL

# Because our tests run in a transaction by default, and this functionality relies on
# database indexes, the indexes never get created, so we need to disable transactions
# and ensure that DatabaseCleaner cleans up after each test.
self.use_transactional_tests = false
DatabaseCleaner.strategy = :truncation

before(:each) do
DatabaseCleaner.start
end

after(:each) do
DatabaseCleaner.clean
end

describe ".with_keyword" do
test "should find documents with title containing keyword" do
it "should find documents with title containing keyword" do
document_with_first_keyword = create(:content_block_document, :email_address)
_edition_with_first_keyword = create(:content_block_edition,
:email_address,
Expand All @@ -14,21 +28,23 @@ class ContentBlockManager::SearchableByKeywordTest < ActiveSupport::TestCase
document_without_first_keyword = create(:content_block_document, :email_address)
_edition_without_first_keyword = create(:content_block_edition, :email_address, document: document_without_first_keyword,
title: "this document is about muppets")

assert_equal [document_with_first_keyword], ContentBlockManager::ContentBlock::Document.with_keyword("klingons")
end

test "should find documents with title containing keywords not in order" do
it "should find documents with title containing keywords not in order" do
document_with_first_keyword = create(:content_block_document, :email_address)
_edition_with_first_keyword = create(:content_block_edition,
:email_address,
document: document_with_first_keyword,
details: { "email_address" => "hello@hello.com" },
title: "klingons and such")
_document_without_first_keyword = create(:content_block_document, :email_address)

assert_equal [document_with_first_keyword], ContentBlockManager::ContentBlock::Document.with_keyword("such klingons")
end

test "should find documents with latest edition's details containing keyword" do
it "should find documents with latest edition's details containing keyword" do
document_with_first_keyword = create(:content_block_document, :email_address)
_edition_with_first_keyword = create(:content_block_edition,
document: document_with_first_keyword,
Expand All @@ -39,10 +55,11 @@ class ContentBlockManager::SearchableByKeywordTest < ActiveSupport::TestCase
document: document_without_first_keyword,
details: { "something" => "something" },
title: "this document is about muppets")

assert_equal [document_with_first_keyword], ContentBlockManager::ContentBlock::Document.with_keyword("foo bar")
end

test "should find documents with instructions to publishers containing keyword" do
it "should find documents with instructions to publishers containing keyword" do
document_with_first_keyword = create(:content_block_document, :email_address)
_edition_with_first_keyword = create(:content_block_edition,
document: document_with_first_keyword,
Expand All @@ -53,10 +70,11 @@ class ContentBlockManager::SearchableByKeywordTest < ActiveSupport::TestCase
document: document_without_first_keyword,
instructions_to_publishers: "bar",
title: "this document is about muppets")

assert_equal [document_with_first_keyword], ContentBlockManager::ContentBlock::Document.with_keyword("foo")
end

test "should find documents with details or title containing keyword" do
it "should find documents with details or title containing keyword" do
document_with_keyword_in_details = create(:content_block_document, :email_address)
_edition_with_keyword = create(:content_block_edition,
document: document_with_keyword_in_details,
Expand All @@ -67,6 +85,7 @@ class ContentBlockManager::SearchableByKeywordTest < ActiveSupport::TestCase
document: document_with_keyword_in_title,
details: { "something" => "something" },
title: "this document is about bar foo")

assert_equal [document_with_keyword_in_details, document_with_keyword_in_title], ContentBlockManager::ContentBlock::Document.with_keyword("foo bar")
end
end
Expand Down

0 comments on commit b4a8866

Please sign in to comment.