activerecord 5.0.7 → 5.1.7

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 (219) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +657 -2080
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/examples/performance.rb +28 -28
  6. data/examples/simple.rb +3 -3
  7. data/lib/active_record/aggregations.rb +244 -244
  8. data/lib/active_record/association_relation.rb +5 -5
  9. data/lib/active_record/associations/alias_tracker.rb +10 -11
  10. data/lib/active_record/associations/association.rb +23 -5
  11. data/lib/active_record/associations/association_scope.rb +95 -81
  12. data/lib/active_record/associations/belongs_to_association.rb +7 -4
  13. data/lib/active_record/associations/builder/belongs_to.rb +30 -16
  14. data/lib/active_record/associations/builder/collection_association.rb +1 -2
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +27 -27
  16. data/lib/active_record/associations/collection_association.rb +36 -205
  17. data/lib/active_record/associations/collection_proxy.rb +132 -63
  18. data/lib/active_record/associations/has_many_association.rb +10 -19
  19. data/lib/active_record/associations/has_many_through_association.rb +12 -4
  20. data/lib/active_record/associations/has_one_association.rb +24 -28
  21. data/lib/active_record/associations/has_one_through_association.rb +5 -1
  22. data/lib/active_record/associations/join_dependency/join_association.rb +4 -28
  23. data/lib/active_record/associations/join_dependency/join_base.rb +1 -1
  24. data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
  25. data/lib/active_record/associations/join_dependency.rb +121 -118
  26. data/lib/active_record/associations/preloader/association.rb +64 -64
  27. data/lib/active_record/associations/preloader/belongs_to.rb +0 -2
  28. data/lib/active_record/associations/preloader/collection_association.rb +6 -6
  29. data/lib/active_record/associations/preloader/has_many.rb +0 -2
  30. data/lib/active_record/associations/preloader/singular_association.rb +6 -8
  31. data/lib/active_record/associations/preloader/through_association.rb +41 -41
  32. data/lib/active_record/associations/preloader.rb +94 -94
  33. data/lib/active_record/associations/singular_association.rb +8 -25
  34. data/lib/active_record/associations/through_association.rb +2 -5
  35. data/lib/active_record/associations.rb +1591 -1562
  36. data/lib/active_record/attribute/user_provided_default.rb +4 -2
  37. data/lib/active_record/attribute.rb +98 -71
  38. data/lib/active_record/attribute_assignment.rb +61 -61
  39. data/lib/active_record/attribute_decorators.rb +35 -13
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -7
  41. data/lib/active_record/attribute_methods/dirty.rb +229 -46
  42. data/lib/active_record/attribute_methods/primary_key.rb +74 -73
  43. data/lib/active_record/attribute_methods/read.rb +39 -35
  44. data/lib/active_record/attribute_methods/serialization.rb +7 -7
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +35 -58
  46. data/lib/active_record/attribute_methods/write.rb +30 -33
  47. data/lib/active_record/attribute_methods.rb +56 -65
  48. data/lib/active_record/attribute_mutation_tracker.rb +63 -11
  49. data/lib/active_record/attribute_set/builder.rb +27 -33
  50. data/lib/active_record/attribute_set/yaml_encoder.rb +41 -0
  51. data/lib/active_record/attribute_set.rb +9 -6
  52. data/lib/active_record/attributes.rb +22 -22
  53. data/lib/active_record/autosave_association.rb +18 -13
  54. data/lib/active_record/base.rb +24 -22
  55. data/lib/active_record/callbacks.rb +56 -14
  56. data/lib/active_record/coders/yaml_column.rb +9 -11
  57. data/lib/active_record/collection_cache_key.rb +3 -4
  58. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +330 -284
  59. data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -3
  60. data/lib/active_record/connection_adapters/abstract/database_statements.rb +39 -37
  61. data/lib/active_record/connection_adapters/abstract/query_cache.rb +32 -27
  62. data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -51
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +10 -20
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +74 -79
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +53 -41
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +120 -100
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +49 -43
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +165 -135
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +404 -424
  70. data/lib/active_record/connection_adapters/column.rb +26 -4
  71. data/lib/active_record/connection_adapters/connection_specification.rb +128 -118
  72. data/lib/active_record/connection_adapters/mysql/column.rb +6 -31
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -49
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +22 -22
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +6 -12
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +16 -19
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -28
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +7 -6
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +23 -27
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +32 -53
  83. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +3 -3
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +19 -9
  85. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +5 -3
  86. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +1 -1
  89. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -3
  90. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +16 -16
  91. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +0 -10
  92. data/lib/active_record/connection_adapters/postgresql/oid/{rails_5_1_point.rb → legacy_point.rb} +9 -16
  93. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +13 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +28 -8
  96. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +32 -30
  97. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -1
  98. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +51 -51
  99. data/lib/active_record/connection_adapters/postgresql/oid.rb +22 -21
  100. data/lib/active_record/connection_adapters/postgresql/quoting.rb +40 -35
  101. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +15 -0
  102. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +37 -24
  103. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +19 -23
  104. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +182 -222
  105. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +6 -4
  106. data/lib/active_record/connection_adapters/postgresql/utils.rb +7 -5
  107. data/lib/active_record/connection_adapters/postgresql_adapter.rb +198 -167
  108. data/lib/active_record/connection_adapters/schema_cache.rb +16 -7
  109. data/lib/active_record/connection_adapters/sql_type_metadata.rb +3 -3
  110. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +1 -1
  111. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +16 -19
  112. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +1 -8
  113. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +28 -0
  114. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +17 -0
  115. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +32 -0
  116. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +184 -167
  117. data/lib/active_record/connection_adapters/statement_pool.rb +7 -7
  118. data/lib/active_record/connection_handling.rb +14 -26
  119. data/lib/active_record/core.rb +109 -93
  120. data/lib/active_record/counter_cache.rb +60 -13
  121. data/lib/active_record/define_callbacks.rb +20 -0
  122. data/lib/active_record/dynamic_matchers.rb +80 -79
  123. data/lib/active_record/enum.rb +8 -6
  124. data/lib/active_record/errors.rb +64 -15
  125. data/lib/active_record/explain.rb +1 -2
  126. data/lib/active_record/explain_registry.rb +1 -1
  127. data/lib/active_record/explain_subscriber.rb +7 -4
  128. data/lib/active_record/fixture_set/file.rb +11 -8
  129. data/lib/active_record/fixtures.rb +66 -53
  130. data/lib/active_record/gem_version.rb +1 -1
  131. data/lib/active_record/inheritance.rb +93 -79
  132. data/lib/active_record/integration.rb +7 -7
  133. data/lib/active_record/internal_metadata.rb +3 -16
  134. data/lib/active_record/legacy_yaml_adapter.rb +1 -1
  135. data/lib/active_record/locking/optimistic.rb +69 -74
  136. data/lib/active_record/locking/pessimistic.rb +10 -1
  137. data/lib/active_record/log_subscriber.rb +23 -28
  138. data/lib/active_record/migration/command_recorder.rb +94 -94
  139. data/lib/active_record/migration/compatibility.rb +100 -47
  140. data/lib/active_record/migration/join_table.rb +6 -6
  141. data/lib/active_record/migration.rb +153 -155
  142. data/lib/active_record/model_schema.rb +94 -107
  143. data/lib/active_record/nested_attributes.rb +200 -199
  144. data/lib/active_record/null_relation.rb +11 -34
  145. data/lib/active_record/persistence.rb +65 -50
  146. data/lib/active_record/query_cache.rb +2 -6
  147. data/lib/active_record/querying.rb +3 -4
  148. data/lib/active_record/railtie.rb +16 -17
  149. data/lib/active_record/railties/controller_runtime.rb +6 -2
  150. data/lib/active_record/railties/databases.rake +105 -133
  151. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  152. data/lib/active_record/readonly_attributes.rb +2 -2
  153. data/lib/active_record/reflection.rb +154 -108
  154. data/lib/active_record/relation/batches/batch_enumerator.rb +1 -1
  155. data/lib/active_record/relation/batches.rb +80 -51
  156. data/lib/active_record/relation/calculations.rb +169 -162
  157. data/lib/active_record/relation/delegation.rb +32 -31
  158. data/lib/active_record/relation/finder_methods.rb +197 -231
  159. data/lib/active_record/relation/merger.rb +58 -62
  160. data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -5
  161. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +23 -23
  162. data/lib/active_record/relation/predicate_builder/base_handler.rb +3 -1
  163. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +0 -8
  164. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +12 -10
  165. data/lib/active_record/relation/predicate_builder/range_handler.rb +0 -8
  166. data/lib/active_record/relation/predicate_builder.rb +92 -89
  167. data/lib/active_record/relation/query_attribute.rb +1 -1
  168. data/lib/active_record/relation/query_methods.rb +255 -293
  169. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  170. data/lib/active_record/relation/spawn_methods.rb +4 -5
  171. data/lib/active_record/relation/where_clause.rb +80 -65
  172. data/lib/active_record/relation/where_clause_factory.rb +47 -8
  173. data/lib/active_record/relation.rb +93 -119
  174. data/lib/active_record/result.rb +41 -32
  175. data/lib/active_record/runtime_registry.rb +3 -3
  176. data/lib/active_record/sanitization.rb +176 -192
  177. data/lib/active_record/schema.rb +3 -3
  178. data/lib/active_record/schema_dumper.rb +15 -38
  179. data/lib/active_record/schema_migration.rb +8 -4
  180. data/lib/active_record/scoping/default.rb +90 -90
  181. data/lib/active_record/scoping/named.rb +11 -11
  182. data/lib/active_record/scoping.rb +6 -6
  183. data/lib/active_record/secure_token.rb +2 -2
  184. data/lib/active_record/statement_cache.rb +13 -15
  185. data/lib/active_record/store.rb +31 -32
  186. data/lib/active_record/suppressor.rb +2 -1
  187. data/lib/active_record/table_metadata.rb +9 -5
  188. data/lib/active_record/tasks/database_tasks.rb +65 -55
  189. data/lib/active_record/tasks/mysql_database_tasks.rb +76 -73
  190. data/lib/active_record/tasks/postgresql_database_tasks.rb +72 -47
  191. data/lib/active_record/tasks/sqlite_database_tasks.rb +18 -16
  192. data/lib/active_record/timestamp.rb +46 -25
  193. data/lib/active_record/touch_later.rb +1 -2
  194. data/lib/active_record/transactions.rb +97 -109
  195. data/lib/active_record/type/adapter_specific_registry.rb +46 -42
  196. data/lib/active_record/type/decimal_without_scale.rb +13 -0
  197. data/lib/active_record/type/hash_lookup_type_map.rb +3 -3
  198. data/lib/active_record/type/internal/abstract_json.rb +4 -0
  199. data/lib/active_record/type/serialized.rb +14 -8
  200. data/lib/active_record/type/text.rb +9 -0
  201. data/lib/active_record/type/time.rb +0 -1
  202. data/lib/active_record/type/type_map.rb +11 -15
  203. data/lib/active_record/type/unsigned_integer.rb +15 -0
  204. data/lib/active_record/type.rb +17 -13
  205. data/lib/active_record/type_caster/connection.rb +8 -6
  206. data/lib/active_record/type_caster/map.rb +3 -1
  207. data/lib/active_record/type_caster.rb +2 -2
  208. data/lib/active_record/validations/associated.rb +1 -1
  209. data/lib/active_record/validations/presence.rb +2 -2
  210. data/lib/active_record/validations/uniqueness.rb +8 -39
  211. data/lib/active_record/validations.rb +4 -4
  212. data/lib/active_record/version.rb +1 -1
  213. data/lib/active_record.rb +20 -20
  214. data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -34
  215. data/lib/rails/generators/active_record/migration.rb +1 -1
  216. data/lib/rails/generators/active_record/model/model_generator.rb +9 -9
  217. data/lib/rails/generators/active_record.rb +4 -4
  218. metadata +24 -13
  219. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
@@ -2,15 +2,15 @@ module ActiveRecord
2
2
  class Relation
3
3
  module RecordFetchWarning
4
4
  # When this module is prepended to ActiveRecord::Relation and
5
- # `config.active_record.warn_on_records_fetched_greater_than` is
5
+ # +config.active_record.warn_on_records_fetched_greater_than+ is
6
6
  # set to an integer, if the number of records a query returns is
7
- # greater than the value of `warn_on_records_fetched_greater_than`,
7
+ # greater than the value of +warn_on_records_fetched_greater_than+,
8
8
  # a warning is logged. This allows for the detection of queries that
9
9
  # return a large number of records, which could cause memory bloat.
10
10
  #
11
11
  # In most cases, fetching large number of records can be performed
12
12
  # efficiently using the ActiveRecord::Batches methods.
13
- # See active_record/lib/relation/batches.rb for more information.
13
+ # See ActiveRecord::Batches for more information.
14
14
  def exec_queries
15
15
  QueryRegistry.reset
16
16
 
@@ -1,10 +1,9 @@
1
- require 'active_support/core_ext/hash/except'
2
- require 'active_support/core_ext/hash/slice'
3
- require 'active_record/relation/merger'
1
+ require "active_support/core_ext/hash/except"
2
+ require "active_support/core_ext/hash/slice"
3
+ require "active_record/relation/merger"
4
4
 
5
5
  module ActiveRecord
6
6
  module SpawnMethods
7
-
8
7
  # This is overridden by Associations::CollectionProxy
9
8
  def spawn #:nodoc:
10
9
  clone
@@ -67,7 +66,7 @@ module ActiveRecord
67
66
 
68
67
  private
69
68
 
70
- def relation_with(values) # :nodoc:
69
+ def relation_with(values)
71
70
  result = Relation.create(klass, table, predicate_builder, values)
72
71
  result.extend(*extending_values) if extending_values.any?
73
72
  result
@@ -25,10 +25,7 @@ module ActiveRecord
25
25
  end
26
26
 
27
27
  def except(*columns)
28
- WhereClause.new(
29
- predicates_except(columns),
30
- binds_except(columns),
31
- )
28
+ WhereClause.new(*except_predicates_and_binds(columns))
32
29
  end
33
30
 
34
31
  def or(other)
@@ -84,91 +81,109 @@ module ActiveRecord
84
81
  @empty ||= new([], [])
85
82
  end
86
83
 
84
+ # TODO Change this to private once we've dropped Ruby 2.2 support.
85
+ # Workaround for Ruby 2.2 "private attribute?" warning.
87
86
  protected
88
87
 
89
- attr_reader :predicates
88
+ attr_reader :predicates
90
89
 
91
- def referenced_columns
92
- @referenced_columns ||= begin
93
- equality_nodes = predicates.select { |n| equality_node?(n) }
94
- Set.new(equality_nodes, &:left)
90
+ def referenced_columns
91
+ @referenced_columns ||= begin
92
+ equality_nodes = predicates.select { |n| equality_node?(n) }
93
+ Set.new(equality_nodes, &:left)
94
+ end
95
95
  end
96
- end
97
96
 
98
97
  private
99
98
 
100
- def predicates_unreferenced_by(other)
101
- predicates.reject do |n|
102
- equality_node?(n) && other.referenced_columns.include?(n.left)
99
+ def predicates_unreferenced_by(other)
100
+ predicates.reject do |n|
101
+ equality_node?(n) && other.referenced_columns.include?(n.left)
102
+ end
103
103
  end
104
- end
105
-
106
- def equality_node?(node)
107
- node.respond_to?(:operator) && node.operator == :==
108
- end
109
104
 
110
- def non_conflicting_binds(other)
111
- conflicts = referenced_columns & other.referenced_columns
112
- conflicts.map! { |node| node.name.to_s }
113
- binds.reject { |attr| conflicts.include?(attr.name) }
114
- end
105
+ def equality_node?(node)
106
+ node.respond_to?(:operator) && node.operator == :==
107
+ end
115
108
 
116
- def inverted_predicates
117
- predicates.map { |node| invert_predicate(node) }
118
- end
109
+ def non_conflicting_binds(other)
110
+ conflicts = referenced_columns & other.referenced_columns
111
+ conflicts.map! { |node| node.name.to_s }
112
+ binds.reject { |attr| conflicts.include?(attr.name) }
113
+ end
119
114
 
120
- def invert_predicate(node)
121
- case node
122
- when NilClass
123
- raise ArgumentError, 'Invalid argument for .where.not(), got nil.'
124
- when Arel::Nodes::In
125
- Arel::Nodes::NotIn.new(node.left, node.right)
126
- when Arel::Nodes::Equality
127
- Arel::Nodes::NotEqual.new(node.left, node.right)
128
- when String
129
- Arel::Nodes::Not.new(Arel::Nodes::SqlLiteral.new(node))
130
- else
131
- Arel::Nodes::Not.new(node)
115
+ def inverted_predicates
116
+ predicates.map { |node| invert_predicate(node) }
132
117
  end
133
- end
134
118
 
135
- def predicates_except(columns)
136
- predicates.reject do |node|
119
+ def invert_predicate(node)
137
120
  case node
138
- when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
139
- subrelation = (node.left.kind_of?(Arel::Attributes::Attribute) ? node.left : node.right)
140
- columns.include?(subrelation.name.to_s)
121
+ when NilClass
122
+ raise ArgumentError, "Invalid argument for .where.not(), got nil."
123
+ when Arel::Nodes::In
124
+ Arel::Nodes::NotIn.new(node.left, node.right)
125
+ when Arel::Nodes::Equality
126
+ Arel::Nodes::NotEqual.new(node.left, node.right)
127
+ when String
128
+ Arel::Nodes::Not.new(Arel::Nodes::SqlLiteral.new(node))
129
+ else
130
+ Arel::Nodes::Not.new(node)
141
131
  end
142
132
  end
143
- end
144
133
 
145
- def binds_except(columns)
146
- binds.reject do |attr|
147
- columns.include?(attr.name)
134
+ def except_predicates_and_binds(columns)
135
+ except_binds = []
136
+ binds_index = 0
137
+
138
+ predicates = self.predicates.reject do |node|
139
+ binds_contains = node.grep(Arel::Nodes::BindParam).size if node.is_a?(Arel::Nodes::Node)
140
+
141
+ except = \
142
+ case node
143
+ when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
144
+ subrelation = (node.left.kind_of?(Arel::Attributes::Attribute) ? node.left : node.right)
145
+ columns.include?(subrelation.name.to_s)
146
+ end
147
+
148
+ if except && binds_contains > 0
149
+ (binds_index...(binds_index + binds_contains)).each do |i|
150
+ except_binds[i] = true
151
+ end
152
+ end
153
+
154
+ binds_index += binds_contains if binds_contains
155
+
156
+ except
157
+ end
158
+
159
+ binds = self.binds.reject.with_index do |_, i|
160
+ except_binds[i]
161
+ end
162
+
163
+ [predicates, binds]
148
164
  end
149
- end
150
165
 
151
- def predicates_with_wrapped_sql_literals
152
- non_empty_predicates.map do |node|
153
- if Arel::Nodes::Equality === node
154
- node
155
- else
156
- wrap_sql_literal(node)
166
+ def predicates_with_wrapped_sql_literals
167
+ non_empty_predicates.map do |node|
168
+ if Arel::Nodes::Equality === node
169
+ node
170
+ else
171
+ wrap_sql_literal(node)
172
+ end
157
173
  end
158
174
  end
159
- end
160
175
 
161
- ARRAY_WITH_EMPTY_STRING = ['']
162
- def non_empty_predicates
163
- predicates - ARRAY_WITH_EMPTY_STRING
164
- end
176
+ ARRAY_WITH_EMPTY_STRING = [""]
177
+ def non_empty_predicates
178
+ predicates - ARRAY_WITH_EMPTY_STRING
179
+ end
165
180
 
166
- def wrap_sql_literal(node)
167
- if ::String === node
168
- node = Arel.sql(node)
181
+ def wrap_sql_literal(node)
182
+ if ::String === node
183
+ node = Arel.sql(node)
184
+ end
185
+ Arel::Nodes::Grouping.new(node)
169
186
  end
170
- Arel::Nodes::Grouping.new(node)
171
- end
172
187
  end
173
188
  end
174
189
  end
@@ -7,8 +7,6 @@ module ActiveRecord
7
7
  end
8
8
 
9
9
  def build(opts, other)
10
- binds = []
11
-
12
10
  case opts
13
11
  when String, Array
14
12
  parts = [klass.send(:sanitize_sql, other.empty? ? opts : ([opts] + other))]
@@ -17,22 +15,63 @@ module ActiveRecord
17
15
  attributes = klass.send(:expand_hash_conditions_for_aggregates, attributes)
18
16
  attributes.stringify_keys!
19
17
 
20
- attributes, binds = predicate_builder.create_binds(attributes)
21
-
22
- parts = predicate_builder.build_from_hash(attributes)
18
+ if perform_case_sensitive?(options = other.last)
19
+ parts, binds = build_for_case_sensitive(attributes, options)
20
+ else
21
+ attributes, binds = predicate_builder.create_binds(attributes)
22
+ parts = predicate_builder.build_from_hash(attributes)
23
+ end
23
24
  when Arel::Nodes::Node
24
25
  parts = [opts]
25
- binds = other
26
26
  else
27
27
  raise ArgumentError, "Unsupported argument type: #{opts} (#{opts.class})"
28
28
  end
29
29
 
30
- WhereClause.new(parts, binds)
30
+ WhereClause.new(parts, binds || [])
31
31
  end
32
32
 
33
+ # TODO Change this to private once we've dropped Ruby 2.2 support.
34
+ # Workaround for Ruby 2.2 "private attribute?" warning.
33
35
  protected
34
36
 
35
- attr_reader :klass, :predicate_builder
37
+ attr_reader :klass, :predicate_builder
38
+
39
+ private
40
+
41
+ def perform_case_sensitive?(options)
42
+ options && options.key?(:case_sensitive)
43
+ end
44
+
45
+ def build_for_case_sensitive(attributes, options)
46
+ parts, binds = [], []
47
+ table = klass.arel_table
48
+
49
+ attributes.each do |attribute, value|
50
+ if reflection = klass._reflect_on_association(attribute)
51
+ attribute = reflection.foreign_key.to_s
52
+ value = value[reflection.klass.primary_key] unless value.nil?
53
+ end
54
+
55
+ if value.nil?
56
+ parts << table[attribute].eq(value)
57
+ else
58
+ column = klass.column_for_attribute(attribute)
59
+
60
+ binds << predicate_builder.send(:build_bind_param, attribute, value)
61
+ value = Arel::Nodes::BindParam.new
62
+
63
+ predicate = if options[:case_sensitive]
64
+ klass.connection.case_sensitive_comparison(table, attribute, column, value)
65
+ else
66
+ klass.connection.case_insensitive_comparison(table, attribute, column, value)
67
+ end
68
+
69
+ parts << predicate
70
+ end
71
+ end
72
+
73
+ [parts, binds]
74
+ end
36
75
  end
37
76
  end
38
77
  end
@@ -1,5 +1,3 @@
1
- require "arel/collectors/bind"
2
-
3
1
  module ActiveRecord
4
2
  # = Active Record \Relation
5
3
  class Relation
@@ -31,9 +29,7 @@ module ActiveRecord
31
29
  end
32
30
 
33
31
  def initialize_copy(other)
34
- # This method is a hot spot, so for now, use Hash[] to dup the hash.
35
- # https://bugs.ruby-lang.org/issues/7166
36
- @values = Hash[@values]
32
+ @values = @values.dup
37
33
  reset
38
34
  end
39
35
 
@@ -64,14 +60,14 @@ module ActiveRecord
64
60
 
65
61
  @klass.connection.insert(
66
62
  im,
67
- 'SQL',
68
- primary_key,
63
+ "SQL",
64
+ primary_key || false,
69
65
  primary_key_value,
70
66
  nil,
71
67
  binds)
72
68
  end
73
69
 
74
- def _update_record(values, id, id_was) # :nodoc:
70
+ def _update_record(values, constraints) # :nodoc:
75
71
  substitutes, binds = substitute_values values
76
72
 
77
73
  scope = @klass.unscoped
@@ -80,7 +76,7 @@ module ActiveRecord
80
76
  scope.unscope!(where: @klass.inheritance_column)
81
77
  end
82
78
 
83
- relation = scope.where(@klass.primary_key => (id_was || id))
79
+ relation = scope.where(constraints)
84
80
  bvs = binds + relation.bound_attributes
85
81
  um = relation
86
82
  .arel
@@ -88,7 +84,7 @@ module ActiveRecord
88
84
 
89
85
  @klass.connection.update(
90
86
  um,
91
- 'SQL',
87
+ "SQL",
92
88
  bvs,
93
89
  )
94
90
  end
@@ -247,7 +243,6 @@ module ActiveRecord
247
243
  # Please see further details in the
248
244
  # {Active Record Query Interface guide}[http://guides.rubyonrails.org/active_record_querying.html#running-explain].
249
245
  def explain
250
- #TODO: Fix for binds.
251
246
  exec_explain(collecting_queries_for_explain { exec_queries })
252
247
  end
253
248
 
@@ -266,10 +261,6 @@ module ActiveRecord
266
261
  coder.represent_seq(nil, records)
267
262
  end
268
263
 
269
- def as_json(options = nil) #:nodoc:
270
- records.as_json(options)
271
- end
272
-
273
264
  # Returns size of the records.
274
265
  def size
275
266
  loaded? ? @records.length : count(:all)
@@ -278,13 +269,7 @@ module ActiveRecord
278
269
  # Returns true if there are no records.
279
270
  def empty?
280
271
  return @records.empty? if loaded?
281
-
282
- if limit_value == 0
283
- true
284
- else
285
- c = count(:all)
286
- c.respond_to?(:zero?) ? c.zero? : c.empty?
287
- end
272
+ !exists?
288
273
  end
289
274
 
290
275
  # Returns true if there are no records.
@@ -383,7 +368,7 @@ module ActiveRecord
383
368
  stmt.set Arel.sql(@klass.send(:sanitize_sql_for_assignment, updates))
384
369
  stmt.table(table)
385
370
 
386
- if joins_values.any?
371
+ if has_join_values?
387
372
  @klass.connection.join_to_update(stmt, arel, arel_attribute(primary_key))
388
373
  else
389
374
  stmt.key = arel_attribute(primary_key)
@@ -392,7 +377,7 @@ module ActiveRecord
392
377
  stmt.wheres = arel.constraints
393
378
  end
394
379
 
395
- @klass.connection.update stmt, 'SQL', bound_attributes
380
+ @klass.connection.update stmt, "SQL", bound_attributes
396
381
  end
397
382
 
398
383
  # Updates an object (or multiple objects) and saves it to the database, if validations pass.
@@ -428,8 +413,7 @@ module ActiveRecord
428
413
  records.each { |record| record.update(attributes) }
429
414
  else
430
415
  if ActiveRecord::Base === id
431
- id = id.id
432
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
416
+ raise ArgumentError, <<-MSG.squish
433
417
  You are passing an instance of ActiveRecord::Base to `update`.
434
418
  Please pass the id of the object by calling `.id`.
435
419
  MSG
@@ -456,16 +440,8 @@ module ActiveRecord
456
440
  # ==== Examples
457
441
  #
458
442
  # Person.where(age: 0..18).destroy_all
459
- def destroy_all(conditions = nil)
460
- if conditions
461
- ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
462
- Passing conditions to destroy_all is deprecated and will be removed in Rails 5.1.
463
- To achieve the same use where(conditions).destroy_all.
464
- MESSAGE
465
- where(conditions).destroy_all
466
- else
467
- records.each(&:destroy).tap { reset }
468
- end
443
+ def destroy_all
444
+ records.each(&:destroy).tap { reset }
469
445
  end
470
446
 
471
447
  # Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
@@ -513,41 +489,28 @@ module ActiveRecord
513
489
  #
514
490
  # Post.limit(100).delete_all
515
491
  # # => ActiveRecord::ActiveRecordError: delete_all doesn't support limit
516
- def delete_all(conditions = nil)
517
- invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select { |method|
518
- if MULTI_VALUE_METHODS.include?(method)
519
- send("#{method}_values").any?
520
- elsif SINGLE_VALUE_METHODS.include?(method)
521
- send("#{method}_value")
522
- elsif CLAUSE_METHODS.include?(method)
523
- send("#{method}_clause").any?
524
- end
525
- }
492
+ def delete_all
493
+ invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select do |method|
494
+ value = get_value(method)
495
+ SINGLE_VALUE_METHODS.include?(method) ? value : value.any?
496
+ end
526
497
  if invalid_methods.any?
527
498
  raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
528
499
  end
529
500
 
530
- if conditions
531
- ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
532
- Passing conditions to delete_all is deprecated and will be removed in Rails 5.1.
533
- To achieve the same use where(conditions).delete_all.
534
- MESSAGE
535
- where(conditions).delete_all
536
- else
537
- stmt = Arel::DeleteManager.new
538
- stmt.from(table)
501
+ stmt = Arel::DeleteManager.new
502
+ stmt.from(table)
539
503
 
540
- if joins_values.any?
541
- @klass.connection.join_to_delete(stmt, arel, arel_attribute(primary_key))
542
- else
543
- stmt.wheres = arel.constraints
544
- end
504
+ if has_join_values?
505
+ @klass.connection.join_to_delete(stmt, arel, arel_attribute(primary_key))
506
+ else
507
+ stmt.wheres = arel.constraints
508
+ end
545
509
 
546
- affected = @klass.connection.delete(stmt, 'SQL', bound_attributes)
510
+ affected = @klass.connection.delete(stmt, "SQL", bound_attributes)
547
511
 
548
- reset
549
- affected
550
- end
512
+ reset
513
+ affected
551
514
  end
552
515
 
553
516
  # Deletes the row with a primary key matching the +id+ argument, using a
@@ -605,19 +568,16 @@ module ActiveRecord
605
568
  # # => SELECT "users".* FROM "users" WHERE "users"."name" = 'Oscar'
606
569
  def to_sql
607
570
  @to_sql ||= begin
608
- relation = self
609
- connection = klass.connection
610
- visitor = connection.visitor
571
+ relation = self
611
572
 
612
573
  if eager_loading?
613
- find_with_associations { |rel| relation = rel }
574
+ find_with_associations { |rel, _| relation = rel }
614
575
  end
615
576
 
616
- binds = relation.bound_attributes
617
- binds = connection.prepare_binds_for_database(binds)
618
- binds.map! { |value| connection.quote(value) }
619
- collect = visitor.accept(relation.arel.ast, Arel::Collectors::Bind.new)
620
- collect.substitute_binds(binds).join
577
+ conn = klass.connection
578
+ conn.unprepared_statement {
579
+ conn.to_sql(relation.arel, relation.bound_attributes)
580
+ }
621
581
  end
622
582
  end
623
583
 
@@ -648,15 +608,6 @@ module ActiveRecord
648
608
  includes_values & joins_values
649
609
  end
650
610
 
651
- # {#uniq}[rdoc-ref:QueryMethods#uniq] and
652
- # {#uniq!}[rdoc-ref:QueryMethods#uniq!] are silently deprecated.
653
- # #uniq_value delegates to #distinct_value to maintain backwards compatibility.
654
- # Use #distinct_value instead.
655
- def uniq_value
656
- distinct_value
657
- end
658
- deprecate uniq_value: :distinct_value
659
-
660
611
  # Compares two relations for equality.
661
612
  def ==(other)
662
613
  case other
@@ -670,7 +621,7 @@ module ActiveRecord
670
621
  end
671
622
 
672
623
  def pretty_print(q)
673
- q.pp(self.records)
624
+ q.pp(records)
674
625
  end
675
626
 
676
627
  # Returns true if relation is blank.
@@ -679,12 +630,14 @@ module ActiveRecord
679
630
  end
680
631
 
681
632
  def values
682
- Hash[@values]
633
+ @values.dup
683
634
  end
684
635
 
685
636
  def inspect
686
- entries = records.take([limit_value, 11].compact.min).map!(&:inspect)
687
- entries[10] = '...' if entries.size == 11
637
+ subject = loaded? ? records : self
638
+ entries = subject.take([limit_value, 11].compact.min).map!(&:inspect)
639
+
640
+ entries[10] = "..." if entries.size == 11
688
641
 
689
642
  "#<#{self.class.name} [#{entries.join(', ')}]>"
690
643
  end
@@ -693,6 +646,10 @@ module ActiveRecord
693
646
  @values == klass.unscoped.values
694
647
  end
695
648
 
649
+ def has_limit_or_offset? # :nodoc:
650
+ limit_value || offset_value
651
+ end
652
+
696
653
  protected
697
654
 
698
655
  def load_records(records)
@@ -702,48 +659,65 @@ module ActiveRecord
702
659
 
703
660
  private
704
661
 
705
- def exec_queries(&block)
706
- @records = eager_loading? ? find_with_associations.freeze : @klass.find_by_sql(arel, bound_attributes, &block).freeze
707
-
708
- preload = preload_values
709
- preload += includes_values unless eager_loading?
710
- preloader = build_preloader
711
- preload.each do |associations|
712
- preloader.preload @records, associations
662
+ def has_join_values?
663
+ joins_values.any? || left_outer_joins_values.any?
713
664
  end
714
665
 
715
- @records.each(&:readonly!) if readonly_value
666
+ def exec_queries(&block)
667
+ @records =
668
+ if eager_loading?
669
+ find_with_associations do |relation, join_dependency|
670
+ if ActiveRecord::NullRelation === relation
671
+ []
672
+ else
673
+ rows = connection.select_all(relation.arel, "SQL", relation.bound_attributes)
674
+ join_dependency.instantiate(rows, &block)
675
+ end.freeze
676
+ end
677
+ else
678
+ klass.find_by_sql(arel, bound_attributes, &block).freeze
679
+ end
680
+
681
+ preload = preload_values
682
+ preload += includes_values unless eager_loading?
683
+ preloader = nil
684
+ preload.each do |associations|
685
+ preloader ||= build_preloader
686
+ preloader.preload @records, associations
687
+ end
716
688
 
717
- @loaded = true
718
- @records
719
- end
689
+ @records.each(&:readonly!) if readonly_value
720
690
 
721
- def build_preloader
722
- ActiveRecord::Associations::Preloader.new
723
- end
691
+ @loaded = true
692
+ @records
693
+ end
724
694
 
725
- def references_eager_loaded_tables?
726
- joined_tables = arel.join_sources.map do |join|
727
- if join.is_a?(Arel::Nodes::StringJoin)
728
- tables_in_string(join.left)
729
- else
730
- [join.left.table_name, join.left.table_alias]
731
- end
695
+ def build_preloader
696
+ ActiveRecord::Associations::Preloader.new
732
697
  end
733
698
 
734
- joined_tables += [table.name, table.table_alias]
699
+ def references_eager_loaded_tables?
700
+ joined_tables = arel.join_sources.map do |join|
701
+ if join.is_a?(Arel::Nodes::StringJoin)
702
+ tables_in_string(join.left)
703
+ else
704
+ [join.left.table_name, join.left.table_alias]
705
+ end
706
+ end
735
707
 
736
- # always convert table names to downcase as in Oracle quoted table names are in uppercase
737
- joined_tables = joined_tables.flatten.compact.map(&:downcase).uniq
708
+ joined_tables += [table.name, table.table_alias]
738
709
 
739
- (references_values - joined_tables).any?
740
- end
710
+ # always convert table names to downcase as in Oracle quoted table names are in uppercase
711
+ joined_tables = joined_tables.flatten.compact.map(&:downcase).uniq
741
712
 
742
- def tables_in_string(string)
743
- return [] if string.blank?
744
- # always convert table names to downcase as in Oracle quoted table names are in uppercase
745
- # ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
746
- string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map(&:downcase).uniq - ['raw_sql_']
747
- end
713
+ (references_values - joined_tables).any?
714
+ end
715
+
716
+ def tables_in_string(string)
717
+ return [] if string.blank?
718
+ # always convert table names to downcase as in Oracle quoted table names are in uppercase
719
+ # ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
720
+ string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map(&:downcase).uniq - ["raw_sql_"]
721
+ end
748
722
  end
749
723
  end