From e82e854bce95a1fedba6a4989365e0b10c89510c Mon Sep 17 00:00:00 2001 From: Jonathan Rochkind Date: Wed, 13 Nov 2024 12:06:01 -0500 Subject: [PATCH 1/4] Polyfill Blacklight endless range behavior https://github.com/projectblacklight/blacklight/pull/3213 https://github.com/projectblacklight/blacklight/pull/3443 --- .../range_limit_builder.rb | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/blacklight_range_limit/range_limit_builder.rb b/lib/blacklight_range_limit/range_limit_builder.rb index 1f4563b..6c880ff 100644 --- a/lib/blacklight_range_limit/range_limit_builder.rb +++ b/lib/blacklight_range_limit/range_limit_builder.rb @@ -61,5 +61,29 @@ def fetch_specific_range_limit(solr_params) return solr_params end + # hacky polyfill for new Blacklight behavior we need, if we don't have it yet + # + # https://github.com/projectblacklight/blacklight/pull/3213 + # https://github.com/projectblacklight/blacklight/pull/3443 + bl_version = Gem.loaded_specs["blacklight"]&.version + if bl_version && (bl_version <= Gem::Version.new("8.6.1")) + def facet_value_to_fq_string(facet_field, value, use_local_params: true) + facet_config = blacklight_config.facet_fields[facet_field] + + # if it's an one-end range, and condition from original that would use query instead isn't met + if value.is_a?(Range) && (value.count == Float::INFINITY) && !facet_config&.query + solr_field = facet_config.field if facet_config && !facet_config.query + solr_field ||= facet_field + + local_params = [] + local_params << "tag=#{facet_config.tag}" if use_local_params && facet_config && facet_config.tag + + "#{solr_field}:[#{value.begin || "*"} TO #{value.end || "*"}]" + else + super + end + end + end + end end From d759d86f57fe265dd15bcc3629f92bee16269d48 Mon Sep 17 00:00:00 2001 From: Jonathan Rochkind Date: Wed, 13 Nov 2024 12:19:23 -0500 Subject: [PATCH 2/4] Support one-ended ranges --- .../range_form_component.rb | 4 +- .../facet_item_presenter.rb | 10 ++--- .../blacklight_range_limit/filter_field.rb | 4 +- .../range_limit_builder.rb | 12 +++++- spec/presenters/filter_field_spec.rb | 37 ++++++++++++++++++- 5 files changed, 55 insertions(+), 12 deletions(-) diff --git a/app/components/blacklight_range_limit/range_form_component.rb b/app/components/blacklight_range_limit/range_form_component.rb index c278394..de6eda2 100644 --- a/app/components/blacklight_range_limit/range_form_component.rb +++ b/app/components/blacklight_range_limit/range_form_component.rb @@ -10,11 +10,11 @@ def initialize(facet_field:, classes: BlacklightRangeLimit.classes) end def begin_value_default - @facet_field.selected_range.is_a?(Range) ? @facet_field.selected_range.first : @facet_field.min + @facet_field.selected_range.is_a?(Range) ? @facet_field.selected_range.begin : @facet_field.min end def end_value_default - @facet_field.selected_range.is_a?(Range) ? @facet_field.selected_range.last : @facet_field.max + @facet_field.selected_range.is_a?(Range) ? @facet_field.selected_range.end : @facet_field.max end def begin_input_name diff --git a/app/presenters/blacklight_range_limit/facet_item_presenter.rb b/app/presenters/blacklight_range_limit/facet_item_presenter.rb index b79f602..79234f2 100644 --- a/app/presenters/blacklight_range_limit/facet_item_presenter.rb +++ b/app/presenters/blacklight_range_limit/facet_item_presenter.rb @@ -15,15 +15,15 @@ def label_for_range view_context.t( range_limit_label_key, - begin: format_range_display_value(value.first), - begin_value: value.first, - end: format_range_display_value(value.last), - end_value: value.last + begin: format_range_display_value(value.begin), + begin_value: value.begin, + end: format_range_display_value(value.end), + end_value: value.end ) end def range_limit_label_key - if value.first == value.last + if value.begin == value.end 'blacklight.range_limit.single_html' else 'blacklight.range_limit.range_html' diff --git a/app/presenters/blacklight_range_limit/filter_field.rb b/app/presenters/blacklight_range_limit/filter_field.rb index 3cec607..48f7c42 100644 --- a/app/presenters/blacklight_range_limit/filter_field.rb +++ b/app/presenters/blacklight_range_limit/filter_field.rb @@ -22,7 +22,7 @@ def add(item) if value.is_a? Range param_key = filters_key params[param_key] = (params[param_key] || {}).dup - params[param_key][config.key] = { begin: value.first, end: value.last } + params[param_key][config.key] = { begin: value.begin, end: value.end } new_state.reset(params) else super @@ -55,7 +55,7 @@ def values(except: []) elsif params.dig(param_key, config.key).is_a? Hash b_bound = params.dig(param_key, config.key, :begin).presence e_bound = params.dig(param_key, config.key, :end).presence - Range.new(b_bound&.to_i, e_bound&.to_i) if b_bound && e_bound + Range.new(b_bound&.to_i, e_bound&.to_i) if b_bound || e_bound end f = except.include?(:filters) ? [] : [range].compact diff --git a/lib/blacklight_range_limit/range_limit_builder.rb b/lib/blacklight_range_limit/range_limit_builder.rb index 6c880ff..5b8c5a0 100644 --- a/lib/blacklight_range_limit/range_limit_builder.rb +++ b/lib/blacklight_range_limit/range_limit_builder.rb @@ -25,9 +25,17 @@ def add_range_limit_params(solr_params) next unless range_config[:chart_js] || range_config[:textual_facets] selected_value = search_state.filter(config.key).values.first - range = (selected_value if selected_value.is_a? Range) || range_config[:assumed_boundaries] - add_range_segments_to_solr!(solr_params, field_key, range.first, range.last) if range.present? + range = if selected_value.is_a? Range + selected_value + elsif range_config[:assumed_boundaries] + Range.new(*range_config[:assumed_boundaries]) + else + nil + end + + # If we have both ends of a range + add_range_segments_to_solr!(solr_params, field_key, range.begin, range.end) if range && range.count != Float::INFINITY end solr_params diff --git a/spec/presenters/filter_field_spec.rb b/spec/presenters/filter_field_spec.rb index 8b8da73..c9e9baf 100644 --- a/spec/presenters/filter_field_spec.rb +++ b/spec/presenters/filter_field_spec.rb @@ -19,9 +19,18 @@ describe '#add' do it 'adds a new range parameter' do new_state = filter.add(1999..2099) - expect(new_state.params.dig(:range, 'some_field')).to include begin: 1999, end: 2099 end + + it "adds end-less range" do + new_state = filter.add(1999..nil) + expect(new_state.params.dig(:range, 'some_field')).to include begin: 1999, end: nil + end + + it "adds begin-less range" do + new_state = filter.add(nil..2099) + expect(new_state.params.dig(:range, 'some_field')).to include begin: nil, end: 2099 + end end context 'with some existing data' do @@ -32,6 +41,12 @@ new_state = filter.add(1999..2099) expect(new_state.params.dig(:range, 'some_field')).to include begin: 1999, end: 2099 + + new_state = filter.add(1999..nil) + expect(new_state.params.dig(:range, 'some_field')).to include begin: 1999, end: nil + + new_state = filter.add(nil..2099) + expect(new_state.params.dig(:range, 'some_field')).to include begin: nil, end: 2099 end end @@ -66,6 +81,26 @@ end end + context 'with an end-less range' do + let(:param_values) { { range: { some_field: { begin: '2013', end: '' } } } } + + describe '#values' do + it 'converts the parameters to a Range' do + expect(filter.values).to eq [2013..nil] + end + end + end + + context 'with an begin-less range' do + let(:param_values) { { range: { some_field: { begin: '', end: '2022' } } } } + + describe '#values' do + it 'converts the parameters to a Range' do + expect(filter.values).to eq [nil..2022] + end + end + end + context 'with empty data' do let(:param_values) { { range: { some_field: { begin: '', end: '' } } } } From f7e777c1c6192e86bcb48b176ca0b183d4e03b65 Mon Sep 17 00:00:00 2001 From: Jonathan Rochkind Date: Wed, 13 Nov 2024 14:25:00 -0500 Subject: [PATCH 3/4] add browser specs for open-ended ranges --- spec/features/run_through_spec.rb | 44 +++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/spec/features/run_through_spec.rb b/spec/features/run_through_spec.rb index 5c9ad09..167958f 100644 --- a/spec/features/run_through_spec.rb +++ b/spec/features/run_through_spec.rb @@ -61,6 +61,50 @@ end end + context "open-ended range" do + it "can search" do + visit search_catalog_path + + click_button 'Publication Date Sort' + + within ".facet-limit.blacklight-pub_date_si" do + find("input#range_pub_date_si_begin").set("") + find("input#range_pub_date_si_end").set(end_range) + click_button "Apply limit" + end + + expect(page).to have_css(".applied-filter", text: /Publication Date Sort +to #{end_range}/) + expect(page).not_to have_text("No entries found") + expect(page).to have_css(".document") + + within ".facet-limit.blacklight-pub_date_si" do + # expect expandable limits + find("summary", text: "Range List").click + expect(page).to have_css("details ul.facet-values li") + end + end + end + + context "submitted with empty boundaries" do + it "does not apply filter" do + visit search_catalog_path + + click_button 'Publication Date Sort' + + within ".facet-limit.blacklight-pub_date_si" do + find("input#range_pub_date_si_begin").set("") + find("input#range_pub_date_si_end").set("") + click_button "Apply limit" + end + expect(page).not_to have_css(".applied-filter") + + click_button 'Publication Date Sort' + within ".facet-limit.blacklight-pub_date_si" do + expect(page).not_to have_css(".selected") + end + end + end + context 'when assumed boundaries configured' do before do CatalogController.blacklight_config.facet_fields['pub_date_si'].range_config = { From 65989bb1215bbadc3f51b29170b4c77680416a6b Mon Sep 17 00:00:00 2001 From: Jonathan Rochkind Date: Wed, 13 Nov 2024 16:19:41 -0500 Subject: [PATCH 4/4] make polyfill match with local_params too --- lib/blacklight_range_limit/range_limit_builder.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/blacklight_range_limit/range_limit_builder.rb b/lib/blacklight_range_limit/range_limit_builder.rb index 5b8c5a0..5c2b6f0 100644 --- a/lib/blacklight_range_limit/range_limit_builder.rb +++ b/lib/blacklight_range_limit/range_limit_builder.rb @@ -80,13 +80,18 @@ def facet_value_to_fq_string(facet_field, value, use_local_params: true) # if it's an one-end range, and condition from original that would use query instead isn't met if value.is_a?(Range) && (value.count == Float::INFINITY) && !facet_config&.query + # Adapted from + # https://github.com/projectblacklight/blacklight/blob/1494bd0884efe7a48623e9b37abe558fa6348e2a/lib/blacklight/solr/search_builder_behavior.rb#L362-L366 + solr_field = facet_config.field if facet_config && !facet_config.query solr_field ||= facet_field local_params = [] local_params << "tag=#{facet_config.tag}" if use_local_params && facet_config && facet_config.tag - "#{solr_field}:[#{value.begin || "*"} TO #{value.end || "*"}]" + prefix = "{!#{local_params.join(' ')}}" unless local_params.empty? + + "#{prefix}#{solr_field}:[#{value.begin || "*"} TO #{value.end || "*"}]" else super end