activerecord 5.0.7.2 → 5.1.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 (216) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +389 -2252
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/examples/performance.rb +28 -28
  6. data/examples/simple.rb +3 -3
  7. data/lib/active_record.rb +20 -20
  8. data/lib/active_record/aggregations.rb +244 -244
  9. data/lib/active_record/association_relation.rb +5 -5
  10. data/lib/active_record/associations.rb +1579 -1569
  11. data/lib/active_record/associations/alias_tracker.rb +1 -1
  12. data/lib/active_record/associations/association.rb +23 -15
  13. data/lib/active_record/associations/association_scope.rb +83 -81
  14. data/lib/active_record/associations/belongs_to_association.rb +0 -1
  15. data/lib/active_record/associations/builder/belongs_to.rb +16 -14
  16. data/lib/active_record/associations/builder/collection_association.rb +1 -2
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +27 -27
  18. data/lib/active_record/associations/collection_association.rb +74 -241
  19. data/lib/active_record/associations/collection_proxy.rb +144 -70
  20. data/lib/active_record/associations/has_many_association.rb +15 -19
  21. data/lib/active_record/associations/has_many_through_association.rb +12 -5
  22. data/lib/active_record/associations/has_one_association.rb +22 -28
  23. data/lib/active_record/associations/has_one_through_association.rb +5 -1
  24. data/lib/active_record/associations/join_dependency.rb +117 -115
  25. data/lib/active_record/associations/join_dependency/join_association.rb +16 -13
  26. data/lib/active_record/associations/join_dependency/join_base.rb +1 -1
  27. data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
  28. data/lib/active_record/associations/preloader.rb +94 -94
  29. data/lib/active_record/associations/preloader/association.rb +87 -64
  30. data/lib/active_record/associations/preloader/belongs_to.rb +0 -2
  31. data/lib/active_record/associations/preloader/collection_association.rb +6 -6
  32. data/lib/active_record/associations/preloader/has_many.rb +0 -2
  33. data/lib/active_record/associations/preloader/singular_association.rb +6 -8
  34. data/lib/active_record/associations/preloader/through_association.rb +34 -41
  35. data/lib/active_record/associations/singular_association.rb +8 -25
  36. data/lib/active_record/associations/through_association.rb +3 -6
  37. data/lib/active_record/attribute.rb +98 -71
  38. data/lib/active_record/attribute/user_provided_default.rb +4 -2
  39. data/lib/active_record/attribute_assignment.rb +61 -61
  40. data/lib/active_record/attribute_decorators.rb +35 -13
  41. data/lib/active_record/attribute_methods.rb +56 -65
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -7
  43. data/lib/active_record/attribute_methods/dirty.rb +216 -34
  44. data/lib/active_record/attribute_methods/primary_key.rb +78 -73
  45. data/lib/active_record/attribute_methods/read.rb +39 -35
  46. data/lib/active_record/attribute_methods/serialization.rb +7 -7
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +35 -58
  48. data/lib/active_record/attribute_methods/write.rb +36 -30
  49. data/lib/active_record/attribute_mutation_tracker.rb +53 -10
  50. data/lib/active_record/attribute_set.rb +9 -6
  51. data/lib/active_record/attribute_set/builder.rb +41 -49
  52. data/lib/active_record/attribute_set/yaml_encoder.rb +41 -0
  53. data/lib/active_record/attributes.rb +21 -21
  54. data/lib/active_record/autosave_association.rb +13 -13
  55. data/lib/active_record/base.rb +24 -22
  56. data/lib/active_record/callbacks.rb +52 -14
  57. data/lib/active_record/coders/yaml_column.rb +9 -11
  58. data/lib/active_record/collection_cache_key.rb +6 -17
  59. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +320 -278
  60. data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -3
  61. data/lib/active_record/connection_adapters/abstract/database_statements.rb +22 -34
  62. data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -27
  63. data/lib/active_record/connection_adapters/abstract/quoting.rb +44 -57
  64. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +9 -19
  65. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +78 -79
  66. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +53 -41
  67. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +99 -93
  68. data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -5
  69. data/lib/active_record/connection_adapters/abstract_adapter.rb +156 -128
  70. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +424 -382
  71. data/lib/active_record/connection_adapters/column.rb +27 -5
  72. data/lib/active_record/connection_adapters/connection_specification.rb +128 -118
  73. data/lib/active_record/connection_adapters/mysql/column.rb +6 -31
  74. data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -43
  75. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +22 -22
  76. data/lib/active_record/connection_adapters/mysql/quoting.rb +6 -12
  77. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
  78. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +16 -19
  79. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +49 -31
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +5 -6
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +24 -26
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +1 -28
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -35
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +3 -3
  85. data/lib/active_record/connection_adapters/postgresql/oid.rb +22 -21
  86. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +9 -9
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +5 -3
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
  91. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -3
  92. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +16 -16
  93. data/lib/active_record/connection_adapters/postgresql/oid/{rails_5_1_point.rb → legacy_point.rb} +9 -16
  94. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  95. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +13 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +28 -8
  97. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +28 -30
  98. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +51 -51
  100. data/lib/active_record/connection_adapters/postgresql/quoting.rb +38 -36
  101. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +15 -0
  102. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +37 -24
  103. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +19 -23
  104. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +161 -170
  105. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +4 -4
  106. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -7
  107. data/lib/active_record/connection_adapters/postgresql_adapter.rb +179 -152
  108. data/lib/active_record/connection_adapters/schema_cache.rb +16 -7
  109. data/lib/active_record/connection_adapters/sql_type_metadata.rb +3 -3
  110. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +1 -1
  111. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +16 -20
  112. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +1 -8
  113. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +28 -0
  114. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +17 -0
  115. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +187 -130
  116. data/lib/active_record/connection_adapters/statement_pool.rb +7 -7
  117. data/lib/active_record/connection_handling.rb +14 -26
  118. data/lib/active_record/core.rb +110 -93
  119. data/lib/active_record/counter_cache.rb +62 -13
  120. data/lib/active_record/define_callbacks.rb +20 -0
  121. data/lib/active_record/dynamic_matchers.rb +80 -79
  122. data/lib/active_record/enum.rb +8 -6
  123. data/lib/active_record/errors.rb +58 -15
  124. data/lib/active_record/explain.rb +1 -2
  125. data/lib/active_record/explain_registry.rb +1 -1
  126. data/lib/active_record/explain_subscriber.rb +7 -4
  127. data/lib/active_record/fixture_set/file.rb +11 -8
  128. data/lib/active_record/fixtures.rb +66 -53
  129. data/lib/active_record/gem_version.rb +3 -3
  130. data/lib/active_record/inheritance.rb +93 -79
  131. data/lib/active_record/integration.rb +7 -7
  132. data/lib/active_record/internal_metadata.rb +3 -16
  133. data/lib/active_record/legacy_yaml_adapter.rb +1 -1
  134. data/lib/active_record/locking/optimistic.rb +64 -56
  135. data/lib/active_record/locking/pessimistic.rb +10 -1
  136. data/lib/active_record/log_subscriber.rb +29 -29
  137. data/lib/active_record/migration.rb +155 -172
  138. data/lib/active_record/migration/command_recorder.rb +94 -94
  139. data/lib/active_record/migration/compatibility.rb +76 -37
  140. data/lib/active_record/migration/join_table.rb +6 -6
  141. data/lib/active_record/model_schema.rb +85 -119
  142. data/lib/active_record/nested_attributes.rb +200 -199
  143. data/lib/active_record/null_relation.rb +10 -33
  144. data/lib/active_record/persistence.rb +45 -38
  145. data/lib/active_record/query_cache.rb +4 -8
  146. data/lib/active_record/querying.rb +2 -3
  147. data/lib/active_record/railtie.rb +16 -17
  148. data/lib/active_record/railties/controller_runtime.rb +6 -2
  149. data/lib/active_record/railties/databases.rake +125 -140
  150. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  151. data/lib/active_record/readonly_attributes.rb +2 -2
  152. data/lib/active_record/reflection.rb +79 -96
  153. data/lib/active_record/relation.rb +72 -115
  154. data/lib/active_record/relation/batches.rb +87 -58
  155. data/lib/active_record/relation/batches/batch_enumerator.rb +1 -1
  156. data/lib/active_record/relation/calculations.rb +154 -160
  157. data/lib/active_record/relation/delegation.rb +30 -29
  158. data/lib/active_record/relation/finder_methods.rb +195 -226
  159. data/lib/active_record/relation/merger.rb +58 -62
  160. data/lib/active_record/relation/predicate_builder.rb +92 -89
  161. data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -5
  162. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +23 -23
  163. data/lib/active_record/relation/predicate_builder/base_handler.rb +3 -1
  164. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +0 -8
  165. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +12 -10
  166. data/lib/active_record/relation/predicate_builder/range_handler.rb +0 -8
  167. data/lib/active_record/relation/query_attribute.rb +1 -1
  168. data/lib/active_record/relation/query_methods.rb +247 -295
  169. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  170. data/lib/active_record/relation/spawn_methods.rb +4 -5
  171. data/lib/active_record/relation/where_clause.rb +79 -65
  172. data/lib/active_record/relation/where_clause_factory.rb +47 -8
  173. data/lib/active_record/result.rb +29 -31
  174. data/lib/active_record/runtime_registry.rb +3 -3
  175. data/lib/active_record/sanitization.rb +182 -197
  176. data/lib/active_record/schema.rb +3 -3
  177. data/lib/active_record/schema_dumper.rb +14 -37
  178. data/lib/active_record/schema_migration.rb +3 -3
  179. data/lib/active_record/scoping.rb +9 -10
  180. data/lib/active_record/scoping/default.rb +87 -91
  181. data/lib/active_record/scoping/named.rb +16 -28
  182. data/lib/active_record/secure_token.rb +2 -2
  183. data/lib/active_record/statement_cache.rb +13 -15
  184. data/lib/active_record/store.rb +31 -32
  185. data/lib/active_record/suppressor.rb +2 -1
  186. data/lib/active_record/table_metadata.rb +9 -5
  187. data/lib/active_record/tasks/database_tasks.rb +72 -65
  188. data/lib/active_record/tasks/mysql_database_tasks.rb +75 -72
  189. data/lib/active_record/tasks/postgresql_database_tasks.rb +53 -48
  190. data/lib/active_record/tasks/sqlite_database_tasks.rb +18 -16
  191. data/lib/active_record/timestamp.rb +39 -25
  192. data/lib/active_record/touch_later.rb +1 -2
  193. data/lib/active_record/transactions.rb +98 -110
  194. data/lib/active_record/type.rb +17 -13
  195. data/lib/active_record/type/adapter_specific_registry.rb +46 -42
  196. data/lib/active_record/type/decimal_without_scale.rb +9 -0
  197. data/lib/active_record/type/hash_lookup_type_map.rb +3 -3
  198. data/lib/active_record/type/serialized.rb +8 -8
  199. data/lib/active_record/type/text.rb +9 -0
  200. data/lib/active_record/type/time.rb +0 -1
  201. data/lib/active_record/type/type_map.rb +11 -15
  202. data/lib/active_record/type/unsigned_integer.rb +15 -0
  203. data/lib/active_record/type_caster.rb +2 -2
  204. data/lib/active_record/type_caster/connection.rb +8 -6
  205. data/lib/active_record/type_caster/map.rb +3 -1
  206. data/lib/active_record/validations.rb +4 -4
  207. data/lib/active_record/validations/associated.rb +1 -1
  208. data/lib/active_record/validations/presence.rb +2 -2
  209. data/lib/active_record/validations/uniqueness.rb +8 -39
  210. data/lib/active_record/version.rb +1 -1
  211. data/lib/rails/generators/active_record.rb +4 -4
  212. data/lib/rails/generators/active_record/migration.rb +2 -2
  213. data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -34
  214. data/lib/rails/generators/active_record/model/model_generator.rb +9 -9
  215. metadata +22 -13
  216. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
@@ -9,9 +9,11 @@ module ActiveRecord
9
9
  predicate_builder.build(attribute, value.id)
10
10
  end
11
11
 
12
+ # TODO Change this to private once we've dropped Ruby 2.2 support.
13
+ # Workaround for Ruby 2.2 "private attribute?" warning.
12
14
  protected
13
15
 
14
- attr_reader :predicate_builder
16
+ attr_reader :predicate_builder
15
17
  end
16
18
  end
17
19
  end
@@ -1,17 +1,9 @@
1
1
  module ActiveRecord
2
2
  class PredicateBuilder
3
3
  class BasicObjectHandler # :nodoc:
4
- def initialize(predicate_builder)
5
- @predicate_builder = predicate_builder
6
- end
7
-
8
4
  def call(attribute, value)
9
5
  attribute.eq(value)
10
6
  end
11
-
12
- protected
13
-
14
- attr_reader :predicate_builder
15
7
  end
16
8
  end
17
9
  end
@@ -21,9 +21,11 @@ module ActiveRecord
21
21
  end
22
22
  end
23
23
 
24
+ # TODO Change this to private once we've dropped Ruby 2.2 support.
25
+ # Workaround for Ruby 2.2 "private attribute?" warning.
24
26
  protected
25
27
 
26
- attr_reader :predicate_builder
28
+ attr_reader :predicate_builder
27
29
  end
28
30
 
29
31
  class PolymorphicArrayValue # :nodoc:
@@ -41,17 +43,17 @@ module ActiveRecord
41
43
 
42
44
  private
43
45
 
44
- def primary_key(value)
45
- associated_table.association_primary_key(base_class(value))
46
- end
46
+ def primary_key(value)
47
+ associated_table.association_primary_key(base_class(value))
48
+ end
47
49
 
48
- def base_class(value)
49
- value.class.base_class
50
- end
50
+ def base_class(value)
51
+ value.class.base_class
52
+ end
51
53
 
52
- def convert_to_id(value)
53
- value._read_attribute(primary_key(value))
54
- end
54
+ def convert_to_id(value)
55
+ value._read_attribute(primary_key(value))
56
+ end
55
57
  end
56
58
  end
57
59
  end
@@ -3,10 +3,6 @@ module ActiveRecord
3
3
  class RangeHandler # :nodoc:
4
4
  RangeWithBinds = Struct.new(:begin, :end, :exclude_end?)
5
5
 
6
- def initialize(predicate_builder)
7
- @predicate_builder = predicate_builder
8
- end
9
-
10
6
  def call(attribute, value)
11
7
  if value.begin.respond_to?(:infinite?) && value.begin.infinite?
12
8
  if value.end.respond_to?(:infinite?) && value.end.infinite?
@@ -24,10 +20,6 @@ module ActiveRecord
24
20
  attribute.between(value)
25
21
  end
26
22
  end
27
-
28
- protected
29
-
30
- attr_reader :predicate_builder
31
23
  end
32
24
  end
33
25
  end
@@ -1,4 +1,4 @@
1
- require 'active_record/attribute'
1
+ require "active_record/attribute"
2
2
 
3
3
  module ActiveRecord
4
4
  class Relation
@@ -2,8 +2,7 @@ require "active_record/relation/from_clause"
2
2
  require "active_record/relation/query_attribute"
3
3
  require "active_record/relation/where_clause"
4
4
  require "active_record/relation/where_clause_factory"
5
- require 'active_model/forbidden_attributes_protection'
6
- require 'active_support/core_ext/string/filters'
5
+ require "active_model/forbidden_attributes_protection"
7
6
 
8
7
  module ActiveRecord
9
8
  module QueryMethods
@@ -55,62 +54,39 @@ module ActiveRecord
55
54
  end
56
55
 
57
56
  FROZEN_EMPTY_ARRAY = [].freeze
58
- Relation::MULTI_VALUE_METHODS.each do |name|
59
- class_eval <<-CODE, __FILE__, __LINE__ + 1
60
- def #{name}_values
61
- @values[:#{name}] || FROZEN_EMPTY_ARRAY
62
- end
57
+ FROZEN_EMPTY_HASH = {}.freeze
63
58
 
64
- def #{name}_values=(values)
65
- assert_mutability!
66
- @values[:#{name}] = values
59
+ Relation::VALUE_METHODS.each do |name|
60
+ method_name = \
61
+ case name
62
+ when *Relation::MULTI_VALUE_METHODS then "#{name}_values"
63
+ when *Relation::SINGLE_VALUE_METHODS then "#{name}_value"
64
+ when *Relation::CLAUSE_METHODS then "#{name}_clause"
67
65
  end
68
- CODE
69
- end
70
-
71
- (Relation::SINGLE_VALUE_METHODS - [:create_with]).each do |name|
72
66
  class_eval <<-CODE, __FILE__, __LINE__ + 1
73
- def #{name}_value # def readonly_value
74
- @values[:#{name}] # @values[:readonly]
67
+ def #{method_name} # def includes_values
68
+ get_value(#{name.inspect}) # get_value(:includes)
75
69
  end # end
76
- CODE
77
- end
78
70
 
79
- Relation::SINGLE_VALUE_METHODS.each do |name|
80
- class_eval <<-CODE, __FILE__, __LINE__ + 1
81
- def #{name}_value=(value) # def readonly_value=(value)
82
- assert_mutability! # assert_mutability!
83
- @values[:#{name}] = value # @values[:readonly] = value
71
+ def #{method_name}=(value) # def includes_values=(value)
72
+ set_value(#{name.inspect}, value) # set_value(:includes, value)
84
73
  end # end
85
74
  CODE
86
75
  end
87
76
 
88
- Relation::CLAUSE_METHODS.each do |name|
89
- class_eval <<-CODE, __FILE__, __LINE__ + 1
90
- def #{name}_clause # def where_clause
91
- @values[:#{name}] || new_#{name}_clause # @values[:where] || new_where_clause
92
- end # end
93
- #
94
- def #{name}_clause=(value) # def where_clause=(value)
95
- assert_mutability! # assert_mutability!
96
- @values[:#{name}] = value # @values[:where] = value
97
- end # end
98
- CODE
99
- end
100
-
101
77
  def bound_attributes
102
- if limit_value && !string_containing_comma?(limit_value)
78
+ if limit_value
103
79
  limit_bind = Attribute.with_cast_value(
104
80
  "LIMIT".freeze,
105
81
  connection.sanitize_limit(limit_value),
106
- Type::Value.new,
82
+ Type.default_value,
107
83
  )
108
84
  end
109
85
  if offset_value
110
86
  offset_bind = Attribute.with_cast_value(
111
87
  "OFFSET".freeze,
112
88
  offset_value.to_i,
113
- Type::Value.new,
89
+ Type.default_value,
114
90
  )
115
91
  end
116
92
  connection.combine_bind_parameters(
@@ -123,11 +99,6 @@ module ActiveRecord
123
99
  )
124
100
  end
125
101
 
126
- FROZEN_EMPTY_HASH = {}.freeze
127
- def create_with_value # :nodoc:
128
- @values[:create_with] || FROZEN_EMPTY_HASH
129
- end
130
-
131
102
  alias extensions extending_values
132
103
 
133
104
  # Specify relationships to be included in the result set. For
@@ -269,8 +240,15 @@ module ActiveRecord
269
240
  # Model.select(:field).first.other_field
270
241
  # # => ActiveModel::MissingAttributeError: missing attribute: other_field
271
242
  def select(*fields)
272
- return super if block_given?
273
- raise ArgumentError, 'Call this with at least one field' if fields.empty?
243
+ if block_given?
244
+ if fields.any?
245
+ raise ArgumentError, "`select' with block doesn't take arguments."
246
+ end
247
+
248
+ return super()
249
+ end
250
+
251
+ raise ArgumentError, "Call this with at least one field" if fields.empty?
274
252
  spawn._select!(*fields)
275
253
  end
276
254
 
@@ -417,7 +395,10 @@ module ActiveRecord
417
395
  args.each do |scope|
418
396
  case scope
419
397
  when Symbol
420
- symbol_unscoping(scope)
398
+ if !VALID_UNSCOPING_VALUES.include?(scope)
399
+ raise ArgumentError, "Called unscope() with invalid unscoping argument ':#{scope}'. Valid arguments are :#{VALID_UNSCOPING_VALUES.to_a.join(", :")}."
400
+ end
401
+ set_value(scope, nil)
421
402
  when Hash
422
403
  scope.each do |key, target_value|
423
404
  if key != :where
@@ -495,7 +476,6 @@ module ActiveRecord
495
476
  self.left_outer_joins_values += args
496
477
  self
497
478
  end
498
- alias :left_joins! :left_outer_joins!
499
479
 
500
480
  # Returns a new relation, which is the result of filtering the current relation
501
481
  # according to the conditions in the arguments.
@@ -658,7 +638,7 @@ module ActiveRecord
658
638
  # present). Neither relation may have a #limit, #offset, or #distinct set.
659
639
  #
660
640
  # Post.where("id = 1").or(Post.where("author_id = 3"))
661
- # # SELECT `posts`.* FROM `posts` WHERE (('id = 1' OR 'author_id = 3'))
641
+ # # SELECT `posts`.* FROM `posts` WHERE ((id = 1) OR (author_id = 3))
662
642
  #
663
643
  def or(other)
664
644
  unless other.is_a? Relation
@@ -676,7 +656,7 @@ module ActiveRecord
676
656
  end
677
657
 
678
658
  self.where_clause = self.where_clause.or(other.where_clause)
679
- self.having_clause = self.having_clause.or(other.having_clause)
659
+ self.having_clause = having_clause.or(other.having_clause)
680
660
 
681
661
  self
682
662
  end
@@ -707,13 +687,6 @@ module ActiveRecord
707
687
  end
708
688
 
709
689
  def limit!(value) # :nodoc:
710
- if string_containing_comma?(value)
711
- # Remove `string_containing_comma?` when removing this deprecation
712
- ActiveSupport::Deprecation.warn(<<-WARNING.squish)
713
- Passing a string to limit in the form "1,2" is deprecated and will be
714
- removed in Rails 5.1. Please call `offset` explicitly instead.
715
- WARNING
716
- end
717
690
  self.limit_value = value
718
691
  self
719
692
  end
@@ -780,7 +753,7 @@ module ActiveRecord
780
753
  # end
781
754
  #
782
755
  def none
783
- where("1=0").extending!(NullRelation)
756
+ spawn.none!
784
757
  end
785
758
 
786
759
  def none! # :nodoc:
@@ -865,16 +838,12 @@ module ActiveRecord
865
838
  def distinct(value = true)
866
839
  spawn.distinct!(value)
867
840
  end
868
- alias uniq distinct
869
- deprecate uniq: :distinct
870
841
 
871
842
  # Like #distinct, but modifies relation in place.
872
843
  def distinct!(value = true) # :nodoc:
873
844
  self.distinct_value = value
874
845
  self
875
846
  end
876
- alias uniq! distinct!
877
- deprecate uniq!: :distinct!
878
847
 
879
848
  # Used to extend a scope with additional methods, either through
880
849
  # a module or through a block provided.
@@ -949,294 +918,277 @@ module ActiveRecord
949
918
  @arel ||= build_arel
950
919
  end
951
920
 
952
- private
953
-
954
- def assert_mutability!
955
- raise ImmutableRelation if @loaded
956
- raise ImmutableRelation if defined?(@arel) && @arel
921
+ # Returns a relation value with a given name
922
+ def get_value(name) # :nodoc:
923
+ @values[name] || default_value_for(name)
957
924
  end
958
925
 
959
- def build_arel
960
- arel = Arel::SelectManager.new(table)
926
+ # Sets the relation value with the given name
927
+ def set_value(name, value) # :nodoc:
928
+ assert_mutability!
929
+ @values[name] = value
930
+ end
961
931
 
962
- build_joins(arel, joins_values.flatten) unless joins_values.empty?
963
- build_left_outer_joins(arel, left_outer_joins_values.flatten) unless left_outer_joins_values.empty?
932
+ private
964
933
 
965
- arel.where(where_clause.ast) unless where_clause.empty?
966
- arel.having(having_clause.ast) unless having_clause.empty?
967
- if limit_value
968
- if string_containing_comma?(limit_value)
969
- arel.take(connection.sanitize_limit(limit_value))
970
- else
971
- arel.take(Arel::Nodes::BindParam.new)
972
- end
934
+ def assert_mutability!
935
+ raise ImmutableRelation if @loaded
936
+ raise ImmutableRelation if defined?(@arel) && @arel
973
937
  end
974
- arel.skip(Arel::Nodes::BindParam.new) if offset_value
975
- arel.group(*arel_columns(group_values.uniq.reject(&:blank?))) unless group_values.empty?
976
938
 
977
- build_order(arel)
939
+ def build_arel
940
+ arel = Arel::SelectManager.new(table)
978
941
 
979
- build_select(arel)
942
+ build_joins(arel, joins_values.flatten) unless joins_values.empty?
943
+ build_left_outer_joins(arel, left_outer_joins_values.flatten) unless left_outer_joins_values.empty?
980
944
 
981
- arel.distinct(distinct_value)
982
- arel.from(build_from) unless from_clause.empty?
983
- arel.lock(lock_value) if lock_value
945
+ arel.where(where_clause.ast) unless where_clause.empty?
946
+ arel.having(having_clause.ast) unless having_clause.empty?
947
+ arel.take(Arel::Nodes::BindParam.new) if limit_value
948
+ arel.skip(Arel::Nodes::BindParam.new) if offset_value
949
+ arel.group(*arel_columns(group_values.uniq.reject(&:blank?))) unless group_values.empty?
984
950
 
985
- arel
986
- end
951
+ build_order(arel)
987
952
 
988
- def symbol_unscoping(scope)
989
- if !VALID_UNSCOPING_VALUES.include?(scope)
990
- raise ArgumentError, "Called unscope() with invalid unscoping argument ':#{scope}'. Valid arguments are :#{VALID_UNSCOPING_VALUES.to_a.join(", :")}."
991
- end
953
+ build_select(arel)
992
954
 
993
- clause_method = Relation::CLAUSE_METHODS.include?(scope)
994
- multi_val_method = Relation::MULTI_VALUE_METHODS.include?(scope)
995
- if clause_method
996
- unscope_code = "#{scope}_clause="
997
- else
998
- unscope_code = "#{scope}_value#{'s' if multi_val_method}="
999
- end
955
+ arel.distinct(distinct_value)
956
+ arel.from(build_from) unless from_clause.empty?
957
+ arel.lock(lock_value) if lock_value
1000
958
 
1001
- case scope
1002
- when :order
1003
- result = []
1004
- else
1005
- result = [] if multi_val_method
959
+ arel
1006
960
  end
1007
961
 
1008
- self.send(unscope_code, result)
1009
- end
1010
-
1011
- def association_for_table(table_name)
1012
- table_name = table_name.to_s
1013
- @klass._reflect_on_association(table_name) ||
1014
- @klass._reflect_on_association(table_name.singularize)
1015
- end
1016
-
1017
- def build_from
1018
- opts = from_clause.value
1019
- name = from_clause.name
1020
- case opts
1021
- when Relation
1022
- name ||= 'subquery'
1023
- opts.arel.as(name.to_s)
1024
- else
1025
- opts
1026
- end
1027
- end
1028
-
1029
- def build_left_outer_joins(manager, outer_joins)
1030
- buckets = outer_joins.group_by do |join|
1031
- case join
1032
- when Hash, Symbol, Array
1033
- :association_join
962
+ def build_from
963
+ opts = from_clause.value
964
+ name = from_clause.name
965
+ case opts
966
+ when Relation
967
+ name ||= "subquery"
968
+ opts.arel.as(name.to_s)
1034
969
  else
1035
- raise ArgumentError, 'only Hash, Symbol and Array are allowed'
970
+ opts
1036
971
  end
1037
972
  end
1038
973
 
1039
- build_join_query(manager, buckets, Arel::Nodes::OuterJoin)
1040
- end
1041
-
1042
- def build_joins(manager, joins)
1043
- buckets = joins.group_by do |join|
1044
- case join
1045
- when String
1046
- :string_join
1047
- when Hash, Symbol, Array
1048
- :association_join
1049
- when ActiveRecord::Associations::JoinDependency
1050
- :stashed_join
1051
- when Arel::Nodes::Join
1052
- :join_node
1053
- else
1054
- raise 'unknown class: %s' % join.class.name
974
+ def build_left_outer_joins(manager, outer_joins)
975
+ buckets = outer_joins.group_by do |join|
976
+ case join
977
+ when Hash, Symbol, Array
978
+ :association_join
979
+ else
980
+ raise ArgumentError, "only Hash, Symbol and Array are allowed"
981
+ end
1055
982
  end
983
+
984
+ build_join_query(manager, buckets, Arel::Nodes::OuterJoin)
1056
985
  end
1057
986
 
1058
- build_join_query(manager, buckets, Arel::Nodes::InnerJoin)
1059
- end
987
+ def build_joins(manager, joins)
988
+ buckets = joins.group_by do |join|
989
+ case join
990
+ when String
991
+ :string_join
992
+ when Hash, Symbol, Array
993
+ :association_join
994
+ when ActiveRecord::Associations::JoinDependency
995
+ :stashed_join
996
+ when Arel::Nodes::Join
997
+ :join_node
998
+ else
999
+ raise "unknown class: %s" % join.class.name
1000
+ end
1001
+ end
1060
1002
 
1061
- def build_join_query(manager, buckets, join_type)
1062
- buckets.default = []
1003
+ build_join_query(manager, buckets, Arel::Nodes::InnerJoin)
1004
+ end
1063
1005
 
1064
- association_joins = buckets[:association_join]
1065
- stashed_association_joins = buckets[:stashed_join]
1066
- join_nodes = buckets[:join_node].uniq
1067
- string_joins = buckets[:string_join].map(&:strip).uniq
1006
+ def build_join_query(manager, buckets, join_type)
1007
+ buckets.default = []
1068
1008
 
1069
- join_list = join_nodes + convert_join_strings_to_ast(manager, string_joins)
1009
+ association_joins = buckets[:association_join]
1010
+ stashed_association_joins = buckets[:stashed_join]
1011
+ join_nodes = buckets[:join_node].uniq
1012
+ string_joins = buckets[:string_join].map(&:strip).uniq
1070
1013
 
1071
- join_dependency = ActiveRecord::Associations::JoinDependency.new(
1072
- @klass,
1073
- association_joins,
1074
- join_list
1075
- )
1014
+ join_list = join_nodes + convert_join_strings_to_ast(manager, string_joins)
1076
1015
 
1077
- join_infos = join_dependency.join_constraints stashed_association_joins, join_type
1016
+ join_dependency = ActiveRecord::Associations::JoinDependency.new(
1017
+ @klass,
1018
+ association_joins,
1019
+ join_list
1020
+ )
1078
1021
 
1079
- join_infos.each do |info|
1080
- info.joins.each { |join| manager.from(join) }
1081
- manager.bind_values.concat info.binds
1082
- end
1022
+ join_infos = join_dependency.join_constraints stashed_association_joins, join_type
1083
1023
 
1084
- manager.join_sources.concat(join_list)
1024
+ join_infos.each do |info|
1025
+ info.joins.each { |join| manager.from(join) }
1026
+ manager.bind_values.concat info.binds
1027
+ end
1085
1028
 
1086
- manager
1087
- end
1029
+ manager.join_sources.concat(join_list)
1088
1030
 
1089
- def convert_join_strings_to_ast(table, joins)
1090
- joins
1091
- .flatten
1092
- .reject(&:blank?)
1093
- .map { |join| table.create_string_join(Arel.sql(join)) }
1094
- end
1031
+ manager
1032
+ end
1095
1033
 
1096
- def build_select(arel)
1097
- if select_values.any?
1098
- arel.project(*arel_columns(select_values.uniq))
1099
- else
1100
- arel.project(@klass.arel_table[Arel.star])
1034
+ def convert_join_strings_to_ast(table, joins)
1035
+ joins
1036
+ .flatten
1037
+ .reject(&:blank?)
1038
+ .map { |join| table.create_string_join(Arel.sql(join)) }
1101
1039
  end
1102
- end
1103
1040
 
1104
- def arel_columns(columns)
1105
- columns.map do |field|
1106
- if (Symbol === field || String === field) && (klass.has_attribute?(field) || klass.attribute_alias?(field)) && !from_clause.value
1107
- arel_attribute(field)
1108
- elsif Symbol === field
1109
- connection.quote_table_name(field.to_s)
1041
+ def build_select(arel)
1042
+ if select_values.any?
1043
+ arel.project(*arel_columns(select_values.uniq))
1110
1044
  else
1111
- field
1045
+ arel.project(@klass.arel_table[Arel.star])
1112
1046
  end
1113
1047
  end
1114
- end
1115
1048
 
1116
- def reverse_sql_order(order_query)
1117
- if order_query.empty?
1118
- return [arel_attribute(primary_key).desc] if primary_key
1119
- raise IrreversibleOrderError,
1120
- "Relation has no current order and table has no primary key to be used as default order"
1049
+ def arel_columns(columns)
1050
+ columns.map do |field|
1051
+ if (Symbol === field || String === field) && (klass.has_attribute?(field) || klass.attribute_alias?(field)) && !from_clause.value
1052
+ arel_attribute(field)
1053
+ elsif Symbol === field
1054
+ connection.quote_table_name(field.to_s)
1055
+ else
1056
+ field
1057
+ end
1058
+ end
1121
1059
  end
1122
1060
 
1123
- order_query.flat_map do |o|
1124
- case o
1125
- when Arel::Attribute
1126
- o.desc
1127
- when Arel::Nodes::Ordering
1128
- o.reverse
1129
- when String
1130
- if does_not_support_reverse?(o)
1131
- raise IrreversibleOrderError, "Order #{o.inspect} can not be reversed automatically"
1132
- end
1133
- o.split(',').map! do |s|
1134
- s.strip!
1135
- s.gsub!(/\sasc\Z/i, ' DESC') || s.gsub!(/\sdesc\Z/i, ' ASC') || s.concat(' DESC')
1061
+ def reverse_sql_order(order_query)
1062
+ if order_query.empty?
1063
+ return [arel_attribute(primary_key).desc] if primary_key
1064
+ raise IrreversibleOrderError,
1065
+ "Relation has no current order and table has no primary key to be used as default order"
1066
+ end
1067
+
1068
+ order_query.flat_map do |o|
1069
+ case o
1070
+ when Arel::Attribute
1071
+ o.desc
1072
+ when Arel::Nodes::Ordering
1073
+ o.reverse
1074
+ when String
1075
+ if does_not_support_reverse?(o)
1076
+ raise IrreversibleOrderError, "Order #{o.inspect} can not be reversed automatically"
1077
+ end
1078
+ o.split(",").map! do |s|
1079
+ s.strip!
1080
+ s.gsub!(/\sasc\Z/i, " DESC") || s.gsub!(/\sdesc\Z/i, " ASC") || s.concat(" DESC")
1081
+ end
1082
+ else
1083
+ o
1136
1084
  end
1137
- else
1138
- o
1139
1085
  end
1140
1086
  end
1141
- end
1142
1087
 
1143
- def does_not_support_reverse?(order)
1144
- # Uses SQL function with multiple arguments.
1145
- (order.include?(',') && order.split(',').find { |section| section.count('(') != section.count(')')}) ||
1146
- # Uses "nulls first" like construction.
1147
- order =~ /nulls (first|last)\Z/i
1148
- end
1088
+ def does_not_support_reverse?(order)
1089
+ # Uses SQL function with multiple arguments.
1090
+ (order.include?(",") && order.split(",").find { |section| section.count("(") != section.count(")") }) ||
1091
+ # Uses "nulls first" like construction.
1092
+ /nulls (first|last)\Z/i.match?(order)
1093
+ end
1149
1094
 
1150
- def build_order(arel)
1151
- orders = order_values.uniq
1152
- orders.reject!(&:blank?)
1095
+ def build_order(arel)
1096
+ orders = order_values.uniq
1097
+ orders.reject!(&:blank?)
1153
1098
 
1154
- arel.order(*orders) unless orders.empty?
1155
- end
1099
+ arel.order(*orders) unless orders.empty?
1100
+ end
1156
1101
 
1157
- VALID_DIRECTIONS = [:asc, :desc, :ASC, :DESC,
1158
- 'asc', 'desc', 'ASC', 'DESC'] # :nodoc:
1102
+ VALID_DIRECTIONS = [:asc, :desc, :ASC, :DESC,
1103
+ "asc", "desc", "ASC", "DESC"] # :nodoc:
1159
1104
 
1160
- def validate_order_args(args)
1161
- args.each do |arg|
1162
- next unless arg.is_a?(Hash)
1163
- arg.each do |_key, value|
1164
- raise ArgumentError, "Direction \"#{value}\" is invalid. Valid " \
1165
- "directions are: #{VALID_DIRECTIONS.inspect}" unless VALID_DIRECTIONS.include?(value)
1105
+ def validate_order_args(args)
1106
+ args.each do |arg|
1107
+ next unless arg.is_a?(Hash)
1108
+ arg.each do |_key, value|
1109
+ raise ArgumentError, "Direction \"#{value}\" is invalid. Valid " \
1110
+ "directions are: #{VALID_DIRECTIONS.inspect}" unless VALID_DIRECTIONS.include?(value)
1111
+ end
1166
1112
  end
1167
1113
  end
1168
- end
1169
1114
 
1170
- def preprocess_order_args(order_args)
1171
- order_args.map! do |arg|
1172
- klass.send(:sanitize_sql_for_order, arg)
1115
+ def preprocess_order_args(order_args)
1116
+ order_args.map! do |arg|
1117
+ klass.send(:sanitize_sql_for_order, arg)
1118
+ end
1119
+ order_args.flatten!
1120
+ validate_order_args(order_args)
1121
+
1122
+ references = order_args.grep(String)
1123
+ references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact!
1124
+ references!(references) if references.any?
1125
+
1126
+ # if a symbol is given we prepend the quoted table name
1127
+ order_args.map! do |arg|
1128
+ case arg
1129
+ when Symbol
1130
+ arel_attribute(arg).asc
1131
+ when Hash
1132
+ arg.map { |field, dir|
1133
+ arel_attribute(field).send(dir.downcase)
1134
+ }
1135
+ else
1136
+ arg
1137
+ end
1138
+ end.flatten!
1173
1139
  end
1174
- order_args.flatten!
1175
- validate_order_args(order_args)
1176
-
1177
- references = order_args.grep(String)
1178
- references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact!
1179
- references!(references) if references.any?
1180
1140
 
1181
- # if a symbol is given we prepend the quoted table name
1182
- order_args.map! do |arg|
1183
- case arg
1184
- when Symbol
1185
- arel_attribute(arg).asc
1186
- when Hash
1187
- arg.map { |field, dir|
1188
- arel_attribute(field).send(dir.downcase)
1189
- }
1190
- else
1191
- arg
1141
+ # Checks to make sure that the arguments are not blank. Note that if some
1142
+ # blank-like object were initially passed into the query method, then this
1143
+ # method will not raise an error.
1144
+ #
1145
+ # Example:
1146
+ #
1147
+ # Post.references() # raises an error
1148
+ # Post.references([]) # does not raise an error
1149
+ #
1150
+ # This particular method should be called with a method_name and the args
1151
+ # passed into that method as an input. For example:
1152
+ #
1153
+ # def references(*args)
1154
+ # check_if_method_has_arguments!("references", args)
1155
+ # ...
1156
+ # end
1157
+ def check_if_method_has_arguments!(method_name, args)
1158
+ if args.blank?
1159
+ raise ArgumentError, "The method .#{method_name}() must contain arguments."
1192
1160
  end
1193
- end.flatten!
1194
- end
1195
-
1196
- # Checks to make sure that the arguments are not blank. Note that if some
1197
- # blank-like object were initially passed into the query method, then this
1198
- # method will not raise an error.
1199
- #
1200
- # Example:
1201
- #
1202
- # Post.references() # raises an error
1203
- # Post.references([]) # does not raise an error
1204
- #
1205
- # This particular method should be called with a method_name and the args
1206
- # passed into that method as an input. For example:
1207
- #
1208
- # def references(*args)
1209
- # check_if_method_has_arguments!("references", args)
1210
- # ...
1211
- # end
1212
- def check_if_method_has_arguments!(method_name, args)
1213
- if args.blank?
1214
- raise ArgumentError, "The method .#{method_name}() must contain arguments."
1215
1161
  end
1216
- end
1217
1162
 
1218
- def structurally_incompatible_values_for_or(other)
1219
- Relation::SINGLE_VALUE_METHODS.reject { |m| send("#{m}_value") == other.send("#{m}_value") } +
1220
- (Relation::MULTI_VALUE_METHODS - [:extending]).reject { |m| send("#{m}_values") == other.send("#{m}_values") } +
1221
- (Relation::CLAUSE_METHODS - [:having, :where]).reject { |m| send("#{m}_clause") == other.send("#{m}_clause") }
1222
- end
1223
-
1224
- def new_where_clause
1225
- Relation::WhereClause.empty
1226
- end
1227
- alias new_having_clause new_where_clause
1228
-
1229
- def where_clause_factory
1230
- @where_clause_factory ||= Relation::WhereClauseFactory.new(klass, predicate_builder)
1231
- end
1232
- alias having_clause_factory where_clause_factory
1233
-
1234
- def new_from_clause
1235
- Relation::FromClause.empty
1236
- end
1163
+ STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having]
1164
+ def structurally_incompatible_values_for_or(other)
1165
+ STRUCTURAL_OR_METHODS.reject do |method|
1166
+ get_value(method) == other.get_value(method)
1167
+ end
1168
+ end
1237
1169
 
1238
- def string_containing_comma?(value)
1239
- ::String === value && value.include?(",")
1240
- end
1170
+ def where_clause_factory
1171
+ @where_clause_factory ||= Relation::WhereClauseFactory.new(klass, predicate_builder)
1172
+ end
1173
+ alias having_clause_factory where_clause_factory
1174
+
1175
+ def default_value_for(name)
1176
+ case name
1177
+ when :create_with
1178
+ FROZEN_EMPTY_HASH
1179
+ when :readonly
1180
+ false
1181
+ when :where, :having
1182
+ Relation::WhereClause.empty
1183
+ when :from
1184
+ Relation::FromClause.empty
1185
+ when *Relation::MULTI_VALUE_METHODS
1186
+ FROZEN_EMPTY_ARRAY
1187
+ when *Relation::SINGLE_VALUE_METHODS
1188
+ nil
1189
+ else
1190
+ raise ArgumentError, "unknown relation value #{name.inspect}"
1191
+ end
1192
+ end
1241
1193
  end
1242
1194
  end