blacklight 7.14.1 → 7.15.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|