diff options
Diffstat (limited to 'activerecord/lib/active_record/relation/query_methods.rb')
-rw-r--r-- | activerecord/lib/active_record/relation/query_methods.rb | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb new file mode 100644 index 0000000000..525a9cb365 --- /dev/null +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -0,0 +1,141 @@ +module ActiveRecord + module QueryMethods + + def preload(*associations) + spawn.tap {|r| r.preload_associations += Array.wrap(associations) } + end + + def includes(*associations) + spawn.tap {|r| r.includes_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? + + builder = PredicateBuilder.new(Arel::Sql::Engine.new(@klass)) + + conditions = if [String, Array].include?(args.first.class) + merged = @klass.send(:merge_conditions, args.size > 1 ? Array.wrap(args) : args.first) + Arel::SqlLiteral.new(merged) if merged + elsif args.first.is_a?(Hash) + attributes = @klass.send(:expand_hash_conditions_for_aggregates, args.first) + builder.build_from_hash(attributes, table) + else + args.first + end + + conditions.is_a?(String) ? spawn(@relation.where(conditions)) : 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 |