Class: Blacklight::SearchBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/blacklight/search_builder.rb

Overview

Blacklight's SearchBuilder converts blacklight request parameters into query parameters appropriate for search index. It does so by evaluating a chain of processing methods to populate a result hash (see #to_hash).

Constant Summary collapse

UNDEFINED =

An undefined value that can be used to detect if a parameter was passed in or not, since nil and false may be valid values for some parameters.

Object.new.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(scope) ⇒ SearchBuilder #initialize(processor_chain, scope) ⇒ SearchBuilder

Returns a new instance of SearchBuilder.

Overloads:

  • #initialize(scope) ⇒ SearchBuilder

    Parameters:

    • scope (Object)

      the scope where the filter methods reside in.

  • #initialize(processor_chain, scope) ⇒ SearchBuilder

    Parameters:

    • processor_chain (List<Symbol>, TrueClass)

      options a list of filter methods to run or true, to use the default methods

    • scope (Object)

      the scope where the filter methods reside in.



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/blacklight/search_builder.rb', line 19

def initialize(*options, blacklight_config: nil)
  case options.size
  when 1
    @processor_chain = default_processor_chain.dup
    @scope = options.first
  when 2
    @processor_chain, @scope = options
  else
    raise ArgumentError, "wrong number of arguments. (#{options.size} for 1..2)"
  end

  @blacklight_config = blacklight_config || @scope&.blacklight_config
  @additional_filters = {}
  @merged_params = {}
  @reverse_merged_params = {}
end

Instance Attribute Details

#blacklight_configObject (readonly)

Returns the value of attribute blacklight_config.



12
13
14
# File 'lib/blacklight/search_builder.rb', line 12

def blacklight_config
  @blacklight_config
end

#processor_chainObject (readonly)

Returns the value of attribute processor_chain.



12
13
14
# File 'lib/blacklight/search_builder.rb', line 12

def processor_chain
  @processor_chain
end

Instance Method Details

#append(*addl_processor_chain) ⇒ Object

Append additional processor chain directives This is used in blacklight_range_limit



71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/blacklight/search_builder.rb', line 71

def append(*addl_processor_chain)
  params_will_change!
  builder = self.class.new(processor_chain + addl_processor_chain, scope)
                .with(search_state)
                .merge(@merged_params)
                .reverse_merge(@reverse_merged_params)

  builder.start = @start if @start
  builder.rows  = @rows if @rows
  builder.page  = @page if @page
  builder.facet = @facet if @facet
  builder
end

#blacklight_paramsObject



43
44
45
# File 'lib/blacklight/search_builder.rb', line 43

def blacklight_params
  search_state.params
end

#default_document_pagination_paramsObject



165
166
167
# File 'lib/blacklight/search_builder.rb', line 165

def default_document_pagination_params
  { fl: blacklight_config.document_model.unique_key }
end

#except(*except_processor_chain) ⇒ Object

Converse to append, remove processor chain directives, returning a new builder that's a copy of receiver with specified change.

Methods in argument that aren't currently in processor chain are ignored as no-ops, rather than raising.



92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/blacklight/search_builder.rb', line 92

def except(*except_processor_chain)
  builder = self.class.new(processor_chain - except_processor_chain, scope)
                .with(search_state)
                .merge(@merged_params)
                .reverse_merge(@reverse_merged_params)

  builder.start = @start if @start
  builder.rows  = @rows if @rows
  builder.page  = @page if @page
  builder.facet = @facet if @facet
  builder
end

#facet(value = nil) ⇒ Object

Parameters:

  • value (Object) (defaults to: nil)


260
261
262
263
264
265
266
# File 'lib/blacklight/search_builder.rb', line 260

def facet(value = nil)
  if value
    self.facet = value
    return self
  end
  @facet
end

#facet=(value) ⇒ Object

sets the facet that this query pertains to, for the purpose of facet pagination



254
255
256
257
# File 'lib/blacklight/search_builder.rb', line 254

def facet=(value)
  params_will_change!
  @facet = value
end

#facet_suggestion_query(value = nil) ⇒ Object



273
274
275
276
277
278
279
# File 'lib/blacklight/search_builder.rb', line 273

def facet_suggestion_query(value = nil)
  if value
    self.facet_suggestion_query = value
    return self
  end
  @facet_suggestion_query
end

#facet_suggestion_query=(value) ⇒ Object



268
269
270
271
# File 'lib/blacklight/search_builder.rb', line 268

def facet_suggestion_query=(value)
  params_will_change!
  @facet_suggestion_query = value
end

#for_previous_and_next_documents(index, window = 1) ⇒ Object



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/blacklight/search_builder.rb', line 169

def for_previous_and_next_documents(index, window = 1)
  document_pagination_params = blacklight_config.document_pagination_params.dup

  if document_pagination_params.empty?
    merge(default_document_pagination_params)
  else
    merge(document_pagination_params)
  end

  if index > 0
    self.start = [index - window, 0].max
    self.rows = (2 * window) + 1
  else
    self.start = 0
    self.rows = 2 * window
  end

  self
end

#merge(extra_params) ⇒ Object

Merge additional, repository-specific parameters



107
108
109
110
111
112
113
# File 'lib/blacklight/search_builder.rb', line 107

def merge(extra_params, &)
  if extra_params
    params_will_change!
    @merged_params.merge!(extra_params.to_hash, &)
  end
  self
end

#page(value = Blacklight::SearchBuilder::UNDEFINED) ⇒ Object

Parameters:

  • value (#to_i) (defaults to: Blacklight::SearchBuilder::UNDEFINED)


221
222
223
224
225
226
227
# File 'lib/blacklight/search_builder.rb', line 221

def page(value = Blacklight::SearchBuilder::UNDEFINED)
  if value != Blacklight::SearchBuilder::UNDEFINED
    self.page = value
    return self
  end
  @page ||= search_state.page
end

#page=(value) ⇒ Object



212
213
214
215
216
217
218
# File 'lib/blacklight/search_builder.rb', line 212

def page=(value)
  return if value.nil?

  params_will_change!
  @page = value.to_i
  @page = 1 if @page < 1
end

#processed_parametersObject

The CatalogController #index action uses this. Solr parameters can come from a number of places. From lowest precedence to highest:

  1. General defaults in blacklight config (are trumped by)
  2. defaults for the particular search field identified by params (are trumped by)
  3. certain parameters directly on input HTTP query params
    • not just any parameter is grabbed willy nilly, only certain ones are allowed by HTTP input)
    • for legacy reasons, qt in http query does not over-ride qt in search field definition default.
  4. extra parameters passed in as argument.

spellcheck.q will be supplied with the [:q] value unless specifically specified otherwise.

Incoming parameter :f is mapped to :fq solr parameter.

Returns:

  • a params hash for searching solr.



157
158
159
160
161
162
163
# File 'lib/blacklight/search_builder.rb', line 157

def processed_parameters
  request.tap do |request_parameters|
    processor_chain.each do |method_name|
      send(method_name, request_parameters)
    end
  end
end

#reverse_merge(extra_params) ⇒ Object

"Reverse merge" additional, repository-specific parameters



117
118
119
120
121
122
123
# File 'lib/blacklight/search_builder.rb', line 117

def reverse_merge(extra_params, &)
  if extra_params
    params_will_change!
    @reverse_merged_params.reverse_merge!(extra_params.to_hash, &)
  end
  self
end

#rows(value = Blacklight::SearchBuilder::UNDEFINED) ⇒ Object Also known as: per

Parameters:

  • value (#to_i) (defaults to: Blacklight::SearchBuilder::UNDEFINED)


238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/blacklight/search_builder.rb', line 238

def rows(value = Blacklight::SearchBuilder::UNDEFINED)
  if value != Blacklight::SearchBuilder::UNDEFINED
    self.rows = value
    return self
  end
  @rows ||= begin
    # user-provided parameters should override any default row
    r = search_state.per_page
    # ensure we don't excede the max page size
    r.nil? ? nil : [r, blacklight_config.max_per_page].map(&:to_i).min
  end
end

#rows=(value) ⇒ Object



229
230
231
232
233
234
235
# File 'lib/blacklight/search_builder.rb', line 229

def rows=(value)
  return if value.nil?

  params_will_change!
  new_rows = value.to_i.then { |parsed| parsed.positive? ? parsed : blacklight_config.default_per_page }
  @rows = [new_rows, blacklight_config.max_per_page.to_i].min
end

#search_stateObject



36
37
38
39
40
41
# File 'lib/blacklight/search_builder.rb', line 36

def search_state
  @search_state ||= begin
    search_state_class = @scope.try(:search_state_class) || Blacklight::SearchState
    @search_state = search_state_class.new({}, blacklight_config, @scope)
  end
end

#sortString

Decode the user provided 'sort' parameter into a sort string that can be passed to the search. This sanitizes the input by ensuring only configured search values are passed through to the search.

Returns:

  • (String)

    the field/fields to sort by



285
286
287
# File 'lib/blacklight/search_builder.rb', line 285

def sort
  search_state.sort_field&.sort
end

#start(value = Blacklight::SearchBuilder::UNDEFINED) ⇒ Object Also known as: padding

Parameters:

  • value (#to_i) (defaults to: Blacklight::SearchBuilder::UNDEFINED)


200
201
202
203
204
205
206
207
208
209
# File 'lib/blacklight/search_builder.rb', line 200

def start(value = Blacklight::SearchBuilder::UNDEFINED)
  if value != Blacklight::SearchBuilder::UNDEFINED
    self.start = value
    return self
  end
  @start ||= (page - 1) * (rows || 10)
  val = @start || 0
  val = 0 if @start < 0
  val
end

#start=(value) ⇒ Object



192
193
194
195
196
197
# File 'lib/blacklight/search_builder.rb', line 192

def start=(value)
  return if value.nil?

  params_will_change!
  @start = value.to_i
end

#to_hashBlacklight::Solr::Response Also known as: query, to_h

a solr query method

Returns:



129
130
131
132
133
134
135
136
# File 'lib/blacklight/search_builder.rb', line 129

def to_hash
  return @params unless params_need_update?

  @params = processed_parameters
            .reverse_merge(@reverse_merged_params)
            .merge(@merged_params)
            .tap { clear_changes }
end

#where(conditions) ⇒ Object

Update the :q (query) parameter

Examples:

search_builder.where(id: [1,2,3]) # produces: q:"{!lucene}id:(1 OR 2 OR 3)"

Parameters:

  • conditions (Hash<Symbol,Object>)

    the field and values to query on



61
62
63
64
65
66
# File 'lib/blacklight/search_builder.rb', line 61

def where(conditions)
  params_will_change!
  @search_state = search_state.reset(search_state.params.merge(q: conditions))
  @additional_filters = conditions
  self
end

#with(blacklight_params_or_search_state = {}) ⇒ Object

Set the parameters to pass through the processor chain



50
51
52
53
54
# File 'lib/blacklight/search_builder.rb', line 50

def with(blacklight_params_or_search_state = {})
  params_will_change!
  @search_state = blacklight_params_or_search_state.is_a?(Blacklight::SearchState) ? blacklight_params_or_search_state : search_state.reset(blacklight_params_or_search_state)
  self
end