activerecord 4.2.11.3 → 5.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (229) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1029 -1349
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -7
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record.rb +7 -3
  7. data/lib/active_record/aggregations.rb +35 -25
  8. data/lib/active_record/association_relation.rb +2 -2
  9. data/lib/active_record/associations.rb +305 -204
  10. data/lib/active_record/associations/alias_tracker.rb +19 -16
  11. data/lib/active_record/associations/association.rb +10 -8
  12. data/lib/active_record/associations/association_scope.rb +73 -102
  13. data/lib/active_record/associations/belongs_to_association.rb +20 -32
  14. data/lib/active_record/associations/builder/association.rb +28 -34
  15. data/lib/active_record/associations/builder/belongs_to.rb +41 -18
  16. data/lib/active_record/associations/builder/collection_association.rb +8 -24
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +11 -11
  18. data/lib/active_record/associations/builder/has_many.rb +4 -4
  19. data/lib/active_record/associations/builder/has_one.rb +10 -5
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -9
  21. data/lib/active_record/associations/collection_association.rb +40 -43
  22. data/lib/active_record/associations/collection_proxy.rb +55 -29
  23. data/lib/active_record/associations/foreign_association.rb +1 -1
  24. data/lib/active_record/associations/has_many_association.rb +20 -71
  25. data/lib/active_record/associations/has_many_through_association.rb +8 -52
  26. data/lib/active_record/associations/has_one_association.rb +12 -5
  27. data/lib/active_record/associations/join_dependency.rb +28 -18
  28. data/lib/active_record/associations/join_dependency/join_association.rb +13 -12
  29. data/lib/active_record/associations/preloader.rb +13 -4
  30. data/lib/active_record/associations/preloader/association.rb +45 -51
  31. data/lib/active_record/associations/preloader/collection_association.rb +0 -6
  32. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  33. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  34. data/lib/active_record/associations/preloader/through_association.rb +5 -4
  35. data/lib/active_record/associations/singular_association.rb +6 -0
  36. data/lib/active_record/associations/through_association.rb +11 -3
  37. data/lib/active_record/attribute.rb +61 -17
  38. data/lib/active_record/attribute/user_provided_default.rb +23 -0
  39. data/lib/active_record/attribute_assignment.rb +27 -140
  40. data/lib/active_record/attribute_decorators.rb +6 -5
  41. data/lib/active_record/attribute_methods.rb +79 -26
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  43. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  44. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  45. data/lib/active_record/attribute_methods/query.rb +2 -2
  46. data/lib/active_record/attribute_methods/read.rb +26 -42
  47. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +42 -9
  49. data/lib/active_record/attribute_methods/write.rb +13 -24
  50. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  51. data/lib/active_record/attribute_set.rb +30 -3
  52. data/lib/active_record/attribute_set/builder.rb +6 -4
  53. data/lib/active_record/attributes.rb +194 -81
  54. data/lib/active_record/autosave_association.rb +33 -15
  55. data/lib/active_record/base.rb +30 -18
  56. data/lib/active_record/callbacks.rb +36 -40
  57. data/lib/active_record/coders/yaml_column.rb +20 -8
  58. data/lib/active_record/collection_cache_key.rb +31 -0
  59. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +431 -122
  60. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  61. data/lib/active_record/connection_adapters/abstract/database_statements.rb +40 -22
  62. data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -8
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +46 -38
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +229 -185
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +52 -13
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +275 -115
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +32 -33
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +83 -32
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +384 -221
  70. data/lib/active_record/connection_adapters/column.rb +27 -41
  71. data/lib/active_record/connection_adapters/connection_specification.rb +2 -21
  72. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  73. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +57 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +69 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +59 -0
  76. data/lib/active_record/connection_adapters/mysql2_adapter.rb +22 -101
  77. data/lib/active_record/connection_adapters/postgresql/column.rb +6 -10
  78. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +3 -3
  79. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  80. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +23 -57
  81. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
  83. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  85. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
  86. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  87. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  90. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +23 -16
  92. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  93. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  96. data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -11
  97. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +54 -0
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +174 -128
  101. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  102. data/lib/active_record/connection_adapters/postgresql_adapter.rb +184 -112
  103. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  104. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  105. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +15 -0
  106. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +134 -110
  107. data/lib/active_record/connection_adapters/statement_pool.rb +28 -11
  108. data/lib/active_record/connection_handling.rb +5 -5
  109. data/lib/active_record/core.rb +72 -104
  110. data/lib/active_record/counter_cache.rb +9 -20
  111. data/lib/active_record/dynamic_matchers.rb +1 -20
  112. data/lib/active_record/enum.rb +110 -76
  113. data/lib/active_record/errors.rb +72 -47
  114. data/lib/active_record/explain_registry.rb +1 -1
  115. data/lib/active_record/explain_subscriber.rb +1 -1
  116. data/lib/active_record/fixture_set/file.rb +19 -4
  117. data/lib/active_record/fixtures.rb +76 -40
  118. data/lib/active_record/gem_version.rb +4 -4
  119. data/lib/active_record/inheritance.rb +27 -40
  120. data/lib/active_record/integration.rb +4 -4
  121. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  122. data/lib/active_record/locale/en.yml +3 -2
  123. data/lib/active_record/locking/optimistic.rb +10 -14
  124. data/lib/active_record/locking/pessimistic.rb +1 -1
  125. data/lib/active_record/log_subscriber.rb +40 -22
  126. data/lib/active_record/migration.rb +304 -133
  127. data/lib/active_record/migration/command_recorder.rb +59 -18
  128. data/lib/active_record/migration/compatibility.rb +90 -0
  129. data/lib/active_record/model_schema.rb +92 -40
  130. data/lib/active_record/nested_attributes.rb +45 -34
  131. data/lib/active_record/null_relation.rb +15 -7
  132. data/lib/active_record/persistence.rb +112 -72
  133. data/lib/active_record/querying.rb +6 -5
  134. data/lib/active_record/railtie.rb +20 -13
  135. data/lib/active_record/railties/controller_runtime.rb +1 -1
  136. data/lib/active_record/railties/databases.rake +47 -38
  137. data/lib/active_record/readonly_attributes.rb +1 -1
  138. data/lib/active_record/reflection.rb +182 -57
  139. data/lib/active_record/relation.rb +152 -100
  140. data/lib/active_record/relation/batches.rb +133 -33
  141. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  142. data/lib/active_record/relation/calculations.rb +80 -101
  143. data/lib/active_record/relation/delegation.rb +6 -19
  144. data/lib/active_record/relation/finder_methods.rb +58 -46
  145. data/lib/active_record/relation/from_clause.rb +32 -0
  146. data/lib/active_record/relation/merger.rb +13 -42
  147. data/lib/active_record/relation/predicate_builder.rb +99 -105
  148. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
  149. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +78 -0
  150. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  151. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  152. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  153. data/lib/active_record/relation/predicate_builder/range_handler.rb +17 -0
  154. data/lib/active_record/relation/query_attribute.rb +19 -0
  155. data/lib/active_record/relation/query_methods.rb +274 -238
  156. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  157. data/lib/active_record/relation/spawn_methods.rb +3 -6
  158. data/lib/active_record/relation/where_clause.rb +173 -0
  159. data/lib/active_record/relation/where_clause_factory.rb +37 -0
  160. data/lib/active_record/result.rb +4 -3
  161. data/lib/active_record/runtime_registry.rb +1 -1
  162. data/lib/active_record/sanitization.rb +94 -65
  163. data/lib/active_record/schema.rb +23 -22
  164. data/lib/active_record/schema_dumper.rb +33 -22
  165. data/lib/active_record/schema_migration.rb +10 -4
  166. data/lib/active_record/scoping.rb +17 -6
  167. data/lib/active_record/scoping/default.rb +19 -6
  168. data/lib/active_record/scoping/named.rb +39 -28
  169. data/lib/active_record/secure_token.rb +38 -0
  170. data/lib/active_record/serialization.rb +2 -4
  171. data/lib/active_record/statement_cache.rb +15 -13
  172. data/lib/active_record/store.rb +8 -3
  173. data/lib/active_record/suppressor.rb +54 -0
  174. data/lib/active_record/table_metadata.rb +64 -0
  175. data/lib/active_record/tasks/database_tasks.rb +30 -40
  176. data/lib/active_record/tasks/mysql_database_tasks.rb +7 -15
  177. data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
  178. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  179. data/lib/active_record/timestamp.rb +16 -9
  180. data/lib/active_record/touch_later.rb +58 -0
  181. data/lib/active_record/transactions.rb +138 -56
  182. data/lib/active_record/type.rb +66 -17
  183. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  184. data/lib/active_record/type/date.rb +2 -45
  185. data/lib/active_record/type/date_time.rb +2 -49
  186. data/lib/active_record/type/internal/abstract_json.rb +33 -0
  187. data/lib/active_record/type/internal/timezone.rb +15 -0
  188. data/lib/active_record/type/serialized.rb +9 -14
  189. data/lib/active_record/type/time.rb +3 -21
  190. data/lib/active_record/type/type_map.rb +4 -4
  191. data/lib/active_record/type_caster.rb +7 -0
  192. data/lib/active_record/type_caster/connection.rb +29 -0
  193. data/lib/active_record/type_caster/map.rb +19 -0
  194. data/lib/active_record/validations.rb +33 -32
  195. data/lib/active_record/validations/absence.rb +24 -0
  196. data/lib/active_record/validations/associated.rb +10 -3
  197. data/lib/active_record/validations/length.rb +36 -0
  198. data/lib/active_record/validations/presence.rb +12 -12
  199. data/lib/active_record/validations/uniqueness.rb +24 -21
  200. data/lib/rails/generators/active_record/migration.rb +7 -0
  201. data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
  202. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  203. data/lib/rails/generators/active_record/migration/templates/migration.rb +4 -1
  204. data/lib/rails/generators/active_record/model/model_generator.rb +21 -15
  205. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  206. metadata +50 -35
  207. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  208. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  209. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  210. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  211. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  212. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  213. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  214. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  215. data/lib/active_record/type/big_integer.rb +0 -13
  216. data/lib/active_record/type/binary.rb +0 -50
  217. data/lib/active_record/type/boolean.rb +0 -31
  218. data/lib/active_record/type/decimal.rb +0 -64
  219. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  220. data/lib/active_record/type/decorator.rb +0 -14
  221. data/lib/active_record/type/float.rb +0 -19
  222. data/lib/active_record/type/integer.rb +0 -59
  223. data/lib/active_record/type/mutable.rb +0 -16
  224. data/lib/active_record/type/numeric.rb +0 -36
  225. data/lib/active_record/type/string.rb +0 -40
  226. data/lib/active_record/type/text.rb +0 -11
  227. data/lib/active_record/type/time_value.rb +0 -38
  228. data/lib/active_record/type/unsigned_integer.rb +0 -15
  229. data/lib/active_record/type/value.rb +0 -110
@@ -1,15 +1,14 @@
1
1
  require 'set'
2
2
  require 'active_support/concern'
3
- require 'active_support/deprecation'
4
3
 
5
4
  module ActiveRecord
6
5
  module Delegation # :nodoc:
7
- module DelegateCache
8
- def relation_delegate_class(klass) # :nodoc:
6
+ module DelegateCache # :nodoc:
7
+ def relation_delegate_class(klass)
9
8
  @relation_delegate_cache[klass]
10
9
  end
11
10
 
12
- def initialize_relation_delegate_cache # :nodoc:
11
+ def initialize_relation_delegate_cache
13
12
  @relation_delegate_cache = cache = {}
14
13
  [
15
14
  ActiveRecord::Relation,
@@ -19,7 +18,7 @@ module ActiveRecord
19
18
  delegate = Class.new(klass) {
20
19
  include ClassSpecificRelation
21
20
  }
22
- const_set klass.name.gsub('::', '_'), delegate
21
+ const_set klass.name.gsub('::'.freeze, '_'.freeze), delegate
23
22
  cache[klass] = delegate
24
23
  end
25
24
  end
@@ -37,13 +36,8 @@ module ActiveRecord
37
36
  # may vary depending on the klass of a relation, so we create a subclass of Relation
38
37
  # for each different klass, and the delegations are compiled into that subclass only.
39
38
 
40
- BLACKLISTED_ARRAY_METHODS = [
41
- :compact!, :flatten!, :reject!, :reverse!, :rotate!, :map!,
42
- :shuffle!, :slice!, :sort!, :sort_by!, :delete_if,
43
- :keep_if, :pop, :shift, :delete_at, :select!
44
- ].to_set # :nodoc:
45
-
46
- delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to_ary, :join, to: :to_a
39
+ delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to_ary, :join,
40
+ :[], :&, :|, :+, :-, :sample, :shuffle, :reverse, :compact, to: :to_a
47
41
 
48
42
  delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key,
49
43
  :connection, :columns_hash, :to => :klass
@@ -115,21 +109,14 @@ module ActiveRecord
115
109
 
116
110
  def respond_to?(method, include_private = false)
117
111
  super || @klass.respond_to?(method, include_private) ||
118
- array_delegable?(method) ||
119
112
  arel.respond_to?(method, include_private)
120
113
  end
121
114
 
122
115
  protected
123
116
 
124
- def array_delegable?(method)
125
- Array.method_defined?(method) && BLACKLISTED_ARRAY_METHODS.exclude?(method)
126
- end
127
-
128
117
  def method_missing(method, *args, &block)
129
118
  if @klass.respond_to?(method)
130
119
  scoping { @klass.public_send(method, *args, &block) }
131
- elsif array_delegable?(method)
132
- to_a.public_send(method, *args, &block)
133
120
  elsif arel.respond_to?(method)
134
121
  arel.public_send(method, *args, &block)
135
122
  else
@@ -1,4 +1,3 @@
1
- require 'active_support/deprecation'
2
1
  require 'active_support/core_ext/string/filters'
3
2
 
4
3
  module ActiveRecord
@@ -6,7 +5,7 @@ module ActiveRecord
6
5
  ONE_AS_ONE = '1 AS one'
7
6
 
8
7
  # Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]).
9
- # If no record can be found for all of the listed ids, then RecordNotFound will be raised. If the primary key
8
+ # If one or more records can not be found for the requested ids, then RecordNotFound will be raised. If the primary key
10
9
  # is an integer, find by id coerces its arguments using +to_i+.
11
10
  #
12
11
  # Person.find(1) # returns the object for ID = 1
@@ -17,10 +16,8 @@ module ActiveRecord
17
16
  # Person.find([1]) # returns an array for the object with ID = 1
18
17
  # Person.where("administrator = 1").order("created_on DESC").find(1)
19
18
  #
20
- # <tt>ActiveRecord::RecordNotFound</tt> will be raised if one or more ids are not found.
21
- #
22
19
  # NOTE: The returned records may not be in the same order as the ids you
23
- # provide since database rows are unordered. You'd need to provide an explicit <tt>order</tt>
20
+ # provide since database rows are unordered. You'd need to provide an explicit QueryMethods#order
24
21
  # option if you want the results are sorted.
25
22
  #
26
23
  # ==== Find with lock
@@ -37,7 +34,7 @@ module ActiveRecord
37
34
  # person.save!
38
35
  # end
39
36
  #
40
- # ==== Variations of +find+
37
+ # ==== Variations of #find
41
38
  #
42
39
  # Person.where(name: 'Spartacus', rating: 4)
43
40
  # # returns a chainable list (which can be empty).
@@ -49,9 +46,9 @@ module ActiveRecord
49
46
  # # returns the first item or returns a new instance (requires you call .save to persist against the database).
50
47
  #
51
48
  # Person.where(name: 'Spartacus', rating: 4).first_or_create
52
- # # returns the first item or creates it and returns it, available since Rails 3.2.1.
49
+ # # returns the first item or creates it and returns it.
53
50
  #
54
- # ==== Alternatives for +find+
51
+ # ==== Alternatives for #find
55
52
  #
56
53
  # Person.where(name: 'Spartacus', rating: 4).exists?(conditions = :none)
57
54
  # # returns a boolean indicating if any record with the given conditions exist.
@@ -60,16 +57,13 @@ module ActiveRecord
60
57
  # # returns a chainable list of instances with only the mentioned fields.
61
58
  #
62
59
  # Person.where(name: 'Spartacus', rating: 4).ids
63
- # # returns an Array of ids, available since Rails 3.2.1.
60
+ # # returns an Array of ids.
64
61
  #
65
62
  # Person.where(name: 'Spartacus', rating: 4).pluck(:field1, :field2)
66
- # # returns an Array of the required fields, available since Rails 3.1.
63
+ # # returns an Array of the required fields.
67
64
  def find(*args)
68
- if block_given?
69
- to_a.find(*args) { |*block_args| yield(*block_args) }
70
- else
71
- find_with_ids(*args)
72
- end
65
+ return super if block_given?
66
+ find_with_ids(*args)
73
67
  end
74
68
 
75
69
  # Finds the first record matching the specified conditions. There
@@ -80,18 +74,19 @@ module ActiveRecord
80
74
  #
81
75
  # Post.find_by name: 'Spartacus', rating: 4
82
76
  # Post.find_by "published_at < ?", 2.weeks.ago
83
- def find_by(*args)
84
- where(*args).take
77
+ def find_by(arg, *args)
78
+ where(arg, *args).take
85
79
  rescue RangeError
86
80
  nil
87
81
  end
88
82
 
89
- # Like <tt>find_by</tt>, except that if no record is found, raises
90
- # an <tt>ActiveRecord::RecordNotFound</tt> error.
91
- def find_by!(*args)
92
- where(*args).take!
83
+ # Like #find_by, except that if no record is found, raises
84
+ # an ActiveRecord::RecordNotFound error.
85
+ def find_by!(arg, *args)
86
+ where(arg, *args).take!
93
87
  rescue RangeError
94
- raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range value"
88
+ raise RecordNotFound.new("Couldn't find #{@klass.name} with an out of range value",
89
+ @klass.name)
95
90
  end
96
91
 
97
92
  # Gives a record (or N records if a parameter is supplied) without any implied
@@ -105,10 +100,10 @@ module ActiveRecord
105
100
  limit ? limit(limit).to_a : find_take
106
101
  end
107
102
 
108
- # Same as +take+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
109
- # is found. Note that <tt>take!</tt> accepts no arguments.
103
+ # Same as #take but raises ActiveRecord::RecordNotFound if no record
104
+ # is found. Note that #take! accepts no arguments.
110
105
  def take!
111
- take or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql}]")
106
+ take or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]")
112
107
  end
113
108
 
114
109
  # Find the first record (or first N records if a parameter is supplied).
@@ -128,8 +123,8 @@ module ActiveRecord
128
123
  end
129
124
  end
130
125
 
131
- # Same as +first+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
132
- # is found. Note that <tt>first!</tt> accepts no arguments.
126
+ # Same as #first but raises ActiveRecord::RecordNotFound if no record
127
+ # is found. Note that #first! accepts no arguments.
133
128
  def first!
134
129
  find_nth! 0
135
130
  end
@@ -161,10 +156,10 @@ module ActiveRecord
161
156
  end
162
157
  end
163
158
 
164
- # Same as +last+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
165
- # is found. Note that <tt>last!</tt> accepts no arguments.
159
+ # Same as #last but raises ActiveRecord::RecordNotFound if no record
160
+ # is found. Note that #last! accepts no arguments.
166
161
  def last!
167
- last or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql}]")
162
+ last or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]")
168
163
  end
169
164
 
170
165
  # Find the second record.
@@ -177,7 +172,7 @@ module ActiveRecord
177
172
  find_nth(1, offset_index)
178
173
  end
179
174
 
180
- # Same as +second+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
175
+ # Same as #second but raises ActiveRecord::RecordNotFound if no record
181
176
  # is found.
182
177
  def second!
183
178
  find_nth! 1
@@ -193,7 +188,7 @@ module ActiveRecord
193
188
  find_nth(2, offset_index)
194
189
  end
195
190
 
196
- # Same as +third+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
191
+ # Same as #third but raises ActiveRecord::RecordNotFound if no record
197
192
  # is found.
198
193
  def third!
199
194
  find_nth! 2
@@ -209,7 +204,7 @@ module ActiveRecord
209
204
  find_nth(3, offset_index)
210
205
  end
211
206
 
212
- # Same as +fourth+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
207
+ # Same as #fourth but raises ActiveRecord::RecordNotFound if no record
213
208
  # is found.
214
209
  def fourth!
215
210
  find_nth! 3
@@ -225,7 +220,7 @@ module ActiveRecord
225
220
  find_nth(4, offset_index)
226
221
  end
227
222
 
228
- # Same as +fifth+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
223
+ # Same as #fifth but raises ActiveRecord::RecordNotFound if no record
229
224
  # is found.
230
225
  def fifth!
231
226
  find_nth! 4
@@ -241,14 +236,14 @@ module ActiveRecord
241
236
  find_nth(41, offset_index)
242
237
  end
243
238
 
244
- # Same as +forty_two+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
239
+ # Same as #forty_two but raises ActiveRecord::RecordNotFound if no record
245
240
  # is found.
246
241
  def forty_two!
247
242
  find_nth! 41
248
243
  end
249
244
 
250
- # Returns +true+ if a record exists in the table that matches the +id+ or
251
- # conditions given, or +false+ otherwise. The argument can take six forms:
245
+ # Returns true if a record exists in the table that matches the +id+ or
246
+ # conditions given, or false otherwise. The argument can take six forms:
252
247
  #
253
248
  # * Integer - Finds the record with this primary key.
254
249
  # * String - Finds the record with a primary key corresponding to this
@@ -261,7 +256,7 @@ module ActiveRecord
261
256
  # * No args - Returns +false+ if the table is empty, +true+ otherwise.
262
257
  #
263
258
  # For more information about specifying conditions as a hash or array,
264
- # see the Conditions section in the introduction to <tt>ActiveRecord::Base</tt>.
259
+ # see the Conditions section in the introduction to ActiveRecord::Base.
265
260
  #
266
261
  # Note: You can't pass in a condition as a string (like <tt>name =
267
262
  # 'Jamie'</tt>), since it would be sanitized and then queried against
@@ -299,11 +294,11 @@ module ActiveRecord
299
294
  end
300
295
  end
301
296
 
302
- connection.select_value(relation, "#{name} Exists", relation.arel.bind_values + relation.bind_values) ? true : false
297
+ connection.select_value(relation, "#{name} Exists", relation.bound_attributes) ? true : false
303
298
  end
304
299
 
305
300
  # This method is called whenever no records are found with either a single
306
- # id or multiple ids and raises a +ActiveRecord::RecordNotFound+ exception.
301
+ # id or multiple ids and raises a ActiveRecord::RecordNotFound exception.
307
302
  #
308
303
  # The error message is different depending on whether a single id or
309
304
  # multiple ids are provided. If multiple ids are provided, then the number
@@ -311,7 +306,7 @@ module ActiveRecord
311
306
  # the expected number of results should be provided in the +expected_size+
312
307
  # argument.
313
308
  def raise_record_not_found_exception!(ids, result_size, expected_size) #:nodoc:
314
- conditions = arel.where_sql
309
+ conditions = arel.where_sql(@klass.arel_engine)
315
310
  conditions = " [#{conditions}]" if conditions
316
311
 
317
312
  if Array(ids).size == 1
@@ -353,7 +348,7 @@ module ActiveRecord
353
348
  []
354
349
  else
355
350
  arel = relation.arel
356
- rows = connection.select_all(arel, 'SQL', arel.bind_values + relation.bind_values)
351
+ rows = connection.select_all(arel, 'SQL', relation.bound_attributes)
357
352
  join_dependency.instantiate(rows, aliases)
358
353
  end
359
354
  end
@@ -385,7 +380,7 @@ module ActiveRecord
385
380
  else
386
381
  if relation.limit_value
387
382
  limited_ids = limited_ids_for(relation)
388
- limited_ids.empty? ? relation.none! : relation.where!(table[primary_key].in(limited_ids))
383
+ limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
389
384
  end
390
385
  relation.except(:limit, :offset)
391
386
  end
@@ -398,12 +393,12 @@ module ActiveRecord
398
393
  relation = relation.except(:select).select(values).distinct!
399
394
  arel = relation.arel
400
395
 
401
- id_rows = @klass.connection.select_all(arel, 'SQL', arel.bind_values + relation.bind_values)
396
+ id_rows = @klass.connection.select_all(arel, 'SQL', relation.bound_attributes)
402
397
  id_rows.map {|row| row[primary_key]}
403
398
  end
404
399
 
405
400
  def using_limitable_reflections?(reflections)
406
- reflections.none? { |r| r.collection? }
401
+ reflections.none?(&:collection?)
407
402
  end
408
403
 
409
404
  protected
@@ -447,6 +442,8 @@ module ActiveRecord
447
442
  end
448
443
 
449
444
  def find_some(ids)
445
+ return find_some_ordered(ids) unless order_values.present?
446
+
450
447
  result = where(primary_key => ids).to_a
451
448
 
452
449
  expected_size =
@@ -468,6 +465,21 @@ module ActiveRecord
468
465
  end
469
466
  end
470
467
 
468
+ def find_some_ordered(ids)
469
+ ids = ids.slice(offset_value || 0, limit_value || ids.size) || []
470
+
471
+ result = except(:limit, :offset).where(primary_key => ids).to_a
472
+
473
+ if result.size == ids.size
474
+ pk_type = @klass.type_for_attribute(primary_key)
475
+
476
+ records_by_id = result.index_by(&:id)
477
+ ids.map { |id| records_by_id.fetch(pk_type.cast(id)) }
478
+ else
479
+ raise_record_not_found_exception!(ids, result.size, ids.size)
480
+ end
481
+ end
482
+
471
483
  def find_take
472
484
  if loaded?
473
485
  @records.first
@@ -486,7 +498,7 @@ module ActiveRecord
486
498
  end
487
499
 
488
500
  def find_nth!(index)
489
- find_nth(index, offset_index) or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql}]")
501
+ find_nth(index, offset_index) or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]")
490
502
  end
491
503
 
492
504
  def find_nth_with_limit(offset, limit)
@@ -0,0 +1,32 @@
1
+ module ActiveRecord
2
+ class Relation
3
+ class FromClause # :nodoc:
4
+ attr_reader :value, :name
5
+
6
+ def initialize(value, name)
7
+ @value = value
8
+ @name = name
9
+ end
10
+
11
+ def binds
12
+ if value.is_a?(Relation)
13
+ value.bound_attributes
14
+ else
15
+ []
16
+ end
17
+ end
18
+
19
+ def merge(other)
20
+ self
21
+ end
22
+
23
+ def empty?
24
+ value.nil?
25
+ end
26
+
27
+ def self.empty
28
+ new(nil, nil)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,5 +1,4 @@
1
1
  require 'active_support/core_ext/hash/keys'
2
- require "set"
3
2
 
4
3
  module ActiveRecord
5
4
  class Relation
@@ -22,7 +21,7 @@ module ActiveRecord
22
21
  # build a relation to merge in rather than directly merging
23
22
  # the values.
24
23
  def other
25
- other = Relation.create(relation.klass, relation.table)
24
+ other = Relation.create(relation.klass, relation.table, relation.predicate_builder)
26
25
  hash.each { |k, v|
27
26
  if k == :joins
28
27
  if Hash === v
@@ -49,10 +48,9 @@ module ActiveRecord
49
48
  @other = other
50
49
  end
51
50
 
52
- NORMAL_VALUES = Relation::SINGLE_VALUE_METHODS +
53
- Relation::MULTI_VALUE_METHODS -
54
- [:includes, :preload, :joins, :where, :order, :bind, :reverse_order, :lock, :create_with, :reordering, :from] # :nodoc:
55
-
51
+ NORMAL_VALUES = Relation::VALUE_METHODS -
52
+ Relation::CLAUSE_METHODS -
53
+ [:includes, :preload, :joins, :order, :reverse_order, :lock, :create_with, :reordering] # :nodoc:
56
54
 
57
55
  def normal_values
58
56
  NORMAL_VALUES
@@ -76,6 +74,7 @@ module ActiveRecord
76
74
 
77
75
  merge_multi_values
78
76
  merge_single_values
77
+ merge_clauses
79
78
  merge_preloads
80
79
  merge_joins
81
80
 
@@ -130,20 +129,6 @@ module ActiveRecord
130
129
  end
131
130
 
132
131
  def merge_multi_values
133
- lhs_wheres = relation.where_values
134
- rhs_wheres = other.where_values
135
-
136
- lhs_binds = relation.bind_values
137
- rhs_binds = other.bind_values
138
-
139
- removed, kept = partition_overwrites(lhs_wheres, rhs_wheres)
140
-
141
- where_values = kept + rhs_wheres
142
- bind_values = filter_binds(lhs_binds, removed) + rhs_binds
143
-
144
- relation.where_values = where_values
145
- relation.bind_values = bind_values
146
-
147
132
  if other.reordering_value
148
133
  # override any order specified in the original relation
149
134
  relation.reorder! other.order_values
@@ -156,36 +141,22 @@ module ActiveRecord
156
141
  end
157
142
 
158
143
  def merge_single_values
159
- relation.from_value = other.from_value unless relation.from_value
160
- relation.lock_value = other.lock_value unless relation.lock_value
144
+ relation.lock_value ||= other.lock_value
161
145
 
162
146
  unless other.create_with_value.blank?
163
147
  relation.create_with_value = (relation.create_with_value || {}).merge(other.create_with_value)
164
148
  end
165
149
  end
166
150
 
167
- def filter_binds(lhs_binds, removed_wheres)
168
- return lhs_binds if removed_wheres.empty?
169
-
170
- set = Set.new removed_wheres.map { |x| x.left.name.to_s }
171
- lhs_binds.dup.delete_if { |col,_| set.include? col.name }
151
+ CLAUSE_METHOD_NAMES = CLAUSE_METHODS.map do |name|
152
+ ["#{name}_clause", "#{name}_clause="]
172
153
  end
173
154
 
174
- # Remove equalities from the existing relation with a LHS which is
175
- # present in the relation being merged in.
176
- # returns [things_to_remove, things_to_keep]
177
- def partition_overwrites(lhs_wheres, rhs_wheres)
178
- if lhs_wheres.empty? || rhs_wheres.empty?
179
- return [[], lhs_wheres]
180
- end
181
-
182
- nodes = rhs_wheres.find_all do |w|
183
- w.respond_to?(:operator) && w.operator == :==
184
- end
185
- seen = Set.new(nodes) { |node| node.left }
186
-
187
- lhs_wheres.partition do |w|
188
- w.respond_to?(:operator) && w.operator == :== && seen.include?(w.left)
155
+ def merge_clauses
156
+ CLAUSE_METHOD_NAMES.each do |(reader, writer)|
157
+ clause = relation.send(reader)
158
+ other_clause = other.send(reader)
159
+ relation.send(writer, clause.merge(other_clause))
189
160
  end
190
161
  end
191
162
  end