module ActiveRecord module QueryMethods def preload(*associations) spawn.tap {|r| r.preload_associations += Array.wrap(associations) } end def eager_load(*associations) spawn.tap {|r| r.eager_load_associations += Array.wrap(associations) } end def readonly(status = true) spawn.tap {|r| r.readonly = status } end def select(selects) if selects.present? relation = spawn(@relation.project(selects)) relation.readonly = @relation.joins(relation).present? ? false : @readonly relation else spawn end end def from(from) from.present? ? spawn(@relation.from(from)) : spawn end def having(*args) return spawn if args.blank? if [String, Hash, Array].include?(args.first.class) havings = @klass.send(:merge_conditions, args.size > 1 ? Array.wrap(args) : args.first) else havings = args.first end spawn(@relation.having(havings)) end def group(groups) groups.present? ? spawn(@relation.group(groups)) : spawn end def order(orders) orders.present? ? spawn(@relation.order(orders)) : spawn end def lock(locks = true) case locks when String spawn(@relation.lock(locks)) when TrueClass, NilClass spawn(@relation.lock) else spawn end end def reverse_order relation = spawn relation.instance_variable_set(:@orders, nil) order_clause = @relation.send(:order_clauses).join(', ') if order_clause.present? relation.order(reverse_sql_order(order_clause)) else relation.order("#{@klass.table_name}.#{@klass.primary_key} DESC") end end def limit(limits) limits.present? ? spawn(@relation.take(limits)) : spawn end def offset(offsets) offsets.present? ? spawn(@relation.skip(offsets)) : spawn end def on(join) spawn(@relation.on(join)) end def joins(join, join_type = nil) return spawn if join.blank? join_relation = case join when String @relation.join(join) when Hash, Array, Symbol if @klass.send(:array_of_strings?, join) @relation.join(join.join(' ')) else @relation.join(@klass.send(:build_association_joins, join)) end else @relation.join(join, join_type) end spawn(join_relation).tap { |r| r.readonly = true } end def where(*args) return spawn if args.blank? if [String, Hash, Array].include?(args.first.class) conditions = @klass.send(:merge_conditions, args.size > 1 ? Array.wrap(args) : args.first) conditions = Arel::SqlLiteral.new(conditions) if conditions else conditions = args.first end spawn(@relation.where(conditions)) end private def reverse_sql_order(order_query) order_query.to_s.split(/,/).each { |s| if s.match(/\s(asc|ASC)$/) s.gsub!(/\s(asc|ASC)$/, ' DESC') elsif s.match(/\s(desc|DESC)$/) s.gsub!(/\s(desc|DESC)$/, ' ASC') else s.concat(' DESC') end }.join(',') end end end