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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +657 -2080
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/examples/performance.rb +28 -28
- data/examples/simple.rb +3 -3
- data/lib/active_record/aggregations.rb +244 -244
- data/lib/active_record/association_relation.rb +5 -5
- data/lib/active_record/associations/alias_tracker.rb +10 -11
- data/lib/active_record/associations/association.rb +23 -5
- data/lib/active_record/associations/association_scope.rb +95 -81
- data/lib/active_record/associations/belongs_to_association.rb +7 -4
- data/lib/active_record/associations/builder/belongs_to.rb +30 -16
- data/lib/active_record/associations/builder/collection_association.rb +1 -2
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +27 -27
- data/lib/active_record/associations/collection_association.rb +36 -205
- data/lib/active_record/associations/collection_proxy.rb +132 -63
- data/lib/active_record/associations/has_many_association.rb +10 -19
- data/lib/active_record/associations/has_many_through_association.rb +12 -4
- data/lib/active_record/associations/has_one_association.rb +24 -28
- data/lib/active_record/associations/has_one_through_association.rb +5 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +4 -28
- data/lib/active_record/associations/join_dependency/join_base.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +121 -118
- data/lib/active_record/associations/preloader/association.rb +64 -64
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -2
- data/lib/active_record/associations/preloader/collection_association.rb +6 -6
- data/lib/active_record/associations/preloader/has_many.rb +0 -2
- data/lib/active_record/associations/preloader/singular_association.rb +6 -8
- data/lib/active_record/associations/preloader/through_association.rb +41 -41
- data/lib/active_record/associations/preloader.rb +94 -94
- data/lib/active_record/associations/singular_association.rb +8 -25
- data/lib/active_record/associations/through_association.rb +2 -5
- data/lib/active_record/associations.rb +1591 -1562
- data/lib/active_record/attribute/user_provided_default.rb +4 -2
- data/lib/active_record/attribute.rb +98 -71
- data/lib/active_record/attribute_assignment.rb +61 -61
- data/lib/active_record/attribute_decorators.rb +35 -13
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -7
- data/lib/active_record/attribute_methods/dirty.rb +229 -46
- data/lib/active_record/attribute_methods/primary_key.rb +74 -73
- data/lib/active_record/attribute_methods/read.rb +39 -35
- data/lib/active_record/attribute_methods/serialization.rb +7 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +35 -58
- data/lib/active_record/attribute_methods/write.rb +30 -33
- data/lib/active_record/attribute_methods.rb +56 -65
- data/lib/active_record/attribute_mutation_tracker.rb +63 -11
- data/lib/active_record/attribute_set/builder.rb +27 -33
- data/lib/active_record/attribute_set/yaml_encoder.rb +41 -0
- data/lib/active_record/attribute_set.rb +9 -6
- data/lib/active_record/attributes.rb +22 -22
- data/lib/active_record/autosave_association.rb +18 -13
- data/lib/active_record/base.rb +24 -22
- data/lib/active_record/callbacks.rb +56 -14
- data/lib/active_record/coders/yaml_column.rb +9 -11
- data/lib/active_record/collection_cache_key.rb +3 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +330 -284
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +39 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +32 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -51
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +10 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +74 -79
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +53 -41
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +120 -100
- data/lib/active_record/connection_adapters/abstract/transaction.rb +49 -43
- data/lib/active_record/connection_adapters/abstract_adapter.rb +165 -135
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +404 -424
- data/lib/active_record/connection_adapters/column.rb +26 -4
- data/lib/active_record/connection_adapters/connection_specification.rb +128 -118
- data/lib/active_record/connection_adapters/mysql/column.rb +6 -31
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -49
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +22 -22
- data/lib/active_record/connection_adapters/mysql/quoting.rb +6 -12
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +16 -19
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -28
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +7 -6
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +23 -27
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +32 -53
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +16 -16
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +0 -10
- data/lib/active_record/connection_adapters/postgresql/oid/{rails_5_1_point.rb → legacy_point.rb} +9 -16
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +28 -8
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +32 -30
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +51 -51
- data/lib/active_record/connection_adapters/postgresql/oid.rb +22 -21
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +40 -35
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +37 -24
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +19 -23
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +182 -222
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +6 -4
- data/lib/active_record/connection_adapters/postgresql/utils.rb +7 -5
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +198 -167
- data/lib/active_record/connection_adapters/schema_cache.rb +16 -7
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +3 -3
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +16 -19
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +1 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +28 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +184 -167
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -7
- data/lib/active_record/connection_handling.rb +14 -26
- data/lib/active_record/core.rb +109 -93
- data/lib/active_record/counter_cache.rb +60 -13
- data/lib/active_record/define_callbacks.rb +20 -0
- data/lib/active_record/dynamic_matchers.rb +80 -79
- data/lib/active_record/enum.rb +8 -6
- data/lib/active_record/errors.rb +64 -15
- data/lib/active_record/explain.rb +1 -2
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +7 -4
- data/lib/active_record/fixture_set/file.rb +11 -8
- data/lib/active_record/fixtures.rb +66 -53
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/inheritance.rb +93 -79
- data/lib/active_record/integration.rb +7 -7
- data/lib/active_record/internal_metadata.rb +3 -16
- data/lib/active_record/legacy_yaml_adapter.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +69 -74
- data/lib/active_record/locking/pessimistic.rb +10 -1
- data/lib/active_record/log_subscriber.rb +23 -28
- data/lib/active_record/migration/command_recorder.rb +94 -94
- data/lib/active_record/migration/compatibility.rb +100 -47
- data/lib/active_record/migration/join_table.rb +6 -6
- data/lib/active_record/migration.rb +153 -155
- data/lib/active_record/model_schema.rb +94 -107
- data/lib/active_record/nested_attributes.rb +200 -199
- data/lib/active_record/null_relation.rb +11 -34
- data/lib/active_record/persistence.rb +65 -50
- data/lib/active_record/query_cache.rb +2 -6
- data/lib/active_record/querying.rb +3 -4
- data/lib/active_record/railtie.rb +16 -17
- data/lib/active_record/railties/controller_runtime.rb +6 -2
- data/lib/active_record/railties/databases.rake +105 -133
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +2 -2
- data/lib/active_record/reflection.rb +154 -108
- data/lib/active_record/relation/batches/batch_enumerator.rb +1 -1
- data/lib/active_record/relation/batches.rb +80 -51
- data/lib/active_record/relation/calculations.rb +169 -162
- data/lib/active_record/relation/delegation.rb +32 -31
- data/lib/active_record/relation/finder_methods.rb +197 -231
- data/lib/active_record/relation/merger.rb +58 -62
- data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -5
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +23 -23
- data/lib/active_record/relation/predicate_builder/base_handler.rb +3 -1
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +0 -8
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +12 -10
- data/lib/active_record/relation/predicate_builder/range_handler.rb +0 -8
- data/lib/active_record/relation/predicate_builder.rb +92 -89
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +255 -293
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +4 -5
- data/lib/active_record/relation/where_clause.rb +80 -65
- data/lib/active_record/relation/where_clause_factory.rb +47 -8
- data/lib/active_record/relation.rb +93 -119
- data/lib/active_record/result.rb +41 -32
- data/lib/active_record/runtime_registry.rb +3 -3
- data/lib/active_record/sanitization.rb +176 -192
- data/lib/active_record/schema.rb +3 -3
- data/lib/active_record/schema_dumper.rb +15 -38
- data/lib/active_record/schema_migration.rb +8 -4
- data/lib/active_record/scoping/default.rb +90 -90
- data/lib/active_record/scoping/named.rb +11 -11
- data/lib/active_record/scoping.rb +6 -6
- data/lib/active_record/secure_token.rb +2 -2
- data/lib/active_record/statement_cache.rb +13 -15
- data/lib/active_record/store.rb +31 -32
- data/lib/active_record/suppressor.rb +2 -1
- data/lib/active_record/table_metadata.rb +9 -5
- data/lib/active_record/tasks/database_tasks.rb +65 -55
- data/lib/active_record/tasks/mysql_database_tasks.rb +76 -73
- data/lib/active_record/tasks/postgresql_database_tasks.rb +72 -47
- data/lib/active_record/tasks/sqlite_database_tasks.rb +18 -16
- data/lib/active_record/timestamp.rb +46 -25
- data/lib/active_record/touch_later.rb +1 -2
- data/lib/active_record/transactions.rb +97 -109
- data/lib/active_record/type/adapter_specific_registry.rb +46 -42
- data/lib/active_record/type/decimal_without_scale.rb +13 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +3 -3
- data/lib/active_record/type/internal/abstract_json.rb +4 -0
- data/lib/active_record/type/serialized.rb +14 -8
- data/lib/active_record/type/text.rb +9 -0
- data/lib/active_record/type/time.rb +0 -1
- data/lib/active_record/type/type_map.rb +11 -15
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type.rb +17 -13
- data/lib/active_record/type_caster/connection.rb +8 -6
- data/lib/active_record/type_caster/map.rb +3 -1
- data/lib/active_record/type_caster.rb +2 -2
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/presence.rb +2 -2
- data/lib/active_record/validations/uniqueness.rb +8 -39
- data/lib/active_record/validations.rb +4 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +20 -20
- data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -34
- data/lib/rails/generators/active_record/migration.rb +1 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -9
- data/lib/rails/generators/active_record.rb +4 -4
- metadata +24 -13
- 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
|
-
#
|
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
|
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
|
13
|
+
# See ActiveRecord::Batches for more information.
|
14
14
|
def exec_queries
|
15
15
|
QueryRegistry.reset
|
16
16
|
|
@@ -1,10 +1,9 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
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)
|
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
|
-
|
88
|
+
attr_reader :predicates
|
90
89
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
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
|
-
|
101
|
-
|
102
|
-
|
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
|
-
|
111
|
-
|
112
|
-
|
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
|
-
|
117
|
-
|
118
|
-
|
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
|
-
|
121
|
-
|
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
|
-
|
136
|
-
predicates.reject do |node|
|
119
|
+
def invert_predicate(node)
|
137
120
|
case node
|
138
|
-
when
|
139
|
-
|
140
|
-
|
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
|
-
|
146
|
-
|
147
|
-
|
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
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
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
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
176
|
+
ARRAY_WITH_EMPTY_STRING = [""]
|
177
|
+
def non_empty_predicates
|
178
|
+
predicates - ARRAY_WITH_EMPTY_STRING
|
179
|
+
end
|
165
180
|
|
166
|
-
|
167
|
-
|
168
|
-
|
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
|
-
|
21
|
-
|
22
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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,
|
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(
|
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
|
-
|
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
|
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,
|
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
|
-
|
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
|
460
|
-
|
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
|
517
|
-
invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select
|
518
|
-
|
519
|
-
|
520
|
-
|
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
|
-
|
531
|
-
|
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
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
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
|
-
|
510
|
+
affected = @klass.connection.delete(stmt, "SQL", bound_attributes)
|
547
511
|
|
548
|
-
|
549
|
-
|
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
|
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
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
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(
|
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
|
-
|
633
|
+
@values.dup
|
683
634
|
end
|
684
635
|
|
685
636
|
def inspect
|
686
|
-
|
687
|
-
entries
|
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
|
-
|
706
|
-
|
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
|
-
|
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
|
-
|
718
|
-
@records
|
719
|
-
end
|
689
|
+
@records.each(&:readonly!) if readonly_value
|
720
690
|
|
721
|
-
|
722
|
-
|
723
|
-
|
691
|
+
@loaded = true
|
692
|
+
@records
|
693
|
+
end
|
724
694
|
|
725
|
-
|
726
|
-
|
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
|
-
|
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
|
-
|
737
|
-
joined_tables = joined_tables.flatten.compact.map(&:downcase).uniq
|
708
|
+
joined_tables += [table.name, table.table_alias]
|
738
709
|
|
739
|
-
|
740
|
-
|
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
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
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
|