activerecord 5.1.7 → 5.2.0.beta1
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 +221 -900
- data/README.rdoc +3 -3
- data/examples/performance.rb +2 -0
- data/examples/simple.rb +2 -0
- data/lib/active_record.rb +10 -3
- data/lib/active_record/aggregations.rb +2 -0
- data/lib/active_record/association_relation.rb +2 -0
- data/lib/active_record/associations.rb +13 -42
- data/lib/active_record/associations/alias_tracker.rb +17 -17
- data/lib/active_record/associations/association.rb +11 -22
- data/lib/active_record/associations/association_scope.rb +32 -44
- data/lib/active_record/associations/belongs_to_association.rb +6 -4
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -1
- data/lib/active_record/associations/builder/association.rb +2 -5
- data/lib/active_record/associations/builder/belongs_to.rb +7 -12
- 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 +41 -33
- data/lib/active_record/associations/collection_proxy.rb +11 -14
- 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 +4 -2
- data/lib/active_record/associations/has_one_association.rb +3 -1
- data/lib/active_record/associations/has_one_through_association.rb +3 -1
- data/lib/active_record/associations/join_dependency.rb +22 -40
- data/lib/active_record/associations/join_dependency/join_association.rb +17 -56
- 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/preloader.rb +17 -37
- data/lib/active_record/associations/preloader/association.rb +42 -58
- data/lib/active_record/associations/preloader/through_association.rb +71 -79
- data/lib/active_record/associations/singular_association.rb +14 -10
- data/lib/active_record/associations/through_association.rb +3 -1
- data/lib/active_record/attribute_assignment.rb +2 -0
- data/lib/active_record/attribute_decorators.rb +3 -2
- data/lib/active_record/attribute_methods.rb +47 -7
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
- data/lib/active_record/attribute_methods/dirty.rb +25 -214
- 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 +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 +21 -9
- data/lib/active_record/attributes.rb +7 -6
- data/lib/active_record/autosave_association.rb +5 -11
- data/lib/active_record/base.rb +2 -0
- data/lib/active_record/callbacks.rb +6 -8
- 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 +10 -5
- 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 +120 -28
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +7 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +14 -33
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +13 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +40 -2
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +103 -63
- data/lib/active_record/connection_adapters/abstract/transaction.rb +45 -9
- data/lib/active_record/connection_adapters/abstract_adapter.rb +62 -90
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +75 -138
- 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 +2 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +3 -1
- 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 -6
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +91 -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.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -11
- 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 -1
- 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 +3 -5
- 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/quoting.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +11 -7
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +79 -65
- 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 +47 -82
- data/lib/active_record/connection_adapters/schema_cache.rb +2 -0
- 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 +19 -2
- 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 +34 -89
- 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 +27 -57
- data/lib/active_record/counter_cache.rb +15 -12
- data/lib/active_record/define_callbacks.rb +5 -3
- data/lib/active_record/dynamic_matchers.rb +9 -9
- data/lib/active_record/enum.rb +15 -13
- data/lib/active_record/errors.rb +54 -21
- 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 +40 -24
- data/lib/active_record/gem_version.rb +5 -3
- data/lib/active_record/inheritance.rb +6 -5
- 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 +31 -20
- data/lib/active_record/locking/pessimistic.rb +10 -7
- data/lib/active_record/log_subscriber.rb +2 -0
- data/lib/active_record/migration.rb +47 -21
- data/lib/active_record/migration/command_recorder.rb +11 -9
- data/lib/active_record/migration/compatibility.rb +20 -2
- data/lib/active_record/migration/join_table.rb +2 -0
- data/lib/active_record/model_schema.rb +29 -38
- 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 +184 -40
- data/lib/active_record/query_cache.rb +17 -12
- data/lib/active_record/querying.rb +3 -1
- data/lib/active_record/railtie.rb +54 -1
- 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 +41 -28
- data/lib/active_record/readonly_attributes.rb +3 -2
- data/lib/active_record/reflection.rb +100 -182
- data/lib/active_record/relation.rb +61 -193
- data/lib/active_record/relation/batches.rb +20 -5
- data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
- data/lib/active_record/relation/calculations.rb +40 -23
- data/lib/active_record/relation/delegation.rb +10 -27
- data/lib/active_record/relation/finder_methods.rb +53 -49
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +22 -19
- data/lib/active_record/relation/predicate_builder.rb +42 -79
- 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/query_attribute.rb +9 -2
- data/lib/active_record/relation/query_methods.rb +80 -69
- data/lib/active_record/relation/record_fetch_warning.rb +2 -0
- data/lib/active_record/relation/spawn_methods.rb +2 -0
- data/lib/active_record/relation/where_clause.rb +50 -67
- data/lib/active_record/relation/where_clause_factory.rb +4 -46
- data/lib/active_record/result.rb +2 -0
- data/lib/active_record/runtime_registry.rb +2 -0
- data/lib/active_record/sanitization.rb +15 -9
- data/lib/active_record/schema.rb +3 -1
- data/lib/active_record/schema_dumper.rb +24 -23
- data/lib/active_record/schema_migration.rb +2 -0
- data/lib/active_record/scoping.rb +9 -8
- data/lib/active_record/scoping/default.rb +6 -7
- data/lib/active_record/scoping/named.rb +15 -7
- 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 +2 -0
- data/lib/active_record/suppressor.rb +2 -0
- data/lib/active_record/table_metadata.rb +3 -1
- data/lib/active_record/tasks/database_tasks.rb +23 -12
- 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 +5 -12
- 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.rb +4 -1
- 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 -4
- 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_caster.rb +2 -0
- data/lib/active_record/type_caster/connection.rb +2 -0
- data/lib/active_record/type_caster/map.rb +2 -0
- data/lib/active_record/validations.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 +36 -6
- data/lib/active_record/version.rb +2 -0
- data/lib/rails/generators/active_record.rb +3 -1
- 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.rb +2 -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/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
- metadata +25 -38
- 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.rb +0 -240
- data/lib/active_record/attribute/user_provided_default.rb +0 -30
- data/lib/active_record/attribute_mutation_tracker.rb +0 -122
- data/lib/active_record/attribute_set.rb +0 -113
- 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/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
@@ -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_keys.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_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,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
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_record/relation/from_clause"
|
2
4
|
require "active_record/relation/query_attribute"
|
3
5
|
require "active_record/relation/where_clause"
|
@@ -74,31 +76,6 @@ module ActiveRecord
|
|
74
76
|
CODE
|
75
77
|
end
|
76
78
|
|
77
|
-
def bound_attributes
|
78
|
-
if limit_value
|
79
|
-
limit_bind = Attribute.with_cast_value(
|
80
|
-
"LIMIT".freeze,
|
81
|
-
connection.sanitize_limit(limit_value),
|
82
|
-
Type.default_value,
|
83
|
-
)
|
84
|
-
end
|
85
|
-
if offset_value
|
86
|
-
offset_bind = Attribute.with_cast_value(
|
87
|
-
"OFFSET".freeze,
|
88
|
-
offset_value.to_i,
|
89
|
-
Type.default_value,
|
90
|
-
)
|
91
|
-
end
|
92
|
-
connection.combine_bind_parameters(
|
93
|
-
from_clause: from_clause.binds,
|
94
|
-
join_clause: arel.bind_values,
|
95
|
-
where_clause: where_clause.binds,
|
96
|
-
having_clause: having_clause.binds,
|
97
|
-
limit: limit_bind,
|
98
|
-
offset: offset_bind,
|
99
|
-
)
|
100
|
-
end
|
101
|
-
|
102
79
|
alias extensions extending_values
|
103
80
|
|
104
81
|
# Specify relationships to be included in the result set. For
|
@@ -202,12 +179,13 @@ module ActiveRecord
|
|
202
179
|
|
203
180
|
# Works in two unique ways.
|
204
181
|
#
|
205
|
-
# First: takes a block so it can be used just like
|
182
|
+
# First: takes a block so it can be used just like <tt>Array#select</tt>.
|
206
183
|
#
|
207
184
|
# Model.all.select { |m| m.field == value }
|
208
185
|
#
|
209
186
|
# This will build an array of objects from the database for the scope,
|
210
|
-
# converting them into an array and iterating through them using
|
187
|
+
# converting them into an array and iterating through them using
|
188
|
+
# <tt>Array#select</tt>.
|
211
189
|
#
|
212
190
|
# Second: Modifies the SELECT statement for the query so that only certain
|
213
191
|
# fields are retrieved:
|
@@ -248,7 +226,7 @@ module ActiveRecord
|
|
248
226
|
return super()
|
249
227
|
end
|
250
228
|
|
251
|
-
raise ArgumentError, "Call
|
229
|
+
raise ArgumentError, "Call `select' with at least one field" if fields.empty?
|
252
230
|
spawn._select!(*fields)
|
253
231
|
end
|
254
232
|
|
@@ -317,6 +295,7 @@ module ActiveRecord
|
|
317
295
|
spawn.order!(*args)
|
318
296
|
end
|
319
297
|
|
298
|
+
# Same as #order but operates on relation in-place instead of copying.
|
320
299
|
def order!(*args) # :nodoc:
|
321
300
|
preprocess_order_args(args)
|
322
301
|
|
@@ -338,6 +317,7 @@ module ActiveRecord
|
|
338
317
|
spawn.reorder!(*args)
|
339
318
|
end
|
340
319
|
|
320
|
+
# Same as #reorder but operates on relation in-place instead of copying.
|
341
321
|
def reorder!(*args) # :nodoc:
|
342
322
|
preprocess_order_args(args)
|
343
323
|
|
@@ -463,7 +443,7 @@ module ActiveRecord
|
|
463
443
|
# => SELECT "users".* FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
|
464
444
|
#
|
465
445
|
def left_outer_joins(*args)
|
466
|
-
check_if_method_has_arguments!(
|
446
|
+
check_if_method_has_arguments!(__callee__, args)
|
467
447
|
|
468
448
|
args.compact!
|
469
449
|
args.flatten!
|
@@ -657,6 +637,7 @@ module ActiveRecord
|
|
657
637
|
|
658
638
|
self.where_clause = self.where_clause.or(other.where_clause)
|
659
639
|
self.having_clause = having_clause.or(other.having_clause)
|
640
|
+
self.references_values += other.references_values
|
660
641
|
|
661
642
|
self
|
662
643
|
end
|
@@ -797,7 +778,7 @@ module ActiveRecord
|
|
797
778
|
value = sanitize_forbidden_attributes(value)
|
798
779
|
self.create_with_value = create_with_value.merge(value)
|
799
780
|
else
|
800
|
-
self.create_with_value =
|
781
|
+
self.create_with_value = FROZEN_EMPTY_HASH
|
801
782
|
end
|
802
783
|
|
803
784
|
self
|
@@ -913,21 +894,27 @@ module ActiveRecord
|
|
913
894
|
self
|
914
895
|
end
|
915
896
|
|
916
|
-
|
917
|
-
|
918
|
-
|
897
|
+
def skip_query_cache! # :nodoc:
|
898
|
+
self.skip_query_cache_value = true
|
899
|
+
self
|
919
900
|
end
|
920
901
|
|
921
|
-
# Returns
|
922
|
-
def
|
923
|
-
@
|
902
|
+
# Returns the Arel object associated with the relation.
|
903
|
+
def arel(aliases = nil) # :nodoc:
|
904
|
+
@arel ||= build_arel(aliases)
|
924
905
|
end
|
925
906
|
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
907
|
+
protected
|
908
|
+
# Returns a relation value with a given name
|
909
|
+
def get_value(name) # :nodoc:
|
910
|
+
@values[name] || default_value_for(name)
|
911
|
+
end
|
912
|
+
|
913
|
+
# Sets the relation value with the given name
|
914
|
+
def set_value(name, value) # :nodoc:
|
915
|
+
assert_mutability!
|
916
|
+
@values[name] = value
|
917
|
+
end
|
931
918
|
|
932
919
|
private
|
933
920
|
|
@@ -936,16 +923,30 @@ module ActiveRecord
|
|
936
923
|
raise ImmutableRelation if defined?(@arel) && @arel
|
937
924
|
end
|
938
925
|
|
939
|
-
def build_arel
|
926
|
+
def build_arel(aliases)
|
940
927
|
arel = Arel::SelectManager.new(table)
|
941
928
|
|
942
|
-
build_joins(arel, joins_values.flatten) unless joins_values.empty?
|
943
|
-
build_left_outer_joins(arel, left_outer_joins_values.flatten) unless left_outer_joins_values.empty?
|
929
|
+
aliases = build_joins(arel, joins_values.flatten, aliases) unless joins_values.empty?
|
930
|
+
build_left_outer_joins(arel, left_outer_joins_values.flatten, aliases) unless left_outer_joins_values.empty?
|
944
931
|
|
945
932
|
arel.where(where_clause.ast) unless where_clause.empty?
|
946
933
|
arel.having(having_clause.ast) unless having_clause.empty?
|
947
|
-
|
948
|
-
|
934
|
+
if limit_value
|
935
|
+
limit_attribute = ActiveModel::Attribute.with_cast_value(
|
936
|
+
"LIMIT".freeze,
|
937
|
+
connection.sanitize_limit(limit_value),
|
938
|
+
Type.default_value,
|
939
|
+
)
|
940
|
+
arel.take(Arel::Nodes::BindParam.new(limit_attribute))
|
941
|
+
end
|
942
|
+
if offset_value
|
943
|
+
offset_attribute = ActiveModel::Attribute.with_cast_value(
|
944
|
+
"OFFSET".freeze,
|
945
|
+
offset_value.to_i,
|
946
|
+
Type.default_value,
|
947
|
+
)
|
948
|
+
arel.skip(Arel::Nodes::BindParam.new(offset_attribute))
|
949
|
+
end
|
949
950
|
arel.group(*arel_columns(group_values.uniq.reject(&:blank?))) unless group_values.empty?
|
950
951
|
|
951
952
|
build_order(arel)
|
@@ -964,6 +965,9 @@ module ActiveRecord
|
|
964
965
|
name = from_clause.name
|
965
966
|
case opts
|
966
967
|
when Relation
|
968
|
+
if opts.eager_loading?
|
969
|
+
opts = opts.send(:apply_join_dependency)
|
970
|
+
end
|
967
971
|
name ||= "subquery"
|
968
972
|
opts.arel.as(name.to_s)
|
969
973
|
else
|
@@ -971,7 +975,7 @@ module ActiveRecord
|
|
971
975
|
end
|
972
976
|
end
|
973
977
|
|
974
|
-
def build_left_outer_joins(manager, outer_joins)
|
978
|
+
def build_left_outer_joins(manager, outer_joins, aliases)
|
975
979
|
buckets = outer_joins.group_by do |join|
|
976
980
|
case join
|
977
981
|
when Hash, Symbol, Array
|
@@ -981,10 +985,10 @@ module ActiveRecord
|
|
981
985
|
end
|
982
986
|
end
|
983
987
|
|
984
|
-
build_join_query(manager, buckets, Arel::Nodes::OuterJoin)
|
988
|
+
build_join_query(manager, buckets, Arel::Nodes::OuterJoin, aliases)
|
985
989
|
end
|
986
990
|
|
987
|
-
def build_joins(manager, joins)
|
991
|
+
def build_joins(manager, joins, aliases)
|
988
992
|
buckets = joins.group_by do |join|
|
989
993
|
case join
|
990
994
|
when String
|
@@ -1000,10 +1004,10 @@ module ActiveRecord
|
|
1000
1004
|
end
|
1001
1005
|
end
|
1002
1006
|
|
1003
|
-
build_join_query(manager, buckets, Arel::Nodes::InnerJoin)
|
1007
|
+
build_join_query(manager, buckets, Arel::Nodes::InnerJoin, aliases)
|
1004
1008
|
end
|
1005
1009
|
|
1006
|
-
def build_join_query(manager, buckets, join_type)
|
1010
|
+
def build_join_query(manager, buckets, join_type, aliases)
|
1007
1011
|
buckets.default = []
|
1008
1012
|
|
1009
1013
|
association_joins = buckets[:association_join]
|
@@ -1012,23 +1016,18 @@ module ActiveRecord
|
|
1012
1016
|
string_joins = buckets[:string_join].map(&:strip).uniq
|
1013
1017
|
|
1014
1018
|
join_list = join_nodes + convert_join_strings_to_ast(manager, string_joins)
|
1019
|
+
alias_tracker = alias_tracker(join_list, aliases)
|
1015
1020
|
|
1016
1021
|
join_dependency = ActiveRecord::Associations::JoinDependency.new(
|
1017
|
-
|
1018
|
-
association_joins,
|
1019
|
-
join_list
|
1022
|
+
klass, table, association_joins, alias_tracker
|
1020
1023
|
)
|
1021
1024
|
|
1022
|
-
|
1023
|
-
|
1024
|
-
join_infos.each do |info|
|
1025
|
-
info.joins.each { |join| manager.from(join) }
|
1026
|
-
manager.bind_values.concat info.binds
|
1027
|
-
end
|
1025
|
+
joins = join_dependency.join_constraints(stashed_association_joins, join_type)
|
1026
|
+
joins.each { |join| manager.from(join) }
|
1028
1027
|
|
1029
1028
|
manager.join_sources.concat(join_list)
|
1030
1029
|
|
1031
|
-
|
1030
|
+
alias_tracker.aliases
|
1032
1031
|
end
|
1033
1032
|
|
1034
1033
|
def convert_join_strings_to_ast(table, joins)
|
@@ -1041,10 +1040,10 @@ module ActiveRecord
|
|
1041
1040
|
def build_select(arel)
|
1042
1041
|
if select_values.any?
|
1043
1042
|
arel.project(*arel_columns(select_values.uniq))
|
1044
|
-
elsif klass.ignored_columns.any?
|
1045
|
-
arel.project(*klass.column_names
|
1043
|
+
elsif @klass.ignored_columns.any?
|
1044
|
+
arel.project(*arel_columns(@klass.column_names))
|
1046
1045
|
else
|
1047
|
-
arel.project(
|
1046
|
+
arel.project(table[Arel.star])
|
1048
1047
|
end
|
1049
1048
|
end
|
1050
1049
|
|
@@ -1088,6 +1087,10 @@ module ActiveRecord
|
|
1088
1087
|
end
|
1089
1088
|
|
1090
1089
|
def does_not_support_reverse?(order)
|
1090
|
+
# Account for String subclasses like Arel::Nodes::SqlLiteral that
|
1091
|
+
# override methods like #count.
|
1092
|
+
order = String.new(order) unless order.instance_of?(String)
|
1093
|
+
|
1091
1094
|
# Uses SQL function with multiple arguments.
|
1092
1095
|
(order.include?(",") && order.split(",").find { |section| section.count("(") != section.count(")") }) ||
|
1093
1096
|
# Uses "nulls first" like construction.
|
@@ -1102,14 +1105,16 @@ module ActiveRecord
|
|
1102
1105
|
end
|
1103
1106
|
|
1104
1107
|
VALID_DIRECTIONS = [:asc, :desc, :ASC, :DESC,
|
1105
|
-
"asc", "desc", "ASC", "DESC"] # :nodoc:
|
1108
|
+
"asc", "desc", "ASC", "DESC"].to_set # :nodoc:
|
1106
1109
|
|
1107
1110
|
def validate_order_args(args)
|
1108
1111
|
args.each do |arg|
|
1109
1112
|
next unless arg.is_a?(Hash)
|
1110
1113
|
arg.each do |_key, value|
|
1111
|
-
|
1112
|
-
|
1114
|
+
unless VALID_DIRECTIONS.include?(value)
|
1115
|
+
raise ArgumentError,
|
1116
|
+
"Direction \"#{value}\" is invalid. Valid directions are: #{VALID_DIRECTIONS.to_a.inspect}"
|
1117
|
+
end
|
1113
1118
|
end
|
1114
1119
|
end
|
1115
1120
|
end
|
@@ -1119,10 +1124,16 @@ module ActiveRecord
|
|
1119
1124
|
klass.send(:sanitize_sql_for_order, arg)
|
1120
1125
|
end
|
1121
1126
|
order_args.flatten!
|
1127
|
+
|
1128
|
+
@klass.enforce_raw_sql_whitelist(
|
1129
|
+
order_args.flat_map { |a| a.is_a?(Hash) ? a.keys : a },
|
1130
|
+
whitelist: AttributeMethods::ClassMethods::COLUMN_NAME_ORDER_WHITELIST
|
1131
|
+
)
|
1132
|
+
|
1122
1133
|
validate_order_args(order_args)
|
1123
1134
|
|
1124
1135
|
references = order_args.grep(String)
|
1125
|
-
references.map! { |arg| arg =~
|
1136
|
+
references.map! { |arg| arg =~ /^\W?(\w+)\W?\./ && $1 }.compact!
|
1126
1137
|
references!(references) if references.any?
|
1127
1138
|
|
1128
1139
|
# if a symbol is given we prepend the quoted table name
|
@@ -1167,7 +1178,7 @@ module ActiveRecord
|
|
1167
1178
|
end
|
1168
1179
|
end
|
1169
1180
|
|
1170
|
-
STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having]
|
1181
|
+
STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having, :unscope, :references]
|
1171
1182
|
def structurally_incompatible_values_for_or(other)
|
1172
1183
|
STRUCTURAL_OR_METHODS.reject do |method|
|
1173
1184
|
get_value(method) == other.get_value(method)
|