class Aliyun::Log::Record::Relation
Public Class Methods
new(klass, opts = {})
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 7 def initialize(klass, opts = {}) @klass = klass @opts = opts @klass.auto_load_schema end
Public Instance Methods
api(opts)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 104 def api(opts) @opts.merge!(opts) self end
count()
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 164 def count query = @opts.dup if query[:select].blank? @opts[:select] = 'COUNT(*) as count' sql = to_sql else _sql = to_sql sql = "SELECT COUNT(*) as count" sql += " FROM(#{_sql})" if _sql.present? end query[:query] = "#{query[:search] || '*'}|#{sql}" res = execute(query) res.dig(0, 'count').to_i end
fifth()
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 33 def fifth find_offset(4) end
find_offset(nth, line = 1, reverse = false)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 42 def find_offset(nth, line = 1, reverse = false) # @opts[:select] = '*' @opts[:line] = line @opts[:offset] = nth if @opts[:order].present? && reverse conds = [] @opts[:order].split(',').each do |field| field.gsub!(/\s+desc|asc.*/i, '') conds << "#{field.strip} DESC" end @opts[:order] = conds.join(', ') end @opts[:order] ||= reverse ? '__time__ DESC' : '__time__ ASC' if @opts[:select].blank? line <= 1 ? load[0] : load else line <= 1 ? result[0] : result end end
first(line = 1)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 17 def first(line = 1) find_offset(0, line, false) end
fourth()
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 29 def fourth find_offset(3) end
from(from)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 70 def from(from) ts = from.is_a?(Integer) ? from : from.to_time.to_i @opts[:from] = ts self end
group(*fields)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 140 def group(*fields) @opts[:group] = fields.join(', ') self end
inspect()
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 13 def inspect "#<#{self.class}>" end
last(line = 1)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 37 def last(line = 1) data = find_offset(0, line, true) line > 1 ? data.reverse : data end
line(val)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 82 def line(val) @opts[:line] = val.to_i self end
Also aliased as: limit
load()
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 200 def load result.map do |json_attr| record = @klass.new json_attr.each do |key, value| record.send("#{key}=", value) if record.respond_to?("#{key}=") end record end end
offset(val)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 88 def offset(val) @opts[:offset] = val.to_i self end
order(*fields)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 145 def order(*fields) if fields[0].is_a?(Hash) @opts[:order] = fields[0].map do |k, v| unless %w[asc desc].include?(v.to_s) raise ArgumentError, "Direction \"#{v}\" is invalid. Valid directions are: [:asc, :desc, :ASC, :DESC]" end "#{k} #{v}" end.join(', ') else @opts[:order] = fields.join(', ') end self end
page(val)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 93 def page(val) @opts[:page] = val - 1 if val >= 1 singleton_class.send(:define_method, :total_count) do @total_count ||= count end singleton_class.send(:define_method, :total_pages) do (total_count.to_f / (@opts[:line] || 100)).ceil end self end
query(opts = {})
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 159 def query(opts = {}) @opts[:query] = opts self end
result()
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 187 def result query = @opts.dup query[:query] = query[:search] || '*' sql = to_sql if sql.present? query[:query] += "|#{sql}" @opts[:line] = nil @opts[:offset] = nil @opts[:page] = nil end execute(query) end
scoping() { || ... }
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 62 def scoping previous = @klass.current_scope @klass.current_scope = self yield ensure @klass.current_scope = previous end
search(*statement)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 109 def search(*statement) ql = statement_ql(*statement) @opts[:search] = ql if ql.present? self end
second()
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 21 def second find_offset(1) end
select(*fields)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 135 def select(*fields) @opts[:select] = fields.join(', ') self end
sql(*statement)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 115 def sql(*statement) unless statement[0].is_a?(String) raise ParseStatementInvalid, 'Only support string statement' end ql = sanitize_array(*statement) @opts[:sql] = ql if ql.present? self end
sum(field)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 179 def sum(field) @opts[:select] = "SUM(#{field}) as sum" query = @opts.dup query[:query] = "#{query[:search] || '*'}|#{to_sql}" res = execute(query) res.dig(0, 'sum').to_f end
third()
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 25 def third find_offset(2) end
to(to)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 76 def to(to) ts = to.is_a?(Integer) ? to : to.to_time.to_i @opts[:to] = ts self end
to_sql()
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 210 def to_sql return @opts[:sql] if @opts[:sql].present? opts = @opts.dup sql_query = [] sql_query << "WHERE #{opts[:where]}" if opts[:where].present? sql_query << "GROUP BY #{opts[:group]}" if opts[:group].present? sql_query << "ORDER BY #{opts[:order]}" if opts[:order].present? if sql_query.present? || opts[:select].present? sql_query.insert(0, "SELECT #{opts[:select] || '*'}") sql_query.insert(1, 'FROM log') unless opts[:select]&.match?(/from\s+log/i) if opts[:line] || opts[:page] || opts[:offset] parse_page sql_query << "LIMIT #{@opts[:offset]},#{@opts[:line]}" end end "#{opts[:query]}#{sql_query.join(' ')}" end
where(*statement)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 124 def where(*statement) if statement[0].is_a?(String) ql = sanitize_array(*statement) @opts[:where] = ql else ql = statement_ql(*statement) @opts[:search] = ql end self end
Private Instance Methods
_quote(type, value)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 328 def _quote(type, value) v = TypeCasting.cast_field(value, cast_type: type || :string) case type when :string, nil then "'#{v.to_s}'" when :bigdecimal then v.to_s("F") when :integer then v.to_s.to_i when :datetime, :date then "'#{v.iso8601}'" else value.to_s end end
_quote_type_value(value)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 340 def _quote_type_value(value) case value.class.name when 'String' then "'#{value.to_s}'" when 'BigDecimal', 'Float' then value.to_s("F") when 'Date', 'DateTime', 'Time' then "'#{value.iso8601}'" else value end end
execute(query)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 230 def execute(query) puts query.slice(:from, :to, :search, :query).to_json res = Log.record_connection.get_logs(@klass.project_name, @klass.logstore_name, query) JSON.parse(res) end
method_missing(method, *args, &block)
click to toggle source
Calls superclass method
# File lib/aliyun/log/record/relation.rb, line 356 def method_missing(method, *args, &block) if @klass.respond_to?(method) scoping { @klass.public_send(method, *args, &block) } else super end end
parse_page()
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 236 def parse_page @opts[:line] ||= 100 @opts[:page] ||= 0 @opts[:offset] = @opts[:page] * @opts[:line] end
raise_if_hash_quote(value)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 350 def raise_if_hash_quote(value) if value.is_a?(Hash) || value.is_a?(ActiveSupport::HashWithIndifferentAccess) raise ParseStatementInvalid, "can't quote Hash" end end
replace_bind_variables(statement, values)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 308 def replace_bind_variables(statement, values) expected = statement.count('?') provided = values.size if expected != provided raise ParseStatementInvalid, "wrong number of bind variables (#{provided} " \ "for #{expected}) in: #{statement}" end bound = values.dup statement.gsub(/\?/) do value = bound.shift raise_if_hash_quote(value) if value.is_a?(Array) || value.is_a?(Range) values = value.map { |v| _quote_type_value(v) } values.join(', ') else _quote_type_value(value) end end end
replace_named_bind_variables(statement, bind_vars)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 291 def replace_named_bind_variables(statement, bind_vars) statement.gsub(/(:?):([a-zA-Z]\w*)/) do |match| if bind_vars.include?(match = Regexp.last_match(2).to_sym) match_value = bind_vars[match] raise_if_hash_quote(match_value) if match_value.is_a?(Array) || match_value.is_a?(Range) values = match_value.map { |v| _quote_type_value(v) } values.join(', ') else _quote_type_value(match_value) end else raise ParseStatementInvalid, "missing value for :#{match} in #{statement}" end end end
sanitize_array(*ary)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 278 def sanitize_array(*ary) statement, *values = ary if values.first.is_a?(Hash) && /:\w+/.match?(statement) replace_named_bind_variables(statement, values.first) elsif statement.include?('?') replace_bind_variables(statement, values) elsif statement.blank? || values.blank? statement else statement % values.collect(&:to_s) end end
sanitize_hash(search_content)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 250 def sanitize_hash(search_content) return search_content unless search_content.is_a?(Hash) search_content.reject { |_, v| v.nil? }.map do |key, value| options = @klass.attributes[:"#{key}"] unless options raise UnknownAttributeError, "unknown field '#{key}' for #{@klass.name}." end raise_if_hash_quote(value) cast_type = options[:cast_type] is_tag = @klass.tag_attributes[:"#{key}"] key = :"__tag__:#{key}" if is_tag if value.is_a?(Array) values = value.uniq.map { |v| is_tag ? v : _quote(cast_type, v) } str_values = values.map { |v| "#{key}: #{v}" }.join(' OR ') values.size > 1 ? "(#{str_values})" : str_values elsif value.is_a?(Range) "#{key} in [#{value.begin} #{value.end}]" else quote_value = is_tag ? value : _quote(cast_type, value) "#{key}: #{quote_value}" end end.join(' AND ') end
statement_ql(*statement)
click to toggle source
# File lib/aliyun/log/record/relation.rb, line 242 def statement_ql(*statement) if statement.size == 1 sanitize_hash(statement.first) elsif statement.size > 1 sanitize_array(*statement) end end