activerecord 5.1.0 → 5.2.0.rc1

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 (260) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +410 -530
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  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 +23 -32
  10. data/lib/active_record/associations/association.rb +20 -21
  11. data/lib/active_record/associations/association_scope.rb +49 -49
  12. data/lib/active_record/associations/belongs_to_association.rb +12 -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 +10 -6
  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 +50 -41
  22. data/lib/active_record/associations/collection_proxy.rb +22 -39
  23. data/lib/active_record/associations/foreign_association.rb +2 -0
  24. data/lib/active_record/associations/has_many_association.rb +4 -2
  25. data/lib/active_record/associations/has_many_through_association.rb +12 -18
  26. data/lib/active_record/associations/has_one_association.rb +5 -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 -64
  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 +27 -44
  32. data/lib/active_record/associations/preloader/association.rb +53 -92
  33. data/lib/active_record/associations/preloader/through_association.rb +72 -73
  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 +26 -11
  37. data/lib/active_record/associations.rb +68 -76
  38. data/lib/active_record/attribute_assignment.rb +2 -0
  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 +24 -214
  42. data/lib/active_record/attribute_methods/primary_key.rb +10 -13
  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 +22 -19
  48. data/lib/active_record/attribute_methods.rb +48 -12
  49. data/lib/active_record/attributes.rb +7 -6
  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 -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 +14 -10
  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 +175 -33
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +8 -2
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +13 -24
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +15 -6
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +58 -3
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +165 -85
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +45 -9
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +83 -97
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +118 -180
  69. data/lib/active_record/connection_adapters/column.rb +4 -2
  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 -17
  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 -23
  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 +30 -1
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -32
  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 +2 -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_time.rb +2 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  96. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -1
  98. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -2
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
  103. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
  104. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -1
  107. data/lib/active_record/connection_adapters/postgresql/quoting.rb +22 -1
  108. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  109. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +269 -126
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -0
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +64 -85
  116. data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
  118. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
  119. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +18 -0
  120. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
  121. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
  122. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
  123. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +71 -1
  124. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +92 -95
  125. data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
  126. data/lib/active_record/connection_handling.rb +4 -2
  127. data/lib/active_record/core.rb +39 -60
  128. data/lib/active_record/counter_cache.rb +3 -2
  129. data/lib/active_record/define_callbacks.rb +5 -3
  130. data/lib/active_record/dynamic_matchers.rb +9 -9
  131. data/lib/active_record/enum.rb +17 -13
  132. data/lib/active_record/errors.rb +42 -3
  133. data/lib/active_record/explain.rb +3 -1
  134. data/lib/active_record/explain_registry.rb +2 -0
  135. data/lib/active_record/explain_subscriber.rb +2 -0
  136. data/lib/active_record/fixture_set/file.rb +2 -0
  137. data/lib/active_record/fixtures.rb +67 -60
  138. data/lib/active_record/gem_version.rb +4 -2
  139. data/lib/active_record/inheritance.rb +9 -9
  140. data/lib/active_record/integration.rb +58 -19
  141. data/lib/active_record/internal_metadata.rb +2 -0
  142. data/lib/active_record/legacy_yaml_adapter.rb +3 -1
  143. data/lib/active_record/locking/optimistic.rb +8 -6
  144. data/lib/active_record/locking/pessimistic.rb +9 -6
  145. data/lib/active_record/log_subscriber.rb +46 -4
  146. data/lib/active_record/migration/command_recorder.rb +11 -9
  147. data/lib/active_record/migration/compatibility.rb +74 -22
  148. data/lib/active_record/migration/join_table.rb +2 -0
  149. data/lib/active_record/migration.rb +181 -137
  150. data/lib/active_record/model_schema.rb +73 -58
  151. data/lib/active_record/nested_attributes.rb +18 -6
  152. data/lib/active_record/no_touching.rb +3 -1
  153. data/lib/active_record/null_relation.rb +2 -0
  154. data/lib/active_record/persistence.rb +153 -18
  155. data/lib/active_record/query_cache.rb +17 -12
  156. data/lib/active_record/querying.rb +4 -2
  157. data/lib/active_record/railtie.rb +61 -3
  158. data/lib/active_record/railties/console_sandbox.rb +2 -0
  159. data/lib/active_record/railties/controller_runtime.rb +2 -0
  160. data/lib/active_record/railties/databases.rake +47 -37
  161. data/lib/active_record/readonly_attributes.rb +3 -2
  162. data/lib/active_record/reflection.rb +131 -204
  163. data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
  164. data/lib/active_record/relation/batches.rb +32 -17
  165. data/lib/active_record/relation/calculations.rb +58 -20
  166. data/lib/active_record/relation/delegation.rb +10 -29
  167. data/lib/active_record/relation/finder_methods.rb +74 -85
  168. data/lib/active_record/relation/from_clause.rb +2 -8
  169. data/lib/active_record/relation/merger.rb +51 -20
  170. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
  171. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  172. data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
  173. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
  174. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +54 -0
  175. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -6
  176. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  177. data/lib/active_record/relation/predicate_builder.rb +53 -78
  178. data/lib/active_record/relation/query_attribute.rb +9 -2
  179. data/lib/active_record/relation/query_methods.rb +101 -95
  180. data/lib/active_record/relation/record_fetch_warning.rb +2 -0
  181. data/lib/active_record/relation/spawn_methods.rb +3 -1
  182. data/lib/active_record/relation/where_clause.rb +65 -67
  183. data/lib/active_record/relation/where_clause_factory.rb +5 -48
  184. data/lib/active_record/relation.rb +99 -202
  185. data/lib/active_record/result.rb +2 -0
  186. data/lib/active_record/runtime_registry.rb +2 -0
  187. data/lib/active_record/sanitization.rb +129 -121
  188. data/lib/active_record/schema.rb +4 -2
  189. data/lib/active_record/schema_dumper.rb +36 -26
  190. data/lib/active_record/schema_migration.rb +2 -0
  191. data/lib/active_record/scoping/default.rb +10 -7
  192. data/lib/active_record/scoping/named.rb +38 -12
  193. data/lib/active_record/scoping.rb +12 -10
  194. data/lib/active_record/secure_token.rb +2 -0
  195. data/lib/active_record/serialization.rb +2 -0
  196. data/lib/active_record/statement_cache.rb +22 -12
  197. data/lib/active_record/store.rb +3 -1
  198. data/lib/active_record/suppressor.rb +2 -0
  199. data/lib/active_record/table_metadata.rb +12 -3
  200. data/lib/active_record/tasks/database_tasks.rb +37 -25
  201. data/lib/active_record/tasks/mysql_database_tasks.rb +11 -50
  202. data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -3
  203. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
  204. data/lib/active_record/timestamp.rb +5 -5
  205. data/lib/active_record/touch_later.rb +2 -0
  206. data/lib/active_record/transactions.rb +9 -7
  207. data/lib/active_record/translation.rb +2 -0
  208. data/lib/active_record/type/adapter_specific_registry.rb +2 -0
  209. data/lib/active_record/type/date.rb +2 -0
  210. data/lib/active_record/type/date_time.rb +2 -0
  211. data/lib/active_record/type/decimal_without_scale.rb +2 -0
  212. data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
  213. data/lib/active_record/type/internal/timezone.rb +2 -0
  214. data/lib/active_record/type/json.rb +30 -0
  215. data/lib/active_record/type/serialized.rb +2 -0
  216. data/lib/active_record/type/text.rb +2 -0
  217. data/lib/active_record/type/time.rb +2 -0
  218. data/lib/active_record/type/type_map.rb +2 -0
  219. data/lib/active_record/type/unsigned_integer.rb +2 -0
  220. data/lib/active_record/type.rb +4 -1
  221. data/lib/active_record/type_caster/connection.rb +2 -0
  222. data/lib/active_record/type_caster/map.rb +3 -1
  223. data/lib/active_record/type_caster.rb +2 -0
  224. data/lib/active_record/validations/absence.rb +2 -0
  225. data/lib/active_record/validations/associated.rb +2 -0
  226. data/lib/active_record/validations/length.rb +2 -0
  227. data/lib/active_record/validations/presence.rb +2 -0
  228. data/lib/active_record/validations/uniqueness.rb +35 -5
  229. data/lib/active_record/validations.rb +2 -0
  230. data/lib/active_record/version.rb +2 -0
  231. data/lib/active_record.rb +11 -4
  232. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  233. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  234. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
  235. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
  236. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
  237. data/lib/rails/generators/active_record/migration.rb +2 -0
  238. data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
  239. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
  240. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  241. data/lib/rails/generators/active_record.rb +3 -1
  242. metadata +25 -37
  243. data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
  244. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  245. data/lib/active_record/associations/preloader/has_many.rb +0 -15
  246. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  247. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  248. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  249. data/lib/active_record/associations/preloader/singular_association.rb +0 -18
  250. data/lib/active_record/attribute/user_provided_default.rb +0 -30
  251. data/lib/active_record/attribute.rb +0 -240
  252. data/lib/active_record/attribute_mutation_tracker.rb +0 -113
  253. data/lib/active_record/attribute_set/builder.rb +0 -124
  254. data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
  255. data/lib/active_record/attribute_set.rb +0 -113
  256. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
  257. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  258. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  259. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
  260. data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -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?)
@@ -1041,8 +1041,10 @@ module ActiveRecord
1041
1041
  def build_select(arel)
1042
1042
  if select_values.any?
1043
1043
  arel.project(*arel_columns(select_values.uniq))
1044
+ elsif klass.ignored_columns.any?
1045
+ arel.project(*klass.column_names.map { |field| arel_attribute(field) })
1044
1046
  else
1045
- arel.project(@klass.arel_table[Arel.star])
1047
+ arel.project(table[Arel.star])
1046
1048
  end
1047
1049
  end
1048
1050
 
@@ -1077,7 +1079,7 @@ module ActiveRecord
1077
1079
  end
1078
1080
  o.split(",").map! do |s|
1079
1081
  s.strip!
1080
- s.gsub!(/\sasc\Z/i, " DESC") || s.gsub!(/\sdesc\Z/i, " ASC") || s.concat(" DESC")
1082
+ s.gsub!(/\sasc\Z/i, " DESC") || s.gsub!(/\sdesc\Z/i, " ASC") || (s << " DESC")
1081
1083
  end
1082
1084
  else
1083
1085
  o
@@ -1086,6 +1088,10 @@ module ActiveRecord
1086
1088
  end
1087
1089
 
1088
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
+
1089
1095
  # Uses SQL function with multiple arguments.
1090
1096
  (order.include?(",") && order.split(",").find { |section| section.count("(") != section.count(")") }) ||
1091
1097
  # Uses "nulls first" like construction.
@@ -1100,27 +1106,35 @@ module ActiveRecord
1100
1106
  end
1101
1107
 
1102
1108
  VALID_DIRECTIONS = [:asc, :desc, :ASC, :DESC,
1103
- "asc", "desc", "ASC", "DESC"] # :nodoc:
1109
+ "asc", "desc", "ASC", "DESC"].to_set # :nodoc:
1104
1110
 
1105
1111
  def validate_order_args(args)
1106
1112
  args.each do |arg|
1107
1113
  next unless arg.is_a?(Hash)
1108
1114
  arg.each do |_key, value|
1109
- raise ArgumentError, "Direction \"#{value}\" is invalid. Valid " \
1110
- "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
1111
1119
  end
1112
1120
  end
1113
1121
  end
1114
1122
 
1115
1123
  def preprocess_order_args(order_args)
1116
1124
  order_args.map! do |arg|
1117
- klass.send(:sanitize_sql_for_order, arg)
1125
+ klass.sanitize_sql_for_order(arg)
1118
1126
  end
1119
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
+
1120
1134
  validate_order_args(order_args)
1121
1135
 
1122
1136
  references = order_args.grep(String)
1123
- references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact!
1137
+ references.map! { |arg| arg =~ /^\W?(\w+)\W?\./ && $1 }.compact!
1124
1138
  references!(references) if references.any?
1125
1139
 
1126
1140
  # if a symbol is given we prepend the quoted table name
@@ -1165,7 +1179,7 @@ module ActiveRecord
1165
1179
  end
1166
1180
  end
1167
1181
 
1168
- STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having]
1182
+ STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having, :unscope, :references]
1169
1183
  def structurally_incompatible_values_for_or(other)
1170
1184
  STRUCTURAL_OR_METHODS.reject do |method|
1171
1185
  get_value(method) == other.get_value(method)
@@ -1177,23 +1191,15 @@ module ActiveRecord
1177
1191
  end
1178
1192
  alias having_clause_factory where_clause_factory
1179
1193
 
1180
- def default_value_for(name)
1181
- case name
1182
- when :create_with
1183
- FROZEN_EMPTY_HASH
1184
- when :readonly
1185
- false
1186
- when :where, :having
1187
- Relation::WhereClause.empty
1188
- when :from
1189
- Relation::FromClause.empty
1190
- when *Relation::MULTI_VALUE_METHODS
1191
- FROZEN_EMPTY_ARRAY
1192
- when *Relation::SINGLE_VALUE_METHODS
1193
- nil
1194
- else
1195
- raise ArgumentError, "unknown relation value #{name.inspect}"
1196
- end
1194
+ DEFAULT_VALUES = {
1195
+ create_with: FROZEN_EMPTY_HASH,
1196
+ where: Relation::WhereClause.empty,
1197
+ having: Relation::WhereClause.empty,
1198
+ from: Relation::FromClause.empty
1199
+ }
1200
+
1201
+ Relation::MULTI_VALUE_METHODS.each do |value|
1202
+ DEFAULT_VALUES[value] ||= FROZEN_EMPTY_ARRAY
1197
1203
  end
1198
1204
  end
1199
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,43 +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
- except = \
140
- case node
141
- 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
142
- binds_contains = node.grep(Arel::Nodes::BindParam).size
143
- subrelation = (node.left.kind_of?(Arel::Attributes::Attribute) ? node.left : node.right)
144
- columns.include?(subrelation.name.to_s)
145
- end
146
-
147
- if except && binds_contains > 0
148
- (binds_index...(binds_index + binds_contains)).each do |i|
149
- except_binds[i] = true
150
- 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)
151
143
  end
152
-
153
- binds_index += binds_contains if binds_contains
154
-
155
- except
156
144
  end
157
-
158
- binds = self.binds.reject.with_index do |_, i|
159
- except_binds[i]
160
- end
161
-
162
- [predicates, binds]
163
145
  end
164
146
 
165
147
  def predicates_with_wrapped_sql_literals
166
148
  non_empty_predicates.map do |node|
167
- if Arel::Nodes::Equality === node
168
- node
169
- else
149
+ case node
150
+ when Arel::Nodes::SqlLiteral, ::String
170
151
  wrap_sql_literal(node)
152
+ else node
171
153
  end
172
154
  end
173
155
  end
@@ -183,6 +165,22 @@ module ActiveRecord
183
165
  end
184
166
  Arel::Nodes::Grouping.new(node)
185
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
186
184
  end
187
185
  end
188
186
  end