query_methods.rb 37.7 KB
Newer Older
1
require 'active_support/core_ext/array/wrap'
X
Xavier Noria 已提交
2
require 'active_support/core_ext/string/filters'
3
require 'active_model/forbidden_attributes_protection'
4

5 6
module ActiveRecord
  module QueryMethods
7 8
    extend ActiveSupport::Concern

9 10
    include ActiveModel::ForbiddenAttributesProtection

11
    # WhereChain objects act as placeholder for queries in which #where does not have any parameter.
12
    # In this case, #where must be chained with #not to return a new relation.
13 14 15 16 17
    class WhereChain
      def initialize(scope)
        @scope = scope
      end

18 19
      # Returns a new relation expressing WHERE + NOT condition according to
      # the conditions in the arguments.
20
      #
21 22
      # +not+ accepts conditions as a string, array, or hash. See #where for
      # more details on each format.
23 24
      #
      #    User.where.not("name = 'Jon'")
25
      #    # SELECT * FROM users WHERE NOT (name = 'Jon')
26 27
      #
      #    User.where.not(["name = ?", "Jon"])
28
      #    # SELECT * FROM users WHERE NOT (name = 'Jon')
29
      #
30
      #    User.where.not(name: "Jon")
31
      #    # SELECT * FROM users WHERE name != 'Jon'
32 33 34 35
      #
      #    User.where.not(name: nil)
      #    # SELECT * FROM users WHERE name IS NOT NULL
      #
36
      #    User.where.not(name: %w(Ko1 Nobu))
37
      #    # SELECT * FROM users WHERE name NOT IN ('Ko1', 'Nobu')
38 39 40
      #
      #    User.where.not(name: "Jon", role: "admin")
      #    # SELECT * FROM users WHERE name != 'Jon' AND role != 'admin'
41 42 43
      def not(opts, *rest)
        where_value = @scope.send(:build_where, opts, rest).map do |rel|
          case rel
44 45
          when NilClass
            raise ArgumentError, 'Invalid argument for .where.not(), got nil.'
46 47
          when Arel::Nodes::In
            Arel::Nodes::NotIn.new(rel.left, rel.right)
48 49
          when Arel::Nodes::Equality
            Arel::Nodes::NotEqual.new(rel.left, rel.right)
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
56 57

        @scope.references!(PredicateBuilder.references(opts)) if Hash === opts
58 59 60 61 62
        @scope.where_values += where_value
        @scope
      end
    end

63 64
    Relation::MULTI_VALUE_METHODS.each do |name|
      class_eval <<-CODE, __FILE__, __LINE__ + 1
65 66 67 68 69 70
        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
71
          check_cached_relation
72 73
          @values[:#{name}] = values         #   @values[:select] = values
        end                                  # end
74 75 76 77 78
      CODE
    end

    (Relation::SINGLE_VALUE_METHODS - [:create_with]).each do |name|
      class_eval <<-CODE, __FILE__, __LINE__ + 1
79 80 81
        def #{name}_value                    # def readonly_value
          @values[:#{name}]                  #   @values[:readonly]
        end                                  # end
82 83 84
      CODE
    end

85 86 87 88
    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
89
          check_cached_relation
90 91 92
          @values[:#{name}] = value          #   @values[:readonly] = value
        end                                  # end
      CODE
93 94
    end

95 96 97
    def check_cached_relation # :nodoc:
      if defined?(@arel) && @arel
        @arel = nil
X
Xavier Noria 已提交
98 99 100 101
        ActiveSupport::Deprecation.warn(<<-MSG.squish)
          Modifying already cached Relation. The cache will be reset. Use a
          cloned Relation to prevent this warning.
        MSG
102 103 104
      end
    end

O
Oscar Del Ben 已提交
105
    def create_with_value # :nodoc:
106
      @values[:create_with] || {}
107
    end
108 109

    alias extensions extending_values
110

O
Oscar Del Ben 已提交
111 112 113 114 115 116 117 118 119 120
    # 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
121 122
    # performance improvement over a simple +join+.
    #
123 124 125 126 127 128 129 130
    # You can also specify multiple relationships, like this:
    #
    #   users = User.includes(:address, :friends)
    #
    # Loading nested relationships is possible using a Hash:
    #
    #   users = User.includes(:address, friends: [:address, :followers])
    #
131 132 133 134 135 136 137 138 139 140
    # === 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)
141 142 143
    #
    # Note that +includes+ works with association names while +references+ needs
    # the actual table name.
144
    def includes(*args)
145
      check_if_method_has_arguments!(:includes, args)
146
      spawn.includes!(*args)
147
    end
148

J
Jon Leighton 已提交
149
    def includes!(*args) # :nodoc:
150 151
      args.reject!(&:blank?)
      args.flatten!
A
Aaron Patterson 已提交
152

153
      self.includes_values |= args
154
      self
155
    end
156

157 158 159 160 161 162
    # 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"
163
    def eager_load(*args)
164
      check_if_method_has_arguments!(:eager_load, args)
165
      spawn.eager_load!(*args)
166
    end
167

J
Jon Leighton 已提交
168
    def eager_load!(*args) # :nodoc:
169 170
      self.eager_load_values += args
      self
171 172
    end

173 174 175 176
    # 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)
177
    def preload(*args)
178
      check_if_method_has_arguments!(:preload, args)
179
      spawn.preload!(*args)
180
    end
181

J
Jon Leighton 已提交
182
    def preload!(*args) # :nodoc:
183 184
      self.preload_values += args
      self
185
    end
186

187 188
    # Use to indicate that the given +table_names+ are referenced by an SQL string,
    # and should therefore be JOINed in any query rather than loaded separately.
189
    # This method only works in conjunction with +includes+.
190
    # See #includes for more details.
191 192 193 194 195 196
    #
    #   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
197 198 199
    def references(*table_names)
      check_if_method_has_arguments!(:references, table_names)
      spawn.references!(*table_names)
200
    end
201

202 203 204
    def references!(*table_names) # :nodoc:
      table_names.flatten!
      table_names.map!(&:to_s)
205

206
      self.references_values |= table_names
207
      self
208 209
    end

210
    # Works in two unique ways.
211
    #
212 213
    # First: takes a block so it can be used just like Array#select.
    #
214
    #   Model.all.select { |m| m.field == value }
215 216 217 218 219
    #
    # 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 已提交
220
    # fields are retrieved:
221
    #
222
    #   Model.select(:field)
223
    #   # => [#<Model id: nil, field: "value">]
224 225
    #
    # Although in the above example it looks as though this method returns an
V
Vijay Dev 已提交
226
    # array, it actually returns a relation object and can have other query
227 228
    # methods appended to it, such as the other methods in ActiveRecord::QueryMethods.
    #
229
    # The argument to the method can also be an array of fields.
230
    #
231
    #   Model.select(:field, :other_field, :and_one_more)
232
    #   # => [#<Model id: nil, field: "value", other_field: "value", and_one_more: "value">]
233
    #
234 235 236
    # 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')
237
    #   # => [#<Model id: nil, field: "value", other_field: "value">]
238 239 240 241 242 243
    #
    # If an alias was specified, it will be accessible from the resulting objects:
    #
    #   Model.select('field AS field_one').first.field_one
    #   # => "value"
    #
244
    # Accessing attributes of an object that do not have fields retrieved by a select
245
    # except +id+ will throw <tt>ActiveModel::MissingAttributeError</tt>:
246
    #
247 248 249
    #   Model.select(:field).first.other_field
    #   # => ActiveModel::MissingAttributeError: missing attribute: other_field
    def select(*fields)
250
      if block_given?
251
        to_a.select { |*block_args| yield(*block_args) }
252
      else
253
        raise ArgumentError, 'Call this with at least one field' if fields.empty?
254
        spawn._select!(*fields)
255 256 257
      end
    end

258
    def _select!(*fields) # :nodoc:
259
      fields.flatten!
260
      fields.map! do |field|
261
        klass.attribute_alias?(field) ? klass.attribute_alias(field) : field
262
      end
263
      self.select_values += fields
264
      self
265
    end
S
Santiago Pastorino 已提交
266

O
Oscar Del Ben 已提交
267 268 269 270 271
    # Allows to specify a group attribute:
    #
    #   User.group(:name)
    #   => SELECT "users".* FROM "users" GROUP BY name
    #
272
    # Returns an array with distinct records based on the +group+ attribute:
O
Oscar Del Ben 已提交
273 274 275 276 277 278
    #
    #   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", ...>]
279 280 281
    #
    #   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, ...>]
282 283 284 285
    #
    # Passing in an array of attributes to group by is also supported.
    #   User.select([:id, :first_name]).group(:id, :first_name).first(3)
    #   => [#<User id: 1, first_name: "Bill">, #<User id: 2, first_name: "Earl">, #<User id: 3, first_name: "Beto">]
286
    def group(*args)
287
      check_if_method_has_arguments!(:group, args)
288
      spawn.group!(*args)
289
    end
290

J
Jon Leighton 已提交
291
    def group!(*args) # :nodoc:
292 293 294
      args.flatten!

      self.group_values += args
295
      self
296
    end
297

O
Oscar Del Ben 已提交
298 299
    # Allows to specify an order attribute:
    #
300 301
    #   User.order(:name)
    #   => SELECT "users".* FROM "users" ORDER BY "users"."name" ASC
302
    #
303 304
    #   User.order(email: :desc)
    #   => SELECT "users".* FROM "users" ORDER BY "users"."email" DESC
305
    #
306 307
    #   User.order(:name, email: :desc)
    #   => SELECT "users".* FROM "users" ORDER BY "users"."name" ASC, "users"."email" DESC
308 309 310 311 312 313 314 315 316
    #
    #   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
317
    def order(*args)
318
      check_if_method_has_arguments!(:order, args)
319
      spawn.order!(*args)
320
    end
321

J
Jon Leighton 已提交
322
    def order!(*args) # :nodoc:
323
      preprocess_order_args(args)
324

325
      self.order_values += args
326
      self
327
    end
328

329 330 331 332 333 334 335 336
    # 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')
    #
337
    # generates a query with 'ORDER BY id ASC, name ASC'.
S
Sebastian Martinez 已提交
338
    def reorder(*args)
339
      check_if_method_has_arguments!(:reorder, args)
340
      spawn.reorder!(*args)
341
    end
342

J
Jon Leighton 已提交
343
    def reorder!(*args) # :nodoc:
344
      preprocess_order_args(args)
345

346
      self.reordering_value = true
347
      self.order_values = args
348
      self
S
Sebastian Martinez 已提交
349 350
    end

351 352 353 354 355 356 357 358
    VALID_UNSCOPING_VALUES = Set.new([:where, :select, :group, :order, :lock,
                                     :limit, :offset, :joins, :includes, :from,
                                     :readonly, :having])

    # Removes an unwanted relation that is already defined on a chain of relations.
    # This is useful when passing around chains of relations and would like to
    # modify the relations without reconstructing the entire chain.
    #
359
    #   User.order('email DESC').unscope(:order) == User.all
360 361 362 363 364
    #
    # The method arguments are symbols which correspond to the names of the methods
    # which should be unscoped. The valid arguments are given in VALID_UNSCOPING_VALUES.
    # The method can also be called with multiple arguments. For example:
    #
365
    #   User.order('email DESC').select('id').where(name: "John")
366 367 368 369 370 371
    #       .unscope(:order, :select, :where) == User.all
    #
    # One can additionally pass a hash as an argument to unscope specific :where values.
    # This is done by passing a hash with a single key-value pair. The key should be
    # :where and the value should be the where value to unscope. For example:
    #
372 373
    #   User.where(name: "John", active: true).unscope(where: :name)
    #       == User.where(active: true)
374
    #
J
Jon Leighton 已提交
375 376
    # This method is similar to <tt>except</tt>, but unlike
    # <tt>except</tt>, it persists across merges:
377
    #
J
Jon Leighton 已提交
378 379
    #   User.order('email').merge(User.except(:order))
    #       == User.order('email')
380
    #
J
Jon Leighton 已提交
381 382 383 384 385 386
    #   User.order('email').merge(User.unscope(:order))
    #       == User.all
    #
    # This means it can be used in association definitions:
    #
    #   has_many :comments, -> { unscope where: :trashed }
387 388
    #
    def unscope(*args)
389
      check_if_method_has_arguments!(:unscope, args)
390 391 392
      spawn.unscope!(*args)
    end

393
    def unscope!(*args) # :nodoc:
394
      args.flatten!
J
Jon Leighton 已提交
395
      self.unscope_values += args
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418

      args.each do |scope|
        case scope
        when Symbol
          symbol_unscoping(scope)
        when Hash
          scope.each do |key, target_value|
            if key != :where
              raise ArgumentError, "Hash arguments in .unscope(*args) must have :where as the key."
            end

            Array(target_value).each do |val|
              where_unscoping(val)
            end
          end
        else
          raise ArgumentError, "Unrecognized scoping: #{args.inspect}. Use .unscope(where: :attribute_name) or .unscope(:order), for example."
        end
      end

      self
    end

419 420 421 422
    # Performs a joins on +args+:
    #
    #   User.joins(:posts)
    #   => SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id"
423 424 425 426 427
    #
    # 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
428
    def joins(*args)
429 430 431 432 433 434
      check_if_method_has_arguments!(:joins, args)

      args.compact!
      args.flatten!

      spawn.joins!(*args)
435
    end
436

J
Jon Leighton 已提交
437
    def joins!(*args) # :nodoc:
438 439
      self.joins_values += args
      self
P
Pratik Naik 已提交
440 441
    end

A
Aaron Patterson 已提交
442
    def bind(value)
J
Jon Leighton 已提交
443
      spawn.bind!(value)
444 445
    end

J
Jon Leighton 已提交
446
    def bind!(value) # :nodoc:
447 448
      self.bind_values += [value]
      self
A
Aaron Patterson 已提交
449 450
    end

451 452 453 454 455 456 457 458 459 460
    # 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
461
    # constructor as an SQL fragment, and used in the where clause of the query.
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525
    #
    #    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')
    #
526 527 528 529 530 531
    # 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 已提交
532 533
    #    Post.where(author: author)
    #    Post.where(author_id: author)
534 535 536
    #
    # This also works with polymorphic belongs_to relationships:
    #
A
AvnerCohen 已提交
537 538
    #    treasure = Treasure.create(name: 'gold coins')
    #    treasure.price_estimates << PriceEstimate.create(price: 125)
539 540
    #
    #    # The following queries will be equivalent:
A
AvnerCohen 已提交
541 542
    #    PriceEstimate.where(estimate_of: treasure)
    #    PriceEstimate.where(estimate_of_type: 'Treasure', estimate_of_id: treasure)
543
    #
544 545 546 547 548 549 550 551 552 553
    # === 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 已提交
554
    #    User.joins(:posts).where({ posts: { published: true } })
555
    #
556
    # === no argument
557
    #
558 559
    # 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.
560 561
    #
    #    User.where.not(name: "Jon")
562
    #    # SELECT * FROM users WHERE name != 'Jon'
563
    #
564
    # See WhereChain for more details on #not.
565
    #
566
    # === blank condition
567
    #
568
    # If the condition is any blank-ish object, then #where is a no-op and returns
569
    # the current relation.
570 571
    def where(opts = :chain, *rest)
      if opts == :chain
572 573 574 575 576 577
        WhereChain.new(spawn)
      elsif opts.blank?
        self
      else
        spawn.where!(opts, *rest)
      end
578 579
    end

580
    def where!(opts, *rest) # :nodoc:
581 582 583 584
      if Hash === opts
        opts = sanitize_forbidden_attributes(opts)
        references!(PredicateBuilder.references(opts))
      end
585

586 587
      self.where_values += build_where(opts, rest)
      self
588
    end
P
Pratik Naik 已提交
589

590 591
    # Allows you to change a previously set where condition for a given attribute, instead of appending to that condition.
    #
592 593 594
    #   Post.where(trashed: true).where(trashed: false)                       # => WHERE `trashed` = 1 AND `trashed` = 0
    #   Post.where(trashed: true).rewhere(trashed: false)                     # => WHERE `trashed` = 0
    #   Post.where(active: true).where(trashed: true).rewhere(trashed: false) # => WHERE `active` = 1 AND `trashed` = 0
595 596 597 598 599 600 601
    #
    # This is short-hand for unscope(where: conditions.keys).where(conditions). Note that unlike reorder, we're only unscoping
    # the named conditions -- not the entire where statement.
    def rewhere(conditions)
      unscope(where: conditions.keys).where(conditions)
    end

602 603 604 605
    # 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')
606
    def having(opts, *rest)
607
      opts.blank? ? self : spawn.having!(opts, *rest)
608 609
    end

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

613 614
      self.having_values += build_where(opts, rest)
      self
615 616
    end

617
    # Specifies a limit for the number of records to retrieve.
618 619 620 621
    #
    #   User.limit(10) # generated SQL has 'LIMIT 10'
    #
    #   User.limit(10).limit(20) # generated SQL has 'LIMIT 20'
622
    def limit(value)
J
Jon Leighton 已提交
623
      spawn.limit!(value)
624 625
    end

J
Jon Leighton 已提交
626
    def limit!(value) # :nodoc:
627 628
      self.limit_value = value
      self
629 630
    end

631 632 633 634
    # Specifies the number of rows to skip before returning rows.
    #
    #   User.offset(10) # generated SQL has "OFFSET 10"
    #
635
    # Should be used with order.
636
    #
637
    #   User.offset(10).order("name ASC")
638
    def offset(value)
J
Jon Leighton 已提交
639
      spawn.offset!(value)
640 641
    end

J
Jon Leighton 已提交
642
    def offset!(value) # :nodoc:
643 644
      self.offset_value = value
      self
645 646
    end

647
    # Specifies locking settings (default to +true+). For more information
648
    # on locking, please see +ActiveRecord::Locking+.
649
    def lock(locks = true)
J
Jon Leighton 已提交
650
      spawn.lock!(locks)
651
    end
652

J
Jon Leighton 已提交
653
    def lock!(locks = true) # :nodoc:
654
      case locks
655
      when String, TrueClass, NilClass
656
        self.lock_value = locks || true
657
      else
658
        self.lock_value = false
659
      end
660

661
      self
662 663
    end

664
    # Returns a chainable relation with zero records.
665
    #
666 667 668
    # The returned relation implements the Null Object pattern. It is an
    # object with defined null behavior and always returns an empty array of
    # records without querying the database.
669 670 671 672
    #
    # Any subsequent condition chained to the returned relation will continue
    # generating an empty relation and will not fire any query to the database.
    #
673 674
    # Used in cases where a method or scope could return zero records but the
    # result needs to be chainable.
675 676 677
    #
    # For example:
    #
A
AvnerCohen 已提交
678
    #   @posts = current_user.visible_posts.where(name: params[:name])
679
    #   # => the visible_posts method is expected to return a chainable Relation
680 681 682
    #
    #   def visible_posts
    #     case role
683
    #     when 'Country Manager'
A
AvnerCohen 已提交
684
    #       Post.where(country: country)
685
    #     when 'Reviewer'
686
    #       Post.published
687
    #     when 'Bad User'
688
    #       Post.none # It can't be chained if [] is returned.
689 690 691 692
    #     end
    #   end
    #
    def none
693
      where("1=0").extending!(NullRelation)
694 695
    end

J
Jon Leighton 已提交
696
    def none! # :nodoc:
697
      where!("1=0").extending!(NullRelation)
698 699
    end

700 701 702 703 704 705
    # 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
706
    def readonly(value = true)
J
Jon Leighton 已提交
707
      spawn.readonly!(value)
708 709
    end

J
Jon Leighton 已提交
710
    def readonly!(value = true) # :nodoc:
711 712
      self.readonly_value = value
      self
713 714
    end

715 716 717 718 719 720 721 722 723 724 725 726 727
    # 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'
728
    def create_with(value)
J
Jon Leighton 已提交
729
      spawn.create_with!(value)
730 731
    end

J
Jon Leighton 已提交
732
    def create_with!(value) # :nodoc:
733 734 735 736 737 738 739
      if value
        value = sanitize_forbidden_attributes(value)
        self.create_with_value = create_with_value.merge(value)
      else
        self.create_with_value = {}
      end

740
      self
741 742
    end

743 744 745
    # Specifies table from which the records will be fetched. For example:
    #
    #   Topic.select('title').from('posts')
746
    #   # => SELECT title FROM posts
747 748 749
    #
    # Can accept other relation objects. For example:
    #
750
    #   Topic.select('title').from(Topic.approved)
751 752
    #   # => SELECT title FROM (SELECT * FROM topics WHERE approved = 't') subquery
    #
753
    #   Topic.select('a.title').from(Topic.approved, :a)
754 755 756 757
    #   # => SELECT a.title FROM (SELECT * FROM topics WHERE approved = 't') a
    #
    def from(value, subquery_name = nil)
      spawn.from!(value, subquery_name)
758 759
    end

J
Jon Leighton 已提交
760
    def from!(value, subquery_name = nil) # :nodoc:
761
      self.from_value = [value, subquery_name]
762
      self
763 764
    end

765 766 767 768 769
    # Specifies whether the records should be unique or not. For example:
    #
    #   User.select(:name)
    #   # => Might return two records with the same name
    #
770 771
    #   User.select(:name).distinct
    #   # => Returns 1 record per distinct name
772
    #
773
    #   User.select(:name).distinct.distinct(false)
774
    #   # => You can also remove the uniqueness
775 776
    def distinct(value = true)
      spawn.distinct!(value)
777
    end
778
    alias uniq distinct
779

780 781 782
    # Like #distinct, but modifies relation in place.
    def distinct!(value = true) # :nodoc:
      self.distinct_value = value
783
      self
784
    end
785
    alias uniq! distinct!
786

787
    # Used to extend a scope with additional methods, either through
788 789
    # a module or through a block provided.
    #
790 791 792 793 794 795 796 797 798 799
    # 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
    #
800
    #   scope = Model.all.extending(Pagination)
801 802
    #   scope.page(params[:page])
    #
V
Vijay Dev 已提交
803
    # You can also pass a list of modules:
804
    #
805
    #   scope = Model.all.extending(Pagination, SomethingElse)
806 807 808
    #
    # === Using a block
    #
809
    #   scope = Model.all.extending do
810
    #     def page(number)
811
    #       # pagination code goes here
812 813 814 815 816 817
    #     end
    #   end
    #   scope.page(params[:page])
    #
    # You can also use a block and a module list:
    #
818
    #   scope = Model.all.extending(Pagination) do
819
    #     def per_page(number)
820
    #       # pagination code goes here
821 822
    #     end
    #   end
823 824
    def extending(*modules, &block)
      if modules.any? || block
J
Jon Leighton 已提交
825
        spawn.extending!(*modules, &block)
826 827 828 829
      else
        self
      end
    end
830

J
Jon Leighton 已提交
831
    def extending!(*modules, &block) # :nodoc:
832 833
      modules << Module.new(&block) if block
      modules.flatten!
834

835
      self.extending_values += modules
836
      extend(*extending_values) if extending_values.any?
837

838
      self
839 840
    end

841 842 843
    # Reverse the existing order clause on the relation.
    #
    #   User.order('name ASC').reverse_order # generated SQL has 'ORDER BY name DESC'
844
    def reverse_order
J
Jon Leighton 已提交
845
      spawn.reverse_order!
846 847
    end

J
Jon Leighton 已提交
848
    def reverse_order! # :nodoc:
849 850 851
      orders = order_values.uniq
      orders.reject!(&:blank?)
      self.order_values = reverse_sql_order(orders)
852
      self
853 854
    end

855
    # Returns the Arel object associated with the relation.
856
    def arel # :nodoc:
857
      @arel ||= build_arel
858 859
    end

860 861
    private

862
    def build_arel
863
      arel = Arel::SelectManager.new(table.engine, table)
864

865
      build_joins(arel, joins_values.flatten) unless joins_values.empty?
866

867
      collapse_wheres(arel, (where_values - [''])) #TODO: Add uniq with real value comparison / ignore uniqs that have binds
868

869
      arel.having(*having_values.uniq.reject(&:blank?)) unless having_values.empty?
870

871 872
      arel.take(connection.sanitize_limit(limit_value)) if limit_value
      arel.skip(offset_value.to_i) if offset_value
A
Aaron Patterson 已提交
873

874
      arel.group(*group_values.uniq.reject(&:blank?)) unless group_values.empty?
875

876
      build_order(arel)
877

878
      build_select(arel, select_values.uniq)
879

880
      arel.distinct(distinct_value)
881
      arel.from(build_from) if from_value
882
      arel.lock(lock_value) if lock_value
883

884
      # Reorder bind indexes if joins produced bind values
885 886 887 888
      bvs = arel.bind_values + bind_values
      arel.ast.grep(Arel::Nodes::BindParam).each_with_index do |bp, i|
        column = bvs[i].first
        bp.replace connection.substitute_at(column, i)
889 890
      end

891
      arel
892 893
    end

894 895 896 897 898 899
    def symbol_unscoping(scope)
      if !VALID_UNSCOPING_VALUES.include?(scope)
        raise ArgumentError, "Called unscope() with invalid unscoping argument ':#{scope}'. Valid arguments are :#{VALID_UNSCOPING_VALUES.to_a.join(", :")}."
      end

      single_val_method = Relation::SINGLE_VALUE_METHODS.include?(scope)
A
Aaron Patterson 已提交
900
      unscope_code = "#{scope}_value#{'s' unless single_val_method}="
901 902 903 904

      case scope
      when :order
        result = []
905 906
      when :where
        self.bind_values = []
907 908 909 910 911 912 913 914
      else
        result = [] unless single_val_method
      end

      self.send(unscope_code, result)
    end

    def where_unscoping(target_value)
A
Aaron Patterson 已提交
915
      target_value = target_value.to_s
916 917 918

      where_values.reject! do |rel|
        case rel
919
        when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThanOrEqual
920
          subrelation = (rel.left.kind_of?(Arel::Attributes::Attribute) ? rel.left : rel.right)
A
Aaron Patterson 已提交
921
          subrelation.name == target_value
922 923
        end
      end
924 925

      bind_values.reject! { |col,_| col.name == target_value }
926 927
    end

928
    def custom_join_ast(table, joins)
929
      joins = joins.reject(&:blank?)
930

931
      return [] if joins.empty?
932

933
      joins.map! do |join|
934 935 936 937 938 939
        case join
        when Array
          join = Arel.sql(join.join(' ')) if array_of_strings?(join)
        when String
          join = Arel.sql(join)
        end
940
        table.create_string_join(join)
941 942 943
      end
    end

944
    def collapse_wheres(arel, wheres)
945 946
      predicates = wheres.map do |where|
        next where if ::Arel::Nodes::Equality === where
947
        where = Arel.sql(where) if String === where
948
        Arel::Nodes::Grouping.new(where)
949
      end
950 951

      arel.where(Arel::Nodes::And.new(predicates)) if predicates.present?
952 953
    end

954
    def build_where(opts, other = [])
A
Aaron Patterson 已提交
955 956
      case opts
      when String, Array
957
        [@klass.send(:sanitize_sql, other.empty? ? opts : ([opts] + other))]
A
Aaron Patterson 已提交
958
      when Hash
959
        opts = PredicateBuilder.resolve_column_aliases(klass, opts)
960

961
        tmp_opts, bind_values = create_binds(opts)
962
        self.bind_values += bind_values
963

964
        attributes = @klass.send(:expand_hash_conditions_for_aggregates, tmp_opts)
965
        add_relations_to_bind_values(attributes)
966

967
        PredicateBuilder.build_from_hash(klass, attributes, table)
968
      else
969
        [opts]
970 971 972
      end
    end

973
    def create_binds(opts)
974
      bindable, non_binds = opts.partition do |column, value|
975
        case value
976
        when String, Integer, ActiveRecord::StatementCache::Substitute
977 978 979
          @klass.columns_hash.include? column.to_s
        else
          false
980 981 982
        end
      end

983 984 985
      new_opts = {}
      binds = []

986
      bindable.each do |(column,value)|
987
        binds.push [@klass.columns_hash[column.to_s], value]
988
        new_opts[column] = connection.substitute_at(column)
989
      end
990 991 992 993

      non_binds.each { |column,value| new_opts[column] = value }

      [new_opts, binds]
994 995
    end

996 997 998 999 1000
    def build_from
      opts, name = from_value
      case opts
      when Relation
        name ||= 'subquery'
1001
        self.bind_values = opts.bind_values + self.bind_values
1002 1003 1004 1005 1006 1007
        opts.arel.as(name.to_s)
      else
        opts
      end
    end

1008
    def build_joins(manager, joins)
A
Aaron Patterson 已提交
1009 1010 1011
      buckets = joins.group_by do |join|
        case join
        when String
1012
          :string_join
A
Aaron Patterson 已提交
1013
        when Hash, Symbol, Array
1014
          :association_join
1015
        when ActiveRecord::Associations::JoinDependency
1016
          :stashed_join
1017
        when Arel::Nodes::Join
1018
          :join_node
A
Aaron Patterson 已提交
1019 1020 1021
        else
          raise 'unknown class: %s' % join.class.name
        end
1022 1023
      end

1024 1025 1026
      association_joins         = buckets[:association_join] || []
      stashed_association_joins = buckets[:stashed_join] || []
      join_nodes                = (buckets[:join_node] || []).uniq
1027
      string_joins              = (buckets[:string_join] || []).map(&:strip).uniq
1028

1029
      join_list = join_nodes + custom_join_ast(manager, string_joins)
1030

1031
      join_dependency = ActiveRecord::Associations::JoinDependency.new(
1032 1033 1034 1035
        @klass,
        association_joins,
        join_list
      )
1036

1037
      join_infos = join_dependency.join_constraints stashed_association_joins
1038

1039 1040
      join_infos.each do |info|
        info.joins.each { |join| manager.from(join) }
1041
        manager.bind_values.concat info.binds
1042
      end
1043

1044
      manager.join_sources.concat(join_list)
1045 1046

      manager
1047 1048
    end

1049
    def build_select(arel, selects)
C
Cody Cutrer 已提交
1050
      if !selects.empty?
1051 1052 1053 1054
        expanded_select = selects.map do |field|
          columns_hash.key?(field.to_s) ? arel_table[field] : field
        end
        arel.project(*expanded_select)
1055
      else
1056
        arel.project(@klass.arel_table[Arel.star])
1057 1058 1059
      end
    end

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

1063
      order_query.flat_map do |o|
1064
        case o
1065
        when Arel::Nodes::Ordering
1066
          o.reverse
1067
        when String
1068
          o.to_s.split(',').map! do |s|
1069 1070 1071
            s.strip!
            s.gsub!(/\sasc\Z/i, ' DESC') || s.gsub!(/\sdesc\Z/i, ' ASC') || s.concat(' DESC')
          end
1072 1073 1074
        else
          o
        end
1075
      end
1076 1077
    end

P
Pratik Naik 已提交
1078
    def array_of_strings?(o)
1079
      o.is_a?(Array) && o.all? { |obj| obj.is_a?(String) }
P
Pratik Naik 已提交
1080
    end
1081

1082
    def build_order(arel)
1083 1084
      orders = order_values.uniq
      orders.reject!(&:blank?)
1085

1086 1087
      arel.order(*orders) unless orders.empty?
    end
1088

1089 1090
    VALID_DIRECTIONS = [:asc, :desc, :ASC, :DESC,
                        'asc', 'desc', 'ASC', 'DESC'] # :nodoc:
1091

1092
    def validate_order_args(args)
Y
Yves Senn 已提交
1093 1094 1095
      args.each do |arg|
        next unless arg.is_a?(Hash)
        arg.each do |_key, value|
1096 1097
          raise ArgumentError, "Direction \"#{value}\" is invalid. Valid " \
                               "directions are: #{VALID_DIRECTIONS.inspect}" unless VALID_DIRECTIONS.include?(value)
1098 1099 1100
        end
      end
    end
P
Pratik Naik 已提交
1101

1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
    def preprocess_order_args(order_args)
      order_args.flatten!
      validate_order_args(order_args)

      references = order_args.grep(String)
      references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact!
      references!(references) if references.any?

      # if a symbol is given we prepend the quoted table name
      order_args.map! do |arg|
1112 1113
        case arg
        when Symbol
1114
          arg = klass.attribute_alias(arg) if klass.attribute_alias?(arg)
1115 1116 1117
          table[arg].asc
        when Hash
          arg.map { |field, dir|
1118
            field = klass.attribute_alias(field) if klass.attribute_alias?(field)
1119
            table[field].send(dir.downcase)
1120 1121 1122 1123 1124
          }
        else
          arg
        end
      end.flatten!
1125 1126
    end

1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139
    # 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)
1140
    #   check_if_method_has_arguments!("references", args)
1141 1142
    #   ...
    # end
1143
    def check_if_method_has_arguments!(method_name, args)
1144 1145 1146 1147
      if args.blank?
        raise ArgumentError, "The method .#{method_name}() must contain arguments."
      end
    end
1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161

    # This function is recursive just for better readablity.
    # #where argument doesn't support more than one level nested hash in real world.
    def add_relations_to_bind_values(attributes)
      if attributes.is_a?(Hash)
        attributes.each_value do |value|
          if value.is_a?(ActiveRecord::Relation)
            self.bind_values += value.bind_values
          else
            add_relations_to_bind_values(value)
          end
        end
      end
    end
1162 1163
  end
end