Skip to content

Commit

Permalink
Merge pull request #2435 from projectblacklight/json-request-api
Browse files Browse the repository at this point in the history
Try harder to map response parameters provided using the JSON Request API
  • Loading branch information
mejackreed authored Apr 1, 2021
2 parents 25fc0f9 + 2a5abb0 commit 7730796
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 33 deletions.
18 changes: 2 additions & 16 deletions lib/blacklight/solr/response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ class Blacklight::Solr::Response < ActiveSupport::HashWithIndifferentAccess
autoload :MoreLikeThis
autoload :GroupResponse
autoload :Group
autoload :Params
end

include PaginationMethods
include Spelling
include Facets
include Response
include MoreLikeThis
include Params

attr_reader :request_params
attr_accessor :blacklight_config, :options
Expand All @@ -33,22 +35,6 @@ def header
self['responseHeader'] || {}
end

def params
header['params'] || request_params
end

def start
params[:start].to_i
end

def rows
params[:rows].to_i
end

def sort
params[:sort]
end

def documents
@documents ||= (response['docs'] || []).collect { |doc| document_factory.build(doc, self, options) }
end
Expand Down
17 changes: 0 additions & 17 deletions lib/blacklight/solr/response/facets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -180,23 +180,6 @@ def facet_field_aggregations
end
end

def facet_field_aggregation_options(facet_field_name)
options = {}
options[:sort] = (params[:"f.#{facet_field_name}.facet.sort"] || params[:'facet.sort'])
if params[:"f.#{facet_field_name}.facet.limit"] || params[:"facet.limit"]
options[:limit] = (params[:"f.#{facet_field_name}.facet.limit"] || params[:"facet.limit"]).to_i
end

if params[:"f.#{facet_field_name}.facet.offset"] || params[:'facet.offset']
options[:offset] = (params[:"f.#{facet_field_name}.facet.offset"] || params[:'facet.offset']).to_i
end

if params[:"f.#{facet_field_name}.facet.prefix"] || params[:'facet.prefix']
options[:prefix] = (params[:"f.#{facet_field_name}.facet.prefix"] || params[:'facet.prefix'])
end
options
end

##
# Aggregate Solr's facet_query response into the virtual facet fields defined
# in the blacklight configuration
Expand Down
96 changes: 96 additions & 0 deletions lib/blacklight/solr/response/params.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# frozen_string_literal: true
module Blacklight::Solr::Response::Params
# From https://solr.apache.org/guide/8_8/json-request-api.html#supported-properties-and-syntax
QUERY_PARAMETER_TO_JSON_PARAMETER_MAPPING = {
q: :query,
fq: :filter,
start: :offset,
rows: :limit,
fl: :fields,
sort: :sort
}.freeze

def params
header['params'] || request_params
end

def start
search_builder&.start || single_valued_param(:start).to_i
end

def rows
search_builder&.rows || single_valued_param(:rows).to_i
end

def sort
search_builder&.sort || single_valued_param(:sort)
end

def facet_field_aggregation_options(facet_field_name)
sort = single_valued_param(:"f.#{facet_field_name}.facet.sort") || single_valued_param(:'facet.sort')
limit_param = single_valued_param(:"f.#{facet_field_name}.facet.limit") || single_valued_param(:"facet.limit")
limit = (limit_param.to_i if limit_param.present?) || 100
offset = single_valued_param(:"f.#{facet_field_name}.facet.offset") || single_valued_param(:"facet.offset")
prefix = single_valued_param(:"f.#{facet_field_name}.facet.prefix") || single_valued_param(:"facet.prefix")

{
sort: sort || (limit.positive? ? 'count' : 'index'),
limit: limit,
offset: (offset.to_i if offset.present?) || 0,
prefix: prefix
}
end

private

def search_builder
request_params if request_params.is_a?(Blacklight::SearchBuilder)
end

# Extract JSON Request API parameters from the response header or the request itself
def json_params
encoded_json_params = header&.dig('params', 'json')

return request_params['json'] || {} if encoded_json_params.blank?

@json_params ||= JSON.parse(encoded_json_params).with_indifferent_access
end

# Handle merging solr parameters from the myriad of ways they may be expressed by applying the single-value
# precedence logic:
#
# From https://solr.apache.org/guide/8_8/json-request-api.html#json-parameter-merging :
# When multiple parameter values conflict with one another a single value is chosen based on the following precedence rules:
# - Traditional query parameters (q, rows, etc.) take first precedence and are used over any other specified values.
# - json-prefixed query parameters are considered next.
# - Values specified in the JSON request body have the lowest precedence and are only used if specified nowhere else.
#
# @param [String] key the solr parameter to use
def single_valued_param(key)
json_key = QUERY_PARAMETER_TO_JSON_PARAMETER_MAPPING[key]

params[key] ||
params["json.#{key}"] ||
json_params[json_key || key] ||
json_params.dig(:params, key) ||
json_params.dig(:params, "json.#{key}")
end

# Merge together multi-valued solr parameters from the myriad of ways they may be expressed.
# Unlike single-valued parameters, this merges all the values across the params.
#
# @param [String] key the solr parameter to use
def multivalued_param(key)
json_key = QUERY_PARAMETER_TO_JSON_PARAMETER_MAPPING[key]

[
params[key],
params["json.#{key}"],
json_params[json_key || key],
json_params.dig(:params, key),
json_params.dig(:params, "json.#{key}")
].select(&:present?).inject([]) do |memo, arr|
memo.concat(Array.wrap(arr))
end
end
end
10 changes: 10 additions & 0 deletions spec/models/blacklight/solr/response_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,16 @@
expect(r.params['test']).to eq :test
end

it 'extracts json params' do
raw_response = eval(mock_query_response)
raw_response['responseHeader']['params']['test'] = 'from query'
raw_response['responseHeader']['params'].delete('rows')
raw_response['responseHeader']['params']['json'] = { limit: 5, params: { test: 'from json params' } }.to_json
r = described_class.new(raw_response, raw_response['params'])
expect(r.params['test']).to eq 'from query'
expect(r.rows).to eq 5
end

it 'provides the solr-returned params and "rows" should be 11' do
raw_response = eval(mock_query_response)
r = described_class.new(raw_response, {})
Expand Down

0 comments on commit 7730796

Please sign in to comment.