Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use lucene query parser for search within user-created browse categories #3004

Merged
merged 1 commit into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion app/models/concerns/spotlight/browse_category_search_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,21 @@ def fix_up_browse_category_queries(solr_params)

solr_params.append_query(query) if query.present?

# for a browse category formed from a saved search, the query syntax reads as two "must" values
# e.g. "json"=>{"query"=>{"bool"=>{"must"=>["savedsearchterm", "browsecategorysearchterm"]}}}}
must_values = solr_params.dig(:json, :query, :bool, :must)

return unless must_values&.any?

# this type of query must be parsed by lucene to function
solr_params[:defType] = 'lucene'

# This replicates existing spotlight 2.x search behavior, more or less. It
# doesn't take into account the possibility that the browse category query
# could use a different search field (which.. doesn't have an existing UI
# control.. and may require additional upstream work to properly encapsulate
# the two query parameters)
solr_params.dig(:json, :query, :bool, :must)&.map! do |q|
must_values.map! do |q|
q.is_a?(String) ? { edismax: { query: q } } : q
end
end
Expand Down
12 changes: 12 additions & 0 deletions spec/factories/searches.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,16 @@

after(:build) { |search| search.thumbnail = FactoryBot.create(:featured_image) }
end

factory :search_field_search, class: 'Spotlight::Search' do
exhibit
title { 'Based on a search field' }
query_params { { 'search_field' => 'search', 'q' => 'model' } }
end

factory :facet_search, class: 'Spotlight::Search' do
exhibit
title { 'Based on a facet' }
query_params { { 'f' => { 'language_ssim' => 'Latin' } } }
end
end
26 changes: 26 additions & 0 deletions spec/features/browse_category_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -156,4 +156,30 @@
expect(page).to have_css "meta[property='og:title'][content='#{search.title}']", visible: false
end
end

context 'with a search field based browse category' do
let(:search) { FactoryBot.create(:search_field_search, title: 'Search field search', exhibit: exhibit, published: true, search_box: true) }

it 'conducts a search within the browse category' do
visit spotlight.exhibit_browse_path(exhibit, search)
expect(search.documents.count).to eq 6

fill_in 'Search within this browse category', with: 'azimuthal'
click_button 'Search within browse category'
expect(page).to have_text('Your search matched 1 of 6 items in this browse category.')
end
end

context 'with a facet based browse category' do
let(:search) { FactoryBot.create(:facet_search, title: 'Facet search', exhibit: exhibit, published: true, search_box: true) }

it 'conducts a search within the browse category' do
visit spotlight.exhibit_browse_path(exhibit, search)
expect(search.documents.count).to eq 3

fill_in 'Search within this browse category', with: 'Stopendael'
click_button 'Search within browse category'
expect(page).to have_text('Your search matched 1 of 3 items in this browse category.')
end
end
end
72 changes: 50 additions & 22 deletions spec/models/spotlight/browse_category_search_builder_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,37 +14,65 @@ class BrowseCategoryMockSearchBuilder < Blacklight::SearchBuilder
end
let(:solr_request) { Blacklight::Solr::Request.new }
let(:blacklight_params) { { browse_category_id: search.id } }
let(:search) { FactoryBot.create(:search, exhibit: exhibit, query_params: { sort: 'type', f: { genre_ssim: ['term'] }, q: 'search query' }) }

describe '#restrict_to_browse_category' do
it 'adds the search query parameters from the browse category' do
params = subject.to_hash.with_indifferent_access
context 'with a facet as the basis of the browse category (no search query present)' do
let(:search) { FactoryBot.create(:search, exhibit: exhibit, query_params: { sort: 'type', f: { genre_ssim: ['genre facet'] } }) }

expect(params).to include(
q: 'search query',
fq: ['{!term f=genre_ssim}term'],
sort: 'sort_type_ssi asc'
)
describe 'constructs params properly' do
it 'adds facet to the solr params' do
params = subject.to_hash.with_indifferent_access

expect(params).to include(
fq: ['{!term f=genre_ssim}genre facet'],
sort: 'sort_type_ssi asc'
)
end

it 'does not override the default query parser' do
params = subject.to_hash.with_indifferent_access
expect(params).not_to include(:defType)
end
end
end

context 'with a user-provided query' do
let(:blacklight_params) { { browse_category_id: search.id, q: 'cats' } }
context 'with a search query as part of the construction of the browse category' do
let(:search) { FactoryBot.create(:search, exhibit: exhibit, query_params: { sort: 'type', f: { genre_ssim: ['term'] }, q: 'search query' }) }

it 'uses the user-provided query to further restrict the search' do
describe 'constructs params properly' do
it 'includes the facet and the seach term information in the params' do
params = subject.to_hash.with_indifferent_access
expect(params).not_to include(:q)

expect(params).to include(
json: {
query: {
bool: {
must: [
{ edismax: { query: 'search query' } },
{ edismax: { query: 'cats' } }
]
q: 'search query',
fq: ['{!term f=genre_ssim}term'],
sort: 'sort_type_ssi asc'
)
end

context 'with a search term present' do
let(:blacklight_params) { { browse_category_id: search.id, q: 'cats' } }

it 'manipulates the solr query as expected into json syntax' do
params = subject.to_hash.with_indifferent_access
expect(params).not_to include(:q)
expect(params).to include(
json: {
query: {
bool: {
must: [
{ edismax: { query: 'search query' } },
{ edismax: { query: 'cats' } }
]
}
}
}
}
)
)
end

it 'overrides the default query parser' do
params = subject.to_hash.with_indifferent_access
expect(params).to include(defType: 'lucene')
end
end
end
end
Expand Down