activerecord 6.0.0 → 6.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (270) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1178 -600
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  5. data/lib/active_record/aggregations.rb +5 -6
  6. data/lib/active_record/association_relation.rb +30 -10
  7. data/lib/active_record/associations/alias_tracker.rb +19 -16
  8. data/lib/active_record/associations/association.rb +55 -29
  9. data/lib/active_record/associations/association_scope.rb +19 -15
  10. data/lib/active_record/associations/belongs_to_association.rb +23 -10
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
  12. data/lib/active_record/associations/builder/association.rb +32 -5
  13. data/lib/active_record/associations/builder/belongs_to.rb +10 -7
  14. data/lib/active_record/associations/builder/collection_association.rb +5 -4
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -3
  16. data/lib/active_record/associations/builder/has_many.rb +6 -2
  17. data/lib/active_record/associations/builder/has_one.rb +11 -14
  18. data/lib/active_record/associations/builder/singular_association.rb +1 -1
  19. data/lib/active_record/associations/collection_association.rb +25 -8
  20. data/lib/active_record/associations/collection_proxy.rb +14 -7
  21. data/lib/active_record/associations/foreign_association.rb +13 -0
  22. data/lib/active_record/associations/has_many_association.rb +24 -3
  23. data/lib/active_record/associations/has_many_through_association.rb +10 -4
  24. data/lib/active_record/associations/has_one_association.rb +15 -1
  25. data/lib/active_record/associations/join_dependency/join_association.rb +39 -16
  26. data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
  27. data/lib/active_record/associations/join_dependency.rb +77 -42
  28. data/lib/active_record/associations/preloader/association.rb +51 -25
  29. data/lib/active_record/associations/preloader/through_association.rb +2 -2
  30. data/lib/active_record/associations/preloader.rb +13 -8
  31. data/lib/active_record/associations/singular_association.rb +1 -1
  32. data/lib/active_record/associations/through_association.rb +1 -1
  33. data/lib/active_record/associations.rb +120 -13
  34. data/lib/active_record/attribute_assignment.rb +10 -9
  35. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
  36. data/lib/active_record/attribute_methods/dirty.rb +3 -13
  37. data/lib/active_record/attribute_methods/primary_key.rb +6 -4
  38. data/lib/active_record/attribute_methods/query.rb +3 -6
  39. data/lib/active_record/attribute_methods/read.rb +8 -12
  40. data/lib/active_record/attribute_methods/serialization.rb +11 -6
  41. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
  42. data/lib/active_record/attribute_methods/write.rb +12 -21
  43. data/lib/active_record/attribute_methods.rb +64 -54
  44. data/lib/active_record/attributes.rb +33 -9
  45. data/lib/active_record/autosave_association.rb +63 -44
  46. data/lib/active_record/base.rb +2 -14
  47. data/lib/active_record/callbacks.rb +153 -24
  48. data/lib/active_record/coders/yaml_column.rb +12 -3
  49. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +202 -138
  50. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  51. data/lib/active_record/connection_adapters/abstract/database_statements.rb +87 -38
  52. data/lib/active_record/connection_adapters/abstract/query_cache.rb +5 -10
  53. data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
  54. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +152 -116
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +141 -52
  57. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  58. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +267 -105
  59. data/lib/active_record/connection_adapters/abstract/transaction.rb +94 -36
  60. data/lib/active_record/connection_adapters/abstract_adapter.rb +76 -79
  61. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -115
  62. data/lib/active_record/connection_adapters/column.rb +15 -1
  63. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  64. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  65. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  66. data/lib/active_record/connection_adapters/mysql/database_statements.rb +30 -36
  67. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  68. data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
  69. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
  70. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  71. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
  72. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +17 -13
  73. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  74. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
  75. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  76. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  77. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  78. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +21 -56
  79. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
  80. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  81. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
  83. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
  87. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
  91. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
  92. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  96. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
  97. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
  101. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  102. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  103. data/lib/active_record/connection_adapters/postgresql_adapter.rb +83 -65
  104. data/lib/active_record/connection_adapters/schema_cache.rb +106 -15
  105. data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
  106. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +38 -12
  107. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
  108. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  109. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
  110. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -57
  111. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  112. data/lib/active_record/connection_adapters.rb +52 -0
  113. data/lib/active_record/connection_handling.rb +219 -81
  114. data/lib/active_record/core.rb +268 -71
  115. data/lib/active_record/counter_cache.rb +4 -1
  116. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  117. data/lib/active_record/database_configurations/database_config.rb +52 -9
  118. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  119. data/lib/active_record/database_configurations/url_config.rb +15 -41
  120. data/lib/active_record/database_configurations.rb +124 -85
  121. data/lib/active_record/delegated_type.rb +209 -0
  122. data/lib/active_record/destroy_association_async_job.rb +36 -0
  123. data/lib/active_record/dynamic_matchers.rb +2 -3
  124. data/lib/active_record/enum.rb +80 -38
  125. data/lib/active_record/errors.rb +47 -12
  126. data/lib/active_record/explain.rb +9 -5
  127. data/lib/active_record/explain_subscriber.rb +1 -1
  128. data/lib/active_record/fixture_set/file.rb +10 -17
  129. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  130. data/lib/active_record/fixture_set/render_context.rb +1 -1
  131. data/lib/active_record/fixture_set/table_row.rb +2 -3
  132. data/lib/active_record/fixture_set/table_rows.rb +0 -1
  133. data/lib/active_record/fixtures.rb +58 -12
  134. data/lib/active_record/gem_version.rb +2 -2
  135. data/lib/active_record/inheritance.rb +40 -21
  136. data/lib/active_record/insert_all.rb +43 -10
  137. data/lib/active_record/integration.rb +3 -5
  138. data/lib/active_record/internal_metadata.rb +16 -7
  139. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  140. data/lib/active_record/locking/optimistic.rb +33 -18
  141. data/lib/active_record/locking/pessimistic.rb +6 -2
  142. data/lib/active_record/log_subscriber.rb +28 -9
  143. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  144. data/lib/active_record/middleware/database_selector/resolver.rb +14 -14
  145. data/lib/active_record/middleware/database_selector.rb +4 -2
  146. data/lib/active_record/migration/command_recorder.rb +53 -45
  147. data/lib/active_record/migration/compatibility.rb +71 -20
  148. data/lib/active_record/migration/join_table.rb +0 -1
  149. data/lib/active_record/migration.rb +115 -85
  150. data/lib/active_record/model_schema.rb +120 -15
  151. data/lib/active_record/nested_attributes.rb +2 -5
  152. data/lib/active_record/no_touching.rb +1 -1
  153. data/lib/active_record/null_relation.rb +0 -1
  154. data/lib/active_record/persistence.rb +50 -46
  155. data/lib/active_record/query_cache.rb +15 -5
  156. data/lib/active_record/querying.rb +12 -7
  157. data/lib/active_record/railtie.rb +65 -45
  158. data/lib/active_record/railties/console_sandbox.rb +2 -4
  159. data/lib/active_record/railties/databases.rake +280 -99
  160. data/lib/active_record/readonly_attributes.rb +4 -0
  161. data/lib/active_record/reflection.rb +77 -63
  162. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  163. data/lib/active_record/relation/batches.rb +38 -32
  164. data/lib/active_record/relation/calculations.rb +106 -45
  165. data/lib/active_record/relation/delegation.rb +9 -7
  166. data/lib/active_record/relation/finder_methods.rb +55 -17
  167. data/lib/active_record/relation/from_clause.rb +5 -1
  168. data/lib/active_record/relation/merger.rb +27 -26
  169. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  170. data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
  171. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
  172. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  173. data/lib/active_record/relation/predicate_builder.rb +59 -40
  174. data/lib/active_record/relation/query_methods.rb +344 -181
  175. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  176. data/lib/active_record/relation/spawn_methods.rb +8 -8
  177. data/lib/active_record/relation/where_clause.rb +111 -62
  178. data/lib/active_record/relation.rb +116 -82
  179. data/lib/active_record/result.rb +41 -34
  180. data/lib/active_record/runtime_registry.rb +2 -2
  181. data/lib/active_record/sanitization.rb +6 -17
  182. data/lib/active_record/schema_dumper.rb +34 -4
  183. data/lib/active_record/schema_migration.rb +2 -8
  184. data/lib/active_record/scoping/default.rb +1 -4
  185. data/lib/active_record/scoping/named.rb +7 -18
  186. data/lib/active_record/scoping.rb +0 -1
  187. data/lib/active_record/secure_token.rb +16 -8
  188. data/lib/active_record/serialization.rb +5 -3
  189. data/lib/active_record/signed_id.rb +116 -0
  190. data/lib/active_record/statement_cache.rb +20 -4
  191. data/lib/active_record/store.rb +3 -3
  192. data/lib/active_record/suppressor.rb +2 -2
  193. data/lib/active_record/table_metadata.rb +42 -36
  194. data/lib/active_record/tasks/database_tasks.rb +140 -113
  195. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
  196. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
  197. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
  198. data/lib/active_record/test_databases.rb +5 -4
  199. data/lib/active_record/test_fixtures.rb +79 -16
  200. data/lib/active_record/timestamp.rb +4 -7
  201. data/lib/active_record/touch_later.rb +20 -21
  202. data/lib/active_record/transactions.rb +26 -73
  203. data/lib/active_record/type/adapter_specific_registry.rb +2 -5
  204. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  205. data/lib/active_record/type/serialized.rb +6 -3
  206. data/lib/active_record/type/time.rb +10 -0
  207. data/lib/active_record/type/type_map.rb +0 -1
  208. data/lib/active_record/type/unsigned_integer.rb +0 -1
  209. data/lib/active_record/type.rb +8 -2
  210. data/lib/active_record/type_caster/connection.rb +0 -1
  211. data/lib/active_record/type_caster/map.rb +8 -5
  212. data/lib/active_record/validations/associated.rb +1 -2
  213. data/lib/active_record/validations/numericality.rb +35 -0
  214. data/lib/active_record/validations/uniqueness.rb +24 -4
  215. data/lib/active_record/validations.rb +3 -3
  216. data/lib/active_record.rb +7 -13
  217. data/lib/arel/attributes/attribute.rb +4 -0
  218. data/lib/arel/collectors/bind.rb +5 -0
  219. data/lib/arel/collectors/composite.rb +8 -0
  220. data/lib/arel/collectors/sql_string.rb +7 -0
  221. data/lib/arel/collectors/substitute_binds.rb +7 -0
  222. data/lib/arel/nodes/binary.rb +82 -8
  223. data/lib/arel/nodes/bind_param.rb +8 -0
  224. data/lib/arel/nodes/casted.rb +21 -9
  225. data/lib/arel/nodes/equality.rb +6 -9
  226. data/lib/arel/nodes/grouping.rb +3 -0
  227. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  228. data/lib/arel/nodes/in.rb +8 -1
  229. data/lib/arel/nodes/infix_operation.rb +13 -1
  230. data/lib/arel/nodes/join_source.rb +1 -1
  231. data/lib/arel/nodes/node.rb +7 -6
  232. data/lib/arel/nodes/ordering.rb +27 -0
  233. data/lib/arel/nodes/sql_literal.rb +3 -0
  234. data/lib/arel/nodes/table_alias.rb +7 -3
  235. data/lib/arel/nodes/unary.rb +0 -1
  236. data/lib/arel/nodes.rb +3 -1
  237. data/lib/arel/predications.rb +17 -24
  238. data/lib/arel/select_manager.rb +1 -2
  239. data/lib/arel/table.rb +13 -5
  240. data/lib/arel/visitors/dot.rb +14 -3
  241. data/lib/arel/visitors/mysql.rb +11 -1
  242. data/lib/arel/visitors/postgresql.rb +15 -5
  243. data/lib/arel/visitors/sqlite.rb +0 -1
  244. data/lib/arel/visitors/to_sql.rb +89 -79
  245. data/lib/arel/visitors/visitor.rb +0 -1
  246. data/lib/arel/visitors.rb +0 -7
  247. data/lib/arel.rb +15 -12
  248. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  249. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  250. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  251. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
  252. data/lib/rails/generators/active_record/migration.rb +6 -2
  253. data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
  254. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  255. metadata +27 -24
  256. data/lib/active_record/attribute_decorators.rb +0 -90
  257. data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
  258. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  259. data/lib/active_record/define_callbacks.rb +0 -22
  260. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  261. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  262. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  263. data/lib/arel/attributes.rb +0 -22
  264. data/lib/arel/visitors/depth_first.rb +0 -204
  265. data/lib/arel/visitors/ibm_db.rb +0 -34
  266. data/lib/arel/visitors/informix.rb +0 -62
  267. data/lib/arel/visitors/mssql.rb +0 -157
  268. data/lib/arel/visitors/oracle.rb +0 -159
  269. data/lib/arel/visitors/oracle12.rb +0 -66
  270. data/lib/arel/visitors/where_sql.rb +0 -23
@@ -9,11 +9,13 @@ module ActiveRecord
9
9
  end
10
10
 
11
11
  def queries
12
+ return [ associated_table.join_foreign_key => values ] if values.empty?
13
+
12
14
  type_to_ids_mapping.map do |type, ids|
13
- {
14
- associated_table.association_foreign_type.to_s => type,
15
- associated_table.association_foreign_key.to_s => ids
16
- }
15
+ query = {}
16
+ query[associated_table.join_foreign_type] = type if type
17
+ query[associated_table.join_foreign_key] = ids
18
+ query
17
19
  end
18
20
  end
19
21
 
@@ -23,12 +25,12 @@ module ActiveRecord
23
25
  def type_to_ids_mapping
24
26
  default_hash = Hash.new { |hsh, key| hsh[key] = [] }
25
27
  values.each_with_object(default_hash) do |value, hash|
26
- hash[klass(value).polymorphic_name] << convert_to_id(value)
28
+ hash[klass(value)&.polymorphic_name] << convert_to_id(value)
27
29
  end
28
30
  end
29
31
 
30
32
  def primary_key(value)
31
- associated_table.association_join_primary_key(klass(value))
33
+ associated_table.join_primary_key(klass(value))
32
34
  end
33
35
 
34
36
  def klass(value)
@@ -46,6 +48,8 @@ module ActiveRecord
46
48
  value._read_attribute(primary_key(value))
47
49
  when Relation
48
50
  value.select(primary_key(value))
51
+ else
52
+ value
49
53
  end
50
54
  end
51
55
  end
@@ -9,7 +9,7 @@ module ActiveRecord
9
9
  end
10
10
 
11
11
  if value.select_values.empty?
12
- value = value.select(value.arel_attribute(value.klass.primary_key))
12
+ value = value.select(value.table[value.klass.primary_key])
13
13
  end
14
14
 
15
15
  attribute.in(value.arel)
@@ -2,34 +2,41 @@
2
2
 
3
3
  module ActiveRecord
4
4
  class PredicateBuilder # :nodoc:
5
- delegate :resolve_column_aliases, to: :table
5
+ require "active_record/relation/predicate_builder/array_handler"
6
+ require "active_record/relation/predicate_builder/basic_object_handler"
7
+ require "active_record/relation/predicate_builder/range_handler"
8
+ require "active_record/relation/predicate_builder/relation_handler"
9
+ require "active_record/relation/predicate_builder/association_query_value"
10
+ require "active_record/relation/predicate_builder/polymorphic_array_value"
11
+
12
+ # No-op BaseHandler to work Mashal.load(File.read("legacy_relation.dump")).
13
+ # TODO: Remove the constant alias once Rails 6.1 has released.
14
+ BaseHandler = BasicObjectHandler
6
15
 
7
16
  def initialize(table)
8
17
  @table = table
9
18
  @handlers = []
10
19
 
11
20
  register_handler(BasicObject, BasicObjectHandler.new(self))
12
- register_handler(Base, BaseHandler.new(self))
13
21
  register_handler(Range, RangeHandler.new(self))
14
22
  register_handler(Relation, RelationHandler.new)
15
23
  register_handler(Array, ArrayHandler.new(self))
16
24
  register_handler(Set, ArrayHandler.new(self))
17
25
  end
18
26
 
19
- def build_from_hash(attributes)
27
+ def build_from_hash(attributes, &block)
20
28
  attributes = convert_dot_notation_to_hash(attributes)
21
- expand_from_hash(attributes)
29
+ expand_from_hash(attributes, &block)
22
30
  end
23
31
 
24
32
  def self.references(attributes)
25
- attributes.map do |key, value|
33
+ attributes.each_with_object([]) do |(key, value), result|
26
34
  if value.is_a?(Hash)
27
- key
28
- else
29
- key = key.to_s
30
- key.split(".").first if key.include?(".")
35
+ result << Arel.sql(key)
36
+ elsif key.include?(".")
37
+ result << Arel.sql(key.split(".").first)
31
38
  end
32
- end.compact
39
+ end
33
40
  end
34
41
 
35
42
  # Define how a class is converted to Arel nodes when passed to +where+.
@@ -47,27 +54,37 @@ module ActiveRecord
47
54
  @handlers.unshift([klass, handler])
48
55
  end
49
56
 
50
- def build(attribute, value)
51
- if table.type(attribute.name).force_equality?(value)
57
+ def [](attr_name, value, operator = nil)
58
+ build(table.arel_table[attr_name], value, operator)
59
+ end
60
+
61
+ def build(attribute, value, operator = nil)
62
+ value = value.id if value.respond_to?(:id)
63
+ if operator ||= table.type(attribute.name).force_equality?(value) && :eq
52
64
  bind = build_bind_attribute(attribute.name, value)
53
- attribute.eq(bind)
65
+ attribute.public_send(operator, bind)
54
66
  else
55
67
  handler_for(value).call(attribute, value)
56
68
  end
57
69
  end
58
70
 
59
71
  def build_bind_attribute(column_name, value)
60
- attr = Relation::QueryAttribute.new(column_name.to_s, value, table.type(column_name))
72
+ attr = Relation::QueryAttribute.new(column_name, value, table.type(column_name))
61
73
  Arel::Nodes::BindParam.new(attr)
62
74
  end
63
75
 
76
+ def resolve_arel_attribute(table_name, column_name, &block)
77
+ table.associated_table(table_name, &block).arel_table[column_name]
78
+ end
79
+
64
80
  protected
65
- def expand_from_hash(attributes)
81
+ def expand_from_hash(attributes, &block)
66
82
  return ["1=0"] if attributes.empty?
67
83
 
68
84
  attributes.flat_map do |key, value|
69
85
  if value.is_a?(Hash) && !table.has_column?(key)
70
- associated_predicate_builder(key).expand_from_hash(value)
86
+ table.associated_table(key, &block)
87
+ .predicate_builder.expand_from_hash(value.stringify_keys)
71
88
  elsif table.associated_with?(key)
72
89
  # Find the foreign key when using queries such as:
73
90
  # Post.where(author: author)
@@ -76,18 +93,22 @@ module ActiveRecord
76
93
  # PriceEstimate.where(estimate_of: treasure)
77
94
  associated_table = table.associated_table(key)
78
95
  if associated_table.polymorphic_association?
79
- case value.is_a?(Array) ? value.first : value
80
- when Base, Relation
81
- value = [value] unless value.is_a?(Array)
82
- klass = PolymorphicArrayValue
83
- end
96
+ value = [value] unless value.is_a?(Array)
97
+ klass = PolymorphicArrayValue
98
+ elsif associated_table.through_association?
99
+ next associated_table.predicate_builder.expand_from_hash(
100
+ associated_table.primary_key => value
101
+ )
84
102
  end
85
103
 
86
104
  klass ||= AssociationQueryValue
87
- queries = klass.new(associated_table, value).queries.map do |query|
88
- expand_from_hash(query).reduce(&:and)
105
+ queries = klass.new(associated_table, value).queries.map! do |query|
106
+ # If the query produced is identical to attributes don't go any deeper.
107
+ # Prevents stack level too deep errors when association and foreign_key are identical.
108
+ query == attributes ? self[key, value] : expand_from_hash(query)
89
109
  end
90
- queries.reduce(&:or)
110
+
111
+ grouping_queries(queries)
91
112
  elsif table.aggregated_with?(key)
92
113
  mapping = table.reflect_on_aggregation(key).mapping
93
114
  values = value.nil? ? [nil] : Array.wrap(value)
@@ -96,17 +117,18 @@ module ActiveRecord
96
117
  values = values.map do |object|
97
118
  object.respond_to?(aggr_attr) ? object.public_send(aggr_attr) : object
98
119
  end
99
- build(table.arel_attribute(column_name), values)
120
+ self[column_name, values]
100
121
  else
101
122
  queries = values.map do |object|
102
123
  mapping.map do |field_attr, aggregate_attr|
103
- build(table.arel_attribute(field_attr), object.try!(aggregate_attr))
104
- end.reduce(&:and)
124
+ self[field_attr, object.try!(aggregate_attr)]
125
+ end
105
126
  end
106
- queries.reduce(&:or)
127
+
128
+ grouping_queries(queries)
107
129
  end
108
130
  else
109
- build(table.arel_attribute(key), value)
131
+ self[key, value]
110
132
  end
111
133
  end
112
134
  end
@@ -114,8 +136,14 @@ module ActiveRecord
114
136
  private
115
137
  attr_reader :table
116
138
 
117
- def associated_predicate_builder(association_name)
118
- self.class.new(table.associated_table(association_name))
139
+ def grouping_queries(queries)
140
+ if queries.one?
141
+ queries.first
142
+ else
143
+ queries.map! { |query| query.reduce(&:and) }
144
+ queries = queries.reduce { |result, query| Arel::Nodes::Or.new(result, query) }
145
+ Arel::Nodes::Grouping.new(queries)
146
+ end
119
147
  end
120
148
 
121
149
  def convert_dot_notation_to_hash(attributes)
@@ -139,12 +167,3 @@ module ActiveRecord
139
167
  end
140
168
  end
141
169
  end
142
-
143
- require "active_record/relation/predicate_builder/array_handler"
144
- require "active_record/relation/predicate_builder/base_handler"
145
- require "active_record/relation/predicate_builder/basic_object_handler"
146
- require "active_record/relation/predicate_builder/range_handler"
147
- require "active_record/relation/predicate_builder/relation_handler"
148
-
149
- require "active_record/relation/predicate_builder/association_query_value"
150
- require "active_record/relation/predicate_builder/polymorphic_array_value"