activerecord 5.1.0 → 5.2.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +410 -530
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- data/examples/performance.rb +2 -0
- data/examples/simple.rb +2 -0
- data/lib/active_record/aggregations.rb +6 -5
- data/lib/active_record/association_relation.rb +4 -2
- data/lib/active_record/associations/alias_tracker.rb +23 -32
- data/lib/active_record/associations/association.rb +20 -21
- data/lib/active_record/associations/association_scope.rb +49 -49
- data/lib/active_record/associations/belongs_to_association.rb +12 -10
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +4 -7
- data/lib/active_record/associations/builder/association.rb +4 -7
- data/lib/active_record/associations/builder/belongs_to.rb +10 -6
- data/lib/active_record/associations/builder/collection_association.rb +1 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +2 -0
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +50 -41
- data/lib/active_record/associations/collection_proxy.rb +22 -39
- data/lib/active_record/associations/foreign_association.rb +2 -0
- data/lib/active_record/associations/has_many_association.rb +4 -2
- data/lib/active_record/associations/has_many_through_association.rb +12 -18
- data/lib/active_record/associations/has_one_association.rb +5 -1
- data/lib/active_record/associations/has_one_through_association.rb +8 -7
- data/lib/active_record/associations/join_dependency/join_association.rb +17 -64
- data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -9
- data/lib/active_record/associations/join_dependency.rb +27 -44
- data/lib/active_record/associations/preloader/association.rb +53 -92
- data/lib/active_record/associations/preloader/through_association.rb +72 -73
- data/lib/active_record/associations/preloader.rb +17 -37
- data/lib/active_record/associations/singular_association.rb +14 -10
- data/lib/active_record/associations/through_association.rb +26 -11
- data/lib/active_record/associations.rb +68 -76
- data/lib/active_record/attribute_assignment.rb +2 -0
- data/lib/active_record/attribute_decorators.rb +3 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
- data/lib/active_record/attribute_methods/dirty.rb +24 -214
- data/lib/active_record/attribute_methods/primary_key.rb +10 -13
- data/lib/active_record/attribute_methods/query.rb +2 -0
- data/lib/active_record/attribute_methods/read.rb +8 -2
- data/lib/active_record/attribute_methods/serialization.rb +23 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
- data/lib/active_record/attribute_methods/write.rb +22 -19
- data/lib/active_record/attribute_methods.rb +48 -12
- data/lib/active_record/attributes.rb +7 -6
- data/lib/active_record/autosave_association.rb +8 -11
- data/lib/active_record/base.rb +2 -0
- data/lib/active_record/callbacks.rb +8 -6
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +2 -0
- data/lib/active_record/collection_cache_key.rb +14 -10
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +110 -35
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +175 -33
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +8 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +13 -24
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +15 -6
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +58 -3
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +165 -85
- data/lib/active_record/connection_adapters/abstract/transaction.rb +45 -9
- data/lib/active_record/connection_adapters/abstract_adapter.rb +83 -97
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +118 -180
- data/lib/active_record/connection_adapters/column.rb +4 -2
- data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +11 -17
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -23
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -32
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +269 -126
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +64 -85
- data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +71 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +92 -95
- data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
- data/lib/active_record/connection_handling.rb +4 -2
- data/lib/active_record/core.rb +39 -60
- data/lib/active_record/counter_cache.rb +3 -2
- data/lib/active_record/define_callbacks.rb +5 -3
- data/lib/active_record/dynamic_matchers.rb +9 -9
- data/lib/active_record/enum.rb +17 -13
- data/lib/active_record/errors.rb +42 -3
- data/lib/active_record/explain.rb +3 -1
- data/lib/active_record/explain_registry.rb +2 -0
- data/lib/active_record/explain_subscriber.rb +2 -0
- data/lib/active_record/fixture_set/file.rb +2 -0
- data/lib/active_record/fixtures.rb +67 -60
- data/lib/active_record/gem_version.rb +4 -2
- data/lib/active_record/inheritance.rb +9 -9
- data/lib/active_record/integration.rb +58 -19
- data/lib/active_record/internal_metadata.rb +2 -0
- data/lib/active_record/legacy_yaml_adapter.rb +3 -1
- data/lib/active_record/locking/optimistic.rb +8 -6
- data/lib/active_record/locking/pessimistic.rb +9 -6
- data/lib/active_record/log_subscriber.rb +46 -4
- data/lib/active_record/migration/command_recorder.rb +11 -9
- data/lib/active_record/migration/compatibility.rb +74 -22
- data/lib/active_record/migration/join_table.rb +2 -0
- data/lib/active_record/migration.rb +181 -137
- data/lib/active_record/model_schema.rb +73 -58
- data/lib/active_record/nested_attributes.rb +18 -6
- data/lib/active_record/no_touching.rb +3 -1
- data/lib/active_record/null_relation.rb +2 -0
- data/lib/active_record/persistence.rb +153 -18
- data/lib/active_record/query_cache.rb +17 -12
- data/lib/active_record/querying.rb +4 -2
- data/lib/active_record/railtie.rb +61 -3
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +2 -0
- data/lib/active_record/railties/databases.rake +47 -37
- data/lib/active_record/readonly_attributes.rb +3 -2
- data/lib/active_record/reflection.rb +131 -204
- data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
- data/lib/active_record/relation/batches.rb +32 -17
- data/lib/active_record/relation/calculations.rb +58 -20
- data/lib/active_record/relation/delegation.rb +10 -29
- data/lib/active_record/relation/finder_methods.rb +74 -85
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +51 -20
- data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +54 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
- data/lib/active_record/relation/predicate_builder.rb +53 -78
- data/lib/active_record/relation/query_attribute.rb +9 -2
- data/lib/active_record/relation/query_methods.rb +101 -95
- data/lib/active_record/relation/record_fetch_warning.rb +2 -0
- data/lib/active_record/relation/spawn_methods.rb +3 -1
- data/lib/active_record/relation/where_clause.rb +65 -67
- data/lib/active_record/relation/where_clause_factory.rb +5 -48
- data/lib/active_record/relation.rb +99 -202
- data/lib/active_record/result.rb +2 -0
- data/lib/active_record/runtime_registry.rb +2 -0
- data/lib/active_record/sanitization.rb +129 -121
- data/lib/active_record/schema.rb +4 -2
- data/lib/active_record/schema_dumper.rb +36 -26
- data/lib/active_record/schema_migration.rb +2 -0
- data/lib/active_record/scoping/default.rb +10 -7
- data/lib/active_record/scoping/named.rb +38 -12
- data/lib/active_record/scoping.rb +12 -10
- data/lib/active_record/secure_token.rb +2 -0
- data/lib/active_record/serialization.rb +2 -0
- data/lib/active_record/statement_cache.rb +22 -12
- data/lib/active_record/store.rb +3 -1
- data/lib/active_record/suppressor.rb +2 -0
- data/lib/active_record/table_metadata.rb +12 -3
- data/lib/active_record/tasks/database_tasks.rb +37 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +11 -50
- data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -3
- data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
- data/lib/active_record/timestamp.rb +5 -5
- data/lib/active_record/touch_later.rb +2 -0
- data/lib/active_record/transactions.rb +9 -7
- data/lib/active_record/translation.rb +2 -0
- data/lib/active_record/type/adapter_specific_registry.rb +2 -0
- data/lib/active_record/type/date.rb +2 -0
- data/lib/active_record/type/date_time.rb +2 -0
- data/lib/active_record/type/decimal_without_scale.rb +2 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
- data/lib/active_record/type/internal/timezone.rb +2 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +2 -0
- data/lib/active_record/type/text.rb +2 -0
- data/lib/active_record/type/time.rb +2 -0
- data/lib/active_record/type/type_map.rb +2 -0
- data/lib/active_record/type/unsigned_integer.rb +2 -0
- data/lib/active_record/type.rb +4 -1
- data/lib/active_record/type_caster/connection.rb +2 -0
- data/lib/active_record/type_caster/map.rb +3 -1
- data/lib/active_record/type_caster.rb +2 -0
- data/lib/active_record/validations/absence.rb +2 -0
- data/lib/active_record/validations/associated.rb +2 -0
- data/lib/active_record/validations/length.rb +2 -0
- data/lib/active_record/validations/presence.rb +2 -0
- data/lib/active_record/validations/uniqueness.rb +35 -5
- data/lib/active_record/validations.rb +2 -0
- data/lib/active_record/version.rb +2 -0
- data/lib/active_record.rb +11 -4
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration.rb +2 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- data/lib/rails/generators/active_record.rb +3 -1
- metadata +25 -37
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
- data/lib/active_record/associations/preloader/collection_association.rb +0 -17
- data/lib/active_record/associations/preloader/has_many.rb +0 -15
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -15
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -18
- data/lib/active_record/attribute/user_provided_default.rb +0 -30
- data/lib/active_record/attribute.rb +0 -240
- data/lib/active_record/attribute_mutation_tracker.rb +0 -113
- data/lib/active_record/attribute_set/builder.rb +0 -124
- data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
- data/lib/active_record/attribute_set.rb +0 -113
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
- data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
class Relation
|
3
5
|
class FromClause # :nodoc:
|
@@ -8,14 +10,6 @@ module ActiveRecord
|
|
8
10
|
@name = name
|
9
11
|
end
|
10
12
|
|
11
|
-
def binds
|
12
|
-
if value.is_a?(Relation)
|
13
|
-
value.bound_attributes
|
14
|
-
else
|
15
|
-
[]
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
13
|
def merge(other)
|
20
14
|
self
|
21
15
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/hash/keys"
|
2
4
|
|
3
5
|
module ActiveRecord
|
@@ -21,7 +23,11 @@ module ActiveRecord
|
|
21
23
|
# build a relation to merge in rather than directly merging
|
22
24
|
# the values.
|
23
25
|
def other
|
24
|
-
other = Relation.create(
|
26
|
+
other = Relation.create(
|
27
|
+
relation.klass,
|
28
|
+
table: relation.table,
|
29
|
+
predicate_builder: relation.predicate_builder
|
30
|
+
)
|
25
31
|
hash.each { |k, v|
|
26
32
|
if k == :joins
|
27
33
|
if Hash === v
|
@@ -50,7 +56,7 @@ module ActiveRecord
|
|
50
56
|
|
51
57
|
NORMAL_VALUES = Relation::VALUE_METHODS -
|
52
58
|
Relation::CLAUSE_METHODS -
|
53
|
-
[:includes, :preload, :joins, :order, :reverse_order, :lock, :create_with, :reordering] # :nodoc:
|
59
|
+
[:includes, :preload, :joins, :left_outer_joins, :order, :reverse_order, :lock, :create_with, :reordering] # :nodoc:
|
54
60
|
|
55
61
|
def normal_values
|
56
62
|
NORMAL_VALUES
|
@@ -77,6 +83,7 @@ module ActiveRecord
|
|
77
83
|
merge_clauses
|
78
84
|
merge_preloads
|
79
85
|
merge_joins
|
86
|
+
merge_outer_joins
|
80
87
|
|
81
88
|
relation
|
82
89
|
end
|
@@ -110,21 +117,43 @@ module ActiveRecord
|
|
110
117
|
if other.klass == relation.klass
|
111
118
|
relation.joins!(*other.joins_values)
|
112
119
|
else
|
113
|
-
|
120
|
+
alias_tracker = nil
|
121
|
+
joins_dependency = other.joins_values.map do |join|
|
114
122
|
case join
|
115
123
|
when Hash, Symbol, Array
|
116
|
-
|
124
|
+
alias_tracker ||= other.alias_tracker
|
125
|
+
ActiveRecord::Associations::JoinDependency.new(
|
126
|
+
other.klass, other.table, join, alias_tracker
|
127
|
+
)
|
117
128
|
else
|
118
|
-
|
129
|
+
join
|
119
130
|
end
|
120
131
|
end
|
121
132
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
relation.joins! rest
|
133
|
+
relation.joins!(*joins_dependency)
|
134
|
+
end
|
135
|
+
end
|
126
136
|
|
127
|
-
|
137
|
+
def merge_outer_joins
|
138
|
+
return if other.left_outer_joins_values.blank?
|
139
|
+
|
140
|
+
if other.klass == relation.klass
|
141
|
+
relation.left_outer_joins!(*other.left_outer_joins_values)
|
142
|
+
else
|
143
|
+
alias_tracker = nil
|
144
|
+
joins_dependency = other.left_outer_joins_values.map do |join|
|
145
|
+
case join
|
146
|
+
when Hash, Symbol, Array
|
147
|
+
alias_tracker ||= other.alias_tracker
|
148
|
+
ActiveRecord::Associations::JoinDependency.new(
|
149
|
+
other.klass, other.table, join, alias_tracker
|
150
|
+
)
|
151
|
+
else
|
152
|
+
join
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
relation.left_outer_joins!(*joins_dependency)
|
128
157
|
end
|
129
158
|
end
|
130
159
|
|
@@ -132,19 +161,17 @@ module ActiveRecord
|
|
132
161
|
if other.reordering_value
|
133
162
|
# override any order specified in the original relation
|
134
163
|
relation.reorder! other.order_values
|
135
|
-
elsif other.order_values
|
164
|
+
elsif other.order_values.any?
|
136
165
|
# merge in order_values from relation
|
137
166
|
relation.order! other.order_values
|
138
167
|
end
|
139
168
|
|
140
|
-
|
169
|
+
extensions = other.extensions - relation.extensions
|
170
|
+
relation.extending!(*extensions) if extensions.any?
|
141
171
|
end
|
142
172
|
|
143
173
|
def merge_single_values
|
144
|
-
if
|
145
|
-
relation.from_clause = other.from_clause
|
146
|
-
end
|
147
|
-
relation.lock_value ||= other.lock_value
|
174
|
+
relation.lock_value ||= other.lock_value if other.lock_value
|
148
175
|
|
149
176
|
unless other.create_with_value.blank?
|
150
177
|
relation.create_with_value = (relation.create_with_value || {}).merge(other.create_with_value)
|
@@ -152,11 +179,15 @@ module ActiveRecord
|
|
152
179
|
end
|
153
180
|
|
154
181
|
def merge_clauses
|
155
|
-
|
156
|
-
|
157
|
-
other_clause = other.get_value(method)
|
158
|
-
relation.set_value(method, clause.merge(other_clause))
|
182
|
+
if relation.from_clause.empty? && !other.from_clause.empty?
|
183
|
+
relation.from_clause = other.from_clause
|
159
184
|
end
|
185
|
+
|
186
|
+
where_clause = relation.where_clause.merge(other.where_clause)
|
187
|
+
relation.where_clause = where_clause unless where_clause.empty?
|
188
|
+
|
189
|
+
having_clause = relation.having_clause.merge(other.having_clause)
|
190
|
+
relation.having_clause = having_clause unless having_clause.empty?
|
160
191
|
end
|
161
192
|
end
|
162
193
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
class PredicateBuilder
|
3
5
|
class ArrayHandler # :nodoc:
|
@@ -6,18 +8,21 @@ module ActiveRecord
|
|
6
8
|
end
|
7
9
|
|
8
10
|
def call(attribute, value)
|
11
|
+
return attribute.in([]) if value.empty?
|
12
|
+
|
9
13
|
values = value.map { |x| x.is_a?(Base) ? x.id : x }
|
10
14
|
nils, values = values.partition(&:nil?)
|
11
|
-
|
12
|
-
return attribute.in([]) if values.empty? && nils.empty?
|
13
|
-
|
14
15
|
ranges, values = values.partition { |v| v.is_a?(Range) }
|
15
16
|
|
16
17
|
values_predicate =
|
17
18
|
case values.length
|
18
19
|
when 0 then NullPredicate
|
19
20
|
when 1 then predicate_builder.build(attribute, values.first)
|
20
|
-
else
|
21
|
+
else
|
22
|
+
bind_values = values.map do |v|
|
23
|
+
predicate_builder.build_bind_attribute(attribute.name, v)
|
24
|
+
end
|
25
|
+
attribute.in(bind_values)
|
21
26
|
end
|
22
27
|
|
23
28
|
unless nils.empty?
|
@@ -26,11 +31,9 @@ module ActiveRecord
|
|
26
31
|
|
27
32
|
array_predicates = ranges.map { |range| predicate_builder.build(attribute, range) }
|
28
33
|
array_predicates.unshift(values_predicate)
|
29
|
-
array_predicates.inject
|
34
|
+
array_predicates.inject(&:or)
|
30
35
|
end
|
31
36
|
|
32
|
-
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
33
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
34
37
|
protected
|
35
38
|
|
36
39
|
attr_reader :predicate_builder
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
class PredicateBuilder
|
5
|
+
class AssociationQueryValue # :nodoc:
|
6
|
+
def initialize(associated_table, value)
|
7
|
+
@associated_table = associated_table
|
8
|
+
@value = value
|
9
|
+
end
|
10
|
+
|
11
|
+
def queries
|
12
|
+
[associated_table.association_join_foreign_key.to_s => ids]
|
13
|
+
end
|
14
|
+
|
15
|
+
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
16
|
+
# Workaround for Ruby 2.2 "private attribute?" warning.
|
17
|
+
protected
|
18
|
+
attr_reader :associated_table, :value
|
19
|
+
|
20
|
+
private
|
21
|
+
def ids
|
22
|
+
case value
|
23
|
+
when Relation
|
24
|
+
value.select_values.empty? ? value.select(primary_key) : value
|
25
|
+
when Array
|
26
|
+
value.map { |v| convert_to_id(v) }
|
27
|
+
else
|
28
|
+
convert_to_id(value)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def primary_key
|
33
|
+
associated_table.association_join_primary_key
|
34
|
+
end
|
35
|
+
|
36
|
+
def convert_to_id(value)
|
37
|
+
case value
|
38
|
+
when Base
|
39
|
+
value._read_attribute(primary_key)
|
40
|
+
else
|
41
|
+
value
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
class PredicateBuilder
|
3
5
|
class BaseHandler # :nodoc:
|
@@ -9,8 +11,6 @@ module ActiveRecord
|
|
9
11
|
predicate_builder.build(attribute, value.id)
|
10
12
|
end
|
11
13
|
|
12
|
-
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
13
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
14
14
|
protected
|
15
15
|
|
16
16
|
attr_reader :predicate_builder
|
@@ -1,9 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
class PredicateBuilder
|
3
5
|
class BasicObjectHandler # :nodoc:
|
6
|
+
def initialize(predicate_builder)
|
7
|
+
@predicate_builder = predicate_builder
|
8
|
+
end
|
9
|
+
|
4
10
|
def call(attribute, value)
|
5
|
-
attribute.
|
11
|
+
bind = predicate_builder.build_bind_attribute(attribute.name, value)
|
12
|
+
attribute.eq(bind)
|
6
13
|
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
attr_reader :predicate_builder
|
7
18
|
end
|
8
19
|
end
|
9
20
|
end
|
@@ -0,0 +1,54 @@
|
|
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) { |value, hash| hash[base_class(value).name] << convert_to_id(value) }
|
29
|
+
end
|
30
|
+
|
31
|
+
def primary_key(value)
|
32
|
+
associated_table.association_join_primary_key(base_class(value))
|
33
|
+
end
|
34
|
+
|
35
|
+
def base_class(value)
|
36
|
+
case value
|
37
|
+
when Base
|
38
|
+
value.class.base_class
|
39
|
+
when Relation
|
40
|
+
value.klass.base_class
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def convert_to_id(value)
|
45
|
+
case value
|
46
|
+
when Base
|
47
|
+
value._read_attribute(primary_key(value))
|
48
|
+
when Relation
|
49
|
+
value.select(primary_key(value))
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -1,25 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
class PredicateBuilder
|
3
5
|
class RangeHandler # :nodoc:
|
4
|
-
RangeWithBinds
|
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)
|
17
|
+
begin_bind = predicate_builder.build_bind_attribute(attribute.name, value.begin)
|
18
|
+
end_bind = predicate_builder.build_bind_attribute(attribute.name, value.end)
|
7
19
|
if value.begin.respond_to?(:infinite?) && value.begin.infinite?
|
8
20
|
if value.end.respond_to?(:infinite?) && value.end.infinite?
|
9
21
|
attribute.not_in([])
|
10
22
|
elsif value.exclude_end?
|
11
|
-
attribute.lt(
|
23
|
+
attribute.lt(end_bind)
|
12
24
|
else
|
13
|
-
attribute.lteq(
|
25
|
+
attribute.lteq(end_bind)
|
14
26
|
end
|
15
27
|
elsif value.end.respond_to?(:infinite?) && value.end.infinite?
|
16
|
-
attribute.gteq(
|
28
|
+
attribute.gteq(begin_bind)
|
17
29
|
elsif value.exclude_end?
|
18
|
-
attribute.gteq(
|
30
|
+
attribute.gteq(begin_bind).and(attribute.lt(end_bind))
|
19
31
|
else
|
20
|
-
attribute.between(
|
32
|
+
attribute.between(RangeWithBinds.new(begin_bind, end_bind))
|
21
33
|
end
|
22
34
|
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
attr_reader :predicate_builder
|
23
39
|
end
|
24
40
|
end
|
25
41
|
end
|
@@ -1,7 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
class PredicateBuilder
|
3
5
|
class RelationHandler # :nodoc:
|
4
6
|
def call(attribute, value)
|
7
|
+
if value.eager_loading?
|
8
|
+
value = value.send(:apply_join_dependency)
|
9
|
+
end
|
10
|
+
|
5
11
|
if value.select_values.empty?
|
6
12
|
value = value.select(value.arel_attribute(value.klass.primary_key))
|
7
13
|
end
|
@@ -1,27 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
class PredicateBuilder # :nodoc:
|
3
|
-
require "active_record/relation/predicate_builder/array_handler"
|
4
|
-
require "active_record/relation/predicate_builder/association_query_handler"
|
5
|
-
require "active_record/relation/predicate_builder/base_handler"
|
6
|
-
require "active_record/relation/predicate_builder/basic_object_handler"
|
7
|
-
require "active_record/relation/predicate_builder/polymorphic_array_handler"
|
8
|
-
require "active_record/relation/predicate_builder/range_handler"
|
9
|
-
require "active_record/relation/predicate_builder/relation_handler"
|
10
|
-
|
11
5
|
delegate :resolve_column_aliases, to: :table
|
12
6
|
|
13
7
|
def initialize(table)
|
14
8
|
@table = table
|
15
9
|
@handlers = []
|
16
10
|
|
17
|
-
register_handler(BasicObject, BasicObjectHandler.new)
|
11
|
+
register_handler(BasicObject, BasicObjectHandler.new(self))
|
18
12
|
register_handler(Base, BaseHandler.new(self))
|
19
|
-
register_handler(Range, RangeHandler.new)
|
20
|
-
register_handler(RangeHandler::RangeWithBinds, RangeHandler.new)
|
13
|
+
register_handler(Range, RangeHandler.new(self))
|
21
14
|
register_handler(Relation, RelationHandler.new)
|
22
15
|
register_handler(Array, ArrayHandler.new(self))
|
23
|
-
register_handler(
|
24
|
-
register_handler(PolymorphicArrayValue, PolymorphicArrayHandler.new(self))
|
16
|
+
register_handler(Set, ArrayHandler.new(self))
|
25
17
|
end
|
26
18
|
|
27
19
|
def build_from_hash(attributes)
|
@@ -29,11 +21,6 @@ module ActiveRecord
|
|
29
21
|
expand_from_hash(attributes)
|
30
22
|
end
|
31
23
|
|
32
|
-
def create_binds(attributes)
|
33
|
-
attributes = convert_dot_notation_to_hash(attributes)
|
34
|
-
create_binds_for_hash(attributes)
|
35
|
-
end
|
36
|
-
|
37
24
|
def self.references(attributes)
|
38
25
|
attributes.map do |key, value|
|
39
26
|
if value.is_a?(Hash)
|
@@ -64,8 +51,11 @@ module ActiveRecord
|
|
64
51
|
handler_for(value).call(attribute, value)
|
65
52
|
end
|
66
53
|
|
67
|
-
|
68
|
-
|
54
|
+
def build_bind_attribute(column_name, value)
|
55
|
+
attr = Relation::QueryAttribute.new(column_name.to_s, value, table.type(column_name))
|
56
|
+
Arel::Nodes::BindParam.new(attr)
|
57
|
+
end
|
58
|
+
|
69
59
|
protected
|
70
60
|
|
71
61
|
attr_reader :table
|
@@ -76,56 +66,46 @@ module ActiveRecord
|
|
76
66
|
attributes.flat_map do |key, value|
|
77
67
|
if value.is_a?(Hash) && !table.has_column?(key)
|
78
68
|
associated_predicate_builder(key).expand_from_hash(value)
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
69
|
+
elsif table.associated_with?(key)
|
70
|
+
# Find the foreign key when using queries such as:
|
71
|
+
# Post.where(author: author)
|
72
|
+
#
|
73
|
+
# For polymorphic relationships, find the foreign key and type:
|
74
|
+
# PriceEstimate.where(estimate_of: treasure)
|
75
|
+
associated_table = table.associated_table(key)
|
76
|
+
if associated_table.polymorphic_association?
|
77
|
+
case value.is_a?(Array) ? value.first : value
|
78
|
+
when Base, Relation
|
79
|
+
value = [value] unless value.is_a?(Array)
|
80
|
+
klass = PolymorphicArrayValue
|
81
|
+
end
|
82
|
+
end
|
84
83
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
attributes.each do |column_name, value|
|
90
|
-
case
|
91
|
-
when value.is_a?(Hash) && !table.has_column?(column_name)
|
92
|
-
attrs, bvs = associated_predicate_builder(column_name).create_binds_for_hash(value)
|
93
|
-
result[column_name] = attrs
|
94
|
-
binds += bvs
|
95
|
-
next
|
96
|
-
when value.is_a?(Relation)
|
97
|
-
binds += value.bound_attributes
|
98
|
-
when value.is_a?(Range) && !table.type(column_name).respond_to?(:subtype)
|
99
|
-
first = value.begin
|
100
|
-
last = value.end
|
101
|
-
unless first.respond_to?(:infinite?) && first.infinite?
|
102
|
-
binds << build_bind_param(column_name, first)
|
103
|
-
first = Arel::Nodes::BindParam.new
|
84
|
+
klass ||= AssociationQueryValue
|
85
|
+
queries = klass.new(associated_table, value).queries.map do |query|
|
86
|
+
expand_from_hash(query).reduce(&:and)
|
104
87
|
end
|
105
|
-
|
106
|
-
|
107
|
-
|
88
|
+
queries.reduce(&:or)
|
89
|
+
elsif table.aggregated_with?(key)
|
90
|
+
mapping = table.reflect_on_aggregation(key).mapping
|
91
|
+
queries = Array.wrap(value).map do |object|
|
92
|
+
mapping.map do |field_attr, aggregate_attr|
|
93
|
+
if mapping.size == 1 && !object.respond_to?(aggregate_attr)
|
94
|
+
build(table.arel_attribute(field_attr), object)
|
95
|
+
else
|
96
|
+
build(table.arel_attribute(field_attr), object.send(aggregate_attr))
|
97
|
+
end
|
98
|
+
end.reduce(&:and)
|
108
99
|
end
|
109
|
-
|
110
|
-
|
100
|
+
queries.reduce(&:or)
|
101
|
+
# FIXME: Deprecate this and provide a public API to force equality
|
102
|
+
elsif (value.is_a?(Range) || value.is_a?(Array)) &&
|
103
|
+
table.type(key.to_s).respond_to?(:subtype)
|
104
|
+
BasicObjectHandler.new(self).call(table.arel_attribute(key), value)
|
111
105
|
else
|
112
|
-
|
113
|
-
result[column_name] = Arel::Nodes::BindParam.new
|
114
|
-
binds << build_bind_param(column_name, value)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
# Find the foreign key when using queries such as:
|
119
|
-
# Post.where(author: author)
|
120
|
-
#
|
121
|
-
# For polymorphic relationships, find the foreign key and type:
|
122
|
-
# PriceEstimate.where(estimate_of: treasure)
|
123
|
-
if table.associated_with?(column_name)
|
124
|
-
result[column_name] = AssociationQueryHandler.value_for(table, column_name, value)
|
106
|
+
build(table.arel_attribute(key), value)
|
125
107
|
end
|
126
108
|
end
|
127
|
-
|
128
|
-
[result, binds]
|
129
109
|
end
|
130
110
|
|
131
111
|
private
|
@@ -153,19 +133,14 @@ module ActiveRecord
|
|
153
133
|
def handler_for(object)
|
154
134
|
@handlers.detect { |klass, _| klass === object }.last
|
155
135
|
end
|
156
|
-
|
157
|
-
def can_be_bound?(column_name, value)
|
158
|
-
return if table.associated_with?(column_name)
|
159
|
-
case value
|
160
|
-
when Array, Range
|
161
|
-
table.type(column_name).respond_to?(:subtype)
|
162
|
-
else
|
163
|
-
!value.nil? && handler_for(value).is_a?(BasicObjectHandler)
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
def build_bind_param(column_name, value)
|
168
|
-
Relation::QueryAttribute.new(column_name.to_s, value, table.type(column_name))
|
169
|
-
end
|
170
136
|
end
|
171
137
|
end
|
138
|
+
|
139
|
+
require "active_record/relation/predicate_builder/array_handler"
|
140
|
+
require "active_record/relation/predicate_builder/base_handler"
|
141
|
+
require "active_record/relation/predicate_builder/basic_object_handler"
|
142
|
+
require "active_record/relation/predicate_builder/range_handler"
|
143
|
+
require "active_record/relation/predicate_builder/relation_handler"
|
144
|
+
|
145
|
+
require "active_record/relation/predicate_builder/association_query_value"
|
146
|
+
require "active_record/relation/predicate_builder/polymorphic_array_value"
|
@@ -1,8 +1,10 @@
|
|
1
|
-
|
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,11 @@ module ActiveRecord
|
|
14
16
|
def with_cast_value(value)
|
15
17
|
QueryAttribute.new(name, value, type)
|
16
18
|
end
|
19
|
+
|
20
|
+
def nil?
|
21
|
+
!value_before_type_cast.is_a?(StatementCache::Substitute) &&
|
22
|
+
(value_before_type_cast.nil? || value_for_database.nil?)
|
23
|
+
end
|
17
24
|
end
|
18
25
|
end
|
19
26
|
end
|