Skip to content

Instantly share code, notes, and snippets.

@felixbuenemann
Last active April 30, 2016 07:09
Show Gist options
  • Save felixbuenemann/eb2e0f6c66469a98f748 to your computer and use it in GitHub Desktop.
Save felixbuenemann/eb2e0f6c66469a98f748 to your computer and use it in GitHub Desktop.
# CASE implementation for Arel
# Based on: https://github.com/take-five/acts_as_ordered_tree/blob/master/lib/acts_as_ordered_tree/transaction/dsl.rb
# Extended with support for CASE expr WHEN expr[, expr, ...] by Felix Buenemann
module Arel
module Nodes
# Case node
#
# @example
# switch.when(table[:x].gt(1), table[:y]).else(table[:z])
# # CASE WHEN "table"."x" > 1 THEN "table"."y" ELSE "table"."z" END
# switch.when(table[:x].gt(1)).then(table[:y]).else(table[:z])
# # CASE "table"."x" WHEN 1 THEN "table"."y" ELSE "table"."z" END
# switch.case(table[:x]).when(1).then(table[:y]).else(table[:z])
class Case < Arel::Nodes::Node
include Arel::Expression
include Arel::Predications
include Arel::AliasPredication
attr_reader :expression, :conditions, :default
def initialize(expression = nil)
@expression = expression
@conditions = []
@default = nil
end
def case(expression)
@expression = expression
self
end
def when(condition, expression = nil)
@conditions << When.new(condition, expression)
self
end
def then(expression)
@conditions.last.right = expression
self
end
def else(expression)
@default = Else.new(expression)
self
end
end
class When < Arel::Nodes::Binary
end
class Else < Arel::Nodes::Unary
end
end
module Visitors
class ToSql < Arel::Visitors::Visitor
private
def visit_Arel_Nodes_Case o, *a
expression = o.expression && visit(o.expression, *a)
conditions = o.conditions.map { |x| visit x, *a }.join(' ')
default = o.default && visit(o.default, *a)
"CASE #{[expression, conditions, default].compact.join(' ')} END"
end
def visit_Arel_Nodes_When o, *a
"WHEN #{visit o.left} THEN #{visit o.right, *a}"
end
def visit_Arel_Nodes_Else o, *a
"ELSE #{visit o.expr, *a}"
end
end
class DepthFirst < Arel::Visitors::Visitor
def visit_Arel_Nodes_Case o, *a
visit o.conditions, *a
visit o.default, *a
end
alias :visit_Arel_Nodes_When :binary
alias :visit_Arel_Nodes_Else :unary
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment