activerecord 4.2.0 → 5.2.8.1

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 (274) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +640 -928
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +10 -11
  5. data/examples/performance.rb +32 -31
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record/aggregations.rb +264 -247
  8. data/lib/active_record/association_relation.rb +24 -6
  9. data/lib/active_record/associations/alias_tracker.rb +29 -35
  10. data/lib/active_record/associations/association.rb +87 -41
  11. data/lib/active_record/associations/association_scope.rb +106 -132
  12. data/lib/active_record/associations/belongs_to_association.rb +55 -36
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
  14. data/lib/active_record/associations/builder/association.rb +29 -38
  15. data/lib/active_record/associations/builder/belongs_to.rb +77 -30
  16. data/lib/active_record/associations/builder/collection_association.rb +14 -23
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +50 -39
  18. data/lib/active_record/associations/builder/has_many.rb +6 -4
  19. data/lib/active_record/associations/builder/has_one.rb +13 -6
  20. data/lib/active_record/associations/builder/singular_association.rb +15 -11
  21. data/lib/active_record/associations/collection_association.rb +145 -266
  22. data/lib/active_record/associations/collection_proxy.rb +242 -138
  23. data/lib/active_record/associations/foreign_association.rb +13 -0
  24. data/lib/active_record/associations/has_many_association.rb +35 -75
  25. data/lib/active_record/associations/has_many_through_association.rb +51 -69
  26. data/lib/active_record/associations/has_one_association.rb +39 -24
  27. data/lib/active_record/associations/has_one_through_association.rb +18 -9
  28. data/lib/active_record/associations/join_dependency/join_association.rb +40 -81
  29. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
  31. data/lib/active_record/associations/join_dependency.rb +134 -154
  32. data/lib/active_record/associations/preloader/association.rb +85 -116
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -74
  34. data/lib/active_record/associations/preloader.rb +83 -93
  35. data/lib/active_record/associations/singular_association.rb +27 -40
  36. data/lib/active_record/associations/through_association.rb +48 -23
  37. data/lib/active_record/associations.rb +1732 -1596
  38. data/lib/active_record/attribute_assignment.rb +58 -182
  39. data/lib/active_record/attribute_decorators.rb +39 -15
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +12 -5
  41. data/lib/active_record/attribute_methods/dirty.rb +94 -125
  42. data/lib/active_record/attribute_methods/primary_key.rb +86 -71
  43. data/lib/active_record/attribute_methods/query.rb +4 -2
  44. data/lib/active_record/attribute_methods/read.rb +45 -63
  45. data/lib/active_record/attribute_methods/serialization.rb +40 -20
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +62 -36
  47. data/lib/active_record/attribute_methods/write.rb +31 -46
  48. data/lib/active_record/attribute_methods.rb +170 -117
  49. data/lib/active_record/attributes.rb +201 -74
  50. data/lib/active_record/autosave_association.rb +118 -45
  51. data/lib/active_record/base.rb +60 -48
  52. data/lib/active_record/callbacks.rb +97 -57
  53. data/lib/active_record/coders/json.rb +3 -1
  54. data/lib/active_record/coders/yaml_column.rb +37 -13
  55. data/lib/active_record/collection_cache_key.rb +53 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +712 -284
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +10 -5
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +254 -87
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +72 -22
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -52
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +6 -4
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +67 -46
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -217
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +81 -36
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +617 -212
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +139 -75
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +332 -191
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +567 -563
  69. data/lib/active_record/connection_adapters/column.rb +50 -41
  70. data/lib/active_record/connection_adapters/connection_specification.rb +147 -135
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +42 -195
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +35 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -115
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -57
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +10 -6
  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 +5 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -13
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +7 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -19
  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 -11
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
  99. data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +65 -51
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +107 -47
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +144 -90
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +466 -280
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +439 -330
  117. data/lib/active_record/connection_adapters/schema_cache.rb +48 -24
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +269 -324
  126. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  127. data/lib/active_record/connection_handling.rb +40 -27
  128. data/lib/active_record/core.rb +205 -202
  129. data/lib/active_record/counter_cache.rb +80 -37
  130. data/lib/active_record/define_callbacks.rb +22 -0
  131. data/lib/active_record/dynamic_matchers.rb +87 -105
  132. data/lib/active_record/enum.rb +136 -90
  133. data/lib/active_record/errors.rb +180 -52
  134. data/lib/active_record/explain.rb +23 -11
  135. data/lib/active_record/explain_registry.rb +4 -2
  136. data/lib/active_record/explain_subscriber.rb +11 -6
  137. data/lib/active_record/fixture_set/file.rb +35 -9
  138. data/lib/active_record/fixtures.rb +193 -135
  139. data/lib/active_record/gem_version.rb +5 -3
  140. data/lib/active_record/inheritance.rb +148 -112
  141. data/lib/active_record/integration.rb +70 -28
  142. data/lib/active_record/internal_metadata.rb +45 -0
  143. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  144. data/lib/active_record/locale/en.yml +3 -2
  145. data/lib/active_record/locking/optimistic.rb +92 -98
  146. data/lib/active_record/locking/pessimistic.rb +15 -3
  147. data/lib/active_record/log_subscriber.rb +95 -33
  148. data/lib/active_record/migration/command_recorder.rb +133 -90
  149. data/lib/active_record/migration/compatibility.rb +217 -0
  150. data/lib/active_record/migration/join_table.rb +8 -6
  151. data/lib/active_record/migration.rb +594 -267
  152. data/lib/active_record/model_schema.rb +292 -111
  153. data/lib/active_record/nested_attributes.rb +266 -214
  154. data/lib/active_record/no_touching.rb +8 -2
  155. data/lib/active_record/null_relation.rb +24 -37
  156. data/lib/active_record/persistence.rb +350 -119
  157. data/lib/active_record/query_cache.rb +13 -24
  158. data/lib/active_record/querying.rb +19 -17
  159. data/lib/active_record/railtie.rb +117 -35
  160. data/lib/active_record/railties/console_sandbox.rb +2 -0
  161. data/lib/active_record/railties/controller_runtime.rb +9 -3
  162. data/lib/active_record/railties/databases.rake +160 -174
  163. data/lib/active_record/readonly_attributes.rb +5 -4
  164. data/lib/active_record/reflection.rb +447 -288
  165. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  166. data/lib/active_record/relation/batches.rb +204 -55
  167. data/lib/active_record/relation/calculations.rb +259 -244
  168. data/lib/active_record/relation/delegation.rb +67 -60
  169. data/lib/active_record/relation/finder_methods.rb +290 -253
  170. data/lib/active_record/relation/from_clause.rb +26 -0
  171. data/lib/active_record/relation/merger.rb +91 -68
  172. data/lib/active_record/relation/predicate_builder/array_handler.rb +24 -23
  173. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  174. data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
  175. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
  176. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  177. data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
  178. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  179. data/lib/active_record/relation/predicate_builder.rb +118 -92
  180. data/lib/active_record/relation/query_attribute.rb +45 -0
  181. data/lib/active_record/relation/query_methods.rb +446 -389
  182. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  183. data/lib/active_record/relation/spawn_methods.rb +18 -16
  184. data/lib/active_record/relation/where_clause.rb +186 -0
  185. data/lib/active_record/relation/where_clause_factory.rb +34 -0
  186. data/lib/active_record/relation.rb +287 -339
  187. data/lib/active_record/result.rb +54 -36
  188. data/lib/active_record/runtime_registry.rb +6 -4
  189. data/lib/active_record/sanitization.rb +155 -124
  190. data/lib/active_record/schema.rb +30 -24
  191. data/lib/active_record/schema_dumper.rb +91 -87
  192. data/lib/active_record/schema_migration.rb +19 -19
  193. data/lib/active_record/scoping/default.rb +102 -84
  194. data/lib/active_record/scoping/named.rb +81 -32
  195. data/lib/active_record/scoping.rb +45 -26
  196. data/lib/active_record/secure_token.rb +40 -0
  197. data/lib/active_record/serialization.rb +5 -5
  198. data/lib/active_record/statement_cache.rb +45 -35
  199. data/lib/active_record/store.rb +42 -36
  200. data/lib/active_record/suppressor.rb +61 -0
  201. data/lib/active_record/table_metadata.rb +82 -0
  202. data/lib/active_record/tasks/database_tasks.rb +136 -95
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +59 -89
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -31
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -16
  206. data/lib/active_record/timestamp.rb +70 -38
  207. data/lib/active_record/touch_later.rb +64 -0
  208. data/lib/active_record/transactions.rb +208 -123
  209. data/lib/active_record/translation.rb +2 -0
  210. data/lib/active_record/type/adapter_specific_registry.rb +136 -0
  211. data/lib/active_record/type/date.rb +4 -41
  212. data/lib/active_record/type/date_time.rb +4 -38
  213. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  214. data/lib/active_record/type/hash_lookup_type_map.rb +13 -5
  215. data/lib/active_record/type/internal/timezone.rb +17 -0
  216. data/lib/active_record/type/json.rb +30 -0
  217. data/lib/active_record/type/serialized.rb +30 -15
  218. data/lib/active_record/type/text.rb +2 -2
  219. data/lib/active_record/type/time.rb +11 -16
  220. data/lib/active_record/type/type_map.rb +15 -17
  221. data/lib/active_record/type/unsigned_integer.rb +9 -7
  222. data/lib/active_record/type.rb +79 -23
  223. data/lib/active_record/type_caster/connection.rb +33 -0
  224. data/lib/active_record/type_caster/map.rb +23 -0
  225. data/lib/active_record/type_caster.rb +9 -0
  226. data/lib/active_record/validations/absence.rb +25 -0
  227. data/lib/active_record/validations/associated.rb +13 -4
  228. data/lib/active_record/validations/length.rb +26 -0
  229. data/lib/active_record/validations/presence.rb +14 -13
  230. data/lib/active_record/validations/uniqueness.rb +41 -32
  231. data/lib/active_record/validations.rb +38 -35
  232. data/lib/active_record/version.rb +3 -1
  233. data/lib/active_record.rb +36 -21
  234. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  235. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  236. data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -35
  237. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +8 -6
  238. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +8 -7
  239. data/lib/rails/generators/active_record/migration.rb +18 -1
  240. data/lib/rails/generators/active_record/model/model_generator.rb +18 -22
  241. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +3 -0
  242. data/lib/rails/generators/active_record.rb +7 -5
  243. metadata +77 -53
  244. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  245. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  246. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  247. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  248. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  249. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  250. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  251. data/lib/active_record/attribute.rb +0 -149
  252. data/lib/active_record/attribute_set/builder.rb +0 -86
  253. data/lib/active_record/attribute_set.rb +0 -77
  254. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  255. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  256. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  257. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  258. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  259. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  260. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  261. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  262. data/lib/active_record/type/big_integer.rb +0 -13
  263. data/lib/active_record/type/binary.rb +0 -50
  264. data/lib/active_record/type/boolean.rb +0 -30
  265. data/lib/active_record/type/decimal.rb +0 -40
  266. data/lib/active_record/type/decorator.rb +0 -14
  267. data/lib/active_record/type/float.rb +0 -19
  268. data/lib/active_record/type/integer.rb +0 -55
  269. data/lib/active_record/type/mutable.rb +0 -16
  270. data/lib/active_record/type/numeric.rb +0 -36
  271. data/lib/active_record/type/string.rb +0 -36
  272. data/lib/active_record/type/time_value.rb +0 -38
  273. data/lib/active_record/type/value.rb +0 -101
  274. /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class Relation
5
+ class FromClause # :nodoc:
6
+ attr_reader :value, :name
7
+
8
+ def initialize(value, name)
9
+ @value = value
10
+ @name = name
11
+ end
12
+
13
+ def merge(other)
14
+ self
15
+ end
16
+
17
+ def empty?
18
+ value.nil?
19
+ end
20
+
21
+ def self.empty
22
+ @empty ||= new(nil, nil)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,5 +1,6 @@
1
- require 'active_support/core_ext/hash/keys'
2
- require "set"
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/hash/keys"
3
4
 
4
5
  module ActiveRecord
5
6
  class Relation
@@ -22,7 +23,11 @@ module ActiveRecord
22
23
  # build a relation to merge in rather than directly merging
23
24
  # the values.
24
25
  def other
25
- other = Relation.create(relation.klass, relation.table)
26
+ other = Relation.create(
27
+ relation.klass,
28
+ table: relation.table,
29
+ predicate_builder: relation.predicate_builder
30
+ )
26
31
  hash.each { |k, v|
27
32
  if k == :joins
28
33
  if Hash === v
@@ -49,9 +54,9 @@ module ActiveRecord
49
54
  @other = other
50
55
  end
51
56
 
52
- NORMAL_VALUES = Relation::SINGLE_VALUE_METHODS +
53
- Relation::MULTI_VALUE_METHODS -
54
- [:joins, :where, :order, :bind, :reverse_order, :lock, :create_with, :reordering, :from] # :nodoc:
57
+ NORMAL_VALUES = Relation::VALUE_METHODS -
58
+ Relation::CLAUSE_METHODS -
59
+ [:includes, :preload, :joins, :left_outer_joins, :order, :reverse_order, :lock, :create_with, :reordering] # :nodoc:
55
60
 
56
61
  def normal_values
57
62
  NORMAL_VALUES
@@ -75,96 +80,114 @@ module ActiveRecord
75
80
 
76
81
  merge_multi_values
77
82
  merge_single_values
83
+ merge_clauses
84
+ merge_preloads
78
85
  merge_joins
86
+ merge_outer_joins
79
87
 
80
88
  relation
81
89
  end
82
90
 
83
91
  private
84
92
 
85
- def merge_joins
86
- return if other.joins_values.blank?
93
+ def merge_preloads
94
+ return if other.preload_values.empty? && other.includes_values.empty?
87
95
 
88
- if other.klass == relation.klass
89
- relation.joins!(*other.joins_values)
90
- else
91
- joins_dependency, rest = other.joins_values.partition do |join|
92
- case join
93
- when Hash, Symbol, Array
94
- true
95
- else
96
- false
97
- end
98
- end
96
+ if other.klass == relation.klass
97
+ relation.preload!(*other.preload_values) unless other.preload_values.empty?
98
+ relation.includes!(other.includes_values) unless other.includes_values.empty?
99
+ else
100
+ reflection = relation.klass.reflect_on_all_associations.find do |r|
101
+ r.class_name == other.klass.name
102
+ end || return
99
103
 
100
- join_dependency = ActiveRecord::Associations::JoinDependency.new(other.klass,
101
- joins_dependency,
102
- [])
103
- relation.joins! rest
104
+ unless other.preload_values.empty?
105
+ relation.preload! reflection.name => other.preload_values
106
+ end
104
107
 
105
- @relation = relation.joins join_dependency
108
+ unless other.includes_values.empty?
109
+ relation.includes! reflection.name => other.includes_values
110
+ end
111
+ end
106
112
  end
107
- end
108
113
 
109
- def merge_multi_values
110
- lhs_wheres = relation.where_values
111
- rhs_wheres = other.where_values
114
+ def merge_joins
115
+ return if other.joins_values.blank?
112
116
 
113
- lhs_binds = relation.bind_values
114
- rhs_binds = other.bind_values
117
+ if other.klass == relation.klass
118
+ relation.joins!(*other.joins_values)
119
+ else
120
+ joins_dependency = other.joins_values.map do |join|
121
+ case join
122
+ when Hash, Symbol, Array
123
+ ActiveRecord::Associations::JoinDependency.new(
124
+ other.klass, other.table, join
125
+ )
126
+ else
127
+ join
128
+ end
129
+ end
115
130
 
116
- removed, kept = partition_overwrites(lhs_wheres, rhs_wheres)
131
+ relation.joins!(*joins_dependency)
132
+ end
133
+ end
117
134
 
118
- where_values = kept + rhs_wheres
119
- bind_values = filter_binds(lhs_binds, removed) + rhs_binds
135
+ def merge_outer_joins
136
+ return if other.left_outer_joins_values.blank?
120
137
 
121
- relation.where_values = where_values
122
- relation.bind_values = bind_values
138
+ if other.klass == relation.klass
139
+ relation.left_outer_joins!(*other.left_outer_joins_values)
140
+ else
141
+ joins_dependency = other.left_outer_joins_values.map do |join|
142
+ case join
143
+ when Hash, Symbol, Array
144
+ ActiveRecord::Associations::JoinDependency.new(
145
+ other.klass, other.table, join
146
+ )
147
+ else
148
+ join
149
+ end
150
+ end
123
151
 
124
- if other.reordering_value
125
- # override any order specified in the original relation
126
- relation.reorder! other.order_values
127
- elsif other.order_values
128
- # merge in order_values from relation
129
- relation.order! other.order_values
152
+ relation.left_outer_joins!(*joins_dependency)
153
+ end
130
154
  end
131
155
 
132
- relation.extend(*other.extending_values) unless other.extending_values.blank?
133
- end
134
-
135
- def merge_single_values
136
- relation.from_value = other.from_value unless relation.from_value
137
- relation.lock_value = other.lock_value unless relation.lock_value
156
+ def merge_multi_values
157
+ if other.reordering_value
158
+ # override any order specified in the original relation
159
+ relation.reorder!(*other.order_values)
160
+ elsif other.order_values.any?
161
+ # merge in order_values from relation
162
+ relation.order!(*other.order_values)
163
+ end
138
164
 
139
- unless other.create_with_value.blank?
140
- relation.create_with_value = (relation.create_with_value || {}).merge(other.create_with_value)
165
+ extensions = other.extensions - relation.extensions
166
+ relation.extending!(*extensions) if extensions.any?
141
167
  end
142
- end
143
168
 
144
- def filter_binds(lhs_binds, removed_wheres)
145
- return lhs_binds if removed_wheres.empty?
169
+ def merge_single_values
170
+ relation.lock_value ||= other.lock_value if other.lock_value
146
171
 
147
- set = Set.new removed_wheres.map { |x| x.left.name.to_s }
148
- lhs_binds.dup.delete_if { |col,_| set.include? col.name }
149
- end
150
-
151
- # Remove equalities from the existing relation with a LHS which is
152
- # present in the relation being merged in.
153
- # returns [things_to_remove, things_to_keep]
154
- def partition_overwrites(lhs_wheres, rhs_wheres)
155
- if lhs_wheres.empty? || rhs_wheres.empty?
156
- return [[], lhs_wheres]
172
+ unless other.create_with_value.blank?
173
+ relation.create_with_value = (relation.create_with_value || {}).merge(other.create_with_value)
174
+ end
157
175
  end
158
176
 
159
- nodes = rhs_wheres.find_all do |w|
160
- w.respond_to?(:operator) && w.operator == :==
177
+ def merge_clauses
178
+ relation.from_clause = other.from_clause if replace_from_clause?
179
+
180
+ where_clause = relation.where_clause.merge(other.where_clause)
181
+ relation.where_clause = where_clause unless where_clause.empty?
182
+
183
+ having_clause = relation.having_clause.merge(other.having_clause)
184
+ relation.having_clause = having_clause unless having_clause.empty?
161
185
  end
162
- seen = Set.new(nodes) { |node| node.left }
163
186
 
164
- lhs_wheres.partition do |w|
165
- w.respond_to?(:operator) && w.operator == :== && seen.include?(w.left)
187
+ def replace_from_clause?
188
+ relation.from_clause.empty? && !other.from_clause.empty? &&
189
+ relation.klass.base_class == other.klass.base_class
166
190
  end
167
- end
168
191
  end
169
192
  end
170
193
  end
@@ -1,47 +1,48 @@
1
- require 'active_support/core_ext/string/filters'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
4
  class PredicateBuilder
5
5
  class ArrayHandler # :nodoc:
6
+ def initialize(predicate_builder)
7
+ @predicate_builder = predicate_builder
8
+ end
9
+
6
10
  def call(attribute, value)
11
+ return attribute.in([]) if value.empty?
12
+
7
13
  values = value.map { |x| x.is_a?(Base) ? x.id : x }
8
14
  nils, values = values.partition(&:nil?)
9
-
10
- if values.any? { |val| val.is_a?(Array) }
11
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
12
- Passing a nested array to Active Record finder methods is
13
- deprecated and will be removed. Flatten your array before using
14
- it for 'IN' conditions.
15
- MSG
16
-
17
- values = values.flatten
18
- end
19
-
20
- return attribute.in([]) if values.empty? && nils.empty?
21
-
22
15
  ranges, values = values.partition { |v| v.is_a?(Range) }
23
16
 
24
17
  values_predicate =
25
18
  case values.length
26
19
  when 0 then NullPredicate
27
- when 1 then attribute.eq(values.first)
28
- else attribute.in(values)
20
+ when 1 then predicate_builder.build(attribute, values.first)
21
+ else
22
+ values.map! do |v|
23
+ predicate_builder.build_bind_attribute(attribute.name, v)
24
+ end
25
+ values.empty? ? NullPredicate : attribute.in(values)
29
26
  end
30
27
 
31
28
  unless nils.empty?
32
- values_predicate = values_predicate.or(attribute.eq(nil))
29
+ values_predicate = values_predicate.or(predicate_builder.build(attribute, nil))
33
30
  end
34
31
 
35
- array_predicates = ranges.map { |range| attribute.between(range) }
32
+ array_predicates = ranges.map { |range| predicate_builder.build(attribute, range) }
36
33
  array_predicates.unshift(values_predicate)
37
- array_predicates.inject { |composite, predicate| composite.or(predicate) }
34
+ array_predicates.inject(&:or)
38
35
  end
39
36
 
40
- module NullPredicate
41
- def self.or(other)
42
- other
37
+ protected
38
+
39
+ attr_reader :predicate_builder
40
+
41
+ module NullPredicate # :nodoc:
42
+ def self.or(other)
43
+ other
44
+ end
43
45
  end
44
- end
45
46
  end
46
47
  end
47
48
  end
@@ -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
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class PredicateBuilder
5
+ class BaseHandler # :nodoc:
6
+ def initialize(predicate_builder)
7
+ @predicate_builder = predicate_builder
8
+ end
9
+
10
+ def call(attribute, value)
11
+ predicate_builder.build(attribute, value.id)
12
+ end
13
+
14
+ protected
15
+
16
+ attr_reader :predicate_builder
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class PredicateBuilder
5
+ class BasicObjectHandler # :nodoc:
6
+ def initialize(predicate_builder)
7
+ @predicate_builder = predicate_builder
8
+ end
9
+
10
+ def call(attribute, value)
11
+ bind = predicate_builder.build_bind_attribute(attribute.name, value)
12
+ attribute.eq(bind)
13
+ end
14
+
15
+ protected
16
+
17
+ attr_reader :predicate_builder
18
+ end
19
+ end
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
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class PredicateBuilder
5
+ class RangeHandler # :nodoc:
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
15
+
16
+ def call(attribute, value)
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?
22
+ attribute.not_in([])
23
+ elsif value.exclude_end?
24
+ attribute.lt(end_bind)
25
+ else
26
+ attribute.lteq(end_bind)
27
+ end
28
+ elsif end_bind.value.infinity?
29
+ attribute.gteq(begin_bind)
30
+ elsif value.exclude_end?
31
+ attribute.gteq(begin_bind).and(attribute.lt(end_bind))
32
+ else
33
+ attribute.between(RangeWithBinds.new(begin_bind, end_bind))
34
+ end
35
+ end
36
+
37
+ protected
38
+
39
+ attr_reader :predicate_builder
40
+ end
41
+ end
42
+ end
@@ -1,9 +1,15 @@
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
- value = value.select(value.klass.arel_table[value.klass.primary_key])
12
+ value = value.select(value.arel_attribute(value.klass.primary_key))
7
13
  end
8
14
 
9
15
  attribute.in(value.arel)