activerecord 6.1.7.10 → 7.0.0.alpha1

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 (220) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +726 -1404
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_record/aggregations.rb +1 -1
  6. data/lib/active_record/association_relation.rb +0 -10
  7. data/lib/active_record/associations/association.rb +31 -9
  8. data/lib/active_record/associations/association_scope.rb +1 -3
  9. data/lib/active_record/associations/belongs_to_association.rb +15 -4
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +8 -2
  12. data/lib/active_record/associations/builder/belongs_to.rb +19 -6
  13. data/lib/active_record/associations/builder/collection_association.rb +1 -1
  14. data/lib/active_record/associations/builder/has_many.rb +3 -2
  15. data/lib/active_record/associations/builder/has_one.rb +2 -1
  16. data/lib/active_record/associations/builder/singular_association.rb +2 -2
  17. data/lib/active_record/associations/collection_association.rb +14 -23
  18. data/lib/active_record/associations/collection_proxy.rb +8 -3
  19. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  20. data/lib/active_record/associations/has_many_association.rb +1 -1
  21. data/lib/active_record/associations/has_many_through_association.rb +2 -1
  22. data/lib/active_record/associations/has_one_association.rb +10 -7
  23. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  24. data/lib/active_record/associations/preloader/association.rb +161 -47
  25. data/lib/active_record/associations/preloader/batch.rb +51 -0
  26. data/lib/active_record/associations/preloader/branch.rb +147 -0
  27. data/lib/active_record/associations/preloader/through_association.rb +37 -11
  28. data/lib/active_record/associations/preloader.rb +46 -110
  29. data/lib/active_record/associations/singular_association.rb +8 -2
  30. data/lib/active_record/associations/through_association.rb +1 -1
  31. data/lib/active_record/associations.rb +76 -81
  32. data/lib/active_record/asynchronous_queries_tracker.rb +57 -0
  33. data/lib/active_record/attribute_assignment.rb +1 -1
  34. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  35. data/lib/active_record/attribute_methods/dirty.rb +41 -16
  36. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  37. data/lib/active_record/attribute_methods/query.rb +2 -2
  38. data/lib/active_record/attribute_methods/read.rb +7 -5
  39. data/lib/active_record/attribute_methods/serialization.rb +66 -12
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
  41. data/lib/active_record/attribute_methods/write.rb +7 -10
  42. data/lib/active_record/attribute_methods.rb +6 -9
  43. data/lib/active_record/attributes.rb +24 -35
  44. data/lib/active_record/autosave_association.rb +3 -18
  45. data/lib/active_record/base.rb +19 -1
  46. data/lib/active_record/callbacks.rb +2 -2
  47. data/lib/active_record/coders/yaml_column.rb +2 -14
  48. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +312 -0
  49. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
  50. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +31 -558
  52. data/lib/active_record/connection_adapters/abstract/database_statements.rb +45 -21
  53. data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
  54. data/lib/active_record/connection_adapters/abstract/quoting.rb +12 -14
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -13
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +60 -16
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +3 -3
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +112 -66
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +96 -81
  61. data/lib/active_record/connection_adapters/mysql/database_statements.rb +33 -23
  62. data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -1
  63. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +1 -1
  64. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  65. data/lib/active_record/connection_adapters/pool_config.rb +1 -3
  66. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -14
  67. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  68. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  69. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  70. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  71. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +28 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  74. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  75. data/lib/active_record/connection_adapters/postgresql/quoting.rb +6 -32
  76. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
  77. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +5 -1
  78. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -12
  79. data/lib/active_record/connection_adapters/postgresql_adapter.rb +159 -102
  80. data/lib/active_record/connection_adapters/schema_cache.rb +36 -37
  81. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +23 -19
  82. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
  83. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
  84. data/lib/active_record/connection_adapters.rb +6 -5
  85. data/lib/active_record/connection_handling.rb +20 -38
  86. data/lib/active_record/core.rb +111 -125
  87. data/lib/active_record/database_configurations/connection_url_resolver.rb +0 -1
  88. data/lib/active_record/database_configurations/database_config.rb +12 -0
  89. data/lib/active_record/database_configurations/hash_config.rb +27 -1
  90. data/lib/active_record/database_configurations/url_config.rb +2 -2
  91. data/lib/active_record/database_configurations.rb +17 -9
  92. data/lib/active_record/delegated_type.rb +33 -11
  93. data/lib/active_record/destroy_association_async_job.rb +1 -1
  94. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  95. data/lib/active_record/dynamic_matchers.rb +1 -1
  96. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  97. data/lib/active_record/encryption/cipher.rb +53 -0
  98. data/lib/active_record/encryption/config.rb +44 -0
  99. data/lib/active_record/encryption/configurable.rb +61 -0
  100. data/lib/active_record/encryption/context.rb +35 -0
  101. data/lib/active_record/encryption/contexts.rb +72 -0
  102. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  103. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  104. data/lib/active_record/encryption/encryptable_record.rb +208 -0
  105. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  106. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  107. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  108. data/lib/active_record/encryption/encryptor.rb +155 -0
  109. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  110. data/lib/active_record/encryption/errors.rb +15 -0
  111. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  112. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +29 -0
  113. data/lib/active_record/encryption/key.rb +28 -0
  114. data/lib/active_record/encryption/key_generator.rb +42 -0
  115. data/lib/active_record/encryption/key_provider.rb +46 -0
  116. data/lib/active_record/encryption/message.rb +33 -0
  117. data/lib/active_record/encryption/message_serializer.rb +80 -0
  118. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  119. data/lib/active_record/encryption/properties.rb +76 -0
  120. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  121. data/lib/active_record/encryption/scheme.rb +99 -0
  122. data/lib/active_record/encryption.rb +55 -0
  123. data/lib/active_record/enum.rb +41 -41
  124. data/lib/active_record/errors.rb +66 -3
  125. data/lib/active_record/fixture_set/file.rb +15 -1
  126. data/lib/active_record/fixture_set/table_row.rb +40 -5
  127. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  128. data/lib/active_record/fixtures.rb +16 -11
  129. data/lib/active_record/future_result.rb +139 -0
  130. data/lib/active_record/gem_version.rb +4 -4
  131. data/lib/active_record/inheritance.rb +55 -17
  132. data/lib/active_record/insert_all.rb +34 -5
  133. data/lib/active_record/integration.rb +1 -1
  134. data/lib/active_record/internal_metadata.rb +1 -5
  135. data/lib/active_record/locking/optimistic.rb +10 -9
  136. data/lib/active_record/log_subscriber.rb +6 -2
  137. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  138. data/lib/active_record/middleware/database_selector.rb +8 -3
  139. data/lib/active_record/migration/command_recorder.rb +4 -4
  140. data/lib/active_record/migration/compatibility.rb +89 -10
  141. data/lib/active_record/migration/join_table.rb +1 -1
  142. data/lib/active_record/migration.rb +109 -79
  143. data/lib/active_record/model_schema.rb +45 -31
  144. data/lib/active_record/nested_attributes.rb +3 -3
  145. data/lib/active_record/no_touching.rb +2 -2
  146. data/lib/active_record/null_relation.rb +2 -6
  147. data/lib/active_record/persistence.rb +134 -45
  148. data/lib/active_record/query_cache.rb +2 -2
  149. data/lib/active_record/query_logs.rb +203 -0
  150. data/lib/active_record/querying.rb +15 -5
  151. data/lib/active_record/railtie.rb +117 -17
  152. data/lib/active_record/railties/controller_runtime.rb +1 -1
  153. data/lib/active_record/railties/databases.rake +72 -48
  154. data/lib/active_record/readonly_attributes.rb +11 -0
  155. data/lib/active_record/reflection.rb +45 -44
  156. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  157. data/lib/active_record/relation/batches.rb +3 -3
  158. data/lib/active_record/relation/calculations.rb +39 -26
  159. data/lib/active_record/relation/delegation.rb +6 -6
  160. data/lib/active_record/relation/finder_methods.rb +31 -22
  161. data/lib/active_record/relation/merger.rb +20 -13
  162. data/lib/active_record/relation/predicate_builder.rb +1 -6
  163. data/lib/active_record/relation/query_attribute.rb +5 -11
  164. data/lib/active_record/relation/query_methods.rb +230 -49
  165. data/lib/active_record/relation/record_fetch_warning.rb +2 -2
  166. data/lib/active_record/relation/spawn_methods.rb +2 -2
  167. data/lib/active_record/relation/where_clause.rb +8 -4
  168. data/lib/active_record/relation.rb +166 -77
  169. data/lib/active_record/result.rb +17 -2
  170. data/lib/active_record/runtime_registry.rb +2 -4
  171. data/lib/active_record/sanitization.rb +11 -7
  172. data/lib/active_record/schema_dumper.rb +3 -3
  173. data/lib/active_record/schema_migration.rb +0 -4
  174. data/lib/active_record/scoping/default.rb +61 -12
  175. data/lib/active_record/scoping/named.rb +3 -11
  176. data/lib/active_record/scoping.rb +40 -22
  177. data/lib/active_record/serialization.rb +1 -1
  178. data/lib/active_record/signed_id.rb +1 -1
  179. data/lib/active_record/store.rb +1 -6
  180. data/lib/active_record/tasks/database_tasks.rb +106 -22
  181. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  182. data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -11
  183. data/lib/active_record/test_databases.rb +1 -1
  184. data/lib/active_record/test_fixtures.rb +9 -13
  185. data/lib/active_record/timestamp.rb +3 -4
  186. data/lib/active_record/transactions.rb +9 -14
  187. data/lib/active_record/translation.rb +2 -2
  188. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  189. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  190. data/lib/active_record/type/internal/timezone.rb +2 -2
  191. data/lib/active_record/type/serialized.rb +1 -1
  192. data/lib/active_record/type/type_map.rb +17 -20
  193. data/lib/active_record/type.rb +1 -2
  194. data/lib/active_record/validations/associated.rb +1 -1
  195. data/lib/active_record.rb +170 -2
  196. data/lib/arel/attributes/attribute.rb +0 -8
  197. data/lib/arel/crud.rb +18 -22
  198. data/lib/arel/delete_manager.rb +2 -4
  199. data/lib/arel/insert_manager.rb +2 -3
  200. data/lib/arel/nodes/casted.rb +1 -1
  201. data/lib/arel/nodes/delete_statement.rb +8 -13
  202. data/lib/arel/nodes/insert_statement.rb +2 -2
  203. data/lib/arel/nodes/select_core.rb +2 -2
  204. data/lib/arel/nodes/select_statement.rb +2 -2
  205. data/lib/arel/nodes/update_statement.rb +3 -2
  206. data/lib/arel/predications.rb +1 -1
  207. data/lib/arel/select_manager.rb +10 -4
  208. data/lib/arel/table.rb +0 -1
  209. data/lib/arel/tree_manager.rb +0 -12
  210. data/lib/arel/update_manager.rb +2 -4
  211. data/lib/arel/visitors/dot.rb +80 -90
  212. data/lib/arel/visitors/mysql.rb +6 -1
  213. data/lib/arel/visitors/postgresql.rb +0 -10
  214. data/lib/arel/visitors/to_sql.rb +43 -2
  215. data/lib/arel.rb +1 -1
  216. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  217. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  218. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  219. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  220. metadata +52 -14
@@ -8,8 +8,6 @@ require "active_support/core_ext/array/wrap"
8
8
 
9
9
  module ActiveRecord
10
10
  module QueryMethods
11
- extend ActiveSupport::Concern
12
-
13
11
  include ActiveModel::ForbiddenAttributesProtection
14
12
 
15
13
  # WhereChain objects act as placeholder for queries in which #where does not have any parameter.
@@ -50,6 +48,34 @@ module ActiveRecord
50
48
  @scope
51
49
  end
52
50
 
51
+ # Returns a new relation with joins and where clause to identify
52
+ # associated relations.
53
+ #
54
+ # For example, posts that are associated to a related author:
55
+ #
56
+ # Post.where.associated(:author)
57
+ # # SELECT "posts".* FROM "posts"
58
+ # # INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
59
+ # # WHERE "authors"."id" IS NOT NULL
60
+ #
61
+ # Additionally, multiple relations can be combined. This will return posts
62
+ # associated to both an author and any comments:
63
+ #
64
+ # Post.where.associated(:author, :comments)
65
+ # # SELECT "posts".* FROM "posts"
66
+ # # INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
67
+ # # INNER JOIN "comments" ON "comments"."post_id" = "posts"."id"
68
+ # # WHERE "authors"."id" IS NOT NULL AND "comments"."id" IS NOT NULL
69
+ def associated(*associations)
70
+ associations.each do |association|
71
+ reflection = @scope.klass._reflect_on_association(association)
72
+ @scope.joins!(association)
73
+ self.not(reflection.table_name => { reflection.association_primary_key => nil })
74
+ end
75
+
76
+ @scope
77
+ end
78
+
53
79
  # Returns a new relation with left outer joins and where clause to identify
54
80
  # missing relations.
55
81
  #
@@ -68,12 +94,11 @@ module ActiveRecord
68
94
  # # LEFT OUTER JOIN "authors" ON "authors"."id" = "posts"."author_id"
69
95
  # # LEFT OUTER JOIN "comments" ON "comments"."post_id" = "posts"."id"
70
96
  # # WHERE "authors"."id" IS NULL AND "comments"."id" IS NULL
71
- def missing(*args)
72
- args.each do |arg|
73
- reflection = @scope.klass._reflect_on_association(arg)
74
- opts = { reflection.table_name => { reflection.association_primary_key => nil } }
75
- @scope.left_outer_joins!(arg)
76
- @scope.where!(opts)
97
+ def missing(*associations)
98
+ associations.each do |association|
99
+ reflection = @scope.klass._reflect_on_association(association)
100
+ @scope.left_outer_joins!(association)
101
+ @scope.where!(reflection.table_name => { reflection.association_primary_key => nil })
77
102
  end
78
103
 
79
104
  @scope
@@ -148,7 +173,7 @@ module ActiveRecord
148
173
  #
149
174
  # User.includes(:posts).where(posts: { name: 'example' })
150
175
  def includes(*args)
151
- check_if_method_has_arguments!(:includes, args)
176
+ check_if_method_has_arguments!(__callee__, args)
152
177
  spawn.includes!(*args)
153
178
  end
154
179
 
@@ -164,7 +189,7 @@ module ActiveRecord
164
189
  # # FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" =
165
190
  # # "users"."id"
166
191
  def eager_load(*args)
167
- check_if_method_has_arguments!(:eager_load, args)
192
+ check_if_method_has_arguments!(__callee__, args)
168
193
  spawn.eager_load!(*args)
169
194
  end
170
195
 
@@ -178,7 +203,7 @@ module ActiveRecord
178
203
  # User.preload(:posts)
179
204
  # # SELECT "posts".* FROM "posts" WHERE "posts"."user_id" IN (1, 2, 3)
180
205
  def preload(*args)
181
- check_if_method_has_arguments!(:preload, args)
206
+ check_if_method_has_arguments!(__callee__, args)
182
207
  spawn.preload!(*args)
183
208
  end
184
209
 
@@ -211,7 +236,7 @@ module ActiveRecord
211
236
  # User.includes(:posts).where("posts.name = 'foo'").references(:posts)
212
237
  # # Query now knows the string references posts, so adds a JOIN
213
238
  def references(*table_names)
214
- check_if_method_has_arguments!(:references, table_names)
239
+ check_if_method_has_arguments!(__callee__, table_names)
215
240
  spawn.references!(*table_names)
216
241
  end
217
242
 
@@ -269,7 +294,7 @@ module ActiveRecord
269
294
  return super()
270
295
  end
271
296
 
272
- check_if_method_has_arguments!(:select, fields, "Call `select' with at least one field.")
297
+ check_if_method_has_arguments!(__callee__, fields, "Call `select' with at least one field.")
273
298
  spawn._select!(*fields)
274
299
  end
275
300
 
@@ -289,7 +314,7 @@ module ActiveRecord
289
314
  # This is short-hand for <tt>unscope(:select).select(fields)</tt>.
290
315
  # Note that we're unscoping the entire select statement.
291
316
  def reselect(*args)
292
- check_if_method_has_arguments!(:reselect, args)
317
+ check_if_method_has_arguments!(__callee__, args)
293
318
  spawn.reselect!(*args)
294
319
  end
295
320
 
@@ -320,7 +345,7 @@ module ActiveRecord
320
345
  # User.select([:id, :first_name]).group(:id, :first_name).first(3)
321
346
  # # => [#<User id: 1, first_name: "Bill">, #<User id: 2, first_name: "Earl">, #<User id: 3, first_name: "Beto">]
322
347
  def group(*args)
323
- check_if_method_has_arguments!(:group, args)
348
+ check_if_method_has_arguments!(__callee__, args)
324
349
  spawn.group!(*args)
325
350
  end
326
351
 
@@ -329,17 +354,37 @@ module ActiveRecord
329
354
  self
330
355
  end
331
356
 
332
- # Allows to specify an order attribute:
357
+ # Applies an <code>ORDER BY</code> clause to a query.
358
+ #
359
+ # #order accepts arguments in one of several formats.
360
+ #
361
+ # === symbols
362
+ #
363
+ # The symbol represents the name of the column you want to order the results by.
333
364
  #
334
365
  # User.order(:name)
335
366
  # # SELECT "users".* FROM "users" ORDER BY "users"."name" ASC
336
367
  #
368
+ # By default, the order is ascending. If you want descending order, you can
369
+ # map the column name symbol to +:desc+.
370
+ #
337
371
  # User.order(email: :desc)
338
372
  # # SELECT "users".* FROM "users" ORDER BY "users"."email" DESC
339
373
  #
374
+ # Multiple columns can be passed this way, and they will be applied in the order specified.
375
+ #
340
376
  # User.order(:name, email: :desc)
341
377
  # # SELECT "users".* FROM "users" ORDER BY "users"."name" ASC, "users"."email" DESC
342
378
  #
379
+ # === strings
380
+ #
381
+ # Strings are passed directly to the database, allowing you to specify
382
+ # simple SQL expressions.
383
+ #
384
+ # This could be a source of SQL injection, so only strings composed of plain
385
+ # column names and simple <code>function(column_name)</code> expressions
386
+ # with optional +ASC+/+DESC+ modifiers are allowed.
387
+ #
343
388
  # User.order('name')
344
389
  # # SELECT "users".* FROM "users" ORDER BY name
345
390
  #
@@ -348,8 +393,21 @@ module ActiveRecord
348
393
  #
349
394
  # User.order('name DESC, email')
350
395
  # # SELECT "users".* FROM "users" ORDER BY name DESC, email
396
+ #
397
+ # === Arel
398
+ #
399
+ # If you need to pass in complicated expressions that you have verified
400
+ # are safe for the database, you can use Arel.
401
+ #
402
+ # User.order(Arel.sql('end_date - start_date'))
403
+ # # SELECT "users".* FROM "users" ORDER BY end_date - start_date
404
+ #
405
+ # Custom query syntax, like JSON columns for Postgres, is supported in this way.
406
+ #
407
+ # User.order(Arel.sql("payload->>'kind'"))
408
+ # # SELECT "users".* FROM "users" ORDER BY payload->>'kind'
351
409
  def order(*args)
352
- check_if_method_has_arguments!(:order, args) do
410
+ check_if_method_has_arguments!(__callee__, args) do
353
411
  sanitize_order_arguments(args)
354
412
  end
355
413
  spawn.order!(*args)
@@ -362,6 +420,23 @@ module ActiveRecord
362
420
  self
363
421
  end
364
422
 
423
+ # Allows to specify an order by a specific set of values. Depending on your
424
+ # adapter this will either use a CASE statement or a built-in function.
425
+ #
426
+ # User.in_order_of(:id, [1, 5, 3])
427
+ # # SELECT "users".* FROM "users" ORDER BY FIELD("users"."id", 1, 5, 3)
428
+ #
429
+ def in_order_of(column, values)
430
+ klass.disallow_raw_sql!([column], permit: connection.column_name_with_order_matcher)
431
+
432
+ references = column_references([column])
433
+ self.references_values |= references unless references.empty?
434
+
435
+ column = order_column(column.to_s) if column.is_a?(Symbol)
436
+
437
+ spawn.order!(connection.field_ordered_value(column, values))
438
+ end
439
+
365
440
  # Replaces any existing order defined on the relation with the specified order.
366
441
  #
367
442
  # User.order('email DESC').reorder('id ASC') # generated SQL has 'ORDER BY id ASC'
@@ -372,7 +447,7 @@ module ActiveRecord
372
447
  #
373
448
  # generates a query with 'ORDER BY id ASC, name ASC'.
374
449
  def reorder(*args)
375
- check_if_method_has_arguments!(:reorder, args) do
450
+ check_if_method_has_arguments!(__callee__, args) do
376
451
  sanitize_order_arguments(args) unless args.all?(&:blank?)
377
452
  end
378
453
  spawn.reorder!(*args)
@@ -425,7 +500,7 @@ module ActiveRecord
425
500
  # has_many :comments, -> { unscope(where: :trashed) }
426
501
  #
427
502
  def unscope(*args)
428
- check_if_method_has_arguments!(:unscope, args)
503
+ check_if_method_has_arguments!(__callee__, args)
429
504
  spawn.unscope!(*args)
430
505
  end
431
506
 
@@ -458,7 +533,7 @@ module ActiveRecord
458
533
  self
459
534
  end
460
535
 
461
- # Performs a joins on +args+. The given symbol(s) should match the name of
536
+ # Performs JOINs on +args+. The given symbol(s) should match the name of
462
537
  # the association(s).
463
538
  #
464
539
  # User.joins(:posts)
@@ -487,7 +562,7 @@ module ActiveRecord
487
562
  # User.joins("LEFT JOIN bookmarks ON bookmarks.bookmarkable_type = 'Post' AND bookmarks.user_id = users.id")
488
563
  # # SELECT "users".* FROM "users" LEFT JOIN bookmarks ON bookmarks.bookmarkable_type = 'Post' AND bookmarks.user_id = users.id
489
564
  def joins(*args)
490
- check_if_method_has_arguments!(:joins, args)
565
+ check_if_method_has_arguments!(__callee__, args)
491
566
  spawn.joins!(*args)
492
567
  end
493
568
 
@@ -496,7 +571,7 @@ module ActiveRecord
496
571
  self
497
572
  end
498
573
 
499
- # Performs a left outer joins on +args+:
574
+ # Performs LEFT OUTER JOINs on +args+:
500
575
  #
501
576
  # User.left_outer_joins(:posts)
502
577
  # => SELECT "users".* FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
@@ -578,13 +653,13 @@ module ActiveRecord
578
653
  #
579
654
  # Fields can be symbols or strings. Values can be single values, arrays, or ranges.
580
655
  #
581
- # User.where({ name: "Joe", email: "joe@example.com" })
656
+ # User.where(name: "Joe", email: "joe@example.com")
582
657
  # # SELECT * FROM users WHERE name = 'Joe' AND email = 'joe@example.com'
583
658
  #
584
- # User.where({ name: ["Alice", "Bob"]})
659
+ # User.where(name: ["Alice", "Bob"])
585
660
  # # SELECT * FROM users WHERE name IN ('Alice', 'Bob')
586
661
  #
587
- # User.where({ created_at: (Time.now.midnight - 1.day)..Time.now.midnight })
662
+ # User.where(created_at: (Time.now.midnight - 1.day)..Time.now.midnight)
588
663
  # # SELECT * FROM users WHERE (created_at BETWEEN '2012-06-09 07:00:00.000000' AND '2012-06-10 07:00:00.000000')
589
664
  #
590
665
  # In the case of a belongs_to relationship, an association key can be used
@@ -614,8 +689,8 @@ module ActiveRecord
614
689
  #
615
690
  # For hash conditions, you can either use the table name in the key, or use a sub-hash.
616
691
  #
617
- # User.joins(:posts).where({ "posts.published" => true })
618
- # User.joins(:posts).where({ posts: { published: true } })
692
+ # User.joins(:posts).where("posts.published" => true)
693
+ # User.joins(:posts).where(posts: { published: true })
619
694
  #
620
695
  # === no argument
621
696
  #
@@ -668,6 +743,59 @@ module ActiveRecord
668
743
  scope
669
744
  end
670
745
 
746
+ # Allows you to invert an entire where clause instead of manually applying conditions.
747
+ #
748
+ # class User
749
+ # scope :active, -> { where(accepted: true, locked: false) }
750
+ # end
751
+ #
752
+ # User.where(accepted: true)
753
+ # # WHERE `accepted` = 1
754
+ #
755
+ # User.where(accepted: true).invert_where
756
+ # # WHERE `accepted` != 1
757
+ #
758
+ # User.active
759
+ # # WHERE `accepted` = 1 AND `locked` = 0
760
+ #
761
+ # User.active.invert_where
762
+ # # WHERE NOT (`accepted` = 1 AND `locked` = 0)
763
+ #
764
+ # Be careful because this inverts all conditions before +invert_where+ call.
765
+ #
766
+ # class User
767
+ # scope :active, -> { where(accepted: true, locked: false) }
768
+ # scope :inactive, -> { active.invert_where } # Do not attempt it
769
+ # end
770
+ #
771
+ # # It also inverts `where(role: 'admin')` unexpectedly.
772
+ # User.where(role: 'admin').inactive
773
+ # # WHERE NOT (`role` = 'admin' AND `accepted` = 1 AND `locked` = 0)
774
+ #
775
+ def invert_where
776
+ spawn.invert_where!
777
+ end
778
+
779
+ def invert_where! # :nodoc:
780
+ self.where_clause = where_clause.invert
781
+ self
782
+ end
783
+
784
+ # Checks whether the given relation is structurally compatible with this relation, to determine
785
+ # if it's possible to use the #and and #or methods without raising an error. Structurally
786
+ # compatible is defined as: they must be scoping the same model, and they must differ only by
787
+ # #where (if no #group has been defined) or #having (if a #group is present).
788
+ #
789
+ # Post.where("id = 1").structurally_compatible?(Post.where("author_id = 3"))
790
+ # # => true
791
+ #
792
+ # Post.joins(:comments).structurally_compatible?(Post.where("id = 1"))
793
+ # # => false
794
+ #
795
+ def structurally_compatible?(other)
796
+ structurally_incompatible_values_for(other).empty?
797
+ end
798
+
671
799
  # Returns a new relation, which is the logical intersection of this relation and the one passed
672
800
  # as an argument.
673
801
  #
@@ -886,7 +1014,7 @@ module ActiveRecord
886
1014
  self
887
1015
  end
888
1016
 
889
- # Specifies table from which the records will be fetched. For example:
1017
+ # Specifies the table from which the records will be fetched. For example:
890
1018
  #
891
1019
  # Topic.select('title').from('posts')
892
1020
  # # SELECT title FROM posts
@@ -896,9 +1024,26 @@ module ActiveRecord
896
1024
  # Topic.select('title').from(Topic.approved)
897
1025
  # # SELECT title FROM (SELECT * FROM topics WHERE approved = 't') subquery
898
1026
  #
1027
+ # Passing a second argument (string or symbol), creates the alias for the SQL from clause. Otherwise the alias "subquery" is used:
1028
+ #
899
1029
  # Topic.select('a.title').from(Topic.approved, :a)
900
1030
  # # SELECT a.title FROM (SELECT * FROM topics WHERE approved = 't') a
901
1031
  #
1032
+ # It does not add multiple arguments to the SQL from clause. The last +from+ chained is the one used:
1033
+ #
1034
+ # Topic.select('title').from(Topic.approved).from(Topic.inactive)
1035
+ # # SELECT title FROM (SELECT topics.* FROM topics WHERE topics.active = 'f') subquery
1036
+ #
1037
+ # For multiple arguments for the SQL from clause, you can pass a string with the exact elements in the SQL from list:
1038
+ #
1039
+ # color = "red"
1040
+ # Color
1041
+ # .from("colors c, JSONB_ARRAY_ELEMENTS(colored_things) AS colorvalues(colorvalue)")
1042
+ # .where("colorvalue->>'color' = ?", color)
1043
+ # .select("c.*").to_a
1044
+ # # SELECT c.*
1045
+ # # FROM colors c, JSONB_ARRAY_ELEMENTS(colored_things) AS colorvalues(colorvalue)
1046
+ # # WHERE (colorvalue->>'color' = 'red')
902
1047
  def from(value, subquery_name = nil)
903
1048
  spawn.from!(value, subquery_name)
904
1049
  end
@@ -994,7 +1139,7 @@ module ActiveRecord
994
1139
  # Topic.optimizer_hints("SeqScan(topics)", "Parallel(topics 8)")
995
1140
  # # SELECT /*+ SeqScan(topics) Parallel(topics 8) */ "topics".* FROM "topics"
996
1141
  def optimizer_hints(*args)
997
- check_if_method_has_arguments!(:optimizer_hints, args)
1142
+ check_if_method_has_arguments!(__callee__, args)
998
1143
  spawn.optimizer_hints!(*args)
999
1144
  end
1000
1145
 
@@ -1035,10 +1180,8 @@ module ActiveRecord
1035
1180
  # # SELECT "users"."name" FROM "users" /* selecting */ /* user */ /* names */
1036
1181
  #
1037
1182
  # The SQL block comment delimiters, "/*" and "*/", will be added automatically.
1038
- #
1039
- # Some escaping is performed, however untrusted user input should not be used.
1040
1183
  def annotate(*args)
1041
- check_if_method_has_arguments!(:annotate, args)
1184
+ check_if_method_has_arguments!(__callee__, args)
1042
1185
  spawn.annotate!(*args)
1043
1186
  end
1044
1187
 
@@ -1056,6 +1199,47 @@ module ActiveRecord
1056
1199
  self
1057
1200
  end
1058
1201
 
1202
+ # Excludes the specified record (or collection of records) from the resulting
1203
+ # relation. For example:
1204
+ #
1205
+ # Post.excluding(post)
1206
+ # # SELECT "posts".* FROM "posts" WHERE "posts"."id" != 1
1207
+ #
1208
+ # Post.excluding(post_one, post_two)
1209
+ # # SELECT "posts".* FROM "posts" WHERE "posts"."id" NOT IN (1, 2)
1210
+ #
1211
+ # This can also be called on associations. As with the above example, either
1212
+ # a single record of collection thereof may be specified:
1213
+ #
1214
+ # post = Post.find(1)
1215
+ # comment = Comment.find(2)
1216
+ # post.comments.excluding(comment)
1217
+ # # SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 1 AND "comments"."id" != 2
1218
+ #
1219
+ # This is short-hand for <tt>.where.not(id: post.id)</tt> and <tt>.where.not(id: [post_one.id, post_two.id])</tt>.
1220
+ #
1221
+ # An <tt>ArgumentError</tt> will be raised if either no records are
1222
+ # specified, or if any of the records in the collection (if a collection
1223
+ # is passed in) are not instances of the same model that the relation is
1224
+ # scoping.
1225
+ def excluding(*records)
1226
+ records.flatten!(1)
1227
+ records.compact!
1228
+
1229
+ unless records.all?(klass)
1230
+ raise ArgumentError, "You must only pass a single or collection of #{klass.name} objects to ##{__callee__}."
1231
+ end
1232
+
1233
+ spawn.excluding!(records)
1234
+ end
1235
+ alias :without :excluding
1236
+
1237
+ def excluding!(records) # :nodoc:
1238
+ predicates = [ predicate_builder[primary_key, records].invert ]
1239
+ self.where_clause += Relation::WhereClause.new(predicates)
1240
+ self
1241
+ end
1242
+
1059
1243
  # Returns the Arel object associated with the relation.
1060
1244
  def arel(aliases = nil) # :nodoc:
1061
1245
  @arel ||= build_arel(aliases)
@@ -1111,11 +1295,9 @@ module ActiveRecord
1111
1295
  nil
1112
1296
  end
1113
1297
 
1114
- def each_join_dependencies(join_dependencies = build_join_dependencies)
1298
+ def each_join_dependencies(join_dependencies = build_join_dependencies, &block)
1115
1299
  join_dependencies.each do |join_dependency|
1116
- join_dependency.each do |join|
1117
- yield join
1118
- end
1300
+ join_dependency.each(&block)
1119
1301
  end
1120
1302
  end
1121
1303
 
@@ -1172,8 +1354,7 @@ module ActiveRecord
1172
1354
  end
1173
1355
 
1174
1356
  def build_cast_value(name, value)
1175
- cast_value = ActiveModel::Attribute.with_cast_value(name, value, Type.default_value)
1176
- Arel::Nodes::BindParam.new(cast_value)
1357
+ ActiveModel::Attribute.with_cast_value(name, value, Type.default_value)
1177
1358
  end
1178
1359
 
1179
1360
  def build_from
@@ -1284,7 +1465,7 @@ module ActiveRecord
1284
1465
  def build_select(arel)
1285
1466
  if select_values.any?
1286
1467
  arel.project(*arel_columns(select_values))
1287
- elsif klass.ignored_columns.any?
1468
+ elsif klass.ignored_columns.any? || klass.enumerate_columns_in_select_statements
1288
1469
  arel.project(*klass.column_names.map { |field| table[field] })
1289
1470
  else
1290
1471
  arel.project(table[Arel.star])
@@ -1430,7 +1611,14 @@ module ActiveRecord
1430
1611
  end
1431
1612
 
1432
1613
  def column_references(order_args)
1433
- references = order_args.grep(String)
1614
+ references = order_args.flat_map do |arg|
1615
+ case arg
1616
+ when String, Symbol
1617
+ arg
1618
+ when Hash
1619
+ arg.keys
1620
+ end
1621
+ end
1434
1622
  references.map! { |arg| arg =~ /^\W?(\w+)\W?\./ && $1 }.compact!
1435
1623
  references
1436
1624
  end
@@ -1478,11 +1666,11 @@ module ActiveRecord
1478
1666
  # Post.references() # raises an error
1479
1667
  # Post.references([]) # does not raise an error
1480
1668
  #
1481
- # This particular method should be called with a method_name and the args
1669
+ # This particular method should be called with a method_name (__callee__) and the args
1482
1670
  # passed into that method as an input. For example:
1483
1671
  #
1484
1672
  # def references(*args)
1485
- # check_if_method_has_arguments!("references", args)
1673
+ # check_if_method_has_arguments!(__callee__, args)
1486
1674
  # ...
1487
1675
  # end
1488
1676
  def check_if_method_has_arguments!(method_name, args, message = nil)
@@ -1514,11 +1702,4 @@ module ActiveRecord
1514
1702
  end
1515
1703
  end
1516
1704
  end
1517
-
1518
- class Relation # :nodoc:
1519
- # No-op WhereClauseFactory to work Mashal.load(File.read("legacy_relation.dump")).
1520
- # TODO: Remove the class once Rails 6.1 has released.
1521
- class WhereClauseFactory # :nodoc:
1522
- end
1523
- end
1524
1705
  end
@@ -17,8 +17,8 @@ module ActiveRecord
17
17
  QueryRegistry.reset
18
18
 
19
19
  super.tap do |records|
20
- if logger && warn_on_records_fetched_greater_than
21
- if records.length > warn_on_records_fetched_greater_than
20
+ if logger && ActiveRecord.warn_on_records_fetched_greater_than
21
+ if records.length > ActiveRecord.warn_on_records_fetched_greater_than
22
22
  logger.warn "Query fetched #{records.size} #{@klass} records: #{QueryRegistry.queries.join(";")}"
23
23
  end
24
24
  end
@@ -7,8 +7,8 @@ require "active_record/relation/merger"
7
7
  module ActiveRecord
8
8
  module SpawnMethods
9
9
  # This is overridden by Associations::CollectionProxy
10
- def spawn #:nodoc:
11
- already_in_scope? ? klass.all : clone
10
+ def spawn # :nodoc:
11
+ already_in_scope?(klass.scope_registry) ? klass.all : clone
12
12
  end
13
13
 
14
14
  # Merges in the conditions from <tt>other</tt>, if <tt>other</tt> is an ActiveRecord::Relation.
@@ -76,6 +76,11 @@ module ActiveRecord
76
76
  other.is_a?(WhereClause) &&
77
77
  predicates == other.predicates
78
78
  end
79
+ alias :eql? :==
80
+
81
+ def hash
82
+ [self.class, predicates].hash
83
+ end
79
84
 
80
85
  def invert
81
86
  if predicates.size == 1
@@ -227,11 +232,10 @@ module ActiveRecord
227
232
  end
228
233
 
229
234
  def extract_node_value(node)
230
- case node
231
- when Array
232
- node.map { |v| extract_node_value(v) }
233
- when Arel::Nodes::BindParam, Arel::Nodes::Casted, Arel::Nodes::Quoted
235
+ if node.respond_to?(:value_before_type_cast)
234
236
  node.value_before_type_cast
237
+ elsif Array === node
238
+ node.map { |v| extract_node_value(v) }
235
239
  end
236
240
  end
237
241
  end