class Hotdog::Expression::UnaryExpressionNode
Attributes
expression[R]
op[R]
Public Class Methods
new(op, expression, options={})
click to toggle source
# File lib/hotdog/expression/semantics.rb, line 30 def initialize(op, expression, options={}) case (op || "not").to_s when "NOOP", "noop" @op = :NOOP when "!", "~", "NOT", "not" @op = :NOT else raise(SyntaxError.new("unknown unary operator: #{op.inspect}")) end @expression = expression @options = {} end
Public Instance Methods
==(other)
click to toggle source
# File lib/hotdog/expression/semantics.rb, line 111 def ==(other) self.class === other and @op == other.op and @expression == other.expression end
compact(options={})
click to toggle source
# File lib/hotdog/expression/semantics.rb, line 99 def compact(options={}) case op when :NOOP expression.compact(options) else UnaryExpressionNode.new( op, expression.compact(options), ) end end
dump(options={})
click to toggle source
# File lib/hotdog/expression/semantics.rb, line 115 def dump(options={}) {unary_op: @op.to_s, expression: @expression.dump(options)} end
evaluate(environment, options={})
click to toggle source
# File lib/hotdog/expression/semantics.rb, line 43 def evaluate(environment, options={}) case @op when :NOOP @expression.evaluate(environment, options) when :NOT values = @expression.evaluate(environment, options).tap do |values| environment.logger.debug("expr: #{values.length} value(s)") end if values.empty? EverythingNode.new().evaluate(environment, options).tap do |values| environment.logger.debug("NOT expr: #{values.length} value(s)") end else # workaround for "too many terms in compound SELECT" min, max = environment.execute("SELECT MIN(id), MAX(id) FROM hosts LIMIT 1;").first.to_a sqlite_limit_compound_select = options[:sqlite_limit_compound_select] || SQLITE_LIMIT_COMPOUND_SELECT (min / (sqlite_limit_compound_select - 2)).upto(max / (sqlite_limit_compound_select - 2)).flat_map { |i| range = ((sqlite_limit_compound_select - 2) * i)...((sqlite_limit_compound_select - 2) * (i + 1)) selected = values.select { |n| range === n } if 0 < selected.length q = "SELECT id FROM hosts " \ "WHERE ? <= id AND id < ? AND id NOT IN (%s);" environment.execute(q % selected.map { "?" }.join(", "), [range.first, range.last] + selected).map { |row| row.first } else [] end }.tap do |values| environment.logger.debug("NOT expr: #{values.length} value(s)") end end else [] end end
optimize(options={})
click to toggle source
# File lib/hotdog/expression/semantics.rb, line 78 def optimize(options={}) o_self = compact(options) if UnaryExpressionNode === o_self case o_self.op when :NOT case o_self.expression when EverythingNode NothingNode.new(options) when NothingNode EverythingNode.new(options) else o_self.optimize1(options) end else o_self.optimize1(options) end else o_self.optimize(options) end end
Protected Instance Methods
optimize1(options={})
click to toggle source
# File lib/hotdog/expression/semantics.rb, line 120 def optimize1(options={}) case op when :NOOP expression.optimize(options) when :NOT if UnaryExpressionNode === expression case expression.op when :NOOP expression.optimize(options) when :NOT expression.expression.optimize(options) else self.dup end else optimize2(options) end else self.dup end end
optimize2(options={})
click to toggle source
# File lib/hotdog/expression/semantics.rb, line 142 def optimize2(options={}) sqlite_limit_compound_select = options[:sqlite_limit_compound_select] || SQLITE_LIMIT_COMPOUND_SELECT case expression when QueryExpressionNode q = expression.query v = expression.values if q and v.length <= sqlite_limit_compound_select QueryExpressionNode.new("SELECT id AS host_id FROM hosts EXCEPT #{q.sub(/\s*;\s*\z/, "")};", v) else self.dup end when TagExpressionNode q = expression.maybe_query(options) v = expression.condition_values(options) if q and v.length <= sqlite_limit_compound_select QueryExpressionNode.new("SELECT id AS host_id FROM hosts EXCEPT #{q.sub(/\s*;\s*\z/, "")};", v) else self.dup end else self.dup end end