activerecord 5.1.5 → 5.2.1

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 (261) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +450 -699
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -5
  5. data/examples/performance.rb +2 -0
  6. data/examples/simple.rb +2 -0
  7. data/lib/active_record/aggregations.rb +6 -5
  8. data/lib/active_record/association_relation.rb +4 -2
  9. data/lib/active_record/associations/alias_tracker.rb +19 -27
  10. data/lib/active_record/associations/association.rb +33 -37
  11. data/lib/active_record/associations/association_scope.rb +38 -50
  12. data/lib/active_record/associations/belongs_to_association.rb +28 -9
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
  14. data/lib/active_record/associations/builder/association.rb +4 -7
  15. data/lib/active_record/associations/builder/belongs_to.rb +14 -5
  16. data/lib/active_record/associations/builder/collection_association.rb +1 -1
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
  18. data/lib/active_record/associations/builder/has_many.rb +2 -0
  19. data/lib/active_record/associations/builder/has_one.rb +2 -0
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  21. data/lib/active_record/associations/collection_association.rb +52 -41
  22. data/lib/active_record/associations/collection_proxy.rb +12 -15
  23. data/lib/active_record/associations/foreign_association.rb +2 -0
  24. data/lib/active_record/associations/has_many_association.rb +3 -1
  25. data/lib/active_record/associations/has_many_through_association.rb +8 -19
  26. data/lib/active_record/associations/has_one_association.rb +12 -1
  27. data/lib/active_record/associations/has_one_through_association.rb +13 -8
  28. data/lib/active_record/associations/join_dependency/join_association.rb +22 -67
  29. data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
  30. data/lib/active_record/associations/join_dependency/join_part.rb +9 -9
  31. data/lib/active_record/associations/join_dependency.rb +48 -93
  32. data/lib/active_record/associations/preloader/association.rb +45 -61
  33. data/lib/active_record/associations/preloader/through_association.rb +71 -79
  34. data/lib/active_record/associations/preloader.rb +17 -37
  35. data/lib/active_record/associations/singular_association.rb +14 -16
  36. data/lib/active_record/associations/through_association.rb +26 -11
  37. data/lib/active_record/associations.rb +40 -63
  38. data/lib/active_record/attribute_assignment.rb +2 -5
  39. data/lib/active_record/attribute_decorators.rb +3 -2
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
  41. data/lib/active_record/attribute_methods/dirty.rb +25 -214
  42. data/lib/active_record/attribute_methods/primary_key.rb +7 -6
  43. data/lib/active_record/attribute_methods/query.rb +2 -0
  44. data/lib/active_record/attribute_methods/read.rb +9 -3
  45. data/lib/active_record/attribute_methods/serialization.rb +23 -0
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
  47. data/lib/active_record/attribute_methods/write.rb +21 -9
  48. data/lib/active_record/attribute_methods.rb +65 -24
  49. data/lib/active_record/attributes.rb +7 -6
  50. data/lib/active_record/autosave_association.rb +16 -14
  51. data/lib/active_record/base.rb +2 -0
  52. data/lib/active_record/callbacks.rb +12 -6
  53. data/lib/active_record/coders/json.rb +2 -0
  54. data/lib/active_record/coders/yaml_column.rb +2 -0
  55. data/lib/active_record/collection_cache_key.rb +11 -7
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +110 -35
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -0
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +157 -29
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +7 -2
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -32
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +14 -5
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +64 -6
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +149 -78
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +81 -96
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +92 -165
  69. data/lib/active_record/connection_adapters/column.rb +3 -1
  70. data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +2 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +47 -2
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +6 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -1
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +8 -2
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +248 -112
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -0
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +57 -73
  117. data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +20 -1
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +75 -1
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +79 -92
  126. data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
  127. data/lib/active_record/connection_handling.rb +4 -2
  128. data/lib/active_record/core.rb +39 -60
  129. data/lib/active_record/counter_cache.rb +20 -15
  130. data/lib/active_record/define_callbacks.rb +5 -3
  131. data/lib/active_record/dynamic_matchers.rb +9 -9
  132. data/lib/active_record/enum.rb +17 -13
  133. data/lib/active_record/errors.rb +42 -3
  134. data/lib/active_record/explain.rb +3 -1
  135. data/lib/active_record/explain_registry.rb +2 -0
  136. data/lib/active_record/explain_subscriber.rb +2 -0
  137. data/lib/active_record/fixture_set/file.rb +2 -0
  138. data/lib/active_record/fixtures.rb +67 -60
  139. data/lib/active_record/gem_version.rb +4 -2
  140. data/lib/active_record/inheritance.rb +49 -19
  141. data/lib/active_record/integration.rb +58 -19
  142. data/lib/active_record/internal_metadata.rb +2 -0
  143. data/lib/active_record/legacy_yaml_adapter.rb +3 -1
  144. data/lib/active_record/locking/optimistic.rb +30 -42
  145. data/lib/active_record/locking/pessimistic.rb +9 -6
  146. data/lib/active_record/log_subscriber.rb +43 -0
  147. data/lib/active_record/migration/command_recorder.rb +11 -9
  148. data/lib/active_record/migration/compatibility.rb +40 -2
  149. data/lib/active_record/migration/join_table.rb +2 -0
  150. data/lib/active_record/migration.rb +189 -139
  151. data/lib/active_record/model_schema.rb +19 -24
  152. data/lib/active_record/nested_attributes.rb +18 -6
  153. data/lib/active_record/no_touching.rb +3 -1
  154. data/lib/active_record/null_relation.rb +2 -0
  155. data/lib/active_record/persistence.rb +196 -48
  156. data/lib/active_record/query_cache.rb +12 -14
  157. data/lib/active_record/querying.rb +3 -1
  158. data/lib/active_record/railtie.rb +61 -3
  159. data/lib/active_record/railties/console_sandbox.rb +2 -0
  160. data/lib/active_record/railties/controller_runtime.rb +2 -0
  161. data/lib/active_record/railties/databases.rake +46 -36
  162. data/lib/active_record/readonly_attributes.rb +3 -2
  163. data/lib/active_record/reflection.rb +110 -192
  164. data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
  165. data/lib/active_record/relation/batches.rb +20 -5
  166. data/lib/active_record/relation/calculations.rb +31 -9
  167. data/lib/active_record/relation/delegation.rb +15 -27
  168. data/lib/active_record/relation/finder_methods.rb +71 -76
  169. data/lib/active_record/relation/from_clause.rb +2 -8
  170. data/lib/active_record/relation/merger.rb +47 -20
  171. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
  172. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  173. data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
  174. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
  175. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  176. data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
  177. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  178. data/lib/active_record/relation/predicate_builder.rb +55 -79
  179. data/lib/active_record/relation/query_attribute.rb +26 -2
  180. data/lib/active_record/relation/query_methods.rb +95 -91
  181. data/lib/active_record/relation/record_fetch_warning.rb +2 -0
  182. data/lib/active_record/relation/spawn_methods.rb +3 -1
  183. data/lib/active_record/relation/where_clause.rb +65 -68
  184. data/lib/active_record/relation/where_clause_factory.rb +5 -48
  185. data/lib/active_record/relation.rb +106 -219
  186. data/lib/active_record/result.rb +2 -0
  187. data/lib/active_record/runtime_registry.rb +2 -0
  188. data/lib/active_record/sanitization.rb +129 -121
  189. data/lib/active_record/schema.rb +4 -2
  190. data/lib/active_record/schema_dumper.rb +36 -26
  191. data/lib/active_record/schema_migration.rb +2 -0
  192. data/lib/active_record/scoping/default.rb +6 -7
  193. data/lib/active_record/scoping/named.rb +21 -7
  194. data/lib/active_record/scoping.rb +9 -8
  195. data/lib/active_record/secure_token.rb +2 -0
  196. data/lib/active_record/serialization.rb +2 -0
  197. data/lib/active_record/statement_cache.rb +22 -12
  198. data/lib/active_record/store.rb +3 -1
  199. data/lib/active_record/suppressor.rb +2 -0
  200. data/lib/active_record/table_metadata.rb +12 -3
  201. data/lib/active_record/tasks/database_tasks.rb +25 -14
  202. data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
  203. data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
  204. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
  205. data/lib/active_record/timestamp.rb +13 -6
  206. data/lib/active_record/touch_later.rb +2 -0
  207. data/lib/active_record/transactions.rb +32 -27
  208. data/lib/active_record/translation.rb +2 -0
  209. data/lib/active_record/type/adapter_specific_registry.rb +2 -0
  210. data/lib/active_record/type/date.rb +2 -0
  211. data/lib/active_record/type/date_time.rb +2 -0
  212. data/lib/active_record/type/decimal_without_scale.rb +2 -0
  213. data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
  214. data/lib/active_record/type/internal/timezone.rb +2 -0
  215. data/lib/active_record/type/json.rb +30 -0
  216. data/lib/active_record/type/serialized.rb +6 -0
  217. data/lib/active_record/type/text.rb +2 -0
  218. data/lib/active_record/type/time.rb +2 -0
  219. data/lib/active_record/type/type_map.rb +2 -0
  220. data/lib/active_record/type/unsigned_integer.rb +2 -0
  221. data/lib/active_record/type.rb +4 -1
  222. data/lib/active_record/type_caster/connection.rb +2 -0
  223. data/lib/active_record/type_caster/map.rb +3 -1
  224. data/lib/active_record/type_caster.rb +2 -0
  225. data/lib/active_record/validations/absence.rb +2 -0
  226. data/lib/active_record/validations/associated.rb +2 -0
  227. data/lib/active_record/validations/length.rb +2 -0
  228. data/lib/active_record/validations/presence.rb +2 -0
  229. data/lib/active_record/validations/uniqueness.rb +36 -6
  230. data/lib/active_record/validations.rb +2 -0
  231. data/lib/active_record/version.rb +2 -0
  232. data/lib/active_record.rb +11 -4
  233. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  234. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  235. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
  236. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
  237. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
  238. data/lib/rails/generators/active_record/migration.rb +2 -0
  239. data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
  240. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
  241. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  242. data/lib/rails/generators/active_record.rb +3 -1
  243. metadata +23 -36
  244. data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
  245. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  246. data/lib/active_record/associations/preloader/has_many.rb +0 -15
  247. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  248. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  249. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  250. data/lib/active_record/associations/preloader/singular_association.rb +0 -18
  251. data/lib/active_record/attribute/user_provided_default.rb +0 -30
  252. data/lib/active_record/attribute.rb +0 -240
  253. data/lib/active_record/attribute_mutation_tracker.rb +0 -114
  254. data/lib/active_record/attribute_set/builder.rb +0 -124
  255. data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
  256. data/lib/active_record/attribute_set.rb +0 -113
  257. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
  258. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  259. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  260. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
  261. data/lib/active_record/type/internal/abstract_json.rb +0 -37
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_record/relation/from_clause"
2
4
  require "active_record/relation/query_attribute"
3
5
  require "active_record/relation/where_clause"
@@ -74,31 +76,6 @@ module ActiveRecord
74
76
  CODE
75
77
  end
76
78
 
77
- def bound_attributes
78
- if limit_value
79
- limit_bind = Attribute.with_cast_value(
80
- "LIMIT".freeze,
81
- connection.sanitize_limit(limit_value),
82
- Type.default_value,
83
- )
84
- end
85
- if offset_value
86
- offset_bind = Attribute.with_cast_value(
87
- "OFFSET".freeze,
88
- offset_value.to_i,
89
- Type.default_value,
90
- )
91
- end
92
- connection.combine_bind_parameters(
93
- from_clause: from_clause.binds,
94
- join_clause: arel.bind_values,
95
- where_clause: where_clause.binds,
96
- having_clause: having_clause.binds,
97
- limit: limit_bind,
98
- offset: offset_bind,
99
- )
100
- end
101
-
102
79
  alias extensions extending_values
103
80
 
104
81
  # Specify relationships to be included in the result set. For
@@ -202,12 +179,13 @@ module ActiveRecord
202
179
 
203
180
  # Works in two unique ways.
204
181
  #
205
- # First: takes a block so it can be used just like +Array#select+.
182
+ # First: takes a block so it can be used just like <tt>Array#select</tt>.
206
183
  #
207
184
  # Model.all.select { |m| m.field == value }
208
185
  #
209
186
  # This will build an array of objects from the database for the scope,
210
- # converting them into an array and iterating through them using +Array#select+.
187
+ # converting them into an array and iterating through them using
188
+ # <tt>Array#select</tt>.
211
189
  #
212
190
  # Second: Modifies the SELECT statement for the query so that only certain
213
191
  # fields are retrieved:
@@ -248,7 +226,7 @@ module ActiveRecord
248
226
  return super()
249
227
  end
250
228
 
251
- raise ArgumentError, "Call this with at least one field" if fields.empty?
229
+ raise ArgumentError, "Call `select' with at least one field" if fields.empty?
252
230
  spawn._select!(*fields)
253
231
  end
254
232
 
@@ -317,6 +295,7 @@ module ActiveRecord
317
295
  spawn.order!(*args)
318
296
  end
319
297
 
298
+ # Same as #order but operates on relation in-place instead of copying.
320
299
  def order!(*args) # :nodoc:
321
300
  preprocess_order_args(args)
322
301
 
@@ -338,6 +317,7 @@ module ActiveRecord
338
317
  spawn.reorder!(*args)
339
318
  end
340
319
 
320
+ # Same as #reorder but operates on relation in-place instead of copying.
341
321
  def reorder!(*args) # :nodoc:
342
322
  preprocess_order_args(args)
343
323
 
@@ -347,8 +327,8 @@ module ActiveRecord
347
327
  end
348
328
 
349
329
  VALID_UNSCOPING_VALUES = Set.new([:where, :select, :group, :order, :lock,
350
- :limit, :offset, :joins, :includes, :from,
351
- :readonly, :having])
330
+ :limit, :offset, :joins, :left_outer_joins,
331
+ :includes, :from, :readonly, :having])
352
332
 
353
333
  # Removes an unwanted relation that is already defined on a chain of relations.
354
334
  # This is useful when passing around chains of relations and would like to
@@ -395,10 +375,11 @@ module ActiveRecord
395
375
  args.each do |scope|
396
376
  case scope
397
377
  when Symbol
378
+ scope = :left_outer_joins if scope == :left_joins
398
379
  if !VALID_UNSCOPING_VALUES.include?(scope)
399
380
  raise ArgumentError, "Called unscope() with invalid unscoping argument ':#{scope}'. Valid arguments are :#{VALID_UNSCOPING_VALUES.to_a.join(", :")}."
400
381
  end
401
- set_value(scope, nil)
382
+ set_value(scope, DEFAULT_VALUES[scope])
402
383
  when Hash
403
384
  scope.each do |key, target_value|
404
385
  if key != :where
@@ -463,16 +444,14 @@ module ActiveRecord
463
444
  # => SELECT "users".* FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
464
445
  #
465
446
  def left_outer_joins(*args)
466
- check_if_method_has_arguments!(:left_outer_joins, args)
467
-
468
- args.compact!
469
- args.flatten!
470
-
447
+ check_if_method_has_arguments!(__callee__, args)
471
448
  spawn.left_outer_joins!(*args)
472
449
  end
473
450
  alias :left_joins :left_outer_joins
474
451
 
475
452
  def left_outer_joins!(*args) # :nodoc:
453
+ args.compact!
454
+ args.flatten!
476
455
  self.left_outer_joins_values += args
477
456
  self
478
457
  end
@@ -657,6 +636,7 @@ module ActiveRecord
657
636
 
658
637
  self.where_clause = self.where_clause.or(other.where_clause)
659
638
  self.having_clause = having_clause.or(other.having_clause)
639
+ self.references_values += other.references_values
660
640
 
661
641
  self
662
642
  end
@@ -797,7 +777,7 @@ module ActiveRecord
797
777
  value = sanitize_forbidden_attributes(value)
798
778
  self.create_with_value = create_with_value.merge(value)
799
779
  else
800
- self.create_with_value = {}
780
+ self.create_with_value = FROZEN_EMPTY_HASH
801
781
  end
802
782
 
803
783
  self
@@ -913,21 +893,28 @@ module ActiveRecord
913
893
  self
914
894
  end
915
895
 
896
+ def skip_query_cache!(value = true) # :nodoc:
897
+ self.skip_query_cache_value = value
898
+ self
899
+ end
900
+
916
901
  # Returns the Arel object associated with the relation.
917
- def arel # :nodoc:
918
- @arel ||= build_arel
902
+ def arel(aliases = nil) # :nodoc:
903
+ @arel ||= build_arel(aliases)
919
904
  end
920
905
 
921
906
  # Returns a relation value with a given name
922
907
  def get_value(name) # :nodoc:
923
- @values[name] || default_value_for(name)
908
+ @values.fetch(name, DEFAULT_VALUES[name])
924
909
  end
925
910
 
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
911
+ protected
912
+
913
+ # Sets the relation value with the given name
914
+ def set_value(name, value) # :nodoc:
915
+ assert_mutability!
916
+ @values[name] = value
917
+ end
931
918
 
932
919
  private
933
920
 
@@ -936,16 +923,30 @@ module ActiveRecord
936
923
  raise ImmutableRelation if defined?(@arel) && @arel
937
924
  end
938
925
 
939
- def build_arel
926
+ def build_arel(aliases)
940
927
  arel = Arel::SelectManager.new(table)
941
928
 
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?
929
+ aliases = build_joins(arel, joins_values.flatten, aliases) unless joins_values.empty?
930
+ build_left_outer_joins(arel, left_outer_joins_values.flatten, aliases) unless left_outer_joins_values.empty?
944
931
 
945
932
  arel.where(where_clause.ast) unless where_clause.empty?
946
933
  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
934
+ if limit_value
935
+ limit_attribute = ActiveModel::Attribute.with_cast_value(
936
+ "LIMIT".freeze,
937
+ connection.sanitize_limit(limit_value),
938
+ Type.default_value,
939
+ )
940
+ arel.take(Arel::Nodes::BindParam.new(limit_attribute))
941
+ end
942
+ if offset_value
943
+ offset_attribute = ActiveModel::Attribute.with_cast_value(
944
+ "OFFSET".freeze,
945
+ offset_value.to_i,
946
+ Type.default_value,
947
+ )
948
+ arel.skip(Arel::Nodes::BindParam.new(offset_attribute))
949
+ end
949
950
  arel.group(*arel_columns(group_values.uniq.reject(&:blank?))) unless group_values.empty?
950
951
 
951
952
  build_order(arel)
@@ -964,6 +965,9 @@ module ActiveRecord
964
965
  name = from_clause.name
965
966
  case opts
966
967
  when Relation
968
+ if opts.eager_loading?
969
+ opts = opts.send(:apply_join_dependency)
970
+ end
967
971
  name ||= "subquery"
968
972
  opts.arel.as(name.to_s)
969
973
  else
@@ -971,20 +975,22 @@ module ActiveRecord
971
975
  end
972
976
  end
973
977
 
974
- def build_left_outer_joins(manager, outer_joins)
978
+ def build_left_outer_joins(manager, outer_joins, aliases)
975
979
  buckets = outer_joins.group_by do |join|
976
980
  case join
977
981
  when Hash, Symbol, Array
978
982
  :association_join
983
+ when ActiveRecord::Associations::JoinDependency
984
+ :stashed_join
979
985
  else
980
986
  raise ArgumentError, "only Hash, Symbol and Array are allowed"
981
987
  end
982
988
  end
983
989
 
984
- build_join_query(manager, buckets, Arel::Nodes::OuterJoin)
990
+ build_join_query(manager, buckets, Arel::Nodes::OuterJoin, aliases)
985
991
  end
986
992
 
987
- def build_joins(manager, joins)
993
+ def build_joins(manager, joins, aliases)
988
994
  buckets = joins.group_by do |join|
989
995
  case join
990
996
  when String
@@ -1000,38 +1006,33 @@ module ActiveRecord
1000
1006
  end
1001
1007
  end
1002
1008
 
1003
- build_join_query(manager, buckets, Arel::Nodes::InnerJoin)
1009
+ build_join_query(manager, buckets, Arel::Nodes::InnerJoin, aliases)
1004
1010
  end
1005
1011
 
1006
- def build_join_query(manager, buckets, join_type)
1012
+ def build_join_query(manager, buckets, join_type, aliases)
1007
1013
  buckets.default = []
1008
1014
 
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
1015
+ association_joins = buckets[:association_join]
1016
+ stashed_joins = buckets[:stashed_join]
1017
+ join_nodes = buckets[:join_node].uniq
1018
+ string_joins = buckets[:string_join].map(&:strip).uniq
1013
1019
 
1014
- join_list = join_nodes + convert_join_strings_to_ast(manager, string_joins)
1020
+ join_list = join_nodes + convert_join_strings_to_ast(string_joins)
1021
+ alias_tracker = alias_tracker(join_list, aliases)
1015
1022
 
1016
1023
  join_dependency = ActiveRecord::Associations::JoinDependency.new(
1017
- @klass,
1018
- association_joins,
1019
- join_list
1024
+ klass, table, association_joins
1020
1025
  )
1021
1026
 
1022
- join_infos = join_dependency.join_constraints stashed_association_joins, join_type
1023
-
1024
- join_infos.each do |info|
1025
- info.joins.each { |join| manager.from(join) }
1026
- manager.bind_values.concat info.binds
1027
- end
1027
+ joins = join_dependency.join_constraints(stashed_joins, join_type, alias_tracker)
1028
+ joins.each { |join| manager.from(join) }
1028
1029
 
1029
1030
  manager.join_sources.concat(join_list)
1030
1031
 
1031
- manager
1032
+ alias_tracker.aliases
1032
1033
  end
1033
1034
 
1034
- def convert_join_strings_to_ast(table, joins)
1035
+ def convert_join_strings_to_ast(joins)
1035
1036
  joins
1036
1037
  .flatten
1037
1038
  .reject(&:blank?)
@@ -1044,16 +1045,18 @@ module ActiveRecord
1044
1045
  elsif klass.ignored_columns.any?
1045
1046
  arel.project(*klass.column_names.map { |field| arel_attribute(field) })
1046
1047
  else
1047
- arel.project(@klass.arel_table[Arel.star])
1048
+ arel.project(table[Arel.star])
1048
1049
  end
1049
1050
  end
1050
1051
 
1051
1052
  def arel_columns(columns)
1052
- columns.map do |field|
1053
+ columns.flat_map do |field|
1053
1054
  if (Symbol === field || String === field) && (klass.has_attribute?(field) || klass.attribute_alias?(field)) && !from_clause.value
1054
1055
  arel_attribute(field)
1055
1056
  elsif Symbol === field
1056
1057
  connection.quote_table_name(field.to_s)
1058
+ elsif Proc === field
1059
+ field.call
1057
1060
  else
1058
1061
  field
1059
1062
  end
@@ -1079,7 +1082,7 @@ module ActiveRecord
1079
1082
  end
1080
1083
  o.split(",").map! do |s|
1081
1084
  s.strip!
1082
- s.gsub!(/\sasc\Z/i, " DESC") || s.gsub!(/\sdesc\Z/i, " ASC") || s.concat(" DESC")
1085
+ s.gsub!(/\sasc\Z/i, " DESC") || s.gsub!(/\sdesc\Z/i, " ASC") || (s << " DESC")
1083
1086
  end
1084
1087
  else
1085
1088
  o
@@ -1088,6 +1091,10 @@ module ActiveRecord
1088
1091
  end
1089
1092
 
1090
1093
  def does_not_support_reverse?(order)
1094
+ # Account for String subclasses like Arel::Nodes::SqlLiteral that
1095
+ # override methods like #count.
1096
+ order = String.new(order) unless order.instance_of?(String)
1097
+
1091
1098
  # Uses SQL function with multiple arguments.
1092
1099
  (order.include?(",") && order.split(",").find { |section| section.count("(") != section.count(")") }) ||
1093
1100
  # Uses "nulls first" like construction.
@@ -1102,27 +1109,35 @@ module ActiveRecord
1102
1109
  end
1103
1110
 
1104
1111
  VALID_DIRECTIONS = [:asc, :desc, :ASC, :DESC,
1105
- "asc", "desc", "ASC", "DESC"] # :nodoc:
1112
+ "asc", "desc", "ASC", "DESC"].to_set # :nodoc:
1106
1113
 
1107
1114
  def validate_order_args(args)
1108
1115
  args.each do |arg|
1109
1116
  next unless arg.is_a?(Hash)
1110
1117
  arg.each do |_key, value|
1111
- raise ArgumentError, "Direction \"#{value}\" is invalid. Valid " \
1112
- "directions are: #{VALID_DIRECTIONS.inspect}" unless VALID_DIRECTIONS.include?(value)
1118
+ unless VALID_DIRECTIONS.include?(value)
1119
+ raise ArgumentError,
1120
+ "Direction \"#{value}\" is invalid. Valid directions are: #{VALID_DIRECTIONS.to_a.inspect}"
1121
+ end
1113
1122
  end
1114
1123
  end
1115
1124
  end
1116
1125
 
1117
1126
  def preprocess_order_args(order_args)
1118
1127
  order_args.map! do |arg|
1119
- klass.send(:sanitize_sql_for_order, arg)
1128
+ klass.sanitize_sql_for_order(arg)
1120
1129
  end
1121
1130
  order_args.flatten!
1131
+
1132
+ @klass.enforce_raw_sql_whitelist(
1133
+ order_args.flat_map { |a| a.is_a?(Hash) ? a.keys : a },
1134
+ whitelist: AttributeMethods::ClassMethods::COLUMN_NAME_ORDER_WHITELIST
1135
+ )
1136
+
1122
1137
  validate_order_args(order_args)
1123
1138
 
1124
1139
  references = order_args.grep(String)
1125
- references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact!
1140
+ references.map! { |arg| arg =~ /^\W?(\w+)\W?\./ && $1 }.compact!
1126
1141
  references!(references) if references.any?
1127
1142
 
1128
1143
  # if a symbol is given we prepend the quoted table name
@@ -1167,7 +1182,7 @@ module ActiveRecord
1167
1182
  end
1168
1183
  end
1169
1184
 
1170
- STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having]
1185
+ STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having, :unscope, :references]
1171
1186
  def structurally_incompatible_values_for_or(other)
1172
1187
  STRUCTURAL_OR_METHODS.reject do |method|
1173
1188
  get_value(method) == other.get_value(method)
@@ -1181,7 +1196,6 @@ module ActiveRecord
1181
1196
 
1182
1197
  DEFAULT_VALUES = {
1183
1198
  create_with: FROZEN_EMPTY_HASH,
1184
- readonly: false,
1185
1199
  where: Relation::WhereClause.empty,
1186
1200
  having: Relation::WhereClause.empty,
1187
1201
  from: Relation::FromClause.empty
@@ -1190,15 +1204,5 @@ module ActiveRecord
1190
1204
  Relation::MULTI_VALUE_METHODS.each do |value|
1191
1205
  DEFAULT_VALUES[value] ||= FROZEN_EMPTY_ARRAY
1192
1206
  end
1193
-
1194
- Relation::SINGLE_VALUE_METHODS.each do |value|
1195
- DEFAULT_VALUES[value] = nil if DEFAULT_VALUES[value].nil?
1196
- end
1197
-
1198
- def default_value_for(name)
1199
- DEFAULT_VALUES.fetch(name) do
1200
- raise ArgumentError, "unknown relation value #{name.inspect}"
1201
- end
1202
- end
1203
1207
  end
1204
1208
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  class Relation
3
5
  module RecordFetchWarning
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/hash/except"
2
4
  require "active_support/core_ext/hash/slice"
3
5
  require "active_record/relation/merger"
@@ -67,7 +69,7 @@ module ActiveRecord
67
69
  private
68
70
 
69
71
  def relation_with(values)
70
- result = Relation.create(klass, table, predicate_builder, values)
72
+ result = Relation.create(klass, values: values)
71
73
  result.extend(*extending_values) if extending_values.any?
72
74
  result
73
75
  end
@@ -1,65 +1,63 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  class Relation
3
5
  class WhereClause # :nodoc:
4
- attr_reader :binds
5
-
6
6
  delegate :any?, :empty?, to: :predicates
7
7
 
8
- def initialize(predicates, binds)
8
+ def initialize(predicates)
9
9
  @predicates = predicates
10
- @binds = binds
11
10
  end
12
11
 
13
12
  def +(other)
14
13
  WhereClause.new(
15
14
  predicates + other.predicates,
16
- binds + other.binds,
15
+ )
16
+ end
17
+
18
+ def -(other)
19
+ WhereClause.new(
20
+ predicates - other.predicates,
17
21
  )
18
22
  end
19
23
 
20
24
  def merge(other)
21
25
  WhereClause.new(
22
26
  predicates_unreferenced_by(other) + other.predicates,
23
- non_conflicting_binds(other) + other.binds,
24
27
  )
25
28
  end
26
29
 
27
30
  def except(*columns)
28
- WhereClause.new(*except_predicates_and_binds(columns))
31
+ WhereClause.new(except_predicates(columns))
29
32
  end
30
33
 
31
34
  def or(other)
32
- if empty?
33
- self
34
- elsif other.empty?
35
- other
35
+ left = self - other
36
+ common = self - left
37
+ right = other - common
38
+
39
+ if left.empty? || right.empty?
40
+ common
36
41
  else
37
- WhereClause.new(
38
- [ast.or(other.ast)],
39
- binds + other.binds
42
+ or_clause = WhereClause.new(
43
+ [left.ast.or(right.ast)],
40
44
  )
45
+ common + or_clause
41
46
  end
42
47
  end
43
48
 
44
49
  def to_h(table_name = nil)
45
- equalities = predicates.grep(Arel::Nodes::Equality)
50
+ equalities = equalities(predicates)
46
51
  if table_name
47
52
  equalities = equalities.select do |node|
48
53
  node.left.relation.name == table_name
49
54
  end
50
55
  end
51
56
 
52
- binds = self.binds.map { |attr| [attr.name, attr.value] }.to_h
53
-
54
57
  equalities.map { |node|
55
- name = node.left.name
56
- [name, binds.fetch(name.to_s) {
57
- case node.right
58
- when Array then node.right.map(&:val)
59
- when Arel::Nodes::Casted, Arel::Nodes::Quoted
60
- node.right.val
61
- end
62
- }]
58
+ name = node.left.name.to_s
59
+ value = extract_node_value(node.right)
60
+ [name, value]
63
61
  }.to_h
64
62
  end
65
63
 
@@ -69,20 +67,17 @@ module ActiveRecord
69
67
 
70
68
  def ==(other)
71
69
  other.is_a?(WhereClause) &&
72
- predicates == other.predicates &&
73
- binds == other.binds
70
+ predicates == other.predicates
74
71
  end
75
72
 
76
73
  def invert
77
- WhereClause.new(inverted_predicates, binds)
74
+ WhereClause.new(inverted_predicates)
78
75
  end
79
76
 
80
77
  def self.empty
81
- @empty ||= new([], [])
78
+ @empty ||= new([])
82
79
  end
83
80
 
84
- # TODO Change this to private once we've dropped Ruby 2.2 support.
85
- # Workaround for Ruby 2.2 "private attribute?" warning.
86
81
  protected
87
82
 
88
83
  attr_reader :predicates
@@ -95,6 +90,20 @@ module ActiveRecord
95
90
  end
96
91
 
97
92
  private
93
+ def equalities(predicates)
94
+ equalities = []
95
+
96
+ predicates.each do |node|
97
+ case node
98
+ when Arel::Nodes::Equality
99
+ equalities << node
100
+ when Arel::Nodes::And
101
+ equalities.concat equalities(node.children)
102
+ end
103
+ end
104
+
105
+ equalities
106
+ end
98
107
 
99
108
  def predicates_unreferenced_by(other)
100
109
  predicates.reject do |n|
@@ -106,12 +115,6 @@ module ActiveRecord
106
115
  node.respond_to?(:operator) && node.operator == :==
107
116
  end
108
117
 
109
- def non_conflicting_binds(other)
110
- conflicts = referenced_columns & other.referenced_columns
111
- conflicts.map! { |node| node.name.to_s }
112
- binds.reject { |attr| conflicts.include?(attr.name) }
113
- end
114
-
115
118
  def inverted_predicates
116
119
  predicates.map { |node| invert_predicate(node) }
117
120
  end
@@ -131,44 +134,22 @@ module ActiveRecord
131
134
  end
132
135
  end
133
136
 
134
- def except_predicates_and_binds(columns)
135
- except_binds = []
136
- binds_index = 0
137
-
138
- predicates = self.predicates.reject do |node|
139
- binds_contains = node.grep(Arel::Nodes::BindParam).size if node.is_a?(Arel::Nodes::Node)
140
-
141
- except = \
142
- case node
143
- when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
144
- subrelation = (node.left.kind_of?(Arel::Attributes::Attribute) ? node.left : node.right)
145
- columns.include?(subrelation.name.to_s)
146
- end
147
-
148
- if except && binds_contains > 0
149
- (binds_index...(binds_index + binds_contains)).each do |i|
150
- except_binds[i] = true
151
- end
137
+ def except_predicates(columns)
138
+ predicates.reject do |node|
139
+ case node
140
+ when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
141
+ subrelation = (node.left.kind_of?(Arel::Attributes::Attribute) ? node.left : node.right)
142
+ columns.include?(subrelation.name.to_s)
152
143
  end
153
-
154
- binds_index += binds_contains if binds_contains
155
-
156
- except
157
- end
158
-
159
- binds = self.binds.reject.with_index do |_, i|
160
- except_binds[i]
161
144
  end
162
-
163
- [predicates, binds]
164
145
  end
165
146
 
166
147
  def predicates_with_wrapped_sql_literals
167
148
  non_empty_predicates.map do |node|
168
- if Arel::Nodes::Equality === node
169
- node
170
- else
149
+ case node
150
+ when Arel::Nodes::SqlLiteral, ::String
171
151
  wrap_sql_literal(node)
152
+ else node
172
153
  end
173
154
  end
174
155
  end
@@ -184,6 +165,22 @@ module ActiveRecord
184
165
  end
185
166
  Arel::Nodes::Grouping.new(node)
186
167
  end
168
+
169
+ def extract_node_value(node)
170
+ case node
171
+ when Array
172
+ node.map { |v| extract_node_value(v) }
173
+ when Arel::Nodes::Casted, Arel::Nodes::Quoted
174
+ node.val
175
+ when Arel::Nodes::BindParam
176
+ value = node.value
177
+ if value.respond_to?(:value_before_type_cast)
178
+ value.value_before_type_cast
179
+ else
180
+ value
181
+ end
182
+ end
183
+ end
187
184
  end
188
185
  end
189
186
  end