Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nestable queries #15

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
76 changes: 47 additions & 29 deletions lib/reso_transport/query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def any(&block)
%i[eq ne gt ge lt le].each do |op|
define_method(op) do |conditions|
conditions.each_pair do |k, v|
current_query_context << "#{k} #{op} #{encode_value(k, v)}"
current_query_context.push "#{k} #{op} #{encode_value(k, v)}"
end
return self
end
Expand Down Expand Up @@ -90,6 +90,8 @@ def next_link=(link)
@next_link = link
end

private

def response
use_next_link? ? resource.get_next_link_results(next_link) : resource.get(compile_params)
rescue Faraday::ConnectionFailed
Expand All @@ -109,58 +111,74 @@ def handle_response(response)
parsed
end

def new_query_context(context)
@last_query_context ||= 0
@current_query_context = @last_query_context + 1
sub_queries[@current_query_context][:context] = context
def options
@options ||= {}
end

def clear_query_context
@last_query_context = @current_query_context
@current_query_context = nil
def query_parameters
@query_parameters ||= {}
end

def current_query_context
@current_query_context ||= nil
sub_queries[@current_query_context || :global][:criteria]
def sub_queries
@sub_queries ||= [SubQuery.new("and")]
end

def options
@options ||= {}
def new_query_context(context)
sub_query = SubQuery.new(context, parens: true)
current_query_context.push sub_query
sub_queries.push sub_query
end

def query_parameters
@query_parameters ||= {}
def clear_query_context
sub_queries.pop
end

def sub_queries
@sub_queries ||= Hash.new { |h, k| h[k] = { context: 'and', criteria: [] } }
def current_query_context
sub_queries.last
end

def compile_filters
groups = sub_queries.dup
global = groups.delete(:global)
filter_groups = groups.values
class SubQuery
def initialize context, criteria=[], parens: false
@context = context
@parens = parens
@criteria = criteria
end

filter_chunks = []
attr_reader :context, :parens, :criteria
alias_method :parens?, :parens

filter_chunks << global[:criteria].join(" #{global[:context]} ") if global && global[:criteria]&.any?
def to_s
out = criteria.select { |x| x.length > 0 }.map(&:to_s).join(" #{context} ")
out = "(#{out})" if parens?
out
end

filter_chunks << filter_groups.map do |g|
"(#{g[:criteria].join(" #{g[:context]} ")})"
end.join(' and ')
def push x
criteria << x
end
alias_method :<<, :push

filter_chunks.reject { |c| c == '' }.join(' and ')
def length
criteria.length
end

def present?
length > 0
end
end

def compile_filters
sub_queries.first.to_s
end

def compile_params
public def compile_params
params = {}

options.each_pair do |k, v|
params["$#{k}"] = v
end

params['$filter'] = compile_filters unless sub_queries.empty?
params['$filter'] = compile_filters if sub_queries.any?(&:present?)
params.merge!(query_parameters) unless query_parameters.empty?

params
Expand Down
27 changes: 27 additions & 0 deletions test/reso_transport/query_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,31 @@ def test_filters
expected = { '$filter' => "ListPrice eq 1000 and (City eq 'Brea' or City eq 'Yorba Linda')" }
assert_equal expected, sample
end

def test_nested_filters
expected = { '$filter' => <<~QUERY.gsub("\n", " ").strip }
(City eq 'Brea' or City eq 'Yorba Linda') and
((MlsStatus eq 'Active' or MlsStatus eq 'Pending') or
(ListOfficeMlsId eq 'Heinz' and (MlsStatus eq 'Sold' or MlsStatus eq 'SoldNotListed')))
QUERY

sample = query.any {
eq(City: "Brea")
eq(City: "Yorba Linda")
}.any {
any {
eq(MlsStatus: "Active")
eq(MlsStatus: "Pending")
}
all {
eq(ListOfficeMlsId: "Heinz")
any {
eq(MlsStatus: "Sold")
eq(MlsStatus: "SoldNotListed")
}
}
}.compile_params

assert_equal expected, sample
end
end