Skip to content

Commit

Permalink
Parse scopes with Symbol keys.
Browse files Browse the repository at this point in the history
  • Loading branch information
sleepingkingstudios committed Jan 17, 2024
1 parent 4bea157 commit 65b7719
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,9 @@ module ShouldParseCriteriaFromABlockContract
end

describe 'with a block returning nil' do
let(:error_message) { 'value must be a Hash with String keys' }
let(:error_message) do
'value must be a Hash with String or Symbol keys'
end

it 'should raise an exception' do
expect { parse_criteria { nil } }
Expand All @@ -533,7 +535,9 @@ module ShouldParseCriteriaFromABlockContract
end

describe 'with a block returning an Object' do
let(:error_message) { 'value must be a Hash with String keys' }
let(:error_message) do
'value must be a Hash with String or Symbol keys'
end

it 'should raise an exception' do
expect { parse_criteria { Object.new.freeze } }
Expand All @@ -542,7 +546,9 @@ module ShouldParseCriteriaFromABlockContract
end

describe 'with a block returning a Hash with invalid keys' do
let(:error_message) { 'value must be a Hash with String keys' }
let(:error_message) do
'value must be a Hash with String or Symbol keys'
end
let(:block) { -> { { nil => 'invalid' } } }

it 'should raise an exception' do
Expand All @@ -569,7 +575,7 @@ module ShouldParseCriteriaFromABlockContract
it { expect(parse_criteria(&block)).to be == expected }
end

describe 'with a Hash with many keys' do
describe 'with a Hash with many String keys' do
let(:operators) { Cuprum::Collections::Queries::Operators }
let(:block) do
lambda do
Expand All @@ -591,6 +597,28 @@ module ShouldParseCriteriaFromABlockContract
it { expect(parse_criteria(&block)).to be == expected }
end

describe 'with a Hash with many Symbol keys' do
let(:operators) { Cuprum::Collections::Queries::Operators }
let(:block) do
lambda do
{
title: 'A Wizard of Earthsea',
author: 'Ursula K. LeGuin',
series: 'Earthsea'
}
end
end
let(:expected) do
[
['title', operators::EQUAL, 'A Wizard of Earthsea'],
['author', operators::EQUAL, 'Ursula K. LeGuin'],
['series', operators::EQUAL, 'Earthsea']
]
end

it { expect(parse_criteria(&block)).to be == expected }
end

describe 'with a Hash with an "eq" operator' do
let(:operators) { Cuprum::Collections::Queries::Operators }
let(:block) do
Expand Down Expand Up @@ -954,7 +982,9 @@ module ShouldParseCriteriaFromAHashContract
# which the contract is applied.
contract do
describe 'with nil' do
let(:error_message) { 'value must be a Hash with String keys' }
let(:error_message) do
'value must be a Hash with String or Symbol keys'
end

it 'should raise an exception' do
expect { parse_criteria(nil) }
Expand All @@ -963,7 +993,9 @@ module ShouldParseCriteriaFromAHashContract
end

describe 'with an Object' do
let(:error_message) { 'value must be a Hash with String keys' }
let(:error_message) do
'value must be a Hash with String or Symbol keys'
end

it 'should raise an exception' do
expect { parse_criteria(Object.new.freeze) }
Expand All @@ -972,7 +1004,9 @@ module ShouldParseCriteriaFromAHashContract
end

describe 'with a Hash with invalid keys' do
let(:error_message) { 'value must be a Hash with String keys' }
let(:error_message) do
'value must be a Hash with String or Symbol keys'
end
let(:value) { { nil => 'invalid' } }

it 'should raise an exception' do
Expand All @@ -999,7 +1033,7 @@ module ShouldParseCriteriaFromAHashContract
it { expect(parse_criteria(value)).to be == expected }
end

describe 'with a Hash with many keys' do
describe 'with a Hash with many String keys' do
let(:operators) { Cuprum::Collections::Queries::Operators }
let(:value) do
{
Expand All @@ -1018,6 +1052,26 @@ module ShouldParseCriteriaFromAHashContract

it { expect(parse_criteria(value)).to be == expected }
end

describe 'with a Hash with many Symbol keys' do
let(:operators) { Cuprum::Collections::Queries::Operators }
let(:value) do
{
title: 'A Wizard of Earthsea',
author: 'Ursula K. LeGuin',
series: 'Earthsea'
}
end
let(:expected) do
[
['title', operators::EQUAL, 'A Wizard of Earthsea'],
['author', operators::EQUAL, 'Ursula K. LeGuin'],
['series', operators::EQUAL, 'Earthsea']
]
end

it { expect(parse_criteria(value)).to be == expected }
end
end
end
end
Expand Down
47 changes: 31 additions & 16 deletions lib/cuprum/collections/scopes/criteria.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,27 +34,38 @@ def parse(*args, &block)
end

# Helper for generating criteria from hash or block inputs.
class Parser
class Parser # rubocop:disable Metrics/ClassLength
OperatorExpression = Struct.new(:operator, :value)
private_constant :OperatorExpression

UNKNOWN = Object.new.freeze
private_constant :UNKNOWN

# @return [Cuprum::Collections::Scopes::Criteria::Parser] a singleton
# instance of the parser class.
def self.instance
@instance ||= new
end
class << self
# @return [Cuprum::Collections::Scopes::Criteria::Parser] a singleton
# instance of the parser class.
def instance
@instance ||= new
end

# @private
def validate_hash(value)
return if valid_hash?(value)

raise ArgumentError,
'value must be a Hash with String or Symbol keys',
caller(1..-1)
end

# @private
def self.validate_hash(value)
return if value.is_a?(Hash) &&
value.each_key.all? { |key| key.is_a?(String) }
private

raise ArgumentError,
'value must be a Hash with String keys',
caller(1..-1)
def valid_hash?(value)
return false unless value.is_a?(Hash)

value.each_key.all? do |key|
key.is_a?(String) || key.is_a?(Symbol)
end
end
end

# @override parse(value = nil, &block)
Expand Down Expand Up @@ -101,9 +112,11 @@ def parse_block(...) # rubocop:disable Metrics/MethodLength

value.map do |attribute, filter|
if filter.is_a?(OperatorExpression)
[attribute, filter.operator, filter.value]
[attribute.to_s, filter.operator, filter.value]
else
[attribute, Cuprum::Collections::Queries::Operators::EQUAL, filter]
operator = Cuprum::Collections::Queries::Operators::EQUAL

[attribute.to_s, operator, filter]
end
end
rescue NameError => exception
Expand All @@ -118,8 +131,10 @@ def parse_block(...) # rubocop:disable Metrics/MethodLength
def parse_hash(value)
Parser.validate_hash(value)

operator = Cuprum::Collections::Queries::Operators::EQUAL

value.map do |attribute, filter|
[attribute, Cuprum::Collections::Queries::Operators::EQUAL, filter]
[attribute.to_s, operator, filter]
end
end

Expand Down

0 comments on commit 65b7719

Please sign in to comment.