Commit 45aeeecd by Pablo Cantero

Simple interface

parent ac410e78
...@@ -28,15 +28,16 @@ Or install it yourself as: ...@@ -28,15 +28,16 @@ Or install it yourself as:
```ruby ```ruby
# GET /customers?q[name_eq]=Pablo&q[middle_name_or_last_name_cont]=Cantero # GET /customers?q[name_eq]=Pablo&q[middle_name_or_last_name_cont]=Cantero
# params[:q] # params[:q]
# => { name_eq: 'Pablo', middle_name_or_last_name_cont: 'Cantero' } # => { name_eq: 'Pablo', middle_name_or_last_name_cont: 'Cantero' }
# query.to_query(params[:q])
# RansackMongo::Query.parse(params[:q])
# => { name: 'Pablo', '$or' => { middle_name: /Cantero/i, last_name: /Cantero/i } } # => { name: 'Pablo', '$or' => { middle_name: /Cantero/i, last_name: /Cantero/i } }
# GET /customers # GET /customers
def index def index
query = RansackMongo::Query.new selector = RansackMongo::Query.parse(params[:q])
selector = query.to_query(params[:q])
# Mongo Ruby Driver # Mongo Ruby Driver
@customers = db.customers.find(selector) @customers = db.customers.find(selector)
...@@ -63,20 +64,23 @@ You can also combine predicates for OR queries. ...@@ -63,20 +64,23 @@ You can also combine predicates for OR queries.
```ruby ```ruby
query_param = { name_eq: 'Pablo', middle_name_or_last_name_cont: 'Cantero' } query_param = { name_eq: 'Pablo', middle_name_or_last_name_cont: 'Cantero' }
query.to_query(params[:q])
RansackMongo::Query.parse(params[:q])
# => { name: 'Pablo', '$or' => { middle_name: /Cantero/i, last_name: /Cantero/i } } # => { name: 'Pablo', '$or' => { middle_name: /Cantero/i, last_name: /Cantero/i } }
``` ```
### to_query! ### parse!
You can use `parse!` for stricter validations. This method will raise an exception if a query cannot be produced.
You can use to_query! for stricter validations. This method will raise an exception if a query cannot be produced.
```ruby ```ruby
# xpto isn't a valid predicate # xpto isn't a valid predicate
query.to_query(name_xpto: 'Pablo') RansackMongo::Query.parse(name_xpto: 'Pablo')
# => {} # => {}
query.to_query!(name_xpto: 'Pablo')
# => RansackMongo::MatcherNotFound: No matchers found. To allow empty queries use .to_query instead RansackMongo::Query.parse!(name_xpto: 'Pablo')
# => RansackMongo::MatcherNotFound: No matchers found. To allow empty queries use .parse instead
``` ```
## Contributing ## Contributing
......
...@@ -3,51 +3,49 @@ module RansackMongo ...@@ -3,51 +3,49 @@ module RansackMongo
# https://github.com/activerecord-hackery/ransack/wiki/Basic-Searching # https://github.com/activerecord-hackery/ransack/wiki/Basic-Searching
class Query class Query
def initialize(db_adapter_class = MongoAdapter) class << self
@db_adapter_class = db_adapter_class def parse(params, db_adapter_class = MongoAdapter)
end parsed_predicates = Predicate.new(db_adapter_class.predicates).parse(params)
def to_query(params) db_adapter = db_adapter_class.new
parsed_predicates = Predicate.new(@db_adapter_class.predicates).parse(params)
parsed_predicates.keys.each do |p|
db_adapter = @db_adapter_class.new parsed_predicates[p].each do |parsed_predicate|
attr = parsed_predicate['attr']
parsed_predicates.keys.each do |p| value = parsed_predicate['value']
parsed_predicates[p].each do |parsed_predicate|
attr = parsed_predicate['attr'] begin
value = parsed_predicate['value'] if attr.include? '_or_'
# attr => name_or_lastname
begin or_query(db_adapter, attr, value, p)
if attr.include? '_or_' else
# attr => name_or_lastname # attr => name
or_query(db_adapter, attr, value, p) db_adapter.send("#{p}_matcher", attr, value)
else end
# attr => name rescue NoMethodError => e
db_adapter.send("#{p}_matcher", attr, value) raise MatcherNotFound, "The matcher #{p} `#{p}_matcher` was not found in the #{db_adapter_class.name}. Check `#{db_adapter_class}.predicates`"
end end
rescue NoMethodError => e
raise MatcherNotFound, "The matcher #{p} `#{p}_matcher` was not found in the #{@db_adapter_class.name}. Check `#{@db_adapter_class}.predicates`"
end end
end end
end
db_adapter.to_query db_adapter.to_query
end end
def to_query!(params) def parse!(params, db_adapter_class = MongoAdapter)
selector = to_query params if (selector = parse(params)).empty?
raise MatcherNotFound, 'No matchers found. To allow empty queries use .parse instead'
end
if selector.empty? selector
raise MatcherNotFound, "No matchers found. To allow empty queries use .to_query instead"
end end
selector private
end
def or_query(db_adapter, attr, value, p) def or_query(db_adapter, attr, value, p)
db_adapter.or_op do db_adapter.or_op do
attr.split('_or_').each do |or_attr| attr.split('_or_').each do |or_attr|
db_adapter.send("#{p}_matcher", or_attr, value) db_adapter.send("#{p}_matcher", or_attr, value)
end
end end
end end
end end
......
...@@ -10,7 +10,7 @@ module RansackMongo ...@@ -10,7 +10,7 @@ module RansackMongo
@query = {} @query = {}
end end
def to_query def parse
@query @query
end end
...@@ -19,12 +19,12 @@ module RansackMongo ...@@ -19,12 +19,12 @@ module RansackMongo
end end
end end
describe '#to_query' do describe '#parse' do
context 'when not implement matcher' do context 'when not implement matcher' do
it 'raises proper exception' do it 'raises proper exception' do
params = { 'name_foo' => 'Pablo' } params = { 'name_foo' => 'Pablo' }
expect { expect {
described_class.new(FooAdapter).to_query(params) described_class.parse(params, FooAdapter)
}.to raise_error(MatcherNotFound, 'The matcher foo `foo_matcher` was not found in the RansackMongo::FooAdapter. Check `RansackMongo::FooAdapter.predicates`') }.to raise_error(MatcherNotFound, 'The matcher foo `foo_matcher` was not found in the RansackMongo::FooAdapter. Check `RansackMongo::FooAdapter.predicates`')
end end
end end
...@@ -32,37 +32,37 @@ module RansackMongo ...@@ -32,37 +32,37 @@ module RansackMongo
end end
context 'when MongoAdapter' do context 'when MongoAdapter' do
describe '#to_query!' do describe '#parse!' do
it 'raises exception when query evaluates to an empty hash' do it 'raises exception when query evaluates to an empty hash' do
params = { 'name' => 'Pablo' } params = { 'name' => 'Pablo' }
expect { described_class.new.to_query!(params) }.to raise_error(MatcherNotFound) expect { described_class.parse!(params) }.to raise_error(MatcherNotFound)
end end
it 'returns the query' do it 'returns the query' do
params = { 'name_eq' => 'Pablo', 'fullname_cont' => 'Cantero' } params = { 'name_eq' => 'Pablo', 'fullname_cont' => 'Cantero' }
expect(described_class.new.to_query!(params)).to eq('name' => 'Pablo', 'fullname' => /Cantero/i) expect(described_class.parse!(params)).to eq('name' => 'Pablo', 'fullname' => /Cantero/i)
end end
end end
describe '#to_query' do describe '#parse' do
it 'returns the query' do it 'returns the query' do
params = { 'name_eq' => 'Pablo', 'fullname_cont' => 'Cantero' } params = { 'name_eq' => 'Pablo', 'fullname_cont' => 'Cantero' }
expect(described_class.new.to_query(params)).to eq('name' => 'Pablo', 'fullname' => /Cantero/i) expect(described_class.parse(params)).to eq('name' => 'Pablo', 'fullname' => /Cantero/i)
end end
context 'when or' do context 'when or' do
it 'returns the query' do it 'returns the query' do
params = { 'name_or_fullname_eq' => 'Pablo' } params = { 'name_or_fullname_eq' => 'Pablo' }
expect(described_class.new.to_query(params)).to eq('$or' => [{ 'name' => 'Pablo' }, { 'fullname' => 'Pablo' }]) expect(described_class.parse(params)).to eq('$or' => [{ 'name' => 'Pablo' }, { 'fullname' => 'Pablo' }])
end end
it 'preserves other criterias' do it 'preserves other criterias' do
params = { 'name_or_fullname_eq' => 'Pablo', 'country_eq' => 'Brazil' } params = { 'name_or_fullname_eq' => 'Pablo', 'country_eq' => 'Brazil' }
expect(described_class.new.to_query(params)).to eq('$or' => [{ 'name' => 'Pablo' }, { 'fullname' => 'Pablo' }], 'country' => 'Brazil') expect(described_class.parse(params)).to eq('$or' => [{ 'name' => 'Pablo' }, { 'fullname' => 'Pablo' }], 'country' => 'Brazil')
end end
end end
end end
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment