class Kasket::Visitor

Public Class Methods

new(model_class, binds) click to toggle source

binds can be removed once we stop supporting Rails < 5.2

Calls superclass method
# File lib/kasket/visitor.rb, line 7
def initialize(model_class, binds)
  @model_class = model_class
  @binds       = binds.dup
  super()
end

Public Instance Methods

accept(node) click to toggle source
Calls superclass method
# File lib/kasket/visitor.rb, line 13
def accept(node)
  self.last_column = nil
  super
end

Private Instance Methods

column_for(name) click to toggle source
# File lib/kasket/visitor.rb, line 28
def column_for(name)
  @model_class.columns_hash[name.to_s]
end
last_column() click to toggle source
# File lib/kasket/visitor.rb, line 24
def last_column
  Thread.current[:arel_visitors_to_sql_last_column]
end
last_column=(col) click to toggle source
# File lib/kasket/visitor.rb, line 20
def last_column=(col)
  Thread.current[:arel_visitors_to_sql_last_column] = col
end
literal(node, *_) click to toggle source
# File lib/kasket/visitor.rb, line 117
def literal(node, *_)
  if ActiveRecord::VERSION::STRING < '5.2'
    if node == '?'
      @binds.shift.last.to_s
    else
      node.to_s
    end
  else
    node.to_s
  end
end
ordered?(node) click to toggle source

any non `id asc` ordering

# File lib/kasket/visitor.rb, line 168
def ordered?(node)
  !node.orders.all? { |o| o.is_a?(Arel::Nodes::Ascending) && o.expr.name == "id" }
end
quoted(node) click to toggle source
# File lib/kasket/visitor.rb, line 163
def quoted(node)
  @model_class.connection.quote(node)
end
visit_Arel_Attributes_Attribute(node, *_) click to toggle source
# File lib/kasket/visitor.rb, line 112
def visit_Arel_Attributes_Attribute(node, *_)
  self.last_column = column_for(node.name)
  node.name.to_sym
end
visit_Arel_Nodes_And(node, *_) click to toggle source
# File lib/kasket/visitor.rb, line 87
def visit_Arel_Nodes_And(node, *_)
  attributes = node.children.map { |child| visit(child) }
  return :unsupported if attributes.include?(:unsupported)

  attributes.sort! { |pair1, pair2| pair1[0].to_s <=> pair2[0].to_s }
  { attributes: attributes }
end
visit_Arel_Nodes_BindParam(node, *_) click to toggle source
# File lib/kasket/visitor.rb, line 129
def visit_Arel_Nodes_BindParam(node, *_)
  if ActiveRecord::VERSION::MAJOR < 5
    visit(@binds.shift[1])
  else
    if ActiveRecord::VERSION::STRING < '5.2'
      visit(@binds.shift)
    else
      visit(node.value.value) unless node.value.value.nil?
    end
  end
end
visit_Arel_Nodes_Casted(node, *_) click to toggle source
# File lib/kasket/visitor.rb, line 146
def visit_Arel_Nodes_Casted(node, *_)
  case node.val
  when nil    then nil
  when String then node.val
  else quoted(node.val)
  end
end
visit_Arel_Nodes_Equality(node, *_) click to toggle source
# File lib/kasket/visitor.rb, line 102
def visit_Arel_Nodes_Equality(node, *_)
  right =
    case node.right
    when false then 0 # This should probably be removed when Rails 3.2 is not supported anymore
    when nil   then nil
    else visit(node.right)
    end
  [visit(node.left), right]
end
visit_Arel_Nodes_In(node, *_) click to toggle source
# File lib/kasket/visitor.rb, line 95
def visit_Arel_Nodes_In(node, *_)
  left = visit(node.left)
  return :unsupported if left != :id

  [left, visit(node.right)]
end
visit_Arel_Nodes_JoinSource(node, *_) click to toggle source
# File lib/kasket/visitor.rb, line 76
def visit_Arel_Nodes_JoinSource(node, *_)
  return :unsupported if !node.left || node.right.any?
  return :unsupported unless node.left.is_a?(Arel::Table)

  visit(node.left)
end
visit_Arel_Nodes_Limit(node, *_) click to toggle source
# File lib/kasket/visitor.rb, line 68
def visit_Arel_Nodes_Limit(node, *_)
  if ActiveRecord::VERSION::MAJOR < 5
    { limit: node.value.to_i }
  else
    { limit: visit(node.value).to_i }
  end
end
visit_Arel_Nodes_SelectCore(node, *_) click to toggle source
# File lib/kasket/visitor.rb, line 50
def visit_Arel_Nodes_SelectCore(node, *_)
  return :unsupported if node.groups.any?
  return :unsupported if ActiveRecord::VERSION::MAJOR < 5 ? node.having : node.havings.present?
  return :unsupported if node.set_quantifier
  return :unsupported if !node.source || node.source.empty?
  return :unsupported if node.projections.size != 1

  select = node.projections[0]
  select = select.name if select.respond_to?(:name)
  return :unsupported if select != '*'

  parts = [visit(node.source)]

  parts += node.wheres.map {|where| visit(where) }

  parts.include?(:unsupported) ? :unsupported : parts
end
visit_Arel_Nodes_SelectStatement(node, *_) click to toggle source
# File lib/kasket/visitor.rb, line 32
def visit_Arel_Nodes_SelectStatement(node, *_)
  return :unsupported if node.with
  return :unsupported if node.offset
  return :unsupported if node.lock
  return :unsupported if ordered?(node)
  return :unsupported if node.cores.size != 1

  query = visit_Arel_Nodes_SelectCore(node.cores[0])
  return query if query == :unsupported

  query = query.inject({}) do |memo, item|
    memo.merge(item)
  end

  query.merge!(visit(node.limit)) if node.limit
  query
end
visit_Arel_Nodes_SqlLiteral(node, *_)
Alias for: literal
visit_Arel_Table(node, *_) click to toggle source
# File lib/kasket/visitor.rb, line 83
def visit_Arel_Table(node, *_)
  { from: node.name }
end
visit_Array(node, *_) click to toggle source
# File lib/kasket/visitor.rb, line 141
def visit_Array(node, *_)
  node.map {|value| visit(value) }
end
visit_Bignum(node, *_)
Alias for: literal
visit_FalseClass(_node) click to toggle source
# File lib/kasket/visitor.rb, line 159
def visit_FalseClass(_node)
  0
end
visit_Fixnum(node, *_)
Alias for: literal
visit_Integer(node, *_)
Alias for: literal
visit_String(node, *_)
Alias for: literal
visit_TrueClass(_node) click to toggle source
# File lib/kasket/visitor.rb, line 155
def visit_TrueClass(_node)
  1
end