blacklight 9.0.0.beta7 → 9.0.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/.docker/app/Dockerfile +2 -1
- data/.github/matrix.json +21 -20
- data/README.md +2 -2
- data/VERSION +1 -1
- data/app/assets/javascripts/blacklight/blacklight.esm.js +13 -7
- data/app/assets/javascripts/blacklight/blacklight.esm.js.map +1 -1
- data/app/assets/javascripts/blacklight/blacklight.js +13 -7
- data/app/assets/javascripts/blacklight/blacklight.js.map +1 -1
- data/app/components/blacklight/advanced_search_form_component.rb +2 -1
- data/app/components/blacklight/document_component.rb +10 -13
- data/app/components/blacklight/facets/filters_component.rb +2 -2
- data/app/components/blacklight/facets/suggest_component.html.erb +17 -12
- data/app/components/blacklight/facets/suggest_component.rb +2 -3
- data/app/components/blacklight/metadata_field_component.html.erb +2 -2
- data/app/components/blacklight/metadata_field_component.rb +2 -1
- data/app/components/blacklight/metadata_field_layout_component.rb +9 -4
- data/app/components/blacklight/search_bar_component.html.erb +1 -1
- data/app/controllers/concerns/blacklight/catalog.rb +3 -4
- data/app/javascript/blacklight-frontend/checkbox_submit.js +2 -2
- data/app/javascript/blacklight-frontend/facet_suggest.js +4 -1
- data/app/javascript/blacklight-frontend/modal.js +7 -4
- data/app/presenters/blacklight/document_presenter.rb +6 -5
- data/app/presenters/blacklight/facet_field_presenter.rb +10 -3
- data/app/presenters/blacklight/field_presenter.rb +4 -2
- data/app/presenters/blacklight/rendering/abstract_step.rb +7 -1
- data/app/presenters/blacklight/rendering/join.rb +9 -5
- data/app/presenters/blacklight/rendering/terminator.rb +1 -1
- data/app/services/blacklight/search_service.rb +4 -2
- data/app/views/catalog/_show_main_content.html.erb +9 -5
- data/app/views/catalog/index.html.erb +0 -1
- data/app/views/catalog/show.html.erb +2 -2
- data/config/locales/blacklight.en.yml +1 -1
- data/lib/blacklight/component.rb +2 -0
- data/lib/blacklight/configuration/facet_field.rb +2 -0
- data/lib/blacklight/configuration/view_config.rb +30 -16
- data/lib/blacklight/configuration.rb +56 -9
- data/lib/blacklight/routes/searchable.rb +1 -1
- data/lib/blacklight/search_builder.rb +160 -1
- data/lib/blacklight/search_state/pivot_filter_field.rb +1 -1
- data/lib/blacklight/solr/field_reflection_search_builder.rb +11 -0
- data/lib/blacklight/solr/repository.rb +5 -5
- data/lib/blacklight/solr/search_builder_behavior.rb +73 -7
- data/lib/blacklight/solr/single_doc_search_builder.rb +25 -0
- data/lib/generators/blacklight/templates/catalog_controller.rb +27 -5
- data/lib/generators/blacklight/templates/solr/conf/solrconfig.xml +0 -67
- data/package.json +1 -1
- data/spec/components/blacklight/document_component_spec.rb +0 -7
- data/spec/components/blacklight/facets/filters_component_spec.rb +3 -3
- data/spec/components/blacklight/facets/suggest_component_spec.rb +14 -1
- data/spec/components/blacklight/search_bar_component_spec.rb +24 -1
- data/spec/controllers/blacklight/catalog_spec.rb +1 -1
- data/spec/features/advanced_search_spec.rb +39 -20
- data/spec/features/facets_spec.rb +9 -0
- data/spec/models/blacklight/configuration_spec.rb +126 -0
- data/spec/models/blacklight/search_builder_spec.rb +11 -1
- data/spec/models/blacklight/solr/repository_spec.rb +6 -0
- data/spec/models/blacklight/solr/search_builder_behavior_spec.rb +214 -8
- data/spec/presenters/blacklight/document_presenter_spec.rb +3 -3
- data/spec/presenters/blacklight/field_presenter_spec.rb +103 -22
- data/spec/presenters/blacklight/rendering/pipeline_spec.rb +130 -14
- metadata +8 -16
- data/app/controllers/concerns/blacklight/facetable.rb +0 -34
- data/app/models/facet_search_builder.rb +0 -5
- data/app/services/blacklight/facet_search_service.rb +0 -44
- data/app/views/shared/_sitelinks_search_box.html.erb +0 -12
- data/lib/blacklight/abstract_search_builder.rb +0 -154
- data/lib/blacklight/facet_search_builder.rb +0 -18
- data/lib/blacklight/solr/facet_search_builder_behavior.rb +0 -62
- data/spec/features/sitelinks_search_box_spec.rb +0 -13
- data/spec/models/blacklight/facet_search_builder_spec.rb +0 -19
- data/spec/models/blacklight/solr/facet_search_builder_behavior_spec.rb +0 -929
|
@@ -47,7 +47,6 @@ module Blacklight
|
|
|
47
47
|
property :header_component, default: Blacklight::HeaderComponent
|
|
48
48
|
property :full_width_layout, default: false
|
|
49
49
|
|
|
50
|
-
# bootstrap_version may be set to 4 or 5
|
|
51
50
|
bootstrap_version = ENV['BOOTSTRAP_VERSION'].presence || "5"
|
|
52
51
|
property :bootstrap_version, default: /(\d)(?:\.\d){0,2}/.match(bootstrap_version)[1].to_i
|
|
53
52
|
|
|
@@ -73,7 +72,8 @@ module Blacklight
|
|
|
73
72
|
# @!attribute json_solr_path
|
|
74
73
|
# @since v7.34.0
|
|
75
74
|
# @return [String] The url path (relative to the solr base url) to use when using Solr's JSON Query DSL (as with the advanced search)
|
|
76
|
-
|
|
75
|
+
# @note You can configure a separate custom 'advanced' requestHandler in solrconfig.xml if desired, but it isn't necessary; the default 'select' handler will work.
|
|
76
|
+
property :json_solr_path, default: 'select'
|
|
77
77
|
# @!attribute document_unique_id_param
|
|
78
78
|
# @since v5.2.0
|
|
79
79
|
# @return [Symbol] The solr query parameter used for sending the unique identifiers for one or more documents
|
|
@@ -103,9 +103,6 @@ module Blacklight
|
|
|
103
103
|
# @!attribute search_builder_class
|
|
104
104
|
# @return [Class] class for converting Blacklight parameters to request parameters for the repository_class
|
|
105
105
|
property :search_builder_class, default: ::SearchBuilder
|
|
106
|
-
# @!attribute search_builder_class
|
|
107
|
-
# @return [Class] class for converting Blacklight parameters to request parameters for the repository_class
|
|
108
|
-
property :facet_search_builder_class, default: ::FacetSearchBuilder
|
|
109
106
|
# @!attribute response_model
|
|
110
107
|
# model that maps index responses to the blacklight response model
|
|
111
108
|
# @return [Class]
|
|
@@ -147,11 +144,15 @@ module Blacklight
|
|
|
147
144
|
# @return [Blacklight::Configuration::ViewConfig::Index]
|
|
148
145
|
property :index, default: ViewConfig::Index.new(
|
|
149
146
|
# document presenter class used by helpers and views
|
|
150
|
-
document_presenter_class:
|
|
147
|
+
document_presenter_class: Blacklight::IndexPresenter,
|
|
151
148
|
# document presenter used for json responses
|
|
152
149
|
json_presenter_class: Blacklight::JsonPresenter,
|
|
153
150
|
# component class used to render a document
|
|
154
151
|
document_component: Blacklight::DocumentComponent,
|
|
152
|
+
document_embed_component: nil,
|
|
153
|
+
document_metadata_component: Blacklight::DocumentMetadataComponent,
|
|
154
|
+
document_thumbnail_component: Blacklight::Document::ThumbnailComponent,
|
|
155
|
+
document_title_component: Blacklight::DocumentTitleComponent,
|
|
155
156
|
sidebar_component: Blacklight::Search::SidebarComponent,
|
|
156
157
|
dropdown_component: Blacklight::System::DropdownComponent,
|
|
157
158
|
# solr field to use to render a document title
|
|
@@ -187,8 +188,9 @@ module Blacklight
|
|
|
187
188
|
# @return [Blacklight::Configuration::ViewConfig::Show]
|
|
188
189
|
property :show, default: ViewConfig::Show.new(
|
|
189
190
|
# document presenter class used by helpers and views
|
|
190
|
-
document_presenter_class:
|
|
191
|
+
document_presenter_class: Blacklight::ShowPresenter,
|
|
191
192
|
document_component: Blacklight::DocumentComponent,
|
|
193
|
+
document_thumbnail_component: nil,
|
|
192
194
|
show_tools_component: Blacklight::Document::ShowToolsComponent,
|
|
193
195
|
show_header_tools_component: nil,
|
|
194
196
|
document_header_component: Blacklight::Document::PageHeaderComponent,
|
|
@@ -269,6 +271,10 @@ module Blacklight
|
|
|
269
271
|
# @since v5.10.0
|
|
270
272
|
# @return [Integer]
|
|
271
273
|
property :default_facet_limit, default: 10
|
|
274
|
+
# @!attribute default_facet_suggest
|
|
275
|
+
# @since v9.0.0
|
|
276
|
+
# @return [Boolean]
|
|
277
|
+
property :default_facet_suggest, default: true
|
|
272
278
|
# @!attribute default_more_limit
|
|
273
279
|
# @since v7.0.0
|
|
274
280
|
# @return [Integer]
|
|
@@ -299,8 +305,13 @@ module Blacklight
|
|
|
299
305
|
|
|
300
306
|
# @!attribute advanced_search
|
|
301
307
|
# @since v7.15.0
|
|
302
|
-
# @return [
|
|
303
|
-
|
|
308
|
+
# @return [OpenStructWithHashAccess] Configuration for advanced search, including:
|
|
309
|
+
# enabled: (Boolean) whether advanced search is enabled
|
|
310
|
+
# form_solr_parameters: (Hash) optional parameters to send to Solr for the advanced search
|
|
311
|
+
# form; can override values that are set automatically via the
|
|
312
|
+
# #copy_facet_field_config_to_advanced! method
|
|
313
|
+
property :advanced_search, default: OpenStructWithHashAccess.new(enabled: true,
|
|
314
|
+
form_solr_parameters: {})
|
|
304
315
|
|
|
305
316
|
# @!attribute enable_search_bar_autofocus
|
|
306
317
|
# @since v7.2.0
|
|
@@ -457,6 +468,42 @@ module Blacklight
|
|
|
457
468
|
facet_fields.map { |_facet, opts| opts[:group] }.uniq
|
|
458
469
|
end
|
|
459
470
|
|
|
471
|
+
# Use existing search field configs to automatically prepare fields for use
|
|
472
|
+
# by the advanced search form.
|
|
473
|
+
def copy_search_field_config_to_advanced!
|
|
474
|
+
search_fields.each_value do |field|
|
|
475
|
+
next if field.include_in_advanced_search == false
|
|
476
|
+
next if field.clause_params
|
|
477
|
+
|
|
478
|
+
field.clause_params = {}
|
|
479
|
+
field.clause_params[:edismax] = field.solr_parameters.dup || {}
|
|
480
|
+
end
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
# Use existing facet field configs to automatically prepare fields for use
|
|
484
|
+
# by the advanced search form. If more specific config is needed, e.g., to
|
|
485
|
+
# set the facet limit for one field to a value other than -1, it can be
|
|
486
|
+
# expressed in the configuration in advanced_search.form_solr_parameters
|
|
487
|
+
def copy_facet_field_config_to_advanced!
|
|
488
|
+
advanced_search.form_solr_parameters ||= {}
|
|
489
|
+
advanced_search.form_solr_parameters['facet.sort'] ||= 'count'
|
|
490
|
+
advanced_search.form_solr_parameters['facet.field'] ||= []
|
|
491
|
+
|
|
492
|
+
facet_fields.each_value do |field|
|
|
493
|
+
next if field.include_in_advanced_search == false
|
|
494
|
+
# Skip query-type and pivot facets that can't be requested via facet.field
|
|
495
|
+
next if field.query || field.pivot || field.range
|
|
496
|
+
|
|
497
|
+
# Add the facet field to the advanced search configuration
|
|
498
|
+
advanced_search.form_solr_parameters['facet.field'] << field.field unless
|
|
499
|
+
advanced_search.form_solr_parameters['facet.field'].include?(field.field)
|
|
500
|
+
|
|
501
|
+
# Set the facet field's limit to -1 to show ALL values in advanced search
|
|
502
|
+
advanced_search.form_solr_parameters["f.#{field.field}.facet.limit"] = -1 unless
|
|
503
|
+
advanced_search.form_solr_parameters["f.#{field.field}.facet.limit"]
|
|
504
|
+
end
|
|
505
|
+
end
|
|
506
|
+
|
|
460
507
|
# Add any configured facet fields to the default solr parameters hash
|
|
461
508
|
# @overload add_facet_fields_to_solr_request!
|
|
462
509
|
# add all facet fields to the solr request
|
|
@@ -18,7 +18,7 @@ module Blacklight
|
|
|
18
18
|
mapper.get "opensearch"
|
|
19
19
|
mapper.get 'suggest', as: 'suggest_index'
|
|
20
20
|
mapper.get "facet/:id", action: 'facet', as: 'facet'
|
|
21
|
-
mapper.get "facet_suggest/:id
|
|
21
|
+
mapper.get "facet_suggest/:id", action: 'facet', as: 'facet_suggest', defaults: { only_values: true }
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
24
|
end
|
|
@@ -5,7 +5,45 @@ module Blacklight
|
|
|
5
5
|
# Blacklight's SearchBuilder converts blacklight request parameters into
|
|
6
6
|
# query parameters appropriate for search index. It does so by evaluating a
|
|
7
7
|
# chain of processing methods to populate a result hash (see {#to_hash}).
|
|
8
|
-
class SearchBuilder
|
|
8
|
+
class SearchBuilder
|
|
9
|
+
class_attribute :default_processor_chain
|
|
10
|
+
self.default_processor_chain = []
|
|
11
|
+
|
|
12
|
+
attr_reader :processor_chain, :search_state, :blacklight_params
|
|
13
|
+
|
|
14
|
+
# @overload initialize(scope)
|
|
15
|
+
# @param [Object] scope the scope where the filter methods reside in.
|
|
16
|
+
# @overload initialize(processor_chain, scope)
|
|
17
|
+
# @param [List<Symbol>,TrueClass] processor_chain options a list of filter methods to run or true, to use the default methods
|
|
18
|
+
# @param [Object] scope the scope where the filter methods reside in.
|
|
19
|
+
def initialize(*options)
|
|
20
|
+
case options.size
|
|
21
|
+
when 1
|
|
22
|
+
@processor_chain = default_processor_chain.dup
|
|
23
|
+
@scope = options.first
|
|
24
|
+
when 2
|
|
25
|
+
@processor_chain, @scope = options
|
|
26
|
+
else
|
|
27
|
+
raise ArgumentError, "wrong number of arguments. (#{options.size} for 1..2)"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
@blacklight_params = {}
|
|
31
|
+
search_state_class = @scope.try(:search_state_class) || Blacklight::SearchState
|
|
32
|
+
@search_state = search_state_class.new(@blacklight_params, @scope&.blacklight_config, @scope)
|
|
33
|
+
@additional_filters = {}
|
|
34
|
+
@merged_params = {}
|
|
35
|
+
@reverse_merged_params = {}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
##
|
|
39
|
+
# Set the parameters to pass through the processor chain
|
|
40
|
+
def with(blacklight_params_or_search_state = {})
|
|
41
|
+
params_will_change!
|
|
42
|
+
@search_state = blacklight_params_or_search_state.is_a?(Blacklight::SearchState) ? blacklight_params_or_search_state : @search_state.reset(blacklight_params_or_search_state)
|
|
43
|
+
@blacklight_params = @search_state.params.dup
|
|
44
|
+
self
|
|
45
|
+
end
|
|
46
|
+
|
|
9
47
|
##
|
|
10
48
|
# Update the :q (query) parameter
|
|
11
49
|
# @param [Hash<Symbol,Object>] conditions the field and values to query on
|
|
@@ -21,6 +59,7 @@ module Blacklight
|
|
|
21
59
|
|
|
22
60
|
##
|
|
23
61
|
# Append additional processor chain directives
|
|
62
|
+
# This is used in blacklight_range_limit
|
|
24
63
|
def append(*addl_processor_chain)
|
|
25
64
|
params_will_change!
|
|
26
65
|
builder = self.class.new(processor_chain + addl_processor_chain, scope)
|
|
@@ -55,6 +94,68 @@ module Blacklight
|
|
|
55
94
|
builder
|
|
56
95
|
end
|
|
57
96
|
|
|
97
|
+
##
|
|
98
|
+
# Merge additional, repository-specific parameters
|
|
99
|
+
def merge(extra_params, &)
|
|
100
|
+
if extra_params
|
|
101
|
+
params_will_change!
|
|
102
|
+
@merged_params.merge!(extra_params.to_hash, &)
|
|
103
|
+
end
|
|
104
|
+
self
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
##
|
|
108
|
+
# "Reverse merge" additional, repository-specific parameters
|
|
109
|
+
def reverse_merge(extra_params, &)
|
|
110
|
+
if extra_params
|
|
111
|
+
params_will_change!
|
|
112
|
+
@reverse_merged_params.reverse_merge!(extra_params.to_hash, &)
|
|
113
|
+
end
|
|
114
|
+
self
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
delegate :[], :key?, to: :to_hash
|
|
118
|
+
|
|
119
|
+
# a solr query method
|
|
120
|
+
# @return [Blacklight::Solr::Response] the solr response object
|
|
121
|
+
def to_hash
|
|
122
|
+
return @params unless params_need_update?
|
|
123
|
+
|
|
124
|
+
@params = processed_parameters
|
|
125
|
+
.reverse_merge(@reverse_merged_params)
|
|
126
|
+
.merge(@merged_params)
|
|
127
|
+
.tap { clear_changes }
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
alias_method :query, :to_hash
|
|
131
|
+
alias_method :to_h, :to_hash
|
|
132
|
+
|
|
133
|
+
# The CatalogController #index action uses this.
|
|
134
|
+
# Solr parameters can come from a number of places. From lowest
|
|
135
|
+
# precedence to highest:
|
|
136
|
+
# 1. General defaults in blacklight config (are trumped by)
|
|
137
|
+
# 2. defaults for the particular search field identified by params[:search_field] (are trumped by)
|
|
138
|
+
# 3. certain parameters directly on input HTTP query params
|
|
139
|
+
# * not just any parameter is grabbed willy nilly, only certain ones are allowed by HTTP input)
|
|
140
|
+
# * for legacy reasons, qt in http query does not over-ride qt in search field definition default.
|
|
141
|
+
# 4. extra parameters passed in as argument.
|
|
142
|
+
#
|
|
143
|
+
# spellcheck.q will be supplied with the [:q] value unless specifically
|
|
144
|
+
# specified otherwise.
|
|
145
|
+
#
|
|
146
|
+
# Incoming parameter :f is mapped to :fq solr parameter.
|
|
147
|
+
#
|
|
148
|
+
# @return a params hash for searching solr.
|
|
149
|
+
def processed_parameters
|
|
150
|
+
request.tap do |request_parameters|
|
|
151
|
+
processor_chain.each do |method_name|
|
|
152
|
+
send(method_name, request_parameters)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
delegate :blacklight_config, to: :scope
|
|
158
|
+
|
|
58
159
|
def start=(value)
|
|
59
160
|
params_will_change!
|
|
60
161
|
@start = value.to_i
|
|
@@ -109,6 +210,34 @@ module Blacklight
|
|
|
109
210
|
|
|
110
211
|
alias per rows
|
|
111
212
|
|
|
213
|
+
# sets the facet that this query pertains to, for the purpose of facet pagination
|
|
214
|
+
def facet=(value)
|
|
215
|
+
params_will_change!
|
|
216
|
+
@facet = value
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# @param [Object] value
|
|
220
|
+
def facet(value = nil)
|
|
221
|
+
if value
|
|
222
|
+
self.facet = value
|
|
223
|
+
return self
|
|
224
|
+
end
|
|
225
|
+
@facet
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def facet_suggestion_query=(value)
|
|
229
|
+
params_will_change!
|
|
230
|
+
@facet_suggestion_query = value
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def facet_suggestion_query(value = nil)
|
|
234
|
+
if value
|
|
235
|
+
self.facet_suggestion_query = value
|
|
236
|
+
return self
|
|
237
|
+
end
|
|
238
|
+
@facet_suggestion_query
|
|
239
|
+
end
|
|
240
|
+
|
|
112
241
|
# Decode the user provided 'sort' parameter into a sort string that can be
|
|
113
242
|
# passed to the search. This sanitizes the input by ensuring only
|
|
114
243
|
# configured search values are passed through to the search.
|
|
@@ -116,5 +245,35 @@ module Blacklight
|
|
|
116
245
|
def sort
|
|
117
246
|
search_state.sort_field&.sort
|
|
118
247
|
end
|
|
248
|
+
|
|
249
|
+
delegate :search_field, to: :search_state
|
|
250
|
+
|
|
251
|
+
private
|
|
252
|
+
|
|
253
|
+
def request
|
|
254
|
+
Blacklight::Solr::Request.new
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def should_add_field_to_request? _field_name, field
|
|
258
|
+
field.include_in_request || (field.include_in_request.nil? && blacklight_config.add_field_configuration_to_solr_request)
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
attr_reader :scope
|
|
262
|
+
|
|
263
|
+
def params_will_change!
|
|
264
|
+
@dirty = true
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def params_changed?
|
|
268
|
+
!!@dirty
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def params_need_update?
|
|
272
|
+
params_changed? || @params.nil?
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def clear_changes
|
|
276
|
+
@dirty = false
|
|
277
|
+
end
|
|
119
278
|
end
|
|
120
279
|
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Blacklight::Solr
|
|
4
|
+
class FieldReflectionSearchBuilder < SearchBuilder
|
|
5
|
+
self.default_processor_chain = [:add_params]
|
|
6
|
+
|
|
7
|
+
def add_params(request)
|
|
8
|
+
request.reverse_merge!({ fl: '*', 'json.nl' => 'map' })
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -7,8 +7,7 @@ module Blacklight::Solr
|
|
|
7
7
|
# @param [String] id document's unique key value
|
|
8
8
|
# @param [Hash] params additional solr query parameters
|
|
9
9
|
def find id, params = {}
|
|
10
|
-
doc_params =
|
|
11
|
-
.merge(blacklight_config.document_unique_id_param => id)
|
|
10
|
+
doc_params = SingleDocSearchBuilder.new(self, id, params)
|
|
12
11
|
|
|
13
12
|
solr_response = send_and_receive blacklight_config.document_solr_path || blacklight_config.solr_path, doc_params
|
|
14
13
|
raise Blacklight::Exceptions::RecordNotFound if solr_response.documents.empty?
|
|
@@ -24,14 +23,14 @@ module Blacklight::Solr
|
|
|
24
23
|
|
|
25
24
|
##
|
|
26
25
|
# Execute a search query against solr
|
|
27
|
-
# @param [Hash] params solr query parameters
|
|
26
|
+
# @param [Hash,Blacklight::SearchBuilder] params solr query parameters
|
|
28
27
|
# @param [String] path solr request handler path
|
|
29
28
|
def search pos_params = nil, path: nil, params: nil, **kwargs
|
|
30
29
|
if pos_params
|
|
31
30
|
Blacklight.deprecation.warn("Passing positional arguments to search() is deprecated. Use the params kwarg instead.")
|
|
32
31
|
end
|
|
33
32
|
|
|
34
|
-
request_params = (params || pos_params).reverse_merge(kwargs).reverse_merge({ qt: blacklight_config.qt })
|
|
33
|
+
request_params = (params || pos_params || {}).reverse_merge(kwargs).reverse_merge({ qt: blacklight_config.qt })
|
|
35
34
|
|
|
36
35
|
send_and_receive(path || default_search_path(request_params), request_params)
|
|
37
36
|
end
|
|
@@ -47,7 +46,8 @@ module Blacklight::Solr
|
|
|
47
46
|
# Gets a list of available fields
|
|
48
47
|
# @return [Hash]
|
|
49
48
|
def reflect_fields
|
|
50
|
-
|
|
49
|
+
doc_params = FieldReflectionSearchBuilder.new(self)
|
|
50
|
+
send_and_receive('admin/luke', doc_params)['fields']
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
##
|
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Blacklight::Solr
|
|
4
|
+
# This depends on being imported into a class that extends AbstractSearchBuilder
|
|
4
5
|
module SearchBuilderBehavior
|
|
5
6
|
extend ActiveSupport::Concern
|
|
6
7
|
|
|
7
8
|
included do
|
|
8
9
|
self.default_processor_chain = [
|
|
9
|
-
:default_solr_parameters,
|
|
10
|
-
:
|
|
11
|
-
:
|
|
12
|
-
:
|
|
10
|
+
:default_solr_parameters,
|
|
11
|
+
:add_search_field_default_parameters,
|
|
12
|
+
:add_query_to_solr,
|
|
13
|
+
:add_facet_fq_to_solr,
|
|
14
|
+
:add_facetting_to_solr,
|
|
15
|
+
:add_solr_fields_to_query,
|
|
16
|
+
:add_paging_to_solr,
|
|
17
|
+
:add_sorting_to_solr,
|
|
18
|
+
:add_group_config_to_solr,
|
|
13
19
|
:add_adv_search_clauses,
|
|
20
|
+
:add_facets_for_advanced_search_form,
|
|
21
|
+
:add_facet_paging_to_solr,
|
|
22
|
+
:add_facet_suggestion_parameters,
|
|
14
23
|
:add_additional_filters
|
|
15
24
|
]
|
|
16
25
|
end
|
|
@@ -95,6 +104,13 @@ module Blacklight::Solr
|
|
|
95
104
|
def add_adv_search_clauses(solr_parameters)
|
|
96
105
|
return if search_state.clause_params.blank?
|
|
97
106
|
|
|
107
|
+
# We need to specify lucene as the top-level defType when using JSON Query DSL in Solr versions
|
|
108
|
+
# between 7.2.0 & 9.4.0. After 9.4.0 this is no longer necessary, but also not harmful to include.
|
|
109
|
+
solr_parameters[:defType] = 'lucene'
|
|
110
|
+
|
|
111
|
+
# Disable spellcheck, which doesn't work when using JSON Query DSL
|
|
112
|
+
solr_parameters[:spellcheck] = 'false'
|
|
113
|
+
|
|
98
114
|
defaults = { must: [], must_not: [], should: [] }
|
|
99
115
|
default_op = blacklight_params[:op]&.to_sym || :must
|
|
100
116
|
solr_parameters[:mm] = 1 if default_op == :should && search_state.clause_params.values.any? { |clause| }
|
|
@@ -117,6 +133,16 @@ module Blacklight::Solr
|
|
|
117
133
|
[op, field.clause_params.transform_values { |v| v.merge(query: clause[:query]) }]
|
|
118
134
|
end
|
|
119
135
|
|
|
136
|
+
# Merge the advanced search form parameters into the solr parameters
|
|
137
|
+
# @param [Hash] solr_parameters the current solr parameters
|
|
138
|
+
# @return [Hash] the solr parameters with the additional advanced search form parameters
|
|
139
|
+
def add_facets_for_advanced_search_form(solr_parameters)
|
|
140
|
+
return unless search_state.controller&.action_name == 'advanced_search' &&
|
|
141
|
+
blacklight_config.advanced_search[:form_solr_parameters]
|
|
142
|
+
|
|
143
|
+
solr_parameters.merge!(blacklight_config.advanced_search[:form_solr_parameters])
|
|
144
|
+
end
|
|
145
|
+
|
|
120
146
|
##
|
|
121
147
|
# Add any existing facet limits, stored in app-level HTTP query
|
|
122
148
|
# as :f, to solr as appropriate :fq query.
|
|
@@ -215,8 +241,6 @@ module Blacklight::Solr
|
|
|
215
241
|
# copy paging params from BL app over to solr, changing
|
|
216
242
|
# app level per_page and page to Solr rows and start.
|
|
217
243
|
def add_paging_to_solr(solr_params)
|
|
218
|
-
rows(solr_params[:rows] || 10) if rows.nil?
|
|
219
|
-
|
|
220
244
|
solr_params[:rows] = rows
|
|
221
245
|
|
|
222
246
|
solr_params[:start] = start if start.nonzero?
|
|
@@ -233,6 +257,48 @@ module Blacklight::Solr
|
|
|
233
257
|
solr_parameters[:group] = false if search_state.filter(grouped_key_for_results).any?
|
|
234
258
|
end
|
|
235
259
|
|
|
260
|
+
def add_facet_paging_to_solr(solr_params)
|
|
261
|
+
return if facet.blank?
|
|
262
|
+
|
|
263
|
+
facet_config = blacklight_config.facet_fields[facet]
|
|
264
|
+
|
|
265
|
+
solr_params[:rows] = 0
|
|
266
|
+
|
|
267
|
+
limit = if solr_params["facet.limit"]
|
|
268
|
+
solr_params["facet.limit"].to_i
|
|
269
|
+
else
|
|
270
|
+
facet_config.fetch(:more_limit, blacklight_config.default_more_limit)
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
page = search_state.facet_page
|
|
274
|
+
sort = search_state.facet_sort
|
|
275
|
+
prefix = search_state.facet_prefix
|
|
276
|
+
offset = (page - 1) * limit
|
|
277
|
+
|
|
278
|
+
if facet_config.json
|
|
279
|
+
add_solr_facet_json_params(solr_parameters, facet, facet_config, limit: limit + 1, offset: offset, sort: sort, prefix: prefix)
|
|
280
|
+
return
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# Now override with our specific things for fetching facet values
|
|
284
|
+
facet_ex = facet_config.respond_to?(:ex) ? facet_config.ex : nil
|
|
285
|
+
solr_params[:'facet.field'] = with_ex_local_param(facet_ex, facet_config.field)
|
|
286
|
+
|
|
287
|
+
# Need to set as f.facet_field.facet.* to make sure we
|
|
288
|
+
# override any field-specific default in the solr request handler.
|
|
289
|
+
solr_params[:"f.#{facet_config.field}.facet.limit"] = limit + 1
|
|
290
|
+
solr_params[:"f.#{facet_config.field}.facet.offset"] = offset
|
|
291
|
+
solr_params[:"f.#{facet_config.field}.facet.sort"] = sort if sort
|
|
292
|
+
solr_params[:"f.#{facet_config.field}.facet.prefix"] = prefix if prefix
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def add_facet_suggestion_parameters(solr_params)
|
|
296
|
+
return if facet.blank? || facet_suggestion_query.blank?
|
|
297
|
+
|
|
298
|
+
solr_params[:'facet.contains'] = facet_suggestion_query[0..50]
|
|
299
|
+
solr_params[:'facet.contains.ignoreCase'] = true
|
|
300
|
+
end
|
|
301
|
+
|
|
236
302
|
def with_ex_local_param(ex, value)
|
|
237
303
|
if ex
|
|
238
304
|
"{!ex=#{ex}}#{value}"
|
|
@@ -243,7 +309,7 @@ module Blacklight::Solr
|
|
|
243
309
|
|
|
244
310
|
# Look up facet limit for given facet_field. Will look at config, and
|
|
245
311
|
# if config is 'true' will look up from Solr @response if available. If
|
|
246
|
-
# no limit is
|
|
312
|
+
# no limit is available, returns nil. Used from #add_facetting_to_solr
|
|
247
313
|
# to supply f.fieldname.facet.limit values in solr request (no @response
|
|
248
314
|
# available), and used in display (with @response available) to create
|
|
249
315
|
# a facet paginator with the right limit.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Blacklight::Solr
|
|
4
|
+
class SingleDocSearchBuilder < SearchBuilder
|
|
5
|
+
self.default_processor_chain = [:add_defaults, :add_qt, :add_unique_id]
|
|
6
|
+
|
|
7
|
+
def initialize(scope, id, other_params)
|
|
8
|
+
@other_params = other_params
|
|
9
|
+
@id = id
|
|
10
|
+
super(scope)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def add_defaults(request)
|
|
14
|
+
request.reverse_merge!(blacklight_config.default_document_solr_params).reverse_merge!(@other_params)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def add_qt(request)
|
|
18
|
+
request[:qt] ||= blacklight_config.document_solr_request_handler if blacklight_config.document_solr_request_handler
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def add_unique_id(request)
|
|
22
|
+
request[blacklight_config.document_unique_id_param] = @id
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -12,7 +12,7 @@ class <%= controller_name.classify %>Controller < ApplicationController
|
|
|
12
12
|
# rescue_from Blacklight::Exceptions::InvalidRequest, with: :my_handling_method
|
|
13
13
|
|
|
14
14
|
configure_blacklight do |config|
|
|
15
|
-
## Specify the style of markup to be generated
|
|
15
|
+
## Specify the style of markup to be generated
|
|
16
16
|
# config.bootstrap_version = 5
|
|
17
17
|
#
|
|
18
18
|
## Class for sending and receiving requests from a search index
|
|
@@ -29,6 +29,13 @@ class <%= controller_name.classify %>Controller < ApplicationController
|
|
|
29
29
|
#
|
|
30
30
|
## Should the raw solr document endpoint (e.g. /catalog/:id/raw) be enabled
|
|
31
31
|
# config.raw_endpoint.enabled = false
|
|
32
|
+
#
|
|
33
|
+
## Should advanced search be enabled
|
|
34
|
+
# config.advanced_search.enabled = true
|
|
35
|
+
#
|
|
36
|
+
## Optional fine-tuning for advanced search, e.g., set different limits for
|
|
37
|
+
## different facets.
|
|
38
|
+
# config.advanced_search.form_solr_parameters = {}
|
|
32
39
|
|
|
33
40
|
## Default parameters to send to solr for all search-like requests. See also SearchBuilder#processed_parameters
|
|
34
41
|
config.default_solr_params = {
|
|
@@ -38,7 +45,7 @@ class <%= controller_name.classify %>Controller < ApplicationController
|
|
|
38
45
|
# solr path which will be added to solr base url before the other solr params.
|
|
39
46
|
#config.solr_path = 'select'
|
|
40
47
|
#config.document_solr_path = 'get'
|
|
41
|
-
#config.json_solr_path = '
|
|
48
|
+
#config.json_solr_path = 'select'
|
|
42
49
|
|
|
43
50
|
# items to show per page, each number in the array represent another option to choose from.
|
|
44
51
|
#config.per_page = [10,20,50,100]
|
|
@@ -105,6 +112,12 @@ class <%= controller_name.classify %>Controller < ApplicationController
|
|
|
105
112
|
# :show may be set to false if you don't want the facet to be drawn in the
|
|
106
113
|
# facet bar
|
|
107
114
|
#
|
|
115
|
+
# Set :include_in_advanced_search to false for any search field or facet field
|
|
116
|
+
# that you want to exclude from appearing in the advanced search page.
|
|
117
|
+
#
|
|
118
|
+
# Set :include_in_simple_select to false for any search field you want to render
|
|
119
|
+
# in the Advanced Search page but exclude from the main search box scope selector.
|
|
120
|
+
#
|
|
108
121
|
# Set :index_range to true if you want the facet pagination view to have facet prefix-based navigation.
|
|
109
122
|
# (useful when user clicks "more" on a large facet and wants to navigate alphabetically across a large set of results)
|
|
110
123
|
# :index_range can be an array or range of prefixes that will be used to create the navigation (note: It is case sensitive when searching values)
|
|
@@ -121,7 +134,9 @@ class <%= controller_name.classify %>Controller < ApplicationController
|
|
|
121
134
|
|
|
122
135
|
config.add_facet_field 'example_pivot_field',
|
|
123
136
|
label: 'Pivot Field',
|
|
124
|
-
pivot: ['language_ssim', 'subject_geo_ssim', 'subject_ssim'],
|
|
137
|
+
pivot: ['language_ssim', 'subject_geo_ssim', 'subject_ssim'],
|
|
138
|
+
collapsing: true,
|
|
139
|
+
include_in_advanced_search: false
|
|
125
140
|
|
|
126
141
|
config.add_facet_field 'example_query_facet_field', label: 'Publish Date', :query => {
|
|
127
142
|
:years_5 => { label: 'within 5 Years', fq: "pub_date_ssim:[#{Time.zone.now.year - 5 } TO *]" },
|
|
@@ -165,7 +180,7 @@ class <%= controller_name.classify %>Controller < ApplicationController
|
|
|
165
180
|
config.add_show_field 'isbn_ssim', label: 'ISBN'
|
|
166
181
|
|
|
167
182
|
# "fielded" search configuration. Used by pulldown among other places.
|
|
168
|
-
# For supported keys in hash, see rdoc for Blacklight::
|
|
183
|
+
# For supported keys in hash, see rdoc for Blacklight::Configuration::SearchField
|
|
169
184
|
#
|
|
170
185
|
# Search fields will inherit the :qt solr request handler from
|
|
171
186
|
# config[:default_solr_parameters], OR can specify a different one
|
|
@@ -208,7 +223,7 @@ class <%= controller_name.classify %>Controller < ApplicationController
|
|
|
208
223
|
|
|
209
224
|
# Specifying a :qt only to show it's possible, and so our internal automated
|
|
210
225
|
# tests can test it. In this case it's the same as
|
|
211
|
-
# config[:default_solr_parameters][:qt], so isn't actually
|
|
226
|
+
# config[:default_solr_parameters][:qt], so isn't actually necessary.
|
|
212
227
|
config.add_search_field('subject') do |field|
|
|
213
228
|
field.qt = 'search'
|
|
214
229
|
field.solr_parameters = {
|
|
@@ -218,6 +233,13 @@ class <%= controller_name.classify %>Controller < ApplicationController
|
|
|
218
233
|
}
|
|
219
234
|
end
|
|
220
235
|
|
|
236
|
+
# Set up a default advanced search configuration by using the current
|
|
237
|
+
# search_fields and facet_fields configs.
|
|
238
|
+
if config.advanced_search.enabled
|
|
239
|
+
config.copy_search_field_config_to_advanced!
|
|
240
|
+
config.copy_facet_field_config_to_advanced!
|
|
241
|
+
end
|
|
242
|
+
|
|
221
243
|
# "sort results by" select (pulldown)
|
|
222
244
|
# label in pulldown is followed by the name of the Solr field to sort by and
|
|
223
245
|
# whether the sort is ascending or descending (it must be asc or desc
|