class Seaquel::ExpressionConverter
Attributes
quoter[R]
Public Class Methods
new(quoter)
click to toggle source
# File lib/seaquel/expression_converter.rb, line 9 def initialize quoter @quoter = quoter end
Public Instance Methods
sql(node)
click to toggle source
# File lib/seaquel/expression_converter.rb, line 152 def sql node # p [:sql, node] case node when nil bit('NULL') when Array sql_bits = node.map { |el| sql(el).at(0) } bit("(" + sql_bits.join(', ') + ")") when String bit(quote_string(node)) when Fixnum bit(quote_number(node)) when true,false node ? bit('TRUE') : bit('FALSE') else node.visit(self) end end
visit_alias(name, to)
click to toggle source
# File lib/seaquel/expression_converter.rb, line 61 def visit_alias name, to prec = precedence(:as) bit("#{sql(to).at(prec)} AS \"#{name}\"") end
visit_assign(left, right)
click to toggle source
# File lib/seaquel/expression_converter.rb, line 22 def visit_assign left, right if left.kind_of? AST::Column bit( [left.as_column_reference(quoter), '=', sql(right).at(0)].join) else bit( [sql(left).at(0), '=', sql(right).at(0)].join) end end
visit_binding(pos)
click to toggle source
# File lib/seaquel/expression_converter.rb, line 139 def visit_binding pos bit("$#{pos}") end
visit_binop(op, left, right)
click to toggle source
# File lib/seaquel/expression_converter.rb, line 66 def visit_binop op, left, right prec = precedence(op) if right.nil? op = :is if op==:eq op = :isnot if op==:noteq end if op==:in && right.kind_of?(Range) raise "Ranges excluding the right side are not permitted in Seaquel." \ if right.exclude_end? return bit([ sql(left).at(0), 'BETWEEN', right.begin, 'AND', right.end].join(' ')) end if binops.has_key?(op) symbol = binops[op] return bit( [sql(left).at(prec), symbol, sql(right).at(prec)].join, prec) end raise "No such operation (#{op.inspect})." end
visit_column(col)
click to toggle source
# File lib/seaquel/expression_converter.rb, line 135 def visit_column col bit(col.as_full_reference(quoter)) end
visit_column_list(elements)
click to toggle source
# File lib/seaquel/expression_converter.rb, line 44 def visit_column_list elements # Column lists only contain columns. bit(elements.map { |e| e.as_column_reference(quoter) }.join(', ')) end
visit_funcall(name, args)
click to toggle source
# File lib/seaquel/expression_converter.rb, line 143 def visit_funcall name, args arglist = args.map { |arg| sql(arg).toplevel }.join(', ') bit("#{name}(#{arglist})") end
visit_joinop(op, exps)
click to toggle source
# File lib/seaquel/expression_converter.rb, line 97 def visit_joinop op, exps # Shortcut if we join one element only. if exps.size == 1 el = exps.first return sql(el) end prec = precedence(op) parts = exps.map { |e| sql(e).at(prec) } sql = case op when :and parts.join(' AND ') when :or parts.join(' OR ') else raise "AF: JoinOp called for #{op.inspect}, but has no branch for it." end bit(sql, prec) end
visit_list(elements)
click to toggle source
# File lib/seaquel/expression_converter.rb, line 40 def visit_list elements bit(elements.map { |e| sql(e).at(0) }.join(', ')) end
visit_literal(literal)
click to toggle source
# File lib/seaquel/expression_converter.rb, line 36 def visit_literal literal bit(literal) end
visit_new_statement(*args)
click to toggle source
# File lib/seaquel/expression_converter.rb, line 32 def visit_new_statement *args ::Seaquel::Generator.new(self).compact_sql end
visit_node(node)
click to toggle source
Gets called whenever the expression contains a statement-type AST::Node
.
# File lib/seaquel/expression_converter.rb, line 15 def visit_node node bit(node.to_sql, 0) end
visit_order(order, expr)
click to toggle source
# File lib/seaquel/expression_converter.rb, line 148 def visit_order order, expr bit("#{sql(expr).at(0)} #{order.upcase}") end
visit_table(table)
click to toggle source
# File lib/seaquel/expression_converter.rb, line 49 def visit_table table bit(table.quote(quoter)) end
visit_table_alias(table, name)
click to toggle source
# File lib/seaquel/expression_converter.rb, line 53 def visit_table_alias table, name bit([ sql(table).at(0), "AS", quoter.identifier(name) ].join(' ')) end
visit_unary(op, exp)
click to toggle source
# File lib/seaquel/expression_converter.rb, line 119 def visit_unary op, exp raise "No such unary operation #{op.inspect}." \ unless unaryops.has_key?(op) symbol, prefix = unaryops[op] prec = precedences[op] parts = [] parts << symbol if prefix parts << sql(exp).at(0) parts << symbol unless prefix bit(parts.join, prec) end
Private Instance Methods
binops()
click to toggle source
# File lib/seaquel/expression_converter.rb, line 180 def binops @binops ||= { :eq => '=', :gt => '>', :gteq => '>=', :lt => '<', :lteq => '<=', :is => ' IS ', :isnot => ' IS NOT ', :noteq => '!=', :in => ' IN ', :like => ' LIKE ', :not_like => ' NOT LIKE ', :ilike => ' ILIKE ', :not_ilike => ' NOT ILIKE ', :similar_to => ' SIMILAR TO ', :not_similar_to => ' NOT SIMILAR TO ', :plus => '+', :minus => '-', :div => '/', :times => '*', :mod => '%', :pow => '^', :sqrt => '|/', :cbrt => '||/', :bitand => '&', :bitor => '|', :bitxor => '#', :sleft => '<<', :sright => '>>' } end
bit(str, precedence=:inf)
click to toggle source
# File lib/seaquel/expression_converter.rb, line 172 def bit str, precedence=:inf Bit.new(str, precedence) end
precedence(op)
click to toggle source
# File lib/seaquel/expression_converter.rb, line 176 def precedence op precedences[op] end
precedences()
click to toggle source
# File lib/seaquel/expression_converter.rb, line 222 def precedences @precedences ||= begin prec = 1 # 0 reserved for simple values precs = Hash.new(0) assign = -> (*list) { list.map { |e| precs[e] = prec } prec += 1 } # By listing something above something else, it gets a lower precedence # assigned. List from lower to higher precedences. Equivalence classes # by extending the argument list. assign[:not] assign[:as, :is, :isnot] assign[:or] assign[:and] assign[:eq, :gt, :gteq, :lt, :lteq] assign[:plus, :minus] assign[:times, :div] precs end end
unaryops()
click to toggle source
# File lib/seaquel/expression_converter.rb, line 213 def unaryops @unaryops ||= { # sym, prefix? :not => ['NOT ', true], :bitnot => ['~', true], :fact => ['!', false], } end