class Sequel::Dataset module Sequelizer def format_eq_expression(l, r) case r when Range: r.exclude_end? ? \ "(#{l} >= #{literal(r.begin)} AND #{l} < #{literal(r.end)})" : \ "(#{l} >= #{literal(r.begin)} AND #{l} <= #{literal(r.end)})" when Array: "#{l} IN (#{literal(r)})" when Sequel::Dataset: "#{l} IN (#{r.sql})" when NilClass: "#{l} IS NULL" else "#{l} = #{literal(r)}" end end def call_expr(e, b) case e[2] when :>, :<, :>=, :<= l = pt_expr(e[1], b) r = pt_expr(e[3][1], b) "#{l} #{e[2]} #{r}" when :==, :=~ l = eval_expr(e[1], b) r = eval_expr(e[3][1], b) format_eq_expression(l, r) when :nil? l = eval_expr(e[1], b) format_eq_expression(l, nil) when :like? l = pt_expr(e[1], b) r = pt_expr(e[3][1], b) "#{l} LIKE #{r}" else eval(RubyToRuby.new.process(e), b) end end def eval_expr(e, b) case e[0] when :call: call_expr(e, b) when :ivar, :cvar, :lvar, :dvar, :vcall, :const: eval(e[1].to_s, b) when :lit, :str: e[1] when :dot2: eval_expr(e[1], b)..eval_expr(e[2], b) when :dot3: eval_expr(e[1], b)...eval_expr(e[2], b) when :colon2: eval_expr(e[1], b).const_get(e[2]) when :false: false when :true: true when :nil: nil when :match3: # regexp l = eval_expr(e[2], b) r = eval_expr(e[1], b) format_eq_expression(l, r) when :dasgn, :dasgn_curr: l = e[1] r = eval_expr(e[2], b) raise SequelError, "Invalid expression #{l} = #{r}. Did you mean :#{l} == #{r}?" else puts e.inspect raise SequelError, "Invalid expression tree: #{e.inspect}" end end def pt_expr(e, b) case e[0] when :not: if (e[1][0] == :lit) && (Symbol === e[1][1]) # translate (!:x) into (x = 'f') format_eq_expression(e[1][1], false) else "NOT (#{pt_expr(e[1], b)})" end when :block, :and: e[1..-1].map {|i| "(#{pt_expr(i, b)})"}.join(" AND ") when :or: "(#{pt_expr(e[1], b)}) OR (#{pt_expr(e[2], b)})" when :call, :vcall: eval_expr(e, b) else literal(eval_expr(e, b)) end end def translate_expr(proc) c = Class.new {define_method(:m, &proc)} pt_expr(ParseTree.translate(c, :m)[2][2], proc.binding) end end end