activerecord 5.1.0 → 5.2.3

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 +5 -5
  2. data/CHANGELOG.md +596 -450
  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.rb +11 -4
  8. data/lib/active_record/aggregations.rb +6 -5
  9. data/lib/active_record/association_relation.rb +7 -5
  10. data/lib/active_record/associations.rb +77 -85
  11. data/lib/active_record/associations/alias_tracker.rb +23 -32
  12. data/lib/active_record/associations/association.rb +49 -35
  13. data/lib/active_record/associations/association_scope.rb +55 -55
  14. data/lib/active_record/associations/belongs_to_association.rb +30 -11
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
  16. data/lib/active_record/associations/builder/association.rb +4 -7
  17. data/lib/active_record/associations/builder/belongs_to.rb +21 -8
  18. data/lib/active_record/associations/builder/collection_association.rb +1 -1
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
  20. data/lib/active_record/associations/builder/has_many.rb +2 -0
  21. data/lib/active_record/associations/builder/has_one.rb +2 -0
  22. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  23. data/lib/active_record/associations/collection_association.rb +66 -53
  24. data/lib/active_record/associations/collection_proxy.rb +30 -73
  25. data/lib/active_record/associations/foreign_association.rb +2 -0
  26. data/lib/active_record/associations/has_many_association.rb +13 -2
  27. data/lib/active_record/associations/has_many_through_association.rb +37 -19
  28. data/lib/active_record/associations/has_one_association.rb +14 -1
  29. data/lib/active_record/associations/has_one_through_association.rb +13 -8
  30. data/lib/active_record/associations/join_dependency.rb +52 -96
  31. data/lib/active_record/associations/join_dependency/join_association.rb +22 -75
  32. data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
  33. data/lib/active_record/associations/join_dependency/join_part.rb +9 -9
  34. data/lib/active_record/associations/preloader.rb +17 -37
  35. data/lib/active_record/associations/preloader/association.rb +53 -92
  36. data/lib/active_record/associations/preloader/through_association.rb +72 -73
  37. data/lib/active_record/associations/singular_association.rb +14 -16
  38. data/lib/active_record/associations/through_association.rb +27 -12
  39. data/lib/active_record/attribute_assignment.rb +2 -5
  40. data/lib/active_record/attribute_decorators.rb +3 -2
  41. data/lib/active_record/attribute_methods.rb +65 -24
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
  43. data/lib/active_record/attribute_methods/dirty.rb +33 -216
  44. data/lib/active_record/attribute_methods/primary_key.rb +10 -13
  45. data/lib/active_record/attribute_methods/query.rb +2 -0
  46. data/lib/active_record/attribute_methods/read.rb +9 -3
  47. data/lib/active_record/attribute_methods/serialization.rb +23 -0
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
  49. data/lib/active_record/attribute_methods/write.rb +22 -19
  50. data/lib/active_record/attributes.rb +7 -6
  51. data/lib/active_record/autosave_association.rb +15 -13
  52. data/lib/active_record/base.rb +2 -0
  53. data/lib/active_record/callbacks.rb +12 -6
  54. data/lib/active_record/coders/json.rb +2 -0
  55. data/lib/active_record/coders/yaml_column.rb +2 -0
  56. data/lib/active_record/collection_cache_key.rb +15 -11
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +120 -39
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +192 -37
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +13 -2
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -25
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +15 -6
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +65 -7
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +158 -87
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +86 -98
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +126 -189
  70. data/lib/active_record/connection_adapters/column.rb +4 -2
  71. data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
  72. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +13 -2
  73. data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
  74. data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -15
  75. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
  76. data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
  77. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
  78. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
  79. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -23
  80. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
  81. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
  82. data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
  83. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
  84. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -32
  85. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +13 -1
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  99. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -1
  101. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +8 -2
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
  106. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  109. data/lib/active_record/connection_adapters/postgresql/quoting.rb +22 -1
  110. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  111. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +50 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
  113. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
  114. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +258 -129
  115. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
  116. data/lib/active_record/connection_adapters/postgresql/utils.rb +3 -1
  117. data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -87
  118. data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
  119. data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
  120. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
  121. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +24 -1
  122. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
  124. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
  125. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +75 -1
  126. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +90 -96
  127. data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
  128. data/lib/active_record/connection_handling.rb +4 -2
  129. data/lib/active_record/core.rb +41 -61
  130. data/lib/active_record/counter_cache.rb +20 -15
  131. data/lib/active_record/define_callbacks.rb +5 -3
  132. data/lib/active_record/dynamic_matchers.rb +9 -9
  133. data/lib/active_record/enum.rb +18 -13
  134. data/lib/active_record/errors.rb +60 -15
  135. data/lib/active_record/explain.rb +3 -1
  136. data/lib/active_record/explain_registry.rb +2 -0
  137. data/lib/active_record/explain_subscriber.rb +2 -0
  138. data/lib/active_record/fixture_set/file.rb +2 -0
  139. data/lib/active_record/fixtures.rb +67 -60
  140. data/lib/active_record/gem_version.rb +4 -2
  141. data/lib/active_record/inheritance.rb +49 -19
  142. data/lib/active_record/integration.rb +58 -19
  143. data/lib/active_record/internal_metadata.rb +2 -0
  144. data/lib/active_record/legacy_yaml_adapter.rb +3 -1
  145. data/lib/active_record/locking/optimistic.rb +30 -42
  146. data/lib/active_record/locking/pessimistic.rb +10 -7
  147. data/lib/active_record/log_subscriber.rb +46 -4
  148. data/lib/active_record/migration.rb +189 -139
  149. data/lib/active_record/migration/command_recorder.rb +11 -9
  150. data/lib/active_record/migration/compatibility.rb +81 -29
  151. data/lib/active_record/migration/join_table.rb +2 -0
  152. data/lib/active_record/model_schema.rb +74 -58
  153. data/lib/active_record/nested_attributes.rb +18 -6
  154. data/lib/active_record/no_touching.rb +3 -1
  155. data/lib/active_record/null_relation.rb +2 -0
  156. data/lib/active_record/persistence.rb +199 -54
  157. data/lib/active_record/query_cache.rb +8 -10
  158. data/lib/active_record/querying.rb +5 -3
  159. data/lib/active_record/railtie.rb +62 -6
  160. data/lib/active_record/railties/console_sandbox.rb +2 -0
  161. data/lib/active_record/railties/controller_runtime.rb +2 -0
  162. data/lib/active_record/railties/databases.rake +48 -38
  163. data/lib/active_record/readonly_attributes.rb +3 -2
  164. data/lib/active_record/reflection.rb +137 -207
  165. data/lib/active_record/relation.rb +132 -207
  166. data/lib/active_record/relation/batches.rb +32 -17
  167. data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
  168. data/lib/active_record/relation/calculations.rb +66 -25
  169. data/lib/active_record/relation/delegation.rb +45 -29
  170. data/lib/active_record/relation/finder_methods.rb +76 -85
  171. data/lib/active_record/relation/from_clause.rb +2 -8
  172. data/lib/active_record/relation/merger.rb +53 -23
  173. data/lib/active_record/relation/predicate_builder.rb +60 -79
  174. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
  175. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  176. data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
  177. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
  178. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  179. data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
  180. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  181. data/lib/active_record/relation/query_attribute.rb +28 -2
  182. data/lib/active_record/relation/query_methods.rb +135 -103
  183. data/lib/active_record/relation/record_fetch_warning.rb +2 -0
  184. data/lib/active_record/relation/spawn_methods.rb +4 -2
  185. data/lib/active_record/relation/where_clause.rb +65 -67
  186. data/lib/active_record/relation/where_clause_factory.rb +5 -48
  187. data/lib/active_record/result.rb +2 -0
  188. data/lib/active_record/runtime_registry.rb +2 -0
  189. data/lib/active_record/sanitization.rb +129 -121
  190. data/lib/active_record/schema.rb +4 -2
  191. data/lib/active_record/schema_dumper.rb +36 -26
  192. data/lib/active_record/schema_migration.rb +2 -0
  193. data/lib/active_record/scoping.rb +12 -10
  194. data/lib/active_record/scoping/default.rb +10 -7
  195. data/lib/active_record/scoping/named.rb +40 -12
  196. data/lib/active_record/secure_token.rb +2 -0
  197. data/lib/active_record/serialization.rb +2 -0
  198. data/lib/active_record/statement_cache.rb +22 -12
  199. data/lib/active_record/store.rb +3 -1
  200. data/lib/active_record/suppressor.rb +2 -0
  201. data/lib/active_record/table_metadata.rb +12 -3
  202. data/lib/active_record/tasks/database_tasks.rb +38 -26
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +11 -50
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -3
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
  206. data/lib/active_record/timestamp.rb +13 -6
  207. data/lib/active_record/touch_later.rb +2 -0
  208. data/lib/active_record/transactions.rb +32 -27
  209. data/lib/active_record/translation.rb +2 -0
  210. data/lib/active_record/type.rb +4 -1
  211. data/lib/active_record/type/adapter_specific_registry.rb +2 -0
  212. data/lib/active_record/type/date.rb +2 -0
  213. data/lib/active_record/type/date_time.rb +2 -0
  214. data/lib/active_record/type/decimal_without_scale.rb +2 -0
  215. data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
  216. data/lib/active_record/type/internal/timezone.rb +2 -0
  217. data/lib/active_record/type/json.rb +30 -0
  218. data/lib/active_record/type/serialized.rb +6 -0
  219. data/lib/active_record/type/text.rb +2 -0
  220. data/lib/active_record/type/time.rb +2 -0
  221. data/lib/active_record/type/type_map.rb +2 -0
  222. data/lib/active_record/type/unsigned_integer.rb +2 -0
  223. data/lib/active_record/type_caster.rb +2 -0
  224. data/lib/active_record/type_caster/connection.rb +2 -0
  225. data/lib/active_record/type_caster/map.rb +3 -1
  226. data/lib/active_record/validations.rb +2 -0
  227. data/lib/active_record/validations/absence.rb +2 -0
  228. data/lib/active_record/validations/associated.rb +2 -0
  229. data/lib/active_record/validations/length.rb +2 -0
  230. data/lib/active_record/validations/presence.rb +2 -0
  231. data/lib/active_record/validations/uniqueness.rb +36 -6
  232. data/lib/active_record/version.rb +2 -0
  233. data/lib/rails/generators/active_record.rb +3 -1
  234. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  235. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  236. data/lib/rails/generators/active_record/migration.rb +2 -0
  237. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
  238. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
  239. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
  240. data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
  241. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
  242. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  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.rb +0 -240
  252. data/lib/active_record/attribute/user_provided_default.rb +0 -30
  253. data/lib/active_record/attribute_mutation_tracker.rb +0 -113
  254. data/lib/active_record/attribute_set.rb +0 -113
  255. data/lib/active_record/attribute_set/builder.rb +0 -124
  256. data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
  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 -33
@@ -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,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,30 @@ module ActiveRecord
14
16
  def with_cast_value(value)
15
17
  QueryAttribute.new(name, value, type)
16
18
  end
19
+
20
+ def nil?
21
+ unless value_before_type_cast.is_a?(StatementCache::Substitute)
22
+ value_before_type_cast.nil? ||
23
+ type.respond_to?(:subtype, true) && value_for_database.nil?
24
+ end
25
+ end
26
+
27
+ def boundable?
28
+ return @_boundable if defined?(@_boundable)
29
+ value_for_database unless value_before_type_cast.is_a?(StatementCache::Substitute)
30
+ @_boundable = true
31
+ rescue ::RangeError
32
+ @_boundable = false
33
+ end
34
+
35
+ def infinity?
36
+ _infinity?(value_before_type_cast) || boundable? && _infinity?(value_for_database)
37
+ end
38
+
39
+ private
40
+ def _infinity?(value)
41
+ value.respond_to?(:infinite?) && value.infinite?
42
+ end
17
43
  end
18
44
  end
19
45
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_record/relation/from_clause"
2
4
  require "active_record/relation/query_attribute"
3
5
  require "active_record/relation/where_clause"
@@ -74,31 +76,6 @@ module ActiveRecord
74
76
  CODE
75
77
  end
76
78
 
77
- def bound_attributes
78
- if limit_value
79
- limit_bind = Attribute.with_cast_value(
80
- "LIMIT".freeze,
81
- connection.sanitize_limit(limit_value),
82
- Type.default_value,
83
- )
84
- end
85
- if offset_value
86
- offset_bind = Attribute.with_cast_value(
87
- "OFFSET".freeze,
88
- offset_value.to_i,
89
- Type.default_value,
90
- )
91
- end
92
- connection.combine_bind_parameters(
93
- from_clause: from_clause.binds,
94
- join_clause: arel.bind_values,
95
- where_clause: where_clause.binds,
96
- having_clause: having_clause.binds,
97
- limit: limit_bind,
98
- offset: offset_bind,
99
- )
100
- end
101
-
102
79
  alias extensions extending_values
103
80
 
104
81
  # Specify relationships to be included in the result set. For
@@ -202,12 +179,13 @@ module ActiveRecord
202
179
 
203
180
  # Works in two unique ways.
204
181
  #
205
- # First: takes a block so it can be used just like +Array#select+.
182
+ # First: takes a block so it can be used just like <tt>Array#select</tt>.
206
183
  #
207
184
  # Model.all.select { |m| m.field == value }
208
185
  #
209
186
  # This will build an array of objects from the database for the scope,
210
- # converting them into an array and iterating through them using +Array#select+.
187
+ # converting them into an array and iterating through them using
188
+ # <tt>Array#select</tt>.
211
189
  #
212
190
  # Second: Modifies the SELECT statement for the query so that only certain
213
191
  # fields are retrieved:
@@ -248,7 +226,7 @@ module ActiveRecord
248
226
  return super()
249
227
  end
250
228
 
251
- raise ArgumentError, "Call this with at least one field" if fields.empty?
229
+ raise ArgumentError, "Call `select' with at least one field" if fields.empty?
252
230
  spawn._select!(*fields)
253
231
  end
254
232
 
@@ -317,6 +295,7 @@ module ActiveRecord
317
295
  spawn.order!(*args)
318
296
  end
319
297
 
298
+ # Same as #order but operates on relation in-place instead of copying.
320
299
  def order!(*args) # :nodoc:
321
300
  preprocess_order_args(args)
322
301
 
@@ -338,6 +317,7 @@ module ActiveRecord
338
317
  spawn.reorder!(*args)
339
318
  end
340
319
 
320
+ # Same as #reorder but operates on relation in-place instead of copying.
341
321
  def reorder!(*args) # :nodoc:
342
322
  preprocess_order_args(args)
343
323
 
@@ -347,8 +327,8 @@ module ActiveRecord
347
327
  end
348
328
 
349
329
  VALID_UNSCOPING_VALUES = Set.new([:where, :select, :group, :order, :lock,
350
- :limit, :offset, :joins, :includes, :from,
351
- :readonly, :having])
330
+ :limit, :offset, :joins, :left_outer_joins,
331
+ :includes, :from, :readonly, :having])
352
332
 
353
333
  # Removes an unwanted relation that is already defined on a chain of relations.
354
334
  # This is useful when passing around chains of relations and would like to
@@ -395,10 +375,11 @@ module ActiveRecord
395
375
  args.each do |scope|
396
376
  case scope
397
377
  when Symbol
378
+ scope = :left_outer_joins if scope == :left_joins
398
379
  if !VALID_UNSCOPING_VALUES.include?(scope)
399
380
  raise ArgumentError, "Called unscope() with invalid unscoping argument ':#{scope}'. Valid arguments are :#{VALID_UNSCOPING_VALUES.to_a.join(", :")}."
400
381
  end
401
- set_value(scope, nil)
382
+ set_value(scope, DEFAULT_VALUES[scope])
402
383
  when Hash
403
384
  scope.each do |key, target_value|
404
385
  if key != :where
@@ -463,16 +444,14 @@ module ActiveRecord
463
444
  # => SELECT "users".* FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
464
445
  #
465
446
  def left_outer_joins(*args)
466
- check_if_method_has_arguments!(:left_outer_joins, args)
467
-
468
- args.compact!
469
- args.flatten!
470
-
447
+ check_if_method_has_arguments!(__callee__, args)
471
448
  spawn.left_outer_joins!(*args)
472
449
  end
473
450
  alias :left_joins :left_outer_joins
474
451
 
475
452
  def left_outer_joins!(*args) # :nodoc:
453
+ args.compact!
454
+ args.flatten!
476
455
  self.left_outer_joins_values += args
477
456
  self
478
457
  end
@@ -657,6 +636,7 @@ module ActiveRecord
657
636
 
658
637
  self.where_clause = self.where_clause.or(other.where_clause)
659
638
  self.having_clause = having_clause.or(other.having_clause)
639
+ self.references_values += other.references_values
660
640
 
661
641
  self
662
642
  end
@@ -797,7 +777,7 @@ module ActiveRecord
797
777
  value = sanitize_forbidden_attributes(value)
798
778
  self.create_with_value = create_with_value.merge(value)
799
779
  else
800
- self.create_with_value = {}
780
+ self.create_with_value = FROZEN_EMPTY_HASH
801
781
  end
802
782
 
803
783
  self
@@ -913,21 +893,28 @@ module ActiveRecord
913
893
  self
914
894
  end
915
895
 
896
+ def skip_query_cache!(value = true) # :nodoc:
897
+ self.skip_query_cache_value = value
898
+ self
899
+ end
900
+
916
901
  # Returns the Arel object associated with the relation.
917
- def arel # :nodoc:
918
- @arel ||= build_arel
902
+ def arel(aliases = nil) # :nodoc:
903
+ @arel ||= build_arel(aliases)
919
904
  end
920
905
 
921
906
  # Returns a relation value with a given name
922
907
  def get_value(name) # :nodoc:
923
- @values[name] || default_value_for(name)
908
+ @values.fetch(name, DEFAULT_VALUES[name])
924
909
  end
925
910
 
926
- # Sets the relation value with the given name
927
- def set_value(name, value) # :nodoc:
928
- assert_mutability!
929
- @values[name] = value
930
- end
911
+ protected
912
+
913
+ # Sets the relation value with the given name
914
+ def set_value(name, value) # :nodoc:
915
+ assert_mutability!
916
+ @values[name] = value
917
+ end
931
918
 
932
919
  private
933
920
 
@@ -936,16 +923,30 @@ module ActiveRecord
936
923
  raise ImmutableRelation if defined?(@arel) && @arel
937
924
  end
938
925
 
939
- def build_arel
926
+ def build_arel(aliases)
940
927
  arel = Arel::SelectManager.new(table)
941
928
 
942
- build_joins(arel, joins_values.flatten) unless joins_values.empty?
943
- build_left_outer_joins(arel, left_outer_joins_values.flatten) unless left_outer_joins_values.empty?
929
+ aliases = build_joins(arel, joins_values.flatten, aliases) unless joins_values.empty?
930
+ build_left_outer_joins(arel, left_outer_joins_values.flatten, aliases) unless left_outer_joins_values.empty?
944
931
 
945
932
  arel.where(where_clause.ast) unless where_clause.empty?
946
933
  arel.having(having_clause.ast) unless having_clause.empty?
947
- arel.take(Arel::Nodes::BindParam.new) if limit_value
948
- arel.skip(Arel::Nodes::BindParam.new) if offset_value
934
+ if limit_value
935
+ limit_attribute = ActiveModel::Attribute.with_cast_value(
936
+ "LIMIT".freeze,
937
+ connection.sanitize_limit(limit_value),
938
+ Type.default_value,
939
+ )
940
+ arel.take(Arel::Nodes::BindParam.new(limit_attribute))
941
+ end
942
+ if offset_value
943
+ offset_attribute = ActiveModel::Attribute.with_cast_value(
944
+ "OFFSET".freeze,
945
+ offset_value.to_i,
946
+ Type.default_value,
947
+ )
948
+ arel.skip(Arel::Nodes::BindParam.new(offset_attribute))
949
+ end
949
950
  arel.group(*arel_columns(group_values.uniq.reject(&:blank?))) unless group_values.empty?
950
951
 
951
952
  build_order(arel)
@@ -964,6 +965,9 @@ module ActiveRecord
964
965
  name = from_clause.name
965
966
  case opts
966
967
  when Relation
968
+ if opts.eager_loading?
969
+ opts = opts.send(:apply_join_dependency)
970
+ end
967
971
  name ||= "subquery"
968
972
  opts.arel.as(name.to_s)
969
973
  else
@@ -971,20 +975,22 @@ module ActiveRecord
971
975
  end
972
976
  end
973
977
 
974
- def build_left_outer_joins(manager, outer_joins)
978
+ def build_left_outer_joins(manager, outer_joins, aliases)
975
979
  buckets = outer_joins.group_by do |join|
976
980
  case join
977
981
  when Hash, Symbol, Array
978
982
  :association_join
983
+ when ActiveRecord::Associations::JoinDependency
984
+ :stashed_join
979
985
  else
980
986
  raise ArgumentError, "only Hash, Symbol and Array are allowed"
981
987
  end
982
988
  end
983
989
 
984
- build_join_query(manager, buckets, Arel::Nodes::OuterJoin)
990
+ build_join_query(manager, buckets, Arel::Nodes::OuterJoin, aliases)
985
991
  end
986
992
 
987
- def build_joins(manager, joins)
993
+ def build_joins(manager, joins, aliases)
988
994
  buckets = joins.group_by do |join|
989
995
  case join
990
996
  when String
@@ -1000,38 +1006,33 @@ module ActiveRecord
1000
1006
  end
1001
1007
  end
1002
1008
 
1003
- build_join_query(manager, buckets, Arel::Nodes::InnerJoin)
1009
+ build_join_query(manager, buckets, Arel::Nodes::InnerJoin, aliases)
1004
1010
  end
1005
1011
 
1006
- def build_join_query(manager, buckets, join_type)
1012
+ def build_join_query(manager, buckets, join_type, aliases)
1007
1013
  buckets.default = []
1008
1014
 
1009
- association_joins = buckets[:association_join]
1010
- stashed_association_joins = buckets[:stashed_join]
1011
- join_nodes = buckets[:join_node].uniq
1012
- string_joins = buckets[:string_join].map(&:strip).uniq
1015
+ association_joins = buckets[:association_join]
1016
+ stashed_joins = buckets[:stashed_join]
1017
+ join_nodes = buckets[:join_node].uniq
1018
+ string_joins = buckets[:string_join].map(&:strip).uniq
1013
1019
 
1014
- join_list = join_nodes + convert_join_strings_to_ast(manager, string_joins)
1020
+ join_list = join_nodes + convert_join_strings_to_ast(string_joins)
1021
+ alias_tracker = alias_tracker(join_list, aliases)
1015
1022
 
1016
1023
  join_dependency = ActiveRecord::Associations::JoinDependency.new(
1017
- @klass,
1018
- association_joins,
1019
- join_list
1024
+ klass, table, association_joins
1020
1025
  )
1021
1026
 
1022
- join_infos = join_dependency.join_constraints stashed_association_joins, join_type
1023
-
1024
- join_infos.each do |info|
1025
- info.joins.each { |join| manager.from(join) }
1026
- manager.bind_values.concat info.binds
1027
- end
1027
+ joins = join_dependency.join_constraints(stashed_joins, join_type, alias_tracker)
1028
+ joins.each { |join| manager.from(join) }
1028
1029
 
1029
1030
  manager.join_sources.concat(join_list)
1030
1031
 
1031
- manager
1032
+ alias_tracker.aliases
1032
1033
  end
1033
1034
 
1034
- def convert_join_strings_to_ast(table, joins)
1035
+ def convert_join_strings_to_ast(joins)
1035
1036
  joins
1036
1037
  .flatten
1037
1038
  .reject(&:blank?)
@@ -1041,23 +1042,44 @@ module ActiveRecord
1041
1042
  def build_select(arel)
1042
1043
  if select_values.any?
1043
1044
  arel.project(*arel_columns(select_values.uniq))
1045
+ elsif klass.ignored_columns.any?
1046
+ arel.project(*klass.column_names.map { |field| arel_attribute(field) })
1044
1047
  else
1045
- arel.project(@klass.arel_table[Arel.star])
1048
+ arel.project(table[Arel.star])
1046
1049
  end
1047
1050
  end
1048
1051
 
1049
1052
  def arel_columns(columns)
1050
- columns.map do |field|
1051
- if (Symbol === field || String === field) && (klass.has_attribute?(field) || klass.attribute_alias?(field)) && !from_clause.value
1052
- arel_attribute(field)
1053
- elsif Symbol === field
1054
- connection.quote_table_name(field.to_s)
1053
+ columns.flat_map do |field|
1054
+ case field
1055
+ when Symbol
1056
+ field = field.to_s
1057
+ arel_column(field) { connection.quote_table_name(field) }
1058
+ when String
1059
+ arel_column(field) { field }
1060
+ when Proc
1061
+ field.call
1055
1062
  else
1056
1063
  field
1057
1064
  end
1058
1065
  end
1059
1066
  end
1060
1067
 
1068
+ def arel_column(field)
1069
+ field = klass.attribute_alias(field) if klass.attribute_alias?(field)
1070
+ from = from_clause.name || from_clause.value
1071
+
1072
+ if klass.columns_hash.key?(field) && (!from || table_name_matches?(from))
1073
+ arel_attribute(field)
1074
+ else
1075
+ yield
1076
+ end
1077
+ end
1078
+
1079
+ def table_name_matches?(from)
1080
+ /(?:\A|(?<!FROM)\s)(?:\b#{table.name}\b|#{connection.quote_table_name(table.name)})(?!\.)/i.match?(from.to_s)
1081
+ end
1082
+
1061
1083
  def reverse_sql_order(order_query)
1062
1084
  if order_query.empty?
1063
1085
  return [arel_attribute(primary_key).desc] if primary_key
@@ -1077,7 +1099,7 @@ module ActiveRecord
1077
1099
  end
1078
1100
  o.split(",").map! do |s|
1079
1101
  s.strip!
1080
- s.gsub!(/\sasc\Z/i, " DESC") || s.gsub!(/\sdesc\Z/i, " ASC") || s.concat(" DESC")
1102
+ s.gsub!(/\sasc\Z/i, " DESC") || s.gsub!(/\sdesc\Z/i, " ASC") || (s << " DESC")
1081
1103
  end
1082
1104
  else
1083
1105
  o
@@ -1086,6 +1108,10 @@ module ActiveRecord
1086
1108
  end
1087
1109
 
1088
1110
  def does_not_support_reverse?(order)
1111
+ # Account for String subclasses like Arel::Nodes::SqlLiteral that
1112
+ # override methods like #count.
1113
+ order = String.new(order) unless order.instance_of?(String)
1114
+
1089
1115
  # Uses SQL function with multiple arguments.
1090
1116
  (order.include?(",") && order.split(",").find { |section| section.count("(") != section.count(")") }) ||
1091
1117
  # Uses "nulls first" like construction.
@@ -1100,41 +1126,55 @@ module ActiveRecord
1100
1126
  end
1101
1127
 
1102
1128
  VALID_DIRECTIONS = [:asc, :desc, :ASC, :DESC,
1103
- "asc", "desc", "ASC", "DESC"] # :nodoc:
1129
+ "asc", "desc", "ASC", "DESC"].to_set # :nodoc:
1104
1130
 
1105
1131
  def validate_order_args(args)
1106
1132
  args.each do |arg|
1107
1133
  next unless arg.is_a?(Hash)
1108
1134
  arg.each do |_key, value|
1109
- raise ArgumentError, "Direction \"#{value}\" is invalid. Valid " \
1110
- "directions are: #{VALID_DIRECTIONS.inspect}" unless VALID_DIRECTIONS.include?(value)
1135
+ unless VALID_DIRECTIONS.include?(value)
1136
+ raise ArgumentError,
1137
+ "Direction \"#{value}\" is invalid. Valid directions are: #{VALID_DIRECTIONS.to_a.inspect}"
1138
+ end
1111
1139
  end
1112
1140
  end
1113
1141
  end
1114
1142
 
1115
1143
  def preprocess_order_args(order_args)
1116
1144
  order_args.map! do |arg|
1117
- klass.send(:sanitize_sql_for_order, arg)
1145
+ klass.sanitize_sql_for_order(arg)
1118
1146
  end
1119
1147
  order_args.flatten!
1148
+
1149
+ @klass.enforce_raw_sql_whitelist(
1150
+ order_args.flat_map { |a| a.is_a?(Hash) ? a.keys : a },
1151
+ whitelist: AttributeMethods::ClassMethods::COLUMN_NAME_ORDER_WHITELIST
1152
+ )
1153
+
1120
1154
  validate_order_args(order_args)
1121
1155
 
1122
1156
  references = order_args.grep(String)
1123
- references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact!
1157
+ references.map! { |arg| arg =~ /^\W?(\w+)\W?\./ && $1 }.compact!
1124
1158
  references!(references) if references.any?
1125
1159
 
1126
1160
  # if a symbol is given we prepend the quoted table name
1127
1161
  order_args.map! do |arg|
1128
1162
  case arg
1129
1163
  when Symbol
1130
- arel_attribute(arg).asc
1164
+ arg = arg.to_s
1165
+ arel_column(arg) {
1166
+ Arel.sql(connection.quote_table_name(arg))
1167
+ }.asc
1131
1168
  when Hash
1132
1169
  arg.map { |field, dir|
1133
1170
  case field
1134
1171
  when Arel::Nodes::SqlLiteral
1135
1172
  field.send(dir.downcase)
1136
1173
  else
1137
- arel_attribute(field).send(dir.downcase)
1174
+ field = field.to_s
1175
+ arel_column(field) {
1176
+ Arel.sql(connection.quote_table_name(field))
1177
+ }.send(dir.downcase)
1138
1178
  end
1139
1179
  }
1140
1180
  else
@@ -1165,7 +1205,7 @@ module ActiveRecord
1165
1205
  end
1166
1206
  end
1167
1207
 
1168
- STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having]
1208
+ STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having, :unscope, :references]
1169
1209
  def structurally_incompatible_values_for_or(other)
1170
1210
  STRUCTURAL_OR_METHODS.reject do |method|
1171
1211
  get_value(method) == other.get_value(method)
@@ -1177,23 +1217,15 @@ module ActiveRecord
1177
1217
  end
1178
1218
  alias having_clause_factory where_clause_factory
1179
1219
 
1180
- def default_value_for(name)
1181
- case name
1182
- when :create_with
1183
- FROZEN_EMPTY_HASH
1184
- when :readonly
1185
- false
1186
- when :where, :having
1187
- Relation::WhereClause.empty
1188
- when :from
1189
- Relation::FromClause.empty
1190
- when *Relation::MULTI_VALUE_METHODS
1191
- FROZEN_EMPTY_ARRAY
1192
- when *Relation::SINGLE_VALUE_METHODS
1193
- nil
1194
- else
1195
- raise ArgumentError, "unknown relation value #{name.inspect}"
1196
- end
1220
+ DEFAULT_VALUES = {
1221
+ create_with: FROZEN_EMPTY_HASH,
1222
+ where: Relation::WhereClause.empty,
1223
+ having: Relation::WhereClause.empty,
1224
+ from: Relation::FromClause.empty
1225
+ }
1226
+
1227
+ Relation::MULTI_VALUE_METHODS.each do |value|
1228
+ DEFAULT_VALUES[value] ||= FROZEN_EMPTY_ARRAY
1197
1229
  end
1198
1230
  end
1199
1231
  end