Skip to content

Instantly share code, notes, and snippets.

Created November 25, 2008 00:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save anonymous/28712 to your computer and use it in GitHub Desktop.
Save anonymous/28712 to your computer and use it in GitHub Desktop.
module Sql
module Syntax
def self.serialize(sexp)
send(*sexp)
end
private
def self.and(*args)
"(" + args.map do |expr|
send(*expr)
end.join(" AND ") + ")"
end
def self.or(*args)
"(" + args.map do |expr|
send(*expr)
end.join(" OR ") + ")"
end
def self.gt(field, value)
"#{field} > #{value}"
end
def self.lt(field, value)
"#{field} < #{value}"
end
def self.eq(field, value)
"#{field} = #{value}"
end
end
end
class UnboundCondition
def self.gt(field, value)
new(:gt, field, value)
end
def self.lt(field, value)
new(:lt, field, value)
end
def self.eq(field, value)
new(:eq, field, value)
end
def initialize(operator, field, value)
@operator = operator
@field = field
@value = value
end
def and(*others)
AndExpression.new(self, *others)
end
def or(*others)
OrExpression.new(self, *others)
end
def to_a
[@operator, @field, @value]
end
end
class Expression
def initialize(*values)
@values = values
end
def or(*values)
OrExpression.new(self, *values)
end
def and(*values)
AndExpression.new(self, *values)
end
def to_a
[self.class.operator, *@values.map { |value| value.to_a }]
end
private
def self.operator
raise NotImplementedError.new("Expression is an abstract class")
end
end
class AndExpression < Expression
private
def self.operator
:and
end
end
class OrExpression < Expression
private
def self.operator
:or
end
end
class Query
class Conditions
def initialize(expression = nil)
@expression = expression
end
def and(expression)
append(:and, expression)
self
end
def or(expression)
append(:or, expression)
self
end
def set(expression)
@expression = expression
self
end
def to_a
@expression.to_a
end
private
def append(method, expression)
if @expression
@expression = case method
when :and then @expression.and(expression)
when :or then @expression.or(expression)
else raise NotImplementedError.new("Method #{method} unsupported")
end
else
@expression = expression
end
end
end
def initialize(root)
@root = root
@conditions = Conditions.new
end
def conditions
@conditions
end
def conditions=(expression)
@conditions = Conditions.new(expression)
end
end
a = [:or,
[:or,
[:eq, :name, "John"],
[:eq, :name, "Jane"]
],
[:and,
[:gt, :age, 3],
[:lt, :age, 65]
]
]
p Sql::Syntax.serialize(a)
q = Query.new(Object)
john = UnboundCondition.eq(:name, "John")
jane = UnboundCondition.eq(:name, "Jane")
toddler = UnboundCondition.gt(:age, 3)
not_senior = UnboundCondition.lt(:age, 65)
q.conditions.set(john.or(jane)).or(toddler.and(not_senior))
p Sql::Syntax.serialize(q.conditions.to_a)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment