activerecord 5.1.6.2 → 5.2.8.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +635 -650
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -5
- 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 +7 -5
- data/lib/active_record/associations/alias_tracker.rb +19 -27
- data/lib/active_record/associations/association.rb +41 -37
- data/lib/active_record/associations/association_scope.rb +38 -50
- data/lib/active_record/associations/belongs_to_association.rb +28 -9
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
- data/lib/active_record/associations/builder/association.rb +4 -7
- data/lib/active_record/associations/builder/belongs_to.rb +14 -5
- data/lib/active_record/associations/builder/collection_association.rb +3 -3
- 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 +59 -47
- data/lib/active_record/associations/collection_proxy.rb +20 -49
- data/lib/active_record/associations/foreign_association.rb +2 -0
- data/lib/active_record/associations/has_many_association.rb +12 -1
- data/lib/active_record/associations/has_many_through_association.rb +36 -30
- data/lib/active_record/associations/has_one_association.rb +12 -1
- data/lib/active_record/associations/has_one_through_association.rb +13 -8
- data/lib/active_record/associations/join_dependency/join_association.rb +39 -63
- data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +9 -9
- data/lib/active_record/associations/join_dependency.rb +48 -93
- data/lib/active_record/associations/preloader/association.rb +45 -61
- data/lib/active_record/associations/preloader/through_association.rb +71 -79
- data/lib/active_record/associations/preloader.rb +18 -38
- data/lib/active_record/associations/singular_association.rb +14 -16
- data/lib/active_record/associations/through_association.rb +26 -11
- data/lib/active_record/associations.rb +40 -63
- data/lib/active_record/attribute_assignment.rb +2 -5
- 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 +32 -216
- data/lib/active_record/attribute_methods/primary_key.rb +7 -6
- data/lib/active_record/attribute_methods/query.rb +2 -0
- data/lib/active_record/attribute_methods/read.rb +9 -3
- 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 +21 -9
- data/lib/active_record/attribute_methods.rb +65 -24
- data/lib/active_record/attributes.rb +6 -5
- data/lib/active_record/autosave_association.rb +35 -19
- data/lib/active_record/base.rb +2 -0
- data/lib/active_record/callbacks.rb +12 -6
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +15 -1
- data/lib/active_record/collection_cache_key.rb +12 -8
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +142 -42
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +174 -33
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +15 -5
- data/lib/active_record/connection_adapters/abstract/quoting.rb +14 -31
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +64 -6
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +152 -81
- data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
- data/lib/active_record/connection_adapters/abstract_adapter.rb +84 -97
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +110 -173
- data/lib/active_record/connection_adapters/column.rb +3 -1
- data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +13 -2
- data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +47 -2
- 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 -30
- 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 +2 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +13 -1
- 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.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +2 -0
- 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 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -3
- 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 +8 -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 +3 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +50 -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 +233 -111
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +66 -74
- 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 +23 -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 +75 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +82 -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 +51 -61
- data/lib/active_record/counter_cache.rb +20 -15
- data/lib/active_record/define_callbacks.rb +5 -3
- data/lib/active_record/dynamic_matchers.rb +9 -9
- data/lib/active_record/enum.rb +18 -13
- data/lib/active_record/errors.rb +60 -15
- 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 +5 -3
- data/lib/active_record/inheritance.rb +49 -19
- 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 +14 -17
- data/lib/active_record/locking/pessimistic.rb +9 -6
- data/lib/active_record/log_subscriber.rb +43 -0
- data/lib/active_record/migration/command_recorder.rb +11 -9
- data/lib/active_record/migration/compatibility.rb +47 -9
- data/lib/active_record/migration/join_table.rb +2 -0
- data/lib/active_record/migration.rb +189 -139
- data/lib/active_record/model_schema.rb +16 -21
- 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 +169 -17
- data/lib/active_record/query_cache.rb +6 -8
- data/lib/active_record/querying.rb +4 -2
- data/lib/active_record/railtie.rb +80 -6
- 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 +46 -36
- data/lib/active_record/readonly_attributes.rb +3 -2
- data/lib/active_record/reflection.rb +108 -194
- data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
- data/lib/active_record/relation/batches.rb +20 -5
- data/lib/active_record/relation/calculations.rb +45 -19
- data/lib/active_record/relation/delegation.rb +45 -27
- data/lib/active_record/relation/finder_methods.rb +77 -78
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +53 -23
- 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 +56 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
- data/lib/active_record/relation/predicate_builder.rb +60 -79
- data/lib/active_record/relation/query_attribute.rb +28 -2
- data/lib/active_record/relation/query_methods.rb +129 -100
- data/lib/active_record/relation/record_fetch_warning.rb +2 -0
- data/lib/active_record/relation/spawn_methods.rb +4 -2
- data/lib/active_record/relation/where_clause.rb +65 -68
- data/lib/active_record/relation/where_clause_factory.rb +5 -48
- data/lib/active_record/relation.rb +120 -214
- 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 +8 -9
- data/lib/active_record/scoping/named.rb +23 -7
- data/lib/active_record/scoping.rb +9 -8
- data/lib/active_record/secure_token.rb +2 -0
- data/lib/active_record/serialization.rb +2 -0
- data/lib/active_record/statement_cache.rb +23 -13
- 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 +26 -15
- data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
- data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
- data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
- data/lib/active_record/timestamp.rb +13 -6
- data/lib/active_record/touch_later.rb +2 -0
- data/lib/active_record/transactions.rb +33 -28
- 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 +6 -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/migration/migration_generator.rb +3 -1
- 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.rb +3 -1
- metadata +26 -39
- 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 -114
- data/lib/active_record/attribute_set/builder.rb +0 -126
- 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 -37
- /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/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/model/templates/{model.rb → model.rb.tt} +0 -0
- /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -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,41 +117,57 @@ module ActiveRecord
|
|
110
117
|
if other.klass == relation.klass
|
111
118
|
relation.joins!(*other.joins_values)
|
112
119
|
else
|
113
|
-
joins_dependency
|
120
|
+
joins_dependency = other.joins_values.map do |join|
|
114
121
|
case join
|
115
122
|
when Hash, Symbol, Array
|
116
|
-
|
123
|
+
ActiveRecord::Associations::JoinDependency.new(
|
124
|
+
other.klass, other.table, join
|
125
|
+
)
|
117
126
|
else
|
118
|
-
|
127
|
+
join
|
119
128
|
end
|
120
129
|
end
|
121
130
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
131
|
+
relation.joins!(*joins_dependency)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def merge_outer_joins
|
136
|
+
return if other.left_outer_joins_values.blank?
|
137
|
+
|
138
|
+
if other.klass == relation.klass
|
139
|
+
relation.left_outer_joins!(*other.left_outer_joins_values)
|
140
|
+
else
|
141
|
+
joins_dependency = other.left_outer_joins_values.map do |join|
|
142
|
+
case join
|
143
|
+
when Hash, Symbol, Array
|
144
|
+
ActiveRecord::Associations::JoinDependency.new(
|
145
|
+
other.klass, other.table, join
|
146
|
+
)
|
147
|
+
else
|
148
|
+
join
|
149
|
+
end
|
150
|
+
end
|
126
151
|
|
127
|
-
|
152
|
+
relation.left_outer_joins!(*joins_dependency)
|
128
153
|
end
|
129
154
|
end
|
130
155
|
|
131
156
|
def merge_multi_values
|
132
157
|
if other.reordering_value
|
133
158
|
# override any order specified in the original relation
|
134
|
-
relation.reorder!
|
135
|
-
elsif other.order_values
|
159
|
+
relation.reorder!(*other.order_values)
|
160
|
+
elsif other.order_values.any?
|
136
161
|
# merge in order_values from relation
|
137
|
-
relation.order!
|
162
|
+
relation.order!(*other.order_values)
|
138
163
|
end
|
139
164
|
|
140
|
-
|
165
|
+
extensions = other.extensions - relation.extensions
|
166
|
+
relation.extending!(*extensions) if extensions.any?
|
141
167
|
end
|
142
168
|
|
143
169
|
def merge_single_values
|
144
|
-
if
|
145
|
-
relation.from_clause = other.from_clause
|
146
|
-
end
|
147
|
-
relation.lock_value ||= other.lock_value
|
170
|
+
relation.lock_value ||= other.lock_value if other.lock_value
|
148
171
|
|
149
172
|
unless other.create_with_value.blank?
|
150
173
|
relation.create_with_value = (relation.create_with_value || {}).merge(other.create_with_value)
|
@@ -152,11 +175,18 @@ module ActiveRecord
|
|
152
175
|
end
|
153
176
|
|
154
177
|
def merge_clauses
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
178
|
+
relation.from_clause = other.from_clause if replace_from_clause?
|
179
|
+
|
180
|
+
where_clause = relation.where_clause.merge(other.where_clause)
|
181
|
+
relation.where_clause = where_clause unless where_clause.empty?
|
182
|
+
|
183
|
+
having_clause = relation.having_clause.merge(other.having_clause)
|
184
|
+
relation.having_clause = having_clause unless having_clause.empty?
|
185
|
+
end
|
186
|
+
|
187
|
+
def replace_from_clause?
|
188
|
+
relation.from_clause.empty? && !other.from_clause.empty? &&
|
189
|
+
relation.klass.base_class == other.klass.base_class
|
160
190
|
end
|
161
191
|
end
|
162
192
|
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
|
+
values.map! do |v|
|
23
|
+
predicate_builder.build_bind_attribute(attribute.name, v)
|
24
|
+
end
|
25
|
+
values.empty? ? NullPredicate : attribute.in(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,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
class PredicateBuilder
|
5
|
+
class PolymorphicArrayValue # :nodoc:
|
6
|
+
def initialize(associated_table, values)
|
7
|
+
@associated_table = associated_table
|
8
|
+
@values = values
|
9
|
+
end
|
10
|
+
|
11
|
+
def queries
|
12
|
+
type_to_ids_mapping.map do |type, ids|
|
13
|
+
{
|
14
|
+
associated_table.association_foreign_type.to_s => type,
|
15
|
+
associated_table.association_foreign_key.to_s => ids
|
16
|
+
}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
21
|
+
# Workaround for Ruby 2.2 "private attribute?" warning.
|
22
|
+
protected
|
23
|
+
attr_reader :associated_table, :values
|
24
|
+
|
25
|
+
private
|
26
|
+
def type_to_ids_mapping
|
27
|
+
default_hash = Hash.new { |hsh, key| hsh[key] = [] }
|
28
|
+
values.each_with_object(default_hash) do |value, hash|
|
29
|
+
hash[klass(value).polymorphic_name] << convert_to_id(value)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def primary_key(value)
|
34
|
+
associated_table.association_join_primary_key(klass(value))
|
35
|
+
end
|
36
|
+
|
37
|
+
def klass(value)
|
38
|
+
case value
|
39
|
+
when Base
|
40
|
+
value.class
|
41
|
+
when Relation
|
42
|
+
value.klass
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def convert_to_id(value)
|
47
|
+
case value
|
48
|
+
when Base
|
49
|
+
value._read_attribute(primary_key(value))
|
50
|
+
when Relation
|
51
|
+
value.select(primary_key(value))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -1,25 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
class PredicateBuilder
|
3
5
|
class RangeHandler # :nodoc:
|
4
|
-
RangeWithBinds
|
6
|
+
class RangeWithBinds < Struct.new(:begin, :end)
|
7
|
+
def exclude_end?
|
8
|
+
false
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(predicate_builder)
|
13
|
+
@predicate_builder = predicate_builder
|
14
|
+
end
|
5
15
|
|
6
16
|
def call(attribute, value)
|
7
|
-
|
8
|
-
|
17
|
+
begin_bind = predicate_builder.build_bind_attribute(attribute.name, value.begin)
|
18
|
+
end_bind = predicate_builder.build_bind_attribute(attribute.name, value.end)
|
19
|
+
|
20
|
+
if begin_bind.value.infinity?
|
21
|
+
if end_bind.value.infinity?
|
9
22
|
attribute.not_in([])
|
10
23
|
elsif value.exclude_end?
|
11
|
-
attribute.lt(
|
24
|
+
attribute.lt(end_bind)
|
12
25
|
else
|
13
|
-
attribute.lteq(
|
26
|
+
attribute.lteq(end_bind)
|
14
27
|
end
|
15
|
-
elsif
|
16
|
-
attribute.gteq(
|
28
|
+
elsif end_bind.value.infinity?
|
29
|
+
attribute.gteq(begin_bind)
|
17
30
|
elsif value.exclude_end?
|
18
|
-
attribute.gteq(
|
31
|
+
attribute.gteq(begin_bind).and(attribute.lt(end_bind))
|
19
32
|
else
|
20
|
-
attribute.between(
|
33
|
+
attribute.between(RangeWithBinds.new(begin_bind, end_bind))
|
21
34
|
end
|
22
35
|
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
|
39
|
+
attr_reader :predicate_builder
|
23
40
|
end
|
24
41
|
end
|
25
42
|
end
|
@@ -1,7 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
class PredicateBuilder
|
3
5
|
class RelationHandler # :nodoc:
|
4
6
|
def call(attribute, value)
|
7
|
+
if value.eager_loading?
|
8
|
+
value = value.send(:apply_join_dependency)
|
9
|
+
end
|
10
|
+
|
5
11
|
if value.select_values.empty?
|
6
12
|
value = value.select(value.arel_attribute(value.klass.primary_key))
|
7
13
|
end
|
@@ -1,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)
|
@@ -61,11 +48,19 @@ module ActiveRecord
|
|
61
48
|
end
|
62
49
|
|
63
50
|
def build(attribute, value)
|
64
|
-
|
51
|
+
if table.type(attribute.name).force_equality?(value)
|
52
|
+
bind = build_bind_attribute(attribute.name, value)
|
53
|
+
attribute.eq(bind)
|
54
|
+
else
|
55
|
+
handler_for(value).call(attribute, value)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def build_bind_attribute(column_name, value)
|
60
|
+
attr = Relation::QueryAttribute.new(column_name.to_s, value, table.type(column_name))
|
61
|
+
Arel::Nodes::BindParam.new(attr)
|
65
62
|
end
|
66
63
|
|
67
|
-
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
68
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
69
64
|
protected
|
70
65
|
|
71
66
|
attr_reader :table
|
@@ -76,56 +71,47 @@ module ActiveRecord
|
|
76
71
|
attributes.flat_map do |key, value|
|
77
72
|
if value.is_a?(Hash) && !table.has_column?(key)
|
78
73
|
associated_predicate_builder(key).expand_from_hash(value)
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
74
|
+
elsif table.associated_with?(key)
|
75
|
+
# Find the foreign key when using queries such as:
|
76
|
+
# Post.where(author: author)
|
77
|
+
#
|
78
|
+
# For polymorphic relationships, find the foreign key and type:
|
79
|
+
# PriceEstimate.where(estimate_of: treasure)
|
80
|
+
associated_table = table.associated_table(key)
|
81
|
+
if associated_table.polymorphic_association?
|
82
|
+
case value.is_a?(Array) ? value.first : value
|
83
|
+
when Base, Relation
|
84
|
+
value = [value] unless value.is_a?(Array)
|
85
|
+
klass = PolymorphicArrayValue
|
86
|
+
end
|
87
|
+
end
|
84
88
|
|
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
|
89
|
+
klass ||= AssociationQueryValue
|
90
|
+
queries = klass.new(associated_table, value).queries.map do |query|
|
91
|
+
expand_from_hash(query).reduce(&:and)
|
104
92
|
end
|
105
|
-
|
106
|
-
|
107
|
-
|
93
|
+
queries.reduce(&:or)
|
94
|
+
elsif table.aggregated_with?(key)
|
95
|
+
mapping = table.reflect_on_aggregation(key).mapping
|
96
|
+
values = value.nil? ? [nil] : Array.wrap(value)
|
97
|
+
if mapping.length == 1 || values.empty?
|
98
|
+
column_name, aggr_attr = mapping.first
|
99
|
+
values = values.map do |object|
|
100
|
+
object.respond_to?(aggr_attr) ? object.public_send(aggr_attr) : object
|
101
|
+
end
|
102
|
+
build(table.arel_attribute(column_name), values)
|
103
|
+
else
|
104
|
+
queries = values.map do |object|
|
105
|
+
mapping.map do |field_attr, aggregate_attr|
|
106
|
+
build(table.arel_attribute(field_attr), object.try!(aggregate_attr))
|
107
|
+
end.reduce(&:and)
|
108
|
+
end
|
109
|
+
queries.reduce(&:or)
|
108
110
|
end
|
109
|
-
|
110
|
-
result[column_name] = RangeHandler::RangeWithBinds.new(first, last, value.exclude_end?)
|
111
111
|
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)
|
112
|
+
build(table.arel_attribute(key), value)
|
125
113
|
end
|
126
114
|
end
|
127
|
-
|
128
|
-
[result, binds]
|
129
115
|
end
|
130
116
|
|
131
117
|
private
|
@@ -153,19 +139,14 @@ module ActiveRecord
|
|
153
139
|
def handler_for(object)
|
154
140
|
@handlers.detect { |klass, _| klass === object }.last
|
155
141
|
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
142
|
end
|
171
143
|
end
|
144
|
+
|
145
|
+
require "active_record/relation/predicate_builder/array_handler"
|
146
|
+
require "active_record/relation/predicate_builder/base_handler"
|
147
|
+
require "active_record/relation/predicate_builder/basic_object_handler"
|
148
|
+
require "active_record/relation/predicate_builder/range_handler"
|
149
|
+
require "active_record/relation/predicate_builder/relation_handler"
|
150
|
+
|
151
|
+
require "active_record/relation/predicate_builder/association_query_value"
|
152
|
+
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,30 @@ module ActiveRecord
|
|
14
16
|
def with_cast_value(value)
|
15
17
|
QueryAttribute.new(name, value, type)
|
16
18
|
end
|
19
|
+
|
20
|
+
def nil?
|
21
|
+
unless value_before_type_cast.is_a?(StatementCache::Substitute)
|
22
|
+
value_before_type_cast.nil? ||
|
23
|
+
type.respond_to?(:subtype, true) && value_for_database.nil?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def boundable?
|
28
|
+
return @_boundable if defined?(@_boundable)
|
29
|
+
value_for_database unless value_before_type_cast.is_a?(StatementCache::Substitute)
|
30
|
+
@_boundable = true
|
31
|
+
rescue ::RangeError
|
32
|
+
@_boundable = false
|
33
|
+
end
|
34
|
+
|
35
|
+
def infinity?
|
36
|
+
_infinity?(value_before_type_cast) || boundable? && _infinity?(value_for_database)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
def _infinity?(value)
|
41
|
+
value.respond_to?(:infinite?) && value.infinite?
|
42
|
+
end
|
17
43
|
end
|
18
44
|
end
|
19
45
|
end
|