query_methods.rb 3.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
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