Skip to content

Commit

Permalink
Allow strings in keys and values.
Browse files Browse the repository at this point in the history
When initializing a query we need to allow for keys and values to be
strings because blacklight automatically turns symbols in params into
strings.
  • Loading branch information
dkinzer committed Mar 21, 2018
1 parent f867544 commit 4d998ad
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 90 deletions.
1 change: 1 addition & 0 deletions bin/console
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

require "bundler/setup"
require "primo"
Expand Down
6 changes: 3 additions & 3 deletions lib/primo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ module Primo
def self.find(options = {})
options ||= {}

if options.instance_of? String
if options.is_a? String
params = find_defaults(value: options)
query = Primo::Pnxs::Query.new params
return find(q: query)
end

if options.fetch(:q, {}).instance_of? Hash
if options.fetch(:q, {}).is_a? Hash
query = Primo::Pnxs::Query.new(find_defaults options[:q])
return find(options.merge(q: query))
end
Expand All @@ -28,7 +28,7 @@ def self.find(options = {})
def self.find_by_id(params = {})
params ||= {}

if params.instance_of? String
if params.is_a? String
return find_by_id(id: params)
end

Expand Down
51 changes: 26 additions & 25 deletions lib/primo/facet.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

class Primo::Pnxs::Facet
class FacetError < ArgumentError
end
Expand All @@ -21,36 +23,35 @@ def to_s

private

DEFAUlT_PRECISION = :exact
DEFAULT_OPERATION = :include

# nil allowed because defaults will be filled in
ALLOWED_PRECISION = [nil, :exact]
ALLOWED_OPERATION = [nil, :include, :exclude]
DEFAUlT_PRECISION = :exact
DEFAULT_OPERATION = :include

REQUIRED_PARAMS = [:field, :value]
# nil allowed because defaults will be filled in
ALLOWED_PRECISION = [nil, :exact]
ALLOWED_OPERATION = [nil, :include, :exclude]

REQUIRED_PARAMS = [:field, :value]

def validators
[{ query: :acceptable_operation?,
message: lambda { |p| "Operation must be :include, :exclude, or not passed (nil) " } },
{ query: :acceptable_precision?,
message: lambda { |p| "Precision must be :exact or not passed (nil)" } },
{ query: :has_required_params?,
message: lambda { |p| "Both :field and :value must be defined"} }
]
end

def acceptable_precision?(params)
ALLOWED_PRECISION.include?(params.fetch(:precision, nil))
end
def validators
[{ query: :acceptable_operation?,
message: lambda { |p| "Operation must be :include, :exclude, or not passed (nil) " } },
{ query: :acceptable_precision?,
message: lambda { |p| "Precision must be :exact or not passed (nil)" } },
{ query: :has_required_params?,
message: lambda { |p| "Both :field and :value must be defined" } }
]
end

def acceptable_operation?(params)
ALLOWED_OPERATION.include?(params.fetch(:operation, nil))
end
def acceptable_precision?(params)
ALLOWED_PRECISION.include?(params.fetch(:precision, nil))
end

def has_required_params?(params)
(REQUIRED_PARAMS - params.keys).empty?
end
def acceptable_operation?(params)
ALLOWED_OPERATION.include?(params.fetch(:operation, nil))
end

def has_required_params?(params)
(REQUIRED_PARAMS - params.keys).empty?
end
end
81 changes: 41 additions & 40 deletions lib/primo/parameter_validatable.rb
Original file line number Diff line number Diff line change
@@ -1,48 +1,49 @@
# frozen_string_literal: true

module Primo
module ParameterValidatable

# A mixin class designed to allow Validations of params
# To use, include it in your class and then define an array of validators
# that are hashes with a :query and :message keys.
# :query is a method you will pass the params to to run a single validations
# :message is a lmbda that retunrs a string telling the user what went wrong
# - the params will be passed to the message so you can
# reference the params in your error message
#
# EXAMPLE Usage #####################
# include Primo::ParameterValidatable
#
# def validators
# [{ query: is_my_param_valid?,
# message: lambda { |params| "Param :q needs to be an integer, but you passed a #{params[:q].class}" }
# }]
# def is_my_param_valid?(params)
# params[:count].is_a? Integer
#
#######################################33
# A mixin class designed to allow Validations of params
# To use, include it in your class and then define an array of validators
# that are hashes with a :query and :message keys.
# :query is a method you will pass the params to to run a single validations
# :message is a lmbda that retunrs a string telling the user what went wrong
# - the params will be passed to the message so you can
# reference the params in your error message
#
# EXAMPLE Usage #####################
# include Primo::ParameterValidatable
#
# def validators
# [{ query: is_my_param_valid?,
# message: lambda { |params| "Param :q needs to be an integer, but you passed a #{params[:q].class}" }
# }]
# def is_my_param_valid?(params)
# params[:count].is_a? Integer
#
#######################################33



def validate(params)
validators.each do |validate|
message = validate[:message][params]
if !send(validate[:query], params)
raise error.new(message)
end
end
end
def validate(params)
validators.each do |validate|
message = validate[:message][params]
if !send(validate[:query], params)
raise error.new(message)
end
end
end

# Use a local error class if the Class has a local error class
# following the convention Primo::ClassName::ClassNameError
# Otherwise use Primo::Pnxs::PnxsError
def error
error_class = Primo::Pnxs::PnxsError
class_name = self.class.to_s.split("::").last
class_error_name = class_name + "Error"
if self.class.const_defined?(class_error_name)
error_class = self.class.const_get(class_error_name)
end
error_class
end
# Use a local error class if the Class has a local error class
# following the convention Primo::ClassName::ClassNameError
# Otherwise use Primo::Pnxs::PnxsError
def error
error_class = Primo::Pnxs::PnxsError
class_name = self.class.to_s.split("::").last
class_error_name = class_name + "Error"
if self.class.const_defined?(class_error_name)
error_class = self.class.const_get(class_error_name)
end
error_class
end
end
end
18 changes: 10 additions & 8 deletions lib/primo/pnxs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def url
end

def params
query = @params[:q]
query = @params[:q] || @params["q"]
@params.merge(auth)
.merge(query.to_h)
end
Expand All @@ -89,16 +89,16 @@ def validators
[{ query: :has_valid_query?,
message: lambda { |p| "field :q must be a valid instance of Primo::Pnxs::Query " } },
{ query: :only_known_parameters?,
message: lambda { |p| "field :q is required " } },
message: lambda { |p| "only known parameters can be passed " } },
]
end

def has_valid_query?(params)
params[:q].instance_of?(Primo::Pnxs::Query)
params[:q].is_a?(Primo::Pnxs::Query)
end

def only_known_parameters?(params)
(params.keys - PARAMETER_KEYS).empty?
(params.keys - PARAMETER_KEYS - PARAMETER_KEYS.map(&:to_s)).empty?
end
end

Expand Down Expand Up @@ -129,12 +129,14 @@ def self.can_process?(params = {})
def validators
[
{ query: :only_known_parameters?,
message: lambda { |p| "field :q is required " } },
message: lambda { |p| "only known parameters are passed " } },
]
end

def only_known_parameters?(params)
(params.keys - PARAMETER_KEYS - URL_KEYS).empty?
keys = (PARAMETER_KEYS + URL_KEYS)
string_keys = keys.map(&:to_s)
(params.keys - keys - string_keys).empty?
end
end

Expand Down Expand Up @@ -178,9 +180,9 @@ def initialize_fields(response)

# Allows us to access returned data using dot notation.
def to_struct(obj)
if obj.instance_of? Hash
if obj.is_a? Hash
OpenStruct.new obj
elsif obj.instance_of? Array
elsif obj.is_a? Array
obj.map { |o| to_struct o }
else
obj
Expand Down
23 changes: 14 additions & 9 deletions lib/primo/query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,11 @@ def exclude_facets

def push(params, operator = nil)
params ||= {}
params = params.map { |k, v| [k.to_sym, v] }.to_h

operator = operator || params[:operator] || Primo.configuration.operator
params[:precision] ||= Primo.configuration.precision

query = @queries.pop

if query
Expand All @@ -138,40 +141,42 @@ def required_params_included?(params)
end

def field_is_known?(params)
field = params.fetch(:field)
field = params[:field].to_sym
REGULAR_FIELDS.include?(field) || FACET_FIELDS.include?(field)
end

def operator_is_known?(params)
operator = params.fetch(:operator, "")
operator.empty? || OPERATOR_VALUES.include?(operator)
operator = params[:operator]
operator.nil? || OPERATOR_VALUES.include?(operator.to_sym)
end

def precision_is_known?(params)
precision = params.fetch(:precision)
precision = params[:precision].to_sym
PRECISION_VALUES.include?(precision)
end

def facet_precision_is_exact?(params)
precision = params.fetch(:precision)
field = params.fetch(:field)
precision = params[:precision].to_sym
field = params[:field].to_sym
REGULAR_FIELDS.include?(field) ||
FACET_FIELDS.include?(field) && precision == :exact
end

def transform(query)
PARAM_ORDER.map { |p|
v = query[p]

if self.respond_to?(p, true)
self.send(p, query[p])
self.send(p, v)
else
query[p]
v
end

}.join(",")
end

def value(value)
value.tr(",", " ")
value.to_s.tr(",", " ")
end

def operator(value)
Expand Down
10 changes: 5 additions & 5 deletions spec/lib/primo/query_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
Primo.configure {}
Primo::Pnxs::Query.new(
precision: :exact,
field: :facet_local23,
"field" => :facet_local23,
value: "bar",
) }
it "transforms to an expected string" do
Expand All @@ -20,10 +20,10 @@
let(:query) {
Primo.configure {}
Primo::Pnxs::Query.new(
precision: :exact,
field: :facet_local23,
value: "bar",
operator: :OR,
"precision" => :exact,
"field" => :facet_local23,
"value" => "bar",
"operator" => :OR,
) }
it "transforms to an expected string" do
expect(query.to_s).to eq("facet_local23,exact,bar,OR")
Expand Down
14 changes: 14 additions & 0 deletions spec/primo_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,20 @@
end
end

context "when we pass options with valid q hash" do
let(:query) {
Primo::Pnxs::Query.new(
"precision" => "contains",
"field" => "title",
"value" => "otter",
"opterator" => "OR",
)
}
it "does not raise a query error" do
expect { Primo.find q: query }.not_to raise_error
end
end

context "when we pass options with valid q Query instance" do
let(:query) {
{ precision: :contains,
Expand Down

0 comments on commit 4d998ad

Please sign in to comment.