query_methods.rb 30.1 KB
Newer Older
1
require 'active_support/core_ext/array/wrap'
2

3 4
module ActiveRecord
  module QueryMethods
5 6
    extend ActiveSupport::Concern

7 8 9 10 11 12 13
    # WhereChain objects act as placeholder for queries in which #where does not have any parameter.
    # In this case, #where must be chained with either #not, #like, or #not_like to return a new relation.
    class WhereChain
      def initialize(scope)
        @scope = scope
      end

14 15
      # Returns a new relation expressing WHERE + NOT condition according to
      # the conditions in the arguments.
16
      #
17 18
      # +not+ accepts conditions as a string, array, or hash. See #where for
      # more details on each format.
19 20
      #
      #    User.where.not("name = 'Jon'")
21
      #    # SELECT * FROM users WHERE NOT (name = 'Jon')
22 23
      #
      #    User.where.not(["name = ?", "Jon"])
24
      #    # SELECT * FROM users WHERE NOT (name = 'Jon')
25
      #
26
      #    User.where.not(name: "Jon")
27
      #    # SELECT * FROM users WHERE name != 'Jon'
28 29 30 31
      #
      #    User.where.not(name: nil)
      #    # SELECT * FROM users WHERE name IS NOT NULL
      #
32
      #    User.where.not(name: %w(Ko1 Nobu))
33
      #    # SELECT * FROM users WHERE name NOT IN ('Ko1', 'Nobu')
34 35 36 37
      #
      #    User.where.not(name: "Jon", role: "admin")
      #    # SELECT * FROM users WHERE name != 'Jon' AND role != 'admin'
      #
38 39 40 41 42
      def not(opts, *rest)
        where_value = @scope.send(:build_where, opts, rest).map do |rel|
          case rel
          when Arel::Nodes::In
            Arel::Nodes::NotIn.new(rel.left, rel.right)
43 44
          when Arel::Nodes::Equality
            Arel::Nodes::NotEqual.new(rel.left, rel.right)
45 46 47 48 49 50 51 52 53 54 55
          when String
            Arel::Nodes::Not.new(Arel::Nodes::SqlLiteral.new(rel))
          else
            Arel::Nodes::Not.new(rel)
          end
        end
        @scope.where_values += where_value
        @scope
      end
    end

56 57
    Relation::MULTI_VALUE_METHODS.each do |name|
      class_eval <<-CODE, __FILE__, __LINE__ + 1
58 59 60 61 62 63 64 65
        def #{name}_values                   # def select_values
          @values[:#{name}] || []            #   @values[:select] || []
        end                                  # end
                                             #
        def #{name}_values=(values)          # def select_values=(values)
          raise ImmutableRelation if @loaded #   raise ImmutableRelation if @loaded
          @values[:#{name}] = values         #   @values[:select] = values
        end                                  # end
66 67 68 69 70
      CODE
    end

    (Relation::SINGLE_VALUE_METHODS - [:create_with]).each do |name|
      class_eval <<-CODE, __FILE__, __LINE__ + 1
71 72 73
        def #{name}_value                    # def readonly_value
          @values[:#{name}]                  #   @values[:readonly]
        end                                  # end
74 75 76
      CODE
    end

77 78 79 80 81 82 83
    Relation::SINGLE_VALUE_METHODS.each do |name|
      class_eval <<-CODE, __FILE__, __LINE__ + 1
        def #{name}_value=(value)            # def readonly_value=(value)
          raise ImmutableRelation if @loaded #   raise ImmutableRelation if @loaded
          @values[:#{name}] = value          #   @values[:readonly] = value
        end                                  # end
      CODE
84 85
    end

O
Oscar Del Ben 已提交
86
    def create_with_value # :nodoc:
87
      @values[:create_with] || {}
88
    end
89 90

    alias extensions extending_values
91

O
Oscar Del Ben 已提交
92 93 94 95 96 97 98 99 100 101
    # Specify relationships to be included in the result set. For
    # example:
    #
    #   users = User.includes(:address)
    #   users.each do |user|
    #     user.address.city
    #   end
    #
    # allows you to access the +address+ attribute of the +User+ model without
    # firing an additional query. This will often result in a
102 103 104 105 106 107 108 109 110 111 112 113
    # performance improvement over a simple +join+.
    #
    # === conditions
    #
    # If you want to add conditions to your included models you'll have
    # to explicitly reference them. For example:
    #
    #   User.includes(:posts).where('posts.name = ?', 'example')
    #
    # Will throw an error, but this will work:
    #
    #   User.includes(:posts).where('posts.name = ?', 'example').references(:posts)
114
    def includes(*args)
115
      check_if_method_has_arguments!("includes", args)
116
      spawn.includes!(*args)
117
    end
118

J
Jon Leighton 已提交
119
    def includes!(*args) # :nodoc:
120
      args.reject! {|a| a.blank? }
A
Aaron Patterson 已提交
121

122 123
      self.includes_values = (includes_values + args).flatten.uniq
      self
124
    end
125

126 127 128 129 130 131
    # Forces eager loading by performing a LEFT OUTER JOIN on +args+:
    #
    #   User.eager_load(:posts)
    #   => SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, ...
    #   FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" =
    #   "users"."id"
132
    def eager_load(*args)
133
      check_if_method_has_arguments!("eager_load", args)
134
      spawn.eager_load!(*args)
135
    end
136

J
Jon Leighton 已提交
137
    def eager_load!(*args) # :nodoc:
138 139
      self.eager_load_values += args
      self
140 141
    end

142 143 144 145
    # Allows preloading of +args+, in the same way that +includes+ does:
    #
    #   User.preload(:posts)
    #   => SELECT "posts".* FROM "posts" WHERE "posts"."user_id" IN (1, 2, 3)
146
    def preload(*args)
147
      check_if_method_has_arguments!("preload", args)
148
      spawn.preload!(*args)
149
    end
150

J
Jon Leighton 已提交
151
    def preload!(*args) # :nodoc:
152 153
      self.preload_values += args
      self
154
    end
155

156 157 158 159 160 161 162 163 164
    # Used to indicate that an association is referenced by an SQL string, and should
    # therefore be JOINed in any query rather than loaded separately.
    #
    #   User.includes(:posts).where("posts.name = 'foo'")
    #   # => Doesn't JOIN the posts table, resulting in an error.
    #
    #   User.includes(:posts).where("posts.name = 'foo'").references(:posts)
    #   # => Query now knows the string references posts, so adds a JOIN
    def references(*args)
165
      check_if_method_has_arguments!("references", args)
166
      spawn.references!(*args)
167
    end
168

J
Jon Leighton 已提交
169
    def references!(*args) # :nodoc:
170 171 172
      args.flatten!

      self.references_values = (references_values + args.map!(&:to_s)).uniq
173
      self
174 175
    end

176
    # Works in two unique ways.
177
    #
178 179
    # First: takes a block so it can be used just like Array#select.
    #
180
    #   Model.all.select { |m| m.field == value }
181 182 183 184 185
    #
    # This will build an array of objects from the database for the scope,
    # converting them into an array and iterating through them using Array#select.
    #
    # Second: Modifies the SELECT statement for the query so that only certain
V
Vijay Dev 已提交
186
    # fields are retrieved:
187
    #
188 189
    #   Model.select(:field)
    #   # => [#<Model field:value>]
190 191
    #
    # Although in the above example it looks as though this method returns an
V
Vijay Dev 已提交
192
    # array, it actually returns a relation object and can have other query
193 194
    # methods appended to it, such as the other methods in ActiveRecord::QueryMethods.
    #
195
    # The argument to the method can also be an array of fields.
196
    #
197 198
    #   Model.select(:field, :other_field, :and_one_more)
    #   # => [#<Model field: "value", other_field: "value", and_one_more: "value">]
199
    #
200 201 202 203 204 205 206 207 208 209
    # You can also use one or more strings, which will be used unchanged as SELECT fields.
    #
    #   Model.select('field AS field_one', 'other_field AS field_two')
    #   # => [#<Model field: "value", other_field: "value">]
    #
    # If an alias was specified, it will be accessible from the resulting objects:
    #
    #   Model.select('field AS field_one').first.field_one
    #   # => "value"
    #
210 211
    # Accessing attributes of an object that do not have fields retrieved by a select
    # will throw <tt>ActiveModel::MissingAttributeError</tt>:
212
    #
213 214 215
    #   Model.select(:field).first.other_field
    #   # => ActiveModel::MissingAttributeError: missing attribute: other_field
    def select(*fields)
216
      if block_given?
217
        to_a.select { |*block_args| yield(*block_args) }
218
      else
219 220
        raise ArgumentError, 'Call this with at least one field' if fields.empty?
        spawn.select!(*fields)
221 222 223
      end
    end

J
Jon Leighton 已提交
224
    def select!(*fields) # :nodoc:
225
      self.select_values += fields.flatten
226
      self
227
    end
S
Santiago Pastorino 已提交
228

O
Oscar Del Ben 已提交
229 230 231 232 233
    # Allows to specify a group attribute:
    #
    #   User.group(:name)
    #   => SELECT "users".* FROM "users" GROUP BY name
    #
234
    # Returns an array with distinct records based on the +group+ attribute:
O
Oscar Del Ben 已提交
235 236 237 238 239 240
    #
    #   User.select([:id, :name])
    #   => [#<User id: 1, name: "Oscar">, #<User id: 2, name: "Oscar">, #<User id: 3, name: "Foo">
    #
    #   User.group(:name)
    #   => [#<User id: 3, name: "Foo", ...>, #<User id: 2, name: "Oscar", ...>]
241 242 243
    #
    #   User.group('name AS grouped_name, age')
    #   => [#<User id: 3, name: "Foo", age: 21, ...>, #<User id: 2, name: "Oscar", age: 21, ...>, #<User id: 5, name: "Foo", age: 23, ...>]
244
    def group(*args)
245
      check_if_method_has_arguments!("group", args)
246
      spawn.group!(*args)
247
    end
248

J
Jon Leighton 已提交
249
    def group!(*args) # :nodoc:
250 251 252
      args.flatten!

      self.group_values += args
253
      self
254
    end
255

O
Oscar Del Ben 已提交
256 257 258 259 260 261 262 263 264 265
    # Allows to specify an order attribute:
    #
    #   User.order('name')
    #   => SELECT "users".* FROM "users" ORDER BY name
    #
    #   User.order('name DESC')
    #   => SELECT "users".* FROM "users" ORDER BY name DESC
    #
    #   User.order('name DESC, email')
    #   => SELECT "users".* FROM "users" ORDER BY name DESC, email
266
    #
267 268
    #   User.order(:name)
    #   => SELECT "users".* FROM "users" ORDER BY "users"."name" ASC
269
    #
270 271
    #   User.order(email: :desc)
    #   => SELECT "users".* FROM "users" ORDER BY "users"."email" DESC
272
    #
273 274
    #   User.order(:name, email: :desc)
    #   => SELECT "users".* FROM "users" ORDER BY "users"."name" ASC, "users"."email" DESC
275
    def order(*args)
276
      check_if_method_has_arguments!("order", args)
277
      spawn.order!(*args)
278
    end
279

J
Jon Leighton 已提交
280
    def order!(*args) # :nodoc:
281
      args.flatten!
282
      validate_order_args args
283

284
      references = args.reject { |arg| Arel::Node === arg }
285
      references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact!
286
      references!(references) if references.any?
287

288 289 290 291 292
      # if a symbol is given we prepend the quoted table name
      args = args.map { |arg|
        arg.is_a?(Symbol) ? "#{quoted_table_name}.#{arg} ASC" : arg
      }

293
      self.order_values = args + self.order_values
294
      self
295
    end
296

297 298 299 300 301 302 303 304
    # Replaces any existing order defined on the relation with the specified order.
    #
    #   User.order('email DESC').reorder('id ASC') # generated SQL has 'ORDER BY id ASC'
    #
    # Subsequent calls to order on the same relation will be appended. For example:
    #
    #   User.order('email DESC').reorder('id ASC').order('name ASC')
    #
305
    # generates a query with 'ORDER BY name ASC, id ASC'.
S
Sebastian Martinez 已提交
306
    def reorder(*args)
307
      check_if_method_has_arguments!("reorder", args)
308
      spawn.reorder!(*args)
309
    end
310

J
Jon Leighton 已提交
311
    def reorder!(*args) # :nodoc:
312
      args.flatten!
313
      validate_order_args args
314

315
      self.reordering_value = true
316
      self.order_values = args
317
      self
S
Sebastian Martinez 已提交
318 319
    end

320 321 322 323
    # Performs a joins on +args+:
    #
    #   User.joins(:posts)
    #   => SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id"
324 325 326 327 328
    #
    # You can use strings in order to customize your joins:
    #
    #   User.joins("LEFT JOIN bookmarks ON bookmarks.bookmarkable_type = 'Post' AND bookmarks.user_id = users.id")
    #   => SELECT "users".* FROM "users" LEFT JOIN bookmarks ON bookmarks.bookmarkable_type = 'Post' AND bookmarks.user_id = users.id
329
    def joins(*args)
330
      check_if_method_has_arguments!("joins", args)
331
      spawn.joins!(*args.compact.flatten)
332
    end
333

J
Jon Leighton 已提交
334
    def joins!(*args) # :nodoc:
335 336
      self.joins_values += args
      self
P
Pratik Naik 已提交
337 338
    end

A
Aaron Patterson 已提交
339
    def bind(value)
J
Jon Leighton 已提交
340
      spawn.bind!(value)
341 342
    end

J
Jon Leighton 已提交
343
    def bind!(value) # :nodoc:
344 345
      self.bind_values += [value]
      self
A
Aaron Patterson 已提交
346 347
    end

348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422
    # Returns a new relation, which is the result of filtering the current relation
    # according to the conditions in the arguments.
    #
    # #where accepts conditions in one of several formats. In the examples below, the resulting
    # SQL is given as an illustration; the actual query generated may be different depending
    # on the database adapter.
    #
    # === string
    #
    # A single string, without additional arguments, is passed to the query
    # constructor as a SQL fragment, and used in the where clause of the query.
    #
    #    Client.where("orders_count = '2'")
    #    # SELECT * from clients where orders_count = '2';
    #
    # Note that building your own string from user input may expose your application
    # to injection attacks if not done properly. As an alternative, it is recommended
    # to use one of the following methods.
    #
    # === array
    #
    # If an array is passed, then the first element of the array is treated as a template, and
    # the remaining elements are inserted into the template to generate the condition.
    # Active Record takes care of building the query to avoid injection attacks, and will
    # convert from the ruby type to the database type where needed. Elements are inserted
    # into the string in the order in which they appear.
    #
    #   User.where(["name = ? and email = ?", "Joe", "joe@example.com"])
    #   # SELECT * FROM users WHERE name = 'Joe' AND email = 'joe@example.com';
    #
    # Alternatively, you can use named placeholders in the template, and pass a hash as the
    # second element of the array. The names in the template are replaced with the corresponding
    # values from the hash.
    #
    #   User.where(["name = :name and email = :email", { name: "Joe", email: "joe@example.com" }])
    #   # SELECT * FROM users WHERE name = 'Joe' AND email = 'joe@example.com';
    #
    # This can make for more readable code in complex queries.
    #
    # Lastly, you can use sprintf-style % escapes in the template. This works slightly differently
    # than the previous methods; you are responsible for ensuring that the values in the template
    # are properly quoted. The values are passed to the connector for quoting, but the caller
    # is responsible for ensuring they are enclosed in quotes in the resulting SQL. After quoting,
    # the values are inserted using the same escapes as the Ruby core method <tt>Kernel::sprintf</tt>.
    #
    #   User.where(["name = '%s' and email = '%s'", "Joe", "joe@example.com"])
    #   # SELECT * FROM users WHERE name = 'Joe' AND email = 'joe@example.com';
    #
    # If #where is called with multiple arguments, these are treated as if they were passed as
    # the elements of a single array.
    #
    #   User.where("name = :name and email = :email", { name: "Joe", email: "joe@example.com" })
    #   # SELECT * FROM users WHERE name = 'Joe' AND email = 'joe@example.com';
    #
    # When using strings to specify conditions, you can use any operator available from
    # the database. While this provides the most flexibility, you can also unintentionally introduce
    # dependencies on the underlying database. If your code is intended for general consumption,
    # test with multiple database backends.
    #
    # === hash
    #
    # #where will also accept a hash condition, in which the keys are fields and the values
    # are values to be searched for.
    #
    # Fields can be symbols or strings. Values can be single values, arrays, or ranges.
    #
    #    User.where({ name: "Joe", email: "joe@example.com" })
    #    # SELECT * FROM users WHERE name = 'Joe' AND email = 'joe@example.com'
    #
    #    User.where({ name: ["Alice", "Bob"]})
    #    # SELECT * FROM users WHERE name IN ('Alice', 'Bob')
    #
    #    User.where({ created_at: (Time.now.midnight - 1.day)..Time.now.midnight })
    #    # SELECT * FROM users WHERE (created_at BETWEEN '2012-06-09 07:00:00.000000' AND '2012-06-10 07:00:00.000000')
    #
423 424 425 426 427 428
    # In the case of a belongs_to relationship, an association key can be used
    # to specify the model if an ActiveRecord object is used as the value.
    #
    #    author = Author.find(1)
    #
    #    # The following queries will be equivalent:
A
AvnerCohen 已提交
429 430
    #    Post.where(author: author)
    #    Post.where(author_id: author)
431 432 433
    #
    # This also works with polymorphic belongs_to relationships:
    #
A
AvnerCohen 已提交
434 435
    #    treasure = Treasure.create(name: 'gold coins')
    #    treasure.price_estimates << PriceEstimate.create(price: 125)
436 437
    #
    #    # The following queries will be equivalent:
A
AvnerCohen 已提交
438 439
    #    PriceEstimate.where(estimate_of: treasure)
    #    PriceEstimate.where(estimate_of_type: 'Treasure', estimate_of_id: treasure)
440
    #
441 442 443 444 445 446 447 448 449 450
    # === Joins
    #
    # If the relation is the result of a join, you may create a condition which uses any of the
    # tables in the join. For string and array conditions, use the table name in the condition.
    #
    #    User.joins(:posts).where("posts.created_at < ?", Time.now)
    #
    # For hash conditions, you can either use the table name in the key, or use a sub-hash.
    #
    #    User.joins(:posts).where({ "posts.published" => true })
A
AvnerCohen 已提交
451
    #    User.joins(:posts).where({ posts: { published: true } })
452
    #
453
    # === no argument
454
    #
455 456
    # If no argument is passed, #where returns a new instance of WhereChain, that
    # can be chained with #not to return a new relation that negates the where clause.
457 458
    #
    #    User.where.not(name: "Jon")
459
    #    # SELECT * FROM users WHERE name != 'Jon'
460
    #
461
    # See WhereChain for more details on #not.
462
    #
463
    # === blank condition
464
    #
465
    # If the condition is any blank-ish object, then #where is a no-op and returns
466
    # the current relation.
467 468
    def where(opts = :chain, *rest)
      if opts == :chain
469 470 471 472 473 474
        WhereChain.new(spawn)
      elsif opts.blank?
        self
      else
        spawn.where!(opts, *rest)
      end
475 476
    end

477 478
    def where!(opts = :chain, *rest) # :nodoc:
      if opts == :chain
479 480 481
        WhereChain.new(self)
      else
        references!(PredicateBuilder.references(opts)) if Hash === opts
482

483 484 485
        self.where_values += build_where(opts, rest)
        self
      end
486
    end
P
Pratik Naik 已提交
487

488 489 490 491
    # Allows to specify a HAVING clause. Note that you can't use HAVING
    # without also specifying a GROUP clause.
    #
    #   Order.having('SUM(price) > 30').group('user_id')
492
    def having(opts, *rest)
493
      opts.blank? ? self : spawn.having!(opts, *rest)
494
      spawn.having!(opts, *rest)
495 496
    end

J
Jon Leighton 已提交
497
    def having!(opts, *rest) # :nodoc:
498
      references!(PredicateBuilder.references(opts)) if Hash === opts
499

500 501
      self.having_values += build_where(opts, rest)
      self
502 503
    end

504
    # Specifies a limit for the number of records to retrieve.
505 506 507 508
    #
    #   User.limit(10) # generated SQL has 'LIMIT 10'
    #
    #   User.limit(10).limit(20) # generated SQL has 'LIMIT 20'
509
    def limit(value)
J
Jon Leighton 已提交
510
      spawn.limit!(value)
511 512
    end

J
Jon Leighton 已提交
513
    def limit!(value) # :nodoc:
514 515
      self.limit_value = value
      self
516 517
    end

518 519 520 521
    # Specifies the number of rows to skip before returning rows.
    #
    #   User.offset(10) # generated SQL has "OFFSET 10"
    #
522
    # Should be used with order.
523
    #
524
    #   User.offset(10).order("name ASC")
525
    def offset(value)
J
Jon Leighton 已提交
526
      spawn.offset!(value)
527 528
    end

J
Jon Leighton 已提交
529
    def offset!(value) # :nodoc:
530 531
      self.offset_value = value
      self
532 533
    end

534
    # Specifies locking settings (default to +true+). For more information
535
    # on locking, please see +ActiveRecord::Locking+.
536
    def lock(locks = true)
J
Jon Leighton 已提交
537
      spawn.lock!(locks)
538
    end
539

J
Jon Leighton 已提交
540
    def lock!(locks = true) # :nodoc:
541
      case locks
542
      when String, TrueClass, NilClass
543
        self.lock_value = locks || true
544
      else
545
        self.lock_value = false
546
      end
547

548
      self
549 550
    end

551
    # Returns a chainable relation with zero records, specifically an
V
Vijay Dev 已提交
552
    # instance of the <tt>ActiveRecord::NullRelation</tt> class.
553
    #
V
Vijay Dev 已提交
554 555 556
    # The returned <tt>ActiveRecord::NullRelation</tt> inherits from Relation and implements the
    # Null Object pattern. It is an object with defined null behavior and always returns an empty
    # array of records without quering the database.
557 558 559 560
    #
    # Any subsequent condition chained to the returned relation will continue
    # generating an empty relation and will not fire any query to the database.
    #
561 562
    # Used in cases where a method or scope could return zero records but the
    # result needs to be chainable.
563 564 565
    #
    # For example:
    #
A
AvnerCohen 已提交
566
    #   @posts = current_user.visible_posts.where(name: params[:name])
567
    #   # => the visible_posts method is expected to return a chainable Relation
568 569 570
    #
    #   def visible_posts
    #     case role
571
    #     when 'Country Manager'
A
AvnerCohen 已提交
572
    #       Post.where(country: country)
573
    #     when 'Reviewer'
574
    #       Post.published
575
    #     when 'Bad User'
576 577 578 579 580
    #       Post.none # => returning [] instead breaks the previous code
    #     end
    #   end
    #
    def none
581
      extending(NullRelation)
582 583
    end

J
Jon Leighton 已提交
584
    def none! # :nodoc:
585 586 587
      extending!(NullRelation)
    end

588 589 590 591 592 593
    # Sets readonly attributes for the returned relation. If value is
    # true (default), attempting to update a record will result in an error.
    #
    #   users = User.readonly
    #   users.first.save
    #   => ActiveRecord::ReadOnlyRecord: ActiveRecord::ReadOnlyRecord
594
    def readonly(value = true)
J
Jon Leighton 已提交
595
      spawn.readonly!(value)
596 597
    end

J
Jon Leighton 已提交
598
    def readonly!(value = true) # :nodoc:
599 600
      self.readonly_value = value
      self
601 602
    end

603 604 605 606 607 608 609 610 611 612 613 614 615
    # Sets attributes to be used when creating new records from a
    # relation object.
    #
    #   users = User.where(name: 'Oscar')
    #   users.new.name # => 'Oscar'
    #
    #   users = users.create_with(name: 'DHH')
    #   users.new.name # => 'DHH'
    #
    # You can pass +nil+ to +create_with+ to reset attributes:
    #
    #   users = users.create_with(nil)
    #   users.new.name # => 'Oscar'
616
    def create_with(value)
J
Jon Leighton 已提交
617
      spawn.create_with!(value)
618 619
    end

J
Jon Leighton 已提交
620
    def create_with!(value) # :nodoc:
621 622
      self.create_with_value = value ? create_with_value.merge(value) : {}
      self
623 624
    end

625 626 627 628 629 630 631
    # Specifies table from which the records will be fetched. For example:
    #
    #   Topic.select('title').from('posts')
    #   #=> SELECT title FROM posts
    #
    # Can accept other relation objects. For example:
    #
632
    #   Topic.select('title').from(Topic.approved)
633 634
    #   # => SELECT title FROM (SELECT * FROM topics WHERE approved = 't') subquery
    #
635
    #   Topic.select('a.title').from(Topic.approved, :a)
636 637 638 639
    #   # => SELECT a.title FROM (SELECT * FROM topics WHERE approved = 't') a
    #
    def from(value, subquery_name = nil)
      spawn.from!(value, subquery_name)
640 641
    end

J
Jon Leighton 已提交
642
    def from!(value, subquery_name = nil) # :nodoc:
643
      self.from_value = [value, subquery_name]
644
      self
645 646
    end

647 648 649 650 651 652 653 654 655 656 657
    # Specifies whether the records should be unique or not. For example:
    #
    #   User.select(:name)
    #   # => Might return two records with the same name
    #
    #   User.select(:name).uniq
    #   # => Returns 1 record per unique name
    #
    #   User.select(:name).uniq.uniq(false)
    #   # => You can also remove the uniqueness
    def uniq(value = true)
J
Jon Leighton 已提交
658
      spawn.uniq!(value)
659 660
    end

661
    # Like #uniq, but modifies relation in place.
J
Jon Leighton 已提交
662
    def uniq!(value = true) # :nodoc:
663 664
      self.uniq_value = value
      self
665 666
    end

667
    # Used to extend a scope with additional methods, either through
668 669
    # a module or through a block provided.
    #
670 671 672 673 674 675 676 677 678 679
    # The object returned is a relation, which can be further extended.
    #
    # === Using a module
    #
    #   module Pagination
    #     def page(number)
    #       # pagination code goes here
    #     end
    #   end
    #
680
    #   scope = Model.all.extending(Pagination)
681 682
    #   scope.page(params[:page])
    #
V
Vijay Dev 已提交
683
    # You can also pass a list of modules:
684
    #
685
    #   scope = Model.all.extending(Pagination, SomethingElse)
686 687 688
    #
    # === Using a block
    #
689
    #   scope = Model.all.extending do
690
    #     def page(number)
691
    #       # pagination code goes here
692 693 694 695 696 697
    #     end
    #   end
    #   scope.page(params[:page])
    #
    # You can also use a block and a module list:
    #
698
    #   scope = Model.all.extending(Pagination) do
699
    #     def per_page(number)
700
    #       # pagination code goes here
701 702
    #     end
    #   end
703 704
    def extending(*modules, &block)
      if modules.any? || block
J
Jon Leighton 已提交
705
        spawn.extending!(*modules, &block)
706 707 708 709
      else
        self
      end
    end
710

J
Jon Leighton 已提交
711
    def extending!(*modules, &block) # :nodoc:
712
      modules << Module.new(&block) if block_given?
713

J
Jon Leighton 已提交
714
      self.extending_values += modules.flatten
715
      extend(*extending_values) if extending_values.any?
716

717
      self
718 719
    end

720 721 722
    # Reverse the existing order clause on the relation.
    #
    #   User.order('name ASC').reverse_order # generated SQL has 'ORDER BY name DESC'
723
    def reverse_order
J
Jon Leighton 已提交
724
      spawn.reverse_order!
725 726
    end

J
Jon Leighton 已提交
727
    def reverse_order! # :nodoc:
728 729
      self.reverse_order_value = !reverse_order_value
      self
730 731
    end

732
    # Returns the Arel object associated with the relation.
733
    def arel
734
      @arel ||= with_default_scope.build_arel
735 736
    end

737
    # Like #arel, but ignores the default scope of the model.
738
    def build_arel
739
      arel = Arel::SelectManager.new(table.engine, table)
740

741
      build_joins(arel, joins_values) unless joins_values.empty?
742

743
      collapse_wheres(arel, (where_values - ['']).uniq)
744

745
      arel.having(*having_values.uniq.reject{|h| h.blank?}) unless having_values.empty?
746

747 748
      arel.take(connection.sanitize_limit(limit_value)) if limit_value
      arel.skip(offset_value.to_i) if offset_value
A
Aaron Patterson 已提交
749

750
      arel.group(*group_values.uniq.reject{|g| g.blank?}) unless group_values.empty?
751

752
      build_order(arel)
753

754
      build_select(arel, select_values.uniq)
755

756
      arel.distinct(uniq_value)
757
      arel.from(build_from) if from_value
758
      arel.lock(lock_value) if lock_value
759 760

      arel
761 762
    end

763 764
    private

765
    def custom_join_ast(table, joins)
766 767
      joins = joins.reject { |join| join.blank? }

768
      return [] if joins.empty?
769 770 771

      @implicit_readonly = true

772
      joins.map do |join|
773 774 775 776 777 778
        case join
        when Array
          join = Arel.sql(join.join(' ')) if array_of_strings?(join)
        when String
          join = Arel.sql(join)
        end
779
        table.create_string_join(join)
780 781 782
      end
    end

783 784 785
    def collapse_wheres(arel, wheres)
      equalities = wheres.grep(Arel::Nodes::Equality)

A
Aaron Patterson 已提交
786
      arel.where(Arel::Nodes::And.new(equalities)) unless equalities.empty?
787 788 789

      (wheres - equalities).each do |where|
        where = Arel.sql(where) if String === where
790
        arel.where(Arel::Nodes::Grouping.new(where))
791 792 793
      end
    end

794
    def build_where(opts, other = [])
A
Aaron Patterson 已提交
795 796
      case opts
      when String, Array
797
        [@klass.send(:sanitize_sql, other.empty? ? opts : ([opts] + other))]
A
Aaron Patterson 已提交
798
      when Hash
799
        attributes = @klass.send(:expand_hash_conditions_for_aggregates, opts)
800 801 802 803 804

        attributes.values.grep(ActiveRecord::Relation) do |rel|
          self.bind_values += rel.bind_values
        end

805
        PredicateBuilder.build_from_hash(klass, attributes, table)
806
      else
807
        [opts]
808 809 810
      end
    end

811 812 813 814 815 816 817 818 819 820 821
    def build_from
      opts, name = from_value
      case opts
      when Relation
        name ||= 'subquery'
        opts.arel.as(name.to_s)
      else
        opts
      end
    end

822
    def build_joins(manager, joins)
A
Aaron Patterson 已提交
823 824 825
      buckets = joins.group_by do |join|
        case join
        when String
826
          :string_join
A
Aaron Patterson 已提交
827
        when Hash, Symbol, Array
828
          :association_join
829
        when ActiveRecord::Associations::JoinDependency::JoinAssociation
830
          :stashed_join
831
        when Arel::Nodes::Join
832
          :join_node
A
Aaron Patterson 已提交
833 834 835
        else
          raise 'unknown class: %s' % join.class.name
        end
836 837
      end

838 839 840 841
      association_joins         = buckets[:association_join] || []
      stashed_association_joins = buckets[:stashed_join] || []
      join_nodes                = (buckets[:join_node] || []).uniq
      string_joins              = (buckets[:string_join] || []).map { |x|
A
Aaron Patterson 已提交
842 843
        x.strip
      }.uniq
844

845
      join_list = join_nodes + custom_join_ast(manager, string_joins)
846

847
      join_dependency = ActiveRecord::Associations::JoinDependency.new(
848 849 850 851
        @klass,
        association_joins,
        join_list
      )
852 853 854 855 856

      join_dependency.graft(*stashed_association_joins)

      @implicit_readonly = true unless association_joins.empty? && stashed_association_joins.empty?

A
Aaron Patterson 已提交
857
      # FIXME: refactor this to build an AST
858
      join_dependency.join_associations.each do |association|
859
        association.join_to(manager)
860 861
      end

862
      manager.join_sources.concat join_list
863 864

      manager
865 866
    end

867
    def build_select(arel, selects)
868
      unless selects.empty?
869
        @implicit_readonly = false
870
        arel.project(*selects)
871
      else
872
        arel.project(@klass.arel_table[Arel.star])
873 874 875
      end
    end

876
    def reverse_sql_order(order_query)
B
Brian Mathiyakom 已提交
877 878
      order_query = ["#{quoted_table_name}.#{quoted_primary_key} ASC"] if order_query.empty?

879
      order_query.flat_map do |o|
880
        case o
881
        when Arel::Nodes::Ordering
882
          o.reverse
883
        when String
884 885 886 887
          o.to_s.split(',').collect do |s|
            s.strip!
            s.gsub!(/\sasc\Z/i, ' DESC') || s.gsub!(/\sdesc\Z/i, ' ASC') || s.concat(' DESC')
          end
888
        when Symbol
889
          { o => :desc }
890
        when Hash
891
          o.each_with_object({}) do |(field, dir), memo|
892 893
            memo[field] = (dir == :asc ? :desc : :asc )
          end
894 895 896
        else
          o
        end
897
      end
898 899
    end

P
Pratik Naik 已提交
900 901 902
    def array_of_strings?(o)
      o.is_a?(Array) && o.all?{|obj| obj.is_a?(String)}
    end
903

904 905 906
    def build_order(arel)
      orders = order_values
      orders = reverse_sql_order(orders) if reverse_order_value
907

908
      orders = orders.uniq.reject(&:blank?).flat_map do |order|
909 910 911 912 913
        case order
        when Symbol
          table[order].asc
        when Hash
          order.map { |field, dir| table[field].send(dir) }
914
        else
915 916
          order
        end
917
      end
918

919 920
      arel.order(*orders) unless orders.empty?
    end
921

922 923 924 925 926 927 928
    def validate_order_args(args)
      args.select { |a| Hash === a  }.each do |h|
        unless (h.values - [:asc, :desc]).empty?
          raise ArgumentError, 'Direction should be :asc or :desc'
        end
      end
    end
P
Pratik Naik 已提交
929

930 931 932 933 934 935 936 937 938 939 940 941 942
    # Checks to make sure that the arguments are not blank. Note that if some
    # blank-like object were initially passed into the query method, then this
    # method will not raise an error.
    #
    # Example:
    #
    #    Post.references()   # => raises an error
    #    Post.references([]) # => does not raise an error
    #
    # This particular method should be called with a method_name and the args
    # passed into that method as an input. For example:
    #
    # def references(*args)
943
    #   check_if_method_has_arguments!("references", args)
944 945
    #   ...
    # end
946
    def check_if_method_has_arguments!(method_name, args)
947 948 949 950
      if args.blank?
        raise ArgumentError, "The method .#{method_name}() must contain arguments."
      end
    end
951 952
  end
end