activerecord 5.1.7 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (261) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +372 -765
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -5
  5. data/examples/performance.rb +2 -0
  6. data/examples/simple.rb +2 -0
  7. data/lib/active_record/aggregations.rb +6 -5
  8. data/lib/active_record/association_relation.rb +4 -2
  9. data/lib/active_record/associations/alias_tracker.rb +19 -27
  10. data/lib/active_record/associations/association.rb +16 -27
  11. data/lib/active_record/associations/association_scope.rb +38 -50
  12. data/lib/active_record/associations/belongs_to_association.rb +20 -10
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +4 -7
  14. data/lib/active_record/associations/builder/association.rb +4 -7
  15. data/lib/active_record/associations/builder/belongs_to.rb +4 -5
  16. data/lib/active_record/associations/builder/collection_association.rb +1 -1
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
  18. data/lib/active_record/associations/builder/has_many.rb +2 -0
  19. data/lib/active_record/associations/builder/has_one.rb +2 -0
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  21. data/lib/active_record/associations/collection_association.rb +43 -35
  22. data/lib/active_record/associations/collection_proxy.rb +12 -15
  23. data/lib/active_record/associations/foreign_association.rb +2 -0
  24. data/lib/active_record/associations/has_many_association.rb +3 -1
  25. data/lib/active_record/associations/has_many_through_association.rb +7 -18
  26. data/lib/active_record/associations/has_one_association.rb +4 -1
  27. data/lib/active_record/associations/has_one_through_association.rb +8 -7
  28. data/lib/active_record/associations/join_dependency/join_association.rb +17 -56
  29. data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
  30. data/lib/active_record/associations/join_dependency/join_part.rb +2 -9
  31. data/lib/active_record/associations/join_dependency.rb +23 -43
  32. data/lib/active_record/associations/preloader/association.rb +45 -61
  33. data/lib/active_record/associations/preloader/through_association.rb +71 -79
  34. data/lib/active_record/associations/preloader.rb +17 -37
  35. data/lib/active_record/associations/singular_association.rb +14 -10
  36. data/lib/active_record/associations/through_association.rb +25 -10
  37. data/lib/active_record/associations.rb +31 -54
  38. data/lib/active_record/attribute_assignment.rb +2 -5
  39. data/lib/active_record/attribute_decorators.rb +3 -2
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
  41. data/lib/active_record/attribute_methods/dirty.rb +25 -214
  42. data/lib/active_record/attribute_methods/primary_key.rb +7 -6
  43. data/lib/active_record/attribute_methods/query.rb +2 -0
  44. data/lib/active_record/attribute_methods/read.rb +8 -2
  45. data/lib/active_record/attribute_methods/serialization.rb +23 -0
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
  47. data/lib/active_record/attribute_methods/write.rb +21 -9
  48. data/lib/active_record/attribute_methods.rb +65 -24
  49. data/lib/active_record/attributes.rb +6 -5
  50. data/lib/active_record/autosave_association.rb +8 -11
  51. data/lib/active_record/base.rb +2 -0
  52. data/lib/active_record/callbacks.rb +8 -10
  53. data/lib/active_record/coders/json.rb +2 -0
  54. data/lib/active_record/coders/yaml_column.rb +2 -0
  55. data/lib/active_record/collection_cache_key.rb +11 -7
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +111 -38
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -0
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +157 -29
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +7 -2
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +13 -32
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +14 -5
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +57 -2
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +158 -78
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +45 -9
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +81 -96
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +111 -183
  69. data/lib/active_record/connection_adapters/column.rb +3 -1
  70. data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +2 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +11 -2
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -11
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +2 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -1
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -6
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +246 -110
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -0
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +58 -82
  117. data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +18 -1
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +71 -1
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +80 -90
  126. data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
  127. data/lib/active_record/connection_handling.rb +4 -2
  128. data/lib/active_record/core.rb +39 -60
  129. data/lib/active_record/counter_cache.rb +15 -12
  130. data/lib/active_record/define_callbacks.rb +5 -3
  131. data/lib/active_record/dynamic_matchers.rb +9 -9
  132. data/lib/active_record/enum.rb +17 -13
  133. data/lib/active_record/errors.rb +54 -21
  134. data/lib/active_record/explain.rb +3 -1
  135. data/lib/active_record/explain_registry.rb +2 -0
  136. data/lib/active_record/explain_subscriber.rb +2 -0
  137. data/lib/active_record/fixture_set/file.rb +2 -0
  138. data/lib/active_record/fixtures.rb +67 -60
  139. data/lib/active_record/gem_version.rb +4 -2
  140. data/lib/active_record/inheritance.rb +49 -19
  141. data/lib/active_record/integration.rb +58 -19
  142. data/lib/active_record/internal_metadata.rb +2 -0
  143. data/lib/active_record/legacy_yaml_adapter.rb +3 -1
  144. data/lib/active_record/locking/optimistic.rb +14 -17
  145. data/lib/active_record/locking/pessimistic.rb +9 -6
  146. data/lib/active_record/log_subscriber.rb +43 -0
  147. data/lib/active_record/migration/command_recorder.rb +11 -9
  148. data/lib/active_record/migration/compatibility.rb +40 -2
  149. data/lib/active_record/migration/join_table.rb +2 -0
  150. data/lib/active_record/migration.rb +189 -139
  151. data/lib/active_record/model_schema.rb +16 -21
  152. data/lib/active_record/nested_attributes.rb +18 -6
  153. data/lib/active_record/no_touching.rb +3 -1
  154. data/lib/active_record/null_relation.rb +2 -0
  155. data/lib/active_record/persistence.rb +166 -16
  156. data/lib/active_record/query_cache.rb +11 -6
  157. data/lib/active_record/querying.rb +3 -1
  158. data/lib/active_record/railtie.rb +61 -3
  159. data/lib/active_record/railties/console_sandbox.rb +2 -0
  160. data/lib/active_record/railties/controller_runtime.rb +2 -0
  161. data/lib/active_record/railties/databases.rake +46 -36
  162. data/lib/active_record/readonly_attributes.rb +3 -2
  163. data/lib/active_record/reflection.rb +110 -192
  164. data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
  165. data/lib/active_record/relation/batches.rb +20 -5
  166. data/lib/active_record/relation/calculations.rb +30 -8
  167. data/lib/active_record/relation/delegation.rb +15 -27
  168. data/lib/active_record/relation/finder_methods.rb +75 -78
  169. data/lib/active_record/relation/from_clause.rb +2 -8
  170. data/lib/active_record/relation/merger.rb +51 -20
  171. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
  172. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  173. data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
  174. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
  175. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  176. data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
  177. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  178. data/lib/active_record/relation/predicate_builder.rb +53 -78
  179. data/lib/active_record/relation/query_attribute.rb +26 -2
  180. data/lib/active_record/relation/query_methods.rb +89 -88
  181. data/lib/active_record/relation/record_fetch_warning.rb +2 -0
  182. data/lib/active_record/relation/spawn_methods.rb +3 -1
  183. data/lib/active_record/relation/where_clause.rb +65 -68
  184. data/lib/active_record/relation/where_clause_factory.rb +5 -48
  185. data/lib/active_record/relation.rb +95 -208
  186. data/lib/active_record/result.rb +2 -0
  187. data/lib/active_record/runtime_registry.rb +2 -0
  188. data/lib/active_record/sanitization.rb +129 -121
  189. data/lib/active_record/schema.rb +4 -2
  190. data/lib/active_record/schema_dumper.rb +36 -26
  191. data/lib/active_record/schema_migration.rb +2 -0
  192. data/lib/active_record/scoping/default.rb +6 -7
  193. data/lib/active_record/scoping/named.rb +21 -7
  194. data/lib/active_record/scoping.rb +9 -8
  195. data/lib/active_record/secure_token.rb +2 -0
  196. data/lib/active_record/serialization.rb +2 -0
  197. data/lib/active_record/statement_cache.rb +22 -12
  198. data/lib/active_record/store.rb +3 -1
  199. data/lib/active_record/suppressor.rb +2 -0
  200. data/lib/active_record/table_metadata.rb +12 -3
  201. data/lib/active_record/tasks/database_tasks.rb +26 -15
  202. data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
  203. data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
  204. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
  205. data/lib/active_record/timestamp.rb +5 -12
  206. data/lib/active_record/touch_later.rb +2 -0
  207. data/lib/active_record/transactions.rb +9 -7
  208. data/lib/active_record/translation.rb +2 -0
  209. data/lib/active_record/type/adapter_specific_registry.rb +2 -0
  210. data/lib/active_record/type/date.rb +2 -0
  211. data/lib/active_record/type/date_time.rb +2 -0
  212. data/lib/active_record/type/decimal_without_scale.rb +2 -0
  213. data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
  214. data/lib/active_record/type/internal/timezone.rb +2 -0
  215. data/lib/active_record/type/json.rb +30 -0
  216. data/lib/active_record/type/serialized.rb +2 -4
  217. data/lib/active_record/type/text.rb +2 -0
  218. data/lib/active_record/type/time.rb +2 -0
  219. data/lib/active_record/type/type_map.rb +2 -0
  220. data/lib/active_record/type/unsigned_integer.rb +2 -0
  221. data/lib/active_record/type.rb +4 -1
  222. data/lib/active_record/type_caster/connection.rb +2 -0
  223. data/lib/active_record/type_caster/map.rb +3 -1
  224. data/lib/active_record/type_caster.rb +2 -0
  225. data/lib/active_record/validations/absence.rb +2 -0
  226. data/lib/active_record/validations/associated.rb +2 -0
  227. data/lib/active_record/validations/length.rb +2 -0
  228. data/lib/active_record/validations/presence.rb +2 -0
  229. data/lib/active_record/validations/uniqueness.rb +35 -5
  230. data/lib/active_record/validations.rb +2 -0
  231. data/lib/active_record/version.rb +2 -0
  232. data/lib/active_record.rb +11 -4
  233. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  234. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  235. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
  236. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
  237. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
  238. data/lib/rails/generators/active_record/migration.rb +2 -0
  239. data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
  240. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
  241. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  242. data/lib/rails/generators/active_record.rb +3 -1
  243. metadata +24 -36
  244. data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
  245. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  246. data/lib/active_record/associations/preloader/has_many.rb +0 -15
  247. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  248. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  249. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  250. data/lib/active_record/associations/preloader/singular_association.rb +0 -18
  251. data/lib/active_record/attribute/user_provided_default.rb +0 -30
  252. data/lib/active_record/attribute.rb +0 -240
  253. data/lib/active_record/attribute_mutation_tracker.rb +0 -122
  254. data/lib/active_record/attribute_set/builder.rb +0 -126
  255. data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
  256. data/lib/active_record/attribute_set.rb +0 -113
  257. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
  258. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  259. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  260. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
  261. data/lib/active_record/type/internal/abstract_json.rb +0 -37
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class PredicateBuilder
5
+ class AssociationQueryValue # :nodoc:
6
+ def initialize(associated_table, value)
7
+ @associated_table = associated_table
8
+ @value = value
9
+ end
10
+
11
+ def queries
12
+ [associated_table.association_join_foreign_key.to_s => ids]
13
+ end
14
+
15
+ # TODO Change this to private once we've dropped Ruby 2.2 support.
16
+ # Workaround for Ruby 2.2 "private attribute?" warning.
17
+ protected
18
+ attr_reader :associated_table, :value
19
+
20
+ private
21
+ def ids
22
+ case value
23
+ when Relation
24
+ value.select_values.empty? ? value.select(primary_key) : value
25
+ when Array
26
+ value.map { |v| convert_to_id(v) }
27
+ else
28
+ convert_to_id(value)
29
+ end
30
+ end
31
+
32
+ def primary_key
33
+ associated_table.association_join_primary_key
34
+ end
35
+
36
+ def convert_to_id(value)
37
+ case value
38
+ when Base
39
+ value._read_attribute(primary_key)
40
+ else
41
+ value
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  class PredicateBuilder
3
5
  class BaseHandler # :nodoc:
@@ -9,8 +11,6 @@ module ActiveRecord
9
11
  predicate_builder.build(attribute, value.id)
10
12
  end
11
13
 
12
- # TODO Change this to private once we've dropped Ruby 2.2 support.
13
- # Workaround for Ruby 2.2 "private attribute?" warning.
14
14
  protected
15
15
 
16
16
  attr_reader :predicate_builder
@@ -1,9 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  class PredicateBuilder
3
5
  class BasicObjectHandler # :nodoc:
6
+ def initialize(predicate_builder)
7
+ @predicate_builder = predicate_builder
8
+ end
9
+
4
10
  def call(attribute, value)
5
- attribute.eq(value)
11
+ bind = predicate_builder.build_bind_attribute(attribute.name, value)
12
+ attribute.eq(bind)
6
13
  end
14
+
15
+ protected
16
+
17
+ attr_reader :predicate_builder
7
18
  end
8
19
  end
9
20
  end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class PredicateBuilder
5
+ class PolymorphicArrayValue # :nodoc:
6
+ def initialize(associated_table, values)
7
+ @associated_table = associated_table
8
+ @values = values
9
+ end
10
+
11
+ def queries
12
+ 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
+ }
17
+ end
18
+ end
19
+
20
+ # TODO Change this to private once we've dropped Ruby 2.2 support.
21
+ # Workaround for Ruby 2.2 "private attribute?" warning.
22
+ protected
23
+ attr_reader :associated_table, :values
24
+
25
+ private
26
+ def type_to_ids_mapping
27
+ default_hash = Hash.new { |hsh, key| hsh[key] = [] }
28
+ values.each_with_object(default_hash) do |value, hash|
29
+ hash[klass(value).polymorphic_name] << convert_to_id(value)
30
+ end
31
+ end
32
+
33
+ def primary_key(value)
34
+ associated_table.association_join_primary_key(klass(value))
35
+ end
36
+
37
+ def klass(value)
38
+ case value
39
+ when Base
40
+ value.class
41
+ when Relation
42
+ value.klass
43
+ end
44
+ end
45
+
46
+ def convert_to_id(value)
47
+ case value
48
+ when Base
49
+ value._read_attribute(primary_key(value))
50
+ when Relation
51
+ value.select(primary_key(value))
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,25 +1,42 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  class PredicateBuilder
3
5
  class RangeHandler # :nodoc:
4
- RangeWithBinds = Struct.new(:begin, :end, :exclude_end?)
6
+ class RangeWithBinds < Struct.new(:begin, :end)
7
+ def exclude_end?
8
+ false
9
+ end
10
+ end
11
+
12
+ def initialize(predicate_builder)
13
+ @predicate_builder = predicate_builder
14
+ end
5
15
 
6
16
  def call(attribute, value)
7
- if value.begin.respond_to?(:infinite?) && value.begin.infinite?
8
- if value.end.respond_to?(:infinite?) && value.end.infinite?
17
+ begin_bind = predicate_builder.build_bind_attribute(attribute.name, value.begin)
18
+ end_bind = predicate_builder.build_bind_attribute(attribute.name, value.end)
19
+
20
+ if begin_bind.value.infinity?
21
+ if end_bind.value.infinity?
9
22
  attribute.not_in([])
10
23
  elsif value.exclude_end?
11
- attribute.lt(value.end)
24
+ attribute.lt(end_bind)
12
25
  else
13
- attribute.lteq(value.end)
26
+ attribute.lteq(end_bind)
14
27
  end
15
- elsif value.end.respond_to?(:infinite?) && value.end.infinite?
16
- attribute.gteq(value.begin)
28
+ elsif end_bind.value.infinity?
29
+ attribute.gteq(begin_bind)
17
30
  elsif value.exclude_end?
18
- attribute.gteq(value.begin).and(attribute.lt(value.end))
31
+ attribute.gteq(begin_bind).and(attribute.lt(end_bind))
19
32
  else
20
- attribute.between(value)
33
+ attribute.between(RangeWithBinds.new(begin_bind, end_bind))
21
34
  end
22
35
  end
36
+
37
+ protected
38
+
39
+ attr_reader :predicate_builder
23
40
  end
24
41
  end
25
42
  end
@@ -1,7 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  class PredicateBuilder
3
5
  class RelationHandler # :nodoc:
4
6
  def call(attribute, value)
7
+ if value.eager_loading?
8
+ value = value.send(:apply_join_dependency)
9
+ end
10
+
5
11
  if value.select_values.empty?
6
12
  value = value.select(value.arel_attribute(value.klass.primary_key))
7
13
  end
@@ -1,27 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  class PredicateBuilder # :nodoc:
3
- require "active_record/relation/predicate_builder/array_handler"
4
- require "active_record/relation/predicate_builder/association_query_handler"
5
- require "active_record/relation/predicate_builder/base_handler"
6
- require "active_record/relation/predicate_builder/basic_object_handler"
7
- require "active_record/relation/predicate_builder/polymorphic_array_handler"
8
- require "active_record/relation/predicate_builder/range_handler"
9
- require "active_record/relation/predicate_builder/relation_handler"
10
-
11
5
  delegate :resolve_column_aliases, to: :table
12
6
 
13
7
  def initialize(table)
14
8
  @table = table
15
9
  @handlers = []
16
10
 
17
- register_handler(BasicObject, BasicObjectHandler.new)
11
+ register_handler(BasicObject, BasicObjectHandler.new(self))
18
12
  register_handler(Base, BaseHandler.new(self))
19
- register_handler(Range, RangeHandler.new)
20
- register_handler(RangeHandler::RangeWithBinds, RangeHandler.new)
13
+ register_handler(Range, RangeHandler.new(self))
21
14
  register_handler(Relation, RelationHandler.new)
22
15
  register_handler(Array, ArrayHandler.new(self))
23
- register_handler(AssociationQueryValue, AssociationQueryHandler.new(self))
24
- register_handler(PolymorphicArrayValue, PolymorphicArrayHandler.new(self))
16
+ register_handler(Set, ArrayHandler.new(self))
25
17
  end
26
18
 
27
19
  def build_from_hash(attributes)
@@ -29,11 +21,6 @@ module ActiveRecord
29
21
  expand_from_hash(attributes)
30
22
  end
31
23
 
32
- def create_binds(attributes)
33
- attributes = convert_dot_notation_to_hash(attributes)
34
- create_binds_for_hash(attributes)
35
- end
36
-
37
24
  def self.references(attributes)
38
25
  attributes.map do |key, value|
39
26
  if value.is_a?(Hash)
@@ -64,8 +51,11 @@ module ActiveRecord
64
51
  handler_for(value).call(attribute, value)
65
52
  end
66
53
 
67
- # TODO Change this to private once we've dropped Ruby 2.2 support.
68
- # Workaround for Ruby 2.2 "private attribute?" warning.
54
+ def build_bind_attribute(column_name, value)
55
+ attr = Relation::QueryAttribute.new(column_name.to_s, value, table.type(column_name))
56
+ Arel::Nodes::BindParam.new(attr)
57
+ end
58
+
69
59
  protected
70
60
 
71
61
  attr_reader :table
@@ -76,56 +66,46 @@ module ActiveRecord
76
66
  attributes.flat_map do |key, value|
77
67
  if value.is_a?(Hash) && !table.has_column?(key)
78
68
  associated_predicate_builder(key).expand_from_hash(value)
79
- else
80
- build(table.arel_attribute(key), value)
81
- end
82
- end
83
- end
69
+ elsif table.associated_with?(key)
70
+ # Find the foreign key when using queries such as:
71
+ # Post.where(author: author)
72
+ #
73
+ # For polymorphic relationships, find the foreign key and type:
74
+ # PriceEstimate.where(estimate_of: treasure)
75
+ associated_table = table.associated_table(key)
76
+ if associated_table.polymorphic_association?
77
+ case value.is_a?(Array) ? value.first : value
78
+ when Base, Relation
79
+ value = [value] unless value.is_a?(Array)
80
+ klass = PolymorphicArrayValue
81
+ end
82
+ end
84
83
 
85
- def create_binds_for_hash(attributes)
86
- result = attributes.dup
87
- binds = []
88
-
89
- attributes.each do |column_name, value|
90
- case
91
- when value.is_a?(Hash) && !table.has_column?(column_name)
92
- attrs, bvs = associated_predicate_builder(column_name).create_binds_for_hash(value)
93
- result[column_name] = attrs
94
- binds += bvs
95
- next
96
- when value.is_a?(Relation)
97
- binds += value.bound_attributes
98
- when value.is_a?(Range) && !table.type(column_name).force_equality?(value)
99
- first = value.begin
100
- last = value.end
101
- unless first.respond_to?(:infinite?) && first.infinite?
102
- binds << build_bind_param(column_name, first)
103
- first = Arel::Nodes::BindParam.new
84
+ klass ||= AssociationQueryValue
85
+ queries = klass.new(associated_table, value).queries.map do |query|
86
+ expand_from_hash(query).reduce(&:and)
104
87
  end
105
- unless last.respond_to?(:infinite?) && last.infinite?
106
- binds << build_bind_param(column_name, last)
107
- last = Arel::Nodes::BindParam.new
88
+ queries.reduce(&:or)
89
+ elsif table.aggregated_with?(key)
90
+ mapping = table.reflect_on_aggregation(key).mapping
91
+ queries = Array.wrap(value).map do |object|
92
+ mapping.map do |field_attr, aggregate_attr|
93
+ if mapping.size == 1 && !object.respond_to?(aggregate_attr)
94
+ build(table.arel_attribute(field_attr), object)
95
+ else
96
+ build(table.arel_attribute(field_attr), object.send(aggregate_attr))
97
+ end
98
+ end.reduce(&:and)
108
99
  end
109
-
110
- result[column_name] = RangeHandler::RangeWithBinds.new(first, last, value.exclude_end?)
100
+ queries.reduce(&:or)
101
+ # FIXME: Deprecate this and provide a public API to force equality
102
+ elsif (value.is_a?(Range) || value.is_a?(Array)) &&
103
+ table.type(key.to_s).respond_to?(:subtype)
104
+ BasicObjectHandler.new(self).call(table.arel_attribute(key), value)
111
105
  else
112
- if can_be_bound?(column_name, value)
113
- result[column_name] = Arel::Nodes::BindParam.new
114
- binds << build_bind_param(column_name, value)
115
- end
116
- end
117
-
118
- # Find the foreign key when using queries such as:
119
- # Post.where(author: author)
120
- #
121
- # For polymorphic relationships, find the foreign key and type:
122
- # PriceEstimate.where(estimate_of: treasure)
123
- if table.associated_with?(column_name)
124
- result[column_name] = AssociationQueryHandler.value_for(table, column_name, value)
106
+ build(table.arel_attribute(key), value)
125
107
  end
126
108
  end
127
-
128
- [result, binds]
129
109
  end
130
110
 
131
111
  private
@@ -153,19 +133,14 @@ module ActiveRecord
153
133
  def handler_for(object)
154
134
  @handlers.detect { |klass, _| klass === object }.last
155
135
  end
156
-
157
- def can_be_bound?(column_name, value)
158
- return if table.associated_with?(column_name)
159
- case value
160
- when Array, Range
161
- table.type(column_name).force_equality?(value)
162
- else
163
- !value.nil? && handler_for(value).is_a?(BasicObjectHandler)
164
- end
165
- end
166
-
167
- def build_bind_param(column_name, value)
168
- Relation::QueryAttribute.new(column_name.to_s, value, table.type(column_name))
169
- end
170
136
  end
171
137
  end
138
+
139
+ require "active_record/relation/predicate_builder/array_handler"
140
+ require "active_record/relation/predicate_builder/base_handler"
141
+ require "active_record/relation/predicate_builder/basic_object_handler"
142
+ require "active_record/relation/predicate_builder/range_handler"
143
+ require "active_record/relation/predicate_builder/relation_handler"
144
+
145
+ require "active_record/relation/predicate_builder/association_query_value"
146
+ require "active_record/relation/predicate_builder/polymorphic_array_value"
@@ -1,8 +1,10 @@
1
- require "active_record/attribute"
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model/attribute"
2
4
 
3
5
  module ActiveRecord
4
6
  class Relation
5
- class QueryAttribute < Attribute # :nodoc:
7
+ class QueryAttribute < ActiveModel::Attribute # :nodoc:
6
8
  def type_cast(value)
7
9
  value
8
10
  end
@@ -14,6 +16,28 @@ module ActiveRecord
14
16
  def with_cast_value(value)
15
17
  QueryAttribute.new(name, value, type)
16
18
  end
19
+
20
+ def nil?
21
+ !value_before_type_cast.is_a?(StatementCache::Substitute) &&
22
+ (value_before_type_cast.nil? || value_for_database.nil?)
23
+ end
24
+
25
+ def boundable?
26
+ return @_boundable if defined?(@_boundable)
27
+ nil?
28
+ @_boundable = true
29
+ rescue ::RangeError
30
+ @_boundable = false
31
+ end
32
+
33
+ def infinity?
34
+ _infinity?(value_before_type_cast) || boundable? && _infinity?(value_for_database)
35
+ end
36
+
37
+ private
38
+ def _infinity?(value)
39
+ value.respond_to?(:infinite?) && value.infinite?
40
+ end
17
41
  end
18
42
  end
19
43
  end