blacklight 7.14.1 → 7.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/app/components/blacklight/advanced_search_form_component.html.erb +46 -0
- data/app/components/blacklight/advanced_search_form_component.rb +75 -0
- data/app/components/blacklight/constraint_component.html.erb +1 -1
- data/app/components/blacklight/constraints_component.rb +36 -17
- data/app/components/blacklight/document/thumbnail_component.html.erb +1 -1
- data/app/components/blacklight/document/thumbnail_component.rb +4 -1
- data/app/components/blacklight/document_component.rb +7 -2
- data/app/components/blacklight/facet_field_checkboxes_component.html.erb +23 -0
- data/app/components/blacklight/facet_field_checkboxes_component.rb +24 -0
- data/app/components/blacklight/facet_field_inclusive_constraint_component.html.erb +6 -0
- data/app/components/blacklight/facet_field_inclusive_constraint_component.rb +29 -0
- data/app/components/blacklight/facet_field_list_component.html.erb +1 -0
- data/app/components/blacklight/facet_item_component.rb +2 -0
- data/app/components/blacklight/search_bar_component.html.erb +4 -0
- data/app/components/blacklight/search_bar_component.rb +4 -2
- data/app/controllers/concerns/blacklight/catalog.rb +6 -0
- data/app/helpers/blacklight/render_constraints_helper_behavior.rb +2 -2
- data/app/presenters/blacklight/clause_presenter.rb +37 -0
- data/app/presenters/blacklight/document_presenter.rb +5 -1
- data/app/presenters/blacklight/facet_field_presenter.rb +4 -0
- data/app/presenters/blacklight/facet_grouped_item_presenter.rb +45 -0
- data/app/presenters/blacklight/facet_item_presenter.rb +32 -20
- data/app/presenters/blacklight/inclusive_facet_item_presenter.rb +16 -0
- data/app/presenters/blacklight/search_bar_presenter.rb +4 -0
- data/app/views/catalog/_advanced_search_form.html.erb +7 -0
- data/app/views/catalog/_advanced_search_help.html.erb +24 -0
- data/app/views/catalog/_search_form.html.erb +1 -0
- data/app/views/catalog/advanced_search.html.erb +17 -0
- data/blacklight.gemspec +1 -1
- data/config/i18n-tasks.yml +1 -0
- data/config/locales/blacklight.en.yml +17 -0
- data/lib/blacklight/configuration.rb +2 -1
- data/lib/blacklight/routes/searchable.rb +1 -0
- data/lib/blacklight/search_builder.rb +2 -0
- data/lib/blacklight/search_state.rb +5 -1
- data/lib/blacklight/search_state/filter_field.rb +17 -7
- data/lib/blacklight/solr/repository.rb +11 -2
- data/lib/blacklight/solr/search_builder_behavior.rb +87 -23
- data/spec/components/blacklight/advanced_search_form_component_spec.rb +51 -0
- data/spec/components/blacklight/document_component_spec.rb +15 -0
- data/spec/components/blacklight/facet_field_checkboxes_component_spec.rb +55 -0
- data/spec/components/blacklight/facet_field_list_component_spec.rb +39 -4
- data/spec/controllers/catalog_controller_spec.rb +9 -0
- data/spec/features/advanced_search_spec.rb +67 -0
- data/spec/lib/blacklight/search_state/filter_field_spec.rb +65 -0
- data/spec/models/blacklight/solr/repository_spec.rb +12 -0
- data/spec/models/blacklight/solr/search_builder_spec.rb +28 -0
- data/spec/presenters/blacklight/clause_presenter_spec.rb +34 -0
- data/spec/presenters/blacklight/document_presenter_spec.rb +13 -0
- data/spec/presenters/blacklight/facet_grouped_item_presenter_spec.rb +41 -0
- metadata +29 -7
@@ -97,8 +97,12 @@ module Blacklight
|
|
97
97
|
field_presenter(field_config, options).render
|
98
98
|
end
|
99
99
|
|
100
|
+
def thumbnail_presenter_class
|
101
|
+
view_config.thumbnail_presenter || thumbnail_presenter
|
102
|
+
end
|
103
|
+
|
100
104
|
def thumbnail
|
101
|
-
@thumbnail ||=
|
105
|
+
@thumbnail ||= thumbnail_presenter_class.new(document, view_context, view_config)
|
102
106
|
end
|
103
107
|
|
104
108
|
##
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Blacklight
|
4
|
+
class FacetGroupedItemPresenter < Blacklight::FacetItemPresenter
|
5
|
+
attr_reader :group
|
6
|
+
|
7
|
+
delegate :key, to: :facet_config
|
8
|
+
|
9
|
+
def initialize(group, facet_item, facet_config, view_context, facet_field, search_state = view_context.search_state)
|
10
|
+
@group = group
|
11
|
+
@facet_item = facet_item
|
12
|
+
@facet_config = facet_config
|
13
|
+
@view_context = view_context
|
14
|
+
@facet_field = facet_field
|
15
|
+
@search_state = search_state
|
16
|
+
end
|
17
|
+
|
18
|
+
##
|
19
|
+
# Check if the query parameters have the given facet field with the
|
20
|
+
# given value.
|
21
|
+
def selected?
|
22
|
+
group.include?(facet_item)
|
23
|
+
end
|
24
|
+
|
25
|
+
# @private
|
26
|
+
def remove_href(path = search_state)
|
27
|
+
new_state = path.filter(facet_config).remove(group)
|
28
|
+
new_state = new_state.filter(facet_config).add(group - [facet_item])
|
29
|
+
|
30
|
+
view_context.search_action_path(new_state)
|
31
|
+
end
|
32
|
+
|
33
|
+
# @private
|
34
|
+
def add_href(_path_options = {})
|
35
|
+
if facet_config.url_method
|
36
|
+
return view_context.public_send(facet_config.url_method, facet_config.key, facet_item)
|
37
|
+
end
|
38
|
+
|
39
|
+
new_state = search_state.filter(facet_config).remove(@group)
|
40
|
+
new_state = new_state.filter(facet_config).add(@group + [facet_item])
|
41
|
+
|
42
|
+
view_context.search_action_path(new_state)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -4,7 +4,7 @@ module Blacklight
|
|
4
4
|
class FacetItemPresenter
|
5
5
|
attr_reader :facet_item, :facet_config, :view_context, :search_state, :facet_field
|
6
6
|
|
7
|
-
delegate :
|
7
|
+
delegate :key, to: :facet_config
|
8
8
|
|
9
9
|
def initialize(facet_item, facet_config, view_context, facet_field, search_state = view_context.search_state)
|
10
10
|
@facet_item = facet_item
|
@@ -14,12 +14,24 @@ module Blacklight
|
|
14
14
|
@search_state = search_state
|
15
15
|
end
|
16
16
|
|
17
|
+
def hits
|
18
|
+
return unless @facet_item.respond_to? :hits
|
19
|
+
|
20
|
+
@facet_item.hits
|
21
|
+
end
|
22
|
+
|
23
|
+
def items
|
24
|
+
return unless @facet_item.respond_to? :items
|
25
|
+
|
26
|
+
@facet_item.items
|
27
|
+
end
|
28
|
+
|
17
29
|
##
|
18
30
|
# Check if the query parameters have the given facet field with the
|
19
31
|
# given value.
|
20
32
|
def selected?
|
21
33
|
Deprecation.silence(Blacklight::SearchState) do
|
22
|
-
search_state.has_facet? facet_config, value:
|
34
|
+
search_state.has_facet? facet_config, value: value
|
23
35
|
end
|
24
36
|
end
|
25
37
|
|
@@ -34,21 +46,29 @@ module Blacklight
|
|
34
46
|
def label
|
35
47
|
return @view_context.facet_display_value(@facet_field, @facet_item) unless @view_context.method(:facet_display_value).owner == Blacklight::FacetsHelperBehavior
|
36
48
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
49
|
+
label_value = if facet_item.respond_to? :label
|
50
|
+
facet_item.label
|
51
|
+
else
|
52
|
+
value
|
53
|
+
end
|
42
54
|
|
43
55
|
if facet_config.helper_method
|
44
|
-
view_context.public_send(facet_config.helper_method,
|
45
|
-
elsif facet_config.query && facet_config.query[
|
46
|
-
facet_config.query[
|
56
|
+
view_context.public_send(facet_config.helper_method, label_value)
|
57
|
+
elsif facet_config.query && facet_config.query[label_value]
|
58
|
+
facet_config.query[label_value][:label]
|
47
59
|
elsif facet_config.date
|
48
60
|
localization_options = facet_config.date == true ? {} : facet_config.date
|
49
|
-
I18n.l(Time.zone.parse(
|
61
|
+
I18n.l(Time.zone.parse(label_value), **localization_options)
|
62
|
+
else
|
63
|
+
label_value
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def value
|
68
|
+
if facet_item.respond_to? :value
|
69
|
+
facet_item.value
|
50
70
|
else
|
51
|
-
|
71
|
+
facet_item
|
52
72
|
end
|
53
73
|
end
|
54
74
|
|
@@ -78,14 +98,6 @@ module Blacklight
|
|
78
98
|
|
79
99
|
private
|
80
100
|
|
81
|
-
def facet_value
|
82
|
-
if facet_item.respond_to? :value
|
83
|
-
facet_item.value
|
84
|
-
else
|
85
|
-
facet_item
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
101
|
def facet_field_presenter
|
90
102
|
@facet_field_presenter ||= view_context.facet_field_presenter(facet_config, {})
|
91
103
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Blacklight
|
4
|
+
class InclusiveFacetItemPresenter < Blacklight::FacetItemPresenter
|
5
|
+
##
|
6
|
+
# Get the displayable version of a facet's value
|
7
|
+
#
|
8
|
+
# @return [String]
|
9
|
+
def label
|
10
|
+
view_context.safe_join(
|
11
|
+
Array(facet_item).map { |value| Blacklight::FacetGroupedItemPresenter.new(facet_item, value, facet_config, view_context, facet_field, search_state).label },
|
12
|
+
view_context.t('blacklight.advanced_search.or_html')
|
13
|
+
)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<%= render(Blacklight::AdvancedSearchFormComponent.new(
|
2
|
+
url: search_action_url,
|
3
|
+
classes: ['advanced', 'form-horizontal'],
|
4
|
+
params: search_state.params_for_search.except(:qt),
|
5
|
+
search_fields: Deprecation.silence(Blacklight::ConfigurationHelperBehavior) { search_fields },
|
6
|
+
response: @response
|
7
|
+
)) %>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<div class='card card-default'>
|
2
|
+
<div class="card-body">
|
3
|
+
<h4 class="card-title">Search tips</h4>
|
4
|
+
<ul class="advanced-help">
|
5
|
+
<li>Select "match all" to require all fields.
|
6
|
+
</li>
|
7
|
+
|
8
|
+
<li>Select "match any" to find at least one field.
|
9
|
+
</li>
|
10
|
+
|
11
|
+
<li>Combine keywords and attributes to find specific items.
|
12
|
+
</li>
|
13
|
+
|
14
|
+
<li>Use quotation marks to search as a phrase.
|
15
|
+
|
16
|
+
<li>Use "+" before a term to make it required. (Otherwise results matching only some of your terms may be included).</li>
|
17
|
+
|
18
|
+
<li>Use "-" before a word or phrase to exclude.
|
19
|
+
|
20
|
+
<li>Use "OR", "AND", and "NOT" to create complex boolean logic. You can use parentheses in your complex expressions. </li>
|
21
|
+
<li>Truncation and wildcards are not supported - word-stemming is done automatically.</li>
|
22
|
+
</ul>
|
23
|
+
</div>
|
24
|
+
</div>
|
@@ -1,5 +1,6 @@
|
|
1
1
|
<%= render(Blacklight::SearchBarComponent.new(
|
2
2
|
url: search_action_url,
|
3
|
+
advanced_search_url: search_action_url(action: 'advanced_search'),
|
3
4
|
params: search_state.params_for_search.except(:qt),
|
4
5
|
search_fields: Deprecation.silence(Blacklight::ConfigurationHelperBehavior) { search_fields },
|
5
6
|
presenter: presenter,
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<% @page_title = t('blacklight.advanced_search.page_title', application_name: application_name) %>
|
2
|
+
|
3
|
+
<div class="advanced-search-form col-sm-12">
|
4
|
+
<h1 class="advanced page-header">
|
5
|
+
<%= t('blacklight.advanced_search.form.title') %>
|
6
|
+
</h1>
|
7
|
+
|
8
|
+
<div class="row">
|
9
|
+
<div class="col-md-8">
|
10
|
+
<%= render 'advanced_search_form' %>
|
11
|
+
</div>
|
12
|
+
|
13
|
+
<div class="col-md-4">
|
14
|
+
<%= render "advanced_search_help" %>
|
15
|
+
</div>
|
16
|
+
</div>
|
17
|
+
</div>
|
data/blacklight.gemspec
CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
24
24
|
s.require_paths = ["lib"]
|
25
25
|
|
26
|
-
s.required_ruby_version = '>= 2.
|
26
|
+
s.required_ruby_version = '>= 2.5'
|
27
27
|
|
28
28
|
s.add_dependency "rails", '>= 5.1', '< 7'
|
29
29
|
s.add_dependency "globalid"
|
data/config/i18n-tasks.yml
CHANGED
@@ -239,3 +239,20 @@ en:
|
|
239
239
|
main:
|
240
240
|
aria:
|
241
241
|
main_container: 'Main content'
|
242
|
+
|
243
|
+
advanced_search:
|
244
|
+
or_html: ' OR '
|
245
|
+
more_options: More options
|
246
|
+
any_of: 'Any of:'
|
247
|
+
op:
|
248
|
+
must: all
|
249
|
+
should: any
|
250
|
+
page_title: Advanced search - %{application_name}
|
251
|
+
form:
|
252
|
+
title: Advanced search
|
253
|
+
search_context: Within search
|
254
|
+
limit_criteria_heading_html: "<strong>AND</strong> have these attributes"
|
255
|
+
query_criteria_heading_html: "Match %{select_menu} of the fields below"
|
256
|
+
sort_label: "Sort results by"
|
257
|
+
start_over_html: "Start over"
|
258
|
+
search_btn_html: 'Search'
|
@@ -132,7 +132,8 @@ module Blacklight
|
|
132
132
|
crawler_detector: nil,
|
133
133
|
autocomplete_suggester: 'mySuggester',
|
134
134
|
raw_endpoint: OpenStructWithHashAccess.new(enabled: false),
|
135
|
-
track_search_session: true
|
135
|
+
track_search_session: true,
|
136
|
+
advanced_search: OpenStruct.new(enabled: false)
|
136
137
|
}
|
137
138
|
end
|
138
139
|
# rubocop:enable Metrics/MethodLength
|
@@ -8,6 +8,7 @@ module Blacklight
|
|
8
8
|
|
9
9
|
def call(mapper, _options = {})
|
10
10
|
mapper.match '/', action: 'index', as: 'search', via: [:get, :post]
|
11
|
+
mapper.get '/advanced', action: 'advanced_search', as: 'advanced_search'
|
11
12
|
|
12
13
|
mapper.post ":id/track", action: 'track', as: 'track'
|
13
14
|
mapper.get ":id/raw", action: 'raw', as: 'raw', defaults: { format: 'json' }
|
@@ -28,6 +28,7 @@ module Blacklight
|
|
28
28
|
|
29
29
|
@blacklight_params = {}
|
30
30
|
@search_state = Blacklight::SearchState.new(@blacklight_params, @scope&.blacklight_config, @scope)
|
31
|
+
@additional_filters = {}
|
31
32
|
@merged_params = {}
|
32
33
|
@reverse_merged_params = {}
|
33
34
|
end
|
@@ -47,6 +48,7 @@ module Blacklight
|
|
47
48
|
params_will_change!
|
48
49
|
@search_state = @search_state.reset(@search_state.params.merge(q: conditions))
|
49
50
|
@blacklight_params = @search_state.params.dup
|
51
|
+
@additional_filters = conditions
|
50
52
|
self
|
51
53
|
end
|
52
54
|
|
@@ -82,7 +82,7 @@ module Blacklight
|
|
82
82
|
|
83
83
|
def has_constraints?
|
84
84
|
Deprecation.silence(Blacklight::SearchState) do
|
85
|
-
!(query_param.blank? && filter_params.blank? && filters.blank?)
|
85
|
+
!(query_param.blank? && filter_params.blank? && filters.blank? && clause_params.blank?)
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
@@ -90,6 +90,10 @@ module Blacklight
|
|
90
90
|
params[:q]
|
91
91
|
end
|
92
92
|
|
93
|
+
def clause_params
|
94
|
+
params[:clause] || {}
|
95
|
+
end
|
96
|
+
|
93
97
|
def filter_params
|
94
98
|
params[:f] || {}
|
95
99
|
end
|
@@ -36,12 +36,16 @@ module Blacklight
|
|
36
36
|
end
|
37
37
|
|
38
38
|
params = new_state.params
|
39
|
+
param = :f
|
39
40
|
value = as_url_parameter(item)
|
41
|
+
param = :f_inclusive if value.is_a?(Array)
|
40
42
|
|
41
43
|
# value could be a string
|
42
44
|
params[param] = (params[param] || {}).dup
|
43
45
|
|
44
|
-
if
|
46
|
+
if value.is_a? Array
|
47
|
+
params[param][key] = value
|
48
|
+
elsif config.single
|
45
49
|
params[param][key] = [value]
|
46
50
|
else
|
47
51
|
params[param][key] = Array(params[param][key] || []).dup
|
@@ -60,7 +64,10 @@ module Blacklight
|
|
60
64
|
end
|
61
65
|
|
62
66
|
params = new_state.params
|
67
|
+
|
68
|
+
param = :f
|
63
69
|
value = as_url_parameter(item)
|
70
|
+
param = :f_inclusive if value.is_a?(Array)
|
64
71
|
|
65
72
|
# need to dup the facet values too,
|
66
73
|
# if the values aren't dup'd, then the values
|
@@ -86,7 +93,10 @@ module Blacklight
|
|
86
93
|
# @return [Array] an array of applied filters
|
87
94
|
def values
|
88
95
|
params = search_state.params
|
89
|
-
Array(params.dig(
|
96
|
+
f = Array(params.dig(:f, key))
|
97
|
+
f_inclusive = [params.dig(:f_inclusive, key)] if params.dig(:f_inclusive, key).present?
|
98
|
+
|
99
|
+
f + (f_inclusive || [])
|
90
100
|
end
|
91
101
|
delegate :any?, to: :values
|
92
102
|
|
@@ -100,15 +110,15 @@ module Blacklight
|
|
100
110
|
value = as_url_parameter(item)
|
101
111
|
params = search_state.params
|
102
112
|
|
103
|
-
|
113
|
+
if value.is_a?(Array)
|
114
|
+
(params.dig(:f_inclusive, key) || []).to_set == value.to_set
|
115
|
+
else
|
116
|
+
(params.dig(:f, key) || []).include?(value)
|
117
|
+
end
|
104
118
|
end
|
105
119
|
|
106
120
|
private
|
107
121
|
|
108
|
-
def param
|
109
|
-
:f
|
110
|
-
end
|
111
|
-
|
112
122
|
# TODO: this code is duplicated in Blacklight::FacetsHelperBehavior
|
113
123
|
def as_url_parameter(item)
|
114
124
|
if item.respond_to? :value
|
@@ -58,8 +58,17 @@ module Blacklight::Solr
|
|
58
58
|
# @return [Blacklight::Solr::Response] the solr response object
|
59
59
|
def send_and_receive(path, solr_params = {})
|
60
60
|
benchmark("Solr fetch", level: :debug) do
|
61
|
-
|
62
|
-
|
61
|
+
res = if solr_params[:json].present?
|
62
|
+
connection.send_and_receive(
|
63
|
+
path,
|
64
|
+
data: { params: solr_params.to_hash.except(:json) }.merge(solr_params[:json]).to_json,
|
65
|
+
method: :post,
|
66
|
+
headers: { 'Content-Type' => 'application/json' }
|
67
|
+
)
|
68
|
+
else
|
69
|
+
key = blacklight_config.http_method == :post ? :data : :params
|
70
|
+
connection.send_and_receive(path, { key => solr_params.to_hash, method: blacklight_config.http_method })
|
71
|
+
end
|
63
72
|
|
64
73
|
solr_response = blacklight_config.response_model.new(res, solr_params, document_model: blacklight_config.document_model, blacklight_config: blacklight_config)
|
65
74
|
|
@@ -8,7 +8,8 @@ module Blacklight::Solr
|
|
8
8
|
:default_solr_parameters, :add_query_to_solr, :add_facet_fq_to_solr,
|
9
9
|
:add_facetting_to_solr, :add_solr_fields_to_query, :add_paging_to_solr,
|
10
10
|
:add_sorting_to_solr, :add_group_config_to_solr,
|
11
|
-
:add_facet_paging_to_solr
|
11
|
+
:add_facet_paging_to_solr, :add_adv_search_clauses,
|
12
|
+
:add_additional_filters
|
12
13
|
]
|
13
14
|
end
|
14
15
|
|
@@ -61,12 +62,62 @@ module Blacklight::Solr
|
|
61
62
|
elsif search_field&.solr_local_parameters.present?
|
62
63
|
add_search_field_with_local_parameters(solr_parameters)
|
63
64
|
elsif search_state.query_param.is_a? Hash
|
64
|
-
|
65
|
-
elsif
|
65
|
+
add_additional_filters(solr_parameters, search_state.query_param)
|
66
|
+
elsif search_state.query_param
|
66
67
|
solr_parameters[:q] = search_state.query_param
|
67
68
|
end
|
68
69
|
end
|
69
70
|
|
71
|
+
def add_additional_filters(solr_parameters, additional_filters = nil)
|
72
|
+
q = additional_filters || @additional_filters
|
73
|
+
|
74
|
+
return if q.blank?
|
75
|
+
|
76
|
+
solr_parameters[:q] = if q.values.any?(&:blank?)
|
77
|
+
# if any field parameters are empty, exclude _all_ results
|
78
|
+
"{!lucene}NOT *:*"
|
79
|
+
else
|
80
|
+
"{!lucene}" + q.map do |field, values|
|
81
|
+
"#{field}:(#{Array(values).map { |x| solr_param_quote(x) }.join(' OR ')})"
|
82
|
+
end.join(" AND ")
|
83
|
+
end
|
84
|
+
|
85
|
+
solr_parameters[:defType] = 'lucene'
|
86
|
+
solr_parameters[:spellcheck] = 'false'
|
87
|
+
end
|
88
|
+
|
89
|
+
# Transform "clause" parameters into the Solr JSON Query DSL
|
90
|
+
def add_adv_search_clauses(solr_parameters)
|
91
|
+
return if search_state.clause_params.blank?
|
92
|
+
|
93
|
+
defaults = { must: [], must_not: [], should: [] }
|
94
|
+
bool_query = (solr_parameters.dig(:json, :query, :bool) || {}).reverse_merge(defaults)
|
95
|
+
|
96
|
+
default_op = blacklight_params[:op]&.to_sym || :must
|
97
|
+
|
98
|
+
search_state.clause_params.each_value do |clause|
|
99
|
+
op, query = adv_search_clause(clause, default_op)
|
100
|
+
bool_query[op] << query if defaults.key?(op) && query
|
101
|
+
end
|
102
|
+
|
103
|
+
return if bool_query.values.all?(&:blank?)
|
104
|
+
|
105
|
+
solr_parameters[:mm] = 1 if default_op == :should
|
106
|
+
solr_parameters[:json] ||= { query: { bool: {} } }
|
107
|
+
solr_parameters[:json][:query] ||= { bool: {} }
|
108
|
+
solr_parameters[:json][:query][:bool] = bool_query.reject { |_k, v| v.blank? }
|
109
|
+
end
|
110
|
+
|
111
|
+
# @return [Array] the first element is the query operator and the second is the value to add
|
112
|
+
def adv_search_clause(clause, default_op)
|
113
|
+
op = clause[:op]&.to_sym || default_op
|
114
|
+
field = (blacklight_config.search_fields || {})[clause[:field]] if clause[:field]
|
115
|
+
|
116
|
+
return unless field&.clause_params && clause[:query].present?
|
117
|
+
|
118
|
+
[op, field.clause_params.transform_values { |v| v.merge(query: clause[:query]) }]
|
119
|
+
end
|
120
|
+
|
70
121
|
##
|
71
122
|
# Add any existing facet limits, stored in app-level HTTP query
|
72
123
|
# as :f, to solr as appropriate :fq query.
|
@@ -84,8 +135,13 @@ module Blacklight::Solr
|
|
84
135
|
solr_parameters.merge!(subqueries) if subqueries
|
85
136
|
else
|
86
137
|
filter.values.reject(&:blank?).each do |value|
|
87
|
-
filter_query, subqueries =
|
88
|
-
|
138
|
+
filter_query, subqueries = if value.is_a?(Array)
|
139
|
+
facet_inclusive_value_to_fq_string(filter.key, value.reject(&:blank?))
|
140
|
+
else
|
141
|
+
facet_value_to_fq_string(filter.config.key, value)
|
142
|
+
end
|
143
|
+
|
144
|
+
solr_parameters.append_filter_query filter_query
|
89
145
|
solr_parameters.merge!(subqueries) if subqueries
|
90
146
|
end
|
91
147
|
end
|
@@ -250,16 +306,17 @@ module Blacklight::Solr
|
|
250
306
|
|
251
307
|
##
|
252
308
|
# Convert a facet/value pair into a solr fq parameter
|
253
|
-
def facet_value_to_fq_string(facet_field, value)
|
309
|
+
def facet_value_to_fq_string(facet_field, value, use_local_params: true)
|
254
310
|
facet_config = blacklight_config.facet_fields[facet_field]
|
255
311
|
|
256
312
|
solr_field = facet_config.field if facet_config && !facet_config.query
|
257
313
|
solr_field ||= facet_field
|
258
314
|
|
259
315
|
local_params = []
|
260
|
-
local_params << "tag=#{facet_config.tag}" if facet_config && facet_config.tag
|
261
316
|
|
262
|
-
|
317
|
+
if use_local_params
|
318
|
+
local_params << "tag=#{facet_config.tag}" if facet_config && facet_config.tag
|
319
|
+
end
|
263
320
|
|
264
321
|
if facet_config && facet_config.query
|
265
322
|
if facet_config.query[value]
|
@@ -269,12 +326,34 @@ module Blacklight::Solr
|
|
269
326
|
'-*:*'
|
270
327
|
end
|
271
328
|
elsif value.is_a?(Range)
|
329
|
+
prefix = "{!#{local_params.join(' ')}}" unless local_params.empty?
|
272
330
|
"#{prefix}#{solr_field}:[#{value.first} TO #{value.last}]"
|
273
331
|
else
|
274
332
|
"{!term f=#{solr_field}#{(' ' + local_params.join(' ')) unless local_params.empty?}}#{convert_to_term_value(value)}"
|
275
333
|
end
|
276
334
|
end
|
277
335
|
|
336
|
+
def facet_inclusive_value_to_fq_string(facet_field, values)
|
337
|
+
return if values.blank?
|
338
|
+
|
339
|
+
return facet_value_to_fq_string(facet_field, values.first) if values.length == 1
|
340
|
+
|
341
|
+
facet_config = blacklight_config.facet_fields[facet_field]
|
342
|
+
|
343
|
+
local_params = []
|
344
|
+
local_params << "tag=#{facet_config.tag}" if facet_config && facet_config.tag
|
345
|
+
|
346
|
+
solr_filters = values.each_with_object({}).with_index do |(v, h), index|
|
347
|
+
h["f_inclusive.#{facet_field}.#{index}"] = facet_value_to_fq_string(facet_field, v, use_local_params: false)
|
348
|
+
end
|
349
|
+
|
350
|
+
filter_query = solr_filters.keys.map do |k|
|
351
|
+
"{!query v=$#{k}}"
|
352
|
+
end.join(' OR ')
|
353
|
+
|
354
|
+
["{!lucene#{(' ' + local_params.join(' ')) unless local_params.empty?}}#{filter_query}", solr_filters]
|
355
|
+
end
|
356
|
+
|
278
357
|
def convert_to_term_value(value)
|
279
358
|
if value.is_a?(DateTime) || value.is_a?(Time)
|
280
359
|
value.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
|
@@ -322,20 +401,5 @@ module Blacklight::Solr
|
|
322
401
|
# params!
|
323
402
|
solr_parameters["spellcheck.q"] ||= search_state.query_param
|
324
403
|
end
|
325
|
-
|
326
|
-
def add_multifield_search_query(solr_parameters)
|
327
|
-
q = search_state.query_param
|
328
|
-
solr_parameters[:q] = if q.values.any?(&:blank?)
|
329
|
-
# if any field parameters are empty, exclude _all_ results
|
330
|
-
"{!lucene}NOT *:*"
|
331
|
-
else
|
332
|
-
"{!lucene}" + q.map do |field, values|
|
333
|
-
"#{field}:(#{Array(values).map { |x| solr_param_quote(x) }.join(' OR ')})"
|
334
|
-
end.join(" AND ")
|
335
|
-
end
|
336
|
-
|
337
|
-
solr_parameters[:defType] = 'lucene'
|
338
|
-
solr_parameters[:spellcheck] = 'false'
|
339
|
-
end
|
340
404
|
end
|
341
405
|
end
|