module Repor module Dimensions class BinDimension class Bin def initialize(min, max) @min = min @max = max end def min @min && parse(@min) end def max @max && parse(@max) end def valid? (@min.nil? || parses?(@min)) && (@max.nil? || parses?(@max)) end def parses?(value) parse(value).present? rescue false end def parse(value) value end def quote(value) ActiveRecord::Base.connection.quote(value) end def cast(value) quote(value) end def bin_text "#{min},#{max}" end def cast_bin_text case Repor.database_type when :postgres, :sqlite "CAST(#{quote(bin_text)} AS text)" else quote(bin_text) end end def row_sql "SELECT #{cast(min)} AS min, #{cast(max)} AS max, #{cast_bin_text} AS bin_text" end def contains_sql(expr) if min && max "(#{expr} >= #{quote(min)} AND #{expr} < #{quote(max)})" elsif max "#{expr} < #{quote(max)}" elsif min "#{expr} >= #{quote(min)}" else "#{expr} IS NULL" end end def self.from_sql(value) case value when /^([^,]+),(.+)$/ then new($1, $2) when /^([^,]+),$/ then new($1, nil) when /^,(.+)$/ then new(nil, $1) when ',' then new(nil, nil) else raise "Unexpected SQL bin format #{value}" end end def self.from_hash(h) # Returns either a bin or nil, depending on whether # the input is valid. return new(nil, nil) if h.nil? return unless h.is_a?(Hash) min, max = h.symbolize_keys.values_at(:min, :max) return if min.blank? && max.blank? new(min.presence, max.presence) end def as_json(*) return @as_json if instance_variable_defined?(:@as_json) @as_json = if min && max { min: min, max: max } elsif min { min: min } elsif max { max: max } else nil end end def [](key) return min if key.to_s == 'min' return max if key.to_s == 'max' end def has_key?(key) key.to_s == 'min' || key.to_s == 'max' end alias key? has_key? def values_at(*keys) keys.map { |k| self[key] } end def inspect "<Bin @min=#{min.inspect} @max=#{max.inspect}>" end def hash as_json.hash end def ==(other) if other.nil? min.nil? && max.nil? else min == other[:min] && max == other[:max] end end alias eql? == end end end end