activerecord 5.1.7 → 5.2.0

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 +372 -765
  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 +16 -27
  11. data/lib/active_record/associations/association_scope.rb +38 -50
  12. data/lib/active_record/associations/belongs_to_association.rb +20 -10
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +4 -7
  14. data/lib/active_record/associations/builder/association.rb +4 -7
  15. data/lib/active_record/associations/builder/belongs_to.rb +4 -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 +43 -35
  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 +7 -18
  26. data/lib/active_record/associations/has_one_association.rb +4 -1
  27. data/lib/active_record/associations/has_one_through_association.rb +8 -7
  28. data/lib/active_record/associations/join_dependency/join_association.rb +17 -56
  29. data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
  30. data/lib/active_record/associations/join_dependency/join_part.rb +2 -9
  31. data/lib/active_record/associations/join_dependency.rb +23 -43
  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 -10
  36. data/lib/active_record/associations/through_association.rb +25 -10
  37. data/lib/active_record/associations.rb +31 -54
  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 +8 -2
  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 +6 -5
  50. data/lib/active_record/autosave_association.rb +8 -11
  51. data/lib/active_record/base.rb +2 -0
  52. data/lib/active_record/callbacks.rb +8 -10
  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 +111 -38
  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 +13 -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 +57 -2
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +158 -78
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +45 -9
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +81 -96
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +111 -183
  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 +11 -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 +3 -11
  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 +2 -0
  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 +4 -6
  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 +246 -110
  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 +58 -82
  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 +18 -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 +71 -1
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +80 -90
  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 +15 -12
  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 +54 -21
  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 +14 -17
  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 +16 -21
  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 +166 -16
  156. data/lib/active_record/query_cache.rb +11 -6
  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 +30 -8
  167. data/lib/active_record/relation/delegation.rb +15 -27
  168. data/lib/active_record/relation/finder_methods.rb +75 -78
  169. data/lib/active_record/relation/from_clause.rb +2 -8
  170. data/lib/active_record/relation/merger.rb +51 -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 +53 -78
  179. data/lib/active_record/relation/query_attribute.rb +26 -2
  180. data/lib/active_record/relation/query_methods.rb +89 -88
  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 +95 -208
  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 +26 -15
  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 +5 -12
  206. data/lib/active_record/touch_later.rb +2 -0
  207. data/lib/active_record/transactions.rb +9 -7
  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 +2 -4
  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 +35 -5
  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 +24 -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 -122
  254. data/lib/active_record/attribute_set/builder.rb +0 -126
  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,27 @@ module ActiveRecord
913
893
  self
914
894
  end
915
895
 
916
- # Returns the Arel object associated with the relation.
917
- def arel # :nodoc:
918
- @arel ||= build_arel
896
+ def skip_query_cache! # :nodoc:
897
+ self.skip_query_cache_value = true
898
+ self
919
899
  end
920
900
 
921
- # Returns a relation value with a given name
922
- def get_value(name) # :nodoc:
923
- @values[name] || default_value_for(name)
901
+ # Returns the Arel object associated with the relation.
902
+ def arel(aliases = nil) # :nodoc:
903
+ @arel ||= build_arel(aliases)
924
904
  end
925
905
 
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
906
+ protected
907
+ # Returns a relation value with a given name
908
+ def get_value(name) # :nodoc:
909
+ @values.fetch(name, DEFAULT_VALUES[name])
910
+ end
911
+
912
+ # Sets the relation value with the given name
913
+ def set_value(name, value) # :nodoc:
914
+ assert_mutability!
915
+ @values[name] = value
916
+ end
931
917
 
932
918
  private
933
919
 
@@ -936,16 +922,30 @@ module ActiveRecord
936
922
  raise ImmutableRelation if defined?(@arel) && @arel
937
923
  end
938
924
 
939
- def build_arel
925
+ def build_arel(aliases)
940
926
  arel = Arel::SelectManager.new(table)
941
927
 
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?
928
+ aliases = build_joins(arel, joins_values.flatten, aliases) unless joins_values.empty?
929
+ build_left_outer_joins(arel, left_outer_joins_values.flatten, aliases) unless left_outer_joins_values.empty?
944
930
 
945
931
  arel.where(where_clause.ast) unless where_clause.empty?
946
932
  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
933
+ if limit_value
934
+ limit_attribute = ActiveModel::Attribute.with_cast_value(
935
+ "LIMIT".freeze,
936
+ connection.sanitize_limit(limit_value),
937
+ Type.default_value,
938
+ )
939
+ arel.take(Arel::Nodes::BindParam.new(limit_attribute))
940
+ end
941
+ if offset_value
942
+ offset_attribute = ActiveModel::Attribute.with_cast_value(
943
+ "OFFSET".freeze,
944
+ offset_value.to_i,
945
+ Type.default_value,
946
+ )
947
+ arel.skip(Arel::Nodes::BindParam.new(offset_attribute))
948
+ end
949
949
  arel.group(*arel_columns(group_values.uniq.reject(&:blank?))) unless group_values.empty?
950
950
 
951
951
  build_order(arel)
@@ -964,6 +964,9 @@ module ActiveRecord
964
964
  name = from_clause.name
965
965
  case opts
966
966
  when Relation
967
+ if opts.eager_loading?
968
+ opts = opts.send(:apply_join_dependency)
969
+ end
967
970
  name ||= "subquery"
968
971
  opts.arel.as(name.to_s)
969
972
  else
@@ -971,20 +974,22 @@ module ActiveRecord
971
974
  end
972
975
  end
973
976
 
974
- def build_left_outer_joins(manager, outer_joins)
977
+ def build_left_outer_joins(manager, outer_joins, aliases)
975
978
  buckets = outer_joins.group_by do |join|
976
979
  case join
977
980
  when Hash, Symbol, Array
978
981
  :association_join
982
+ when ActiveRecord::Associations::JoinDependency
983
+ :stashed_join
979
984
  else
980
985
  raise ArgumentError, "only Hash, Symbol and Array are allowed"
981
986
  end
982
987
  end
983
988
 
984
- build_join_query(manager, buckets, Arel::Nodes::OuterJoin)
989
+ build_join_query(manager, buckets, Arel::Nodes::OuterJoin, aliases)
985
990
  end
986
991
 
987
- def build_joins(manager, joins)
992
+ def build_joins(manager, joins, aliases)
988
993
  buckets = joins.group_by do |join|
989
994
  case join
990
995
  when String
@@ -1000,10 +1005,10 @@ module ActiveRecord
1000
1005
  end
1001
1006
  end
1002
1007
 
1003
- build_join_query(manager, buckets, Arel::Nodes::InnerJoin)
1008
+ build_join_query(manager, buckets, Arel::Nodes::InnerJoin, aliases)
1004
1009
  end
1005
1010
 
1006
- def build_join_query(manager, buckets, join_type)
1011
+ def build_join_query(manager, buckets, join_type, aliases)
1007
1012
  buckets.default = []
1008
1013
 
1009
1014
  association_joins = buckets[:association_join]
@@ -1011,27 +1016,22 @@ module ActiveRecord
1011
1016
  join_nodes = buckets[:join_node].uniq
1012
1017
  string_joins = buckets[:string_join].map(&:strip).uniq
1013
1018
 
1014
- join_list = join_nodes + convert_join_strings_to_ast(manager, string_joins)
1019
+ join_list = join_nodes + convert_join_strings_to_ast(string_joins)
1020
+ alias_tracker = alias_tracker(join_list, aliases)
1015
1021
 
1016
1022
  join_dependency = ActiveRecord::Associations::JoinDependency.new(
1017
- @klass,
1018
- association_joins,
1019
- join_list
1023
+ klass, table, association_joins, alias_tracker
1020
1024
  )
1021
1025
 
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
1026
+ joins = join_dependency.join_constraints(stashed_association_joins, join_type)
1027
+ joins.each { |join| manager.from(join) }
1028
1028
 
1029
1029
  manager.join_sources.concat(join_list)
1030
1030
 
1031
- manager
1031
+ alias_tracker.aliases
1032
1032
  end
1033
1033
 
1034
- def convert_join_strings_to_ast(table, joins)
1034
+ def convert_join_strings_to_ast(joins)
1035
1035
  joins
1036
1036
  .flatten
1037
1037
  .reject(&:blank?)
@@ -1044,7 +1044,7 @@ module ActiveRecord
1044
1044
  elsif klass.ignored_columns.any?
1045
1045
  arel.project(*klass.column_names.map { |field| arel_attribute(field) })
1046
1046
  else
1047
- arel.project(@klass.arel_table[Arel.star])
1047
+ arel.project(table[Arel.star])
1048
1048
  end
1049
1049
  end
1050
1050
 
@@ -1088,6 +1088,10 @@ module ActiveRecord
1088
1088
  end
1089
1089
 
1090
1090
  def does_not_support_reverse?(order)
1091
+ # Account for String subclasses like Arel::Nodes::SqlLiteral that
1092
+ # override methods like #count.
1093
+ order = String.new(order) unless order.instance_of?(String)
1094
+
1091
1095
  # Uses SQL function with multiple arguments.
1092
1096
  (order.include?(",") && order.split(",").find { |section| section.count("(") != section.count(")") }) ||
1093
1097
  # Uses "nulls first" like construction.
@@ -1102,27 +1106,35 @@ module ActiveRecord
1102
1106
  end
1103
1107
 
1104
1108
  VALID_DIRECTIONS = [:asc, :desc, :ASC, :DESC,
1105
- "asc", "desc", "ASC", "DESC"] # :nodoc:
1109
+ "asc", "desc", "ASC", "DESC"].to_set # :nodoc:
1106
1110
 
1107
1111
  def validate_order_args(args)
1108
1112
  args.each do |arg|
1109
1113
  next unless arg.is_a?(Hash)
1110
1114
  arg.each do |_key, value|
1111
- raise ArgumentError, "Direction \"#{value}\" is invalid. Valid " \
1112
- "directions are: #{VALID_DIRECTIONS.inspect}" unless VALID_DIRECTIONS.include?(value)
1115
+ unless VALID_DIRECTIONS.include?(value)
1116
+ raise ArgumentError,
1117
+ "Direction \"#{value}\" is invalid. Valid directions are: #{VALID_DIRECTIONS.to_a.inspect}"
1118
+ end
1113
1119
  end
1114
1120
  end
1115
1121
  end
1116
1122
 
1117
1123
  def preprocess_order_args(order_args)
1118
1124
  order_args.map! do |arg|
1119
- klass.send(:sanitize_sql_for_order, arg)
1125
+ klass.sanitize_sql_for_order(arg)
1120
1126
  end
1121
1127
  order_args.flatten!
1128
+
1129
+ @klass.enforce_raw_sql_whitelist(
1130
+ order_args.flat_map { |a| a.is_a?(Hash) ? a.keys : a },
1131
+ whitelist: AttributeMethods::ClassMethods::COLUMN_NAME_ORDER_WHITELIST
1132
+ )
1133
+
1122
1134
  validate_order_args(order_args)
1123
1135
 
1124
1136
  references = order_args.grep(String)
1125
- references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact!
1137
+ references.map! { |arg| arg =~ /^\W?(\w+)\W?\./ && $1 }.compact!
1126
1138
  references!(references) if references.any?
1127
1139
 
1128
1140
  # if a symbol is given we prepend the quoted table name
@@ -1167,7 +1179,7 @@ module ActiveRecord
1167
1179
  end
1168
1180
  end
1169
1181
 
1170
- STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having]
1182
+ STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having, :unscope, :references]
1171
1183
  def structurally_incompatible_values_for_or(other)
1172
1184
  STRUCTURAL_OR_METHODS.reject do |method|
1173
1185
  get_value(method) == other.get_value(method)
@@ -1181,7 +1193,6 @@ module ActiveRecord
1181
1193
 
1182
1194
  DEFAULT_VALUES = {
1183
1195
  create_with: FROZEN_EMPTY_HASH,
1184
- readonly: false,
1185
1196
  where: Relation::WhereClause.empty,
1186
1197
  having: Relation::WhereClause.empty,
1187
1198
  from: Relation::FromClause.empty
@@ -1190,15 +1201,5 @@ module ActiveRecord
1190
1201
  Relation::MULTI_VALUE_METHODS.each do |value|
1191
1202
  DEFAULT_VALUES[value] ||= FROZEN_EMPTY_ARRAY
1192
1203
  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
1204
  end
1204
1205
  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