activerecord 5.1.0 → 5.2.3
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 +596 -450
- 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.rb +11 -4
- data/lib/active_record/aggregations.rb +6 -5
- data/lib/active_record/association_relation.rb +7 -5
- data/lib/active_record/associations.rb +77 -85
- data/lib/active_record/associations/alias_tracker.rb +23 -32
- data/lib/active_record/associations/association.rb +49 -35
- data/lib/active_record/associations/association_scope.rb +55 -55
- data/lib/active_record/associations/belongs_to_association.rb +30 -11
- 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 +21 -8
- 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 +66 -53
- data/lib/active_record/associations/collection_proxy.rb +30 -73
- data/lib/active_record/associations/foreign_association.rb +2 -0
- data/lib/active_record/associations/has_many_association.rb +13 -2
- data/lib/active_record/associations/has_many_through_association.rb +37 -19
- data/lib/active_record/associations/has_one_association.rb +14 -1
- data/lib/active_record/associations/has_one_through_association.rb +13 -8
- data/lib/active_record/associations/join_dependency.rb +52 -96
- data/lib/active_record/associations/join_dependency/join_association.rb +22 -75
- 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/preloader.rb +17 -37
- 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/singular_association.rb +14 -16
- data/lib/active_record/associations/through_association.rb +27 -12
- data/lib/active_record/attribute_assignment.rb +2 -5
- data/lib/active_record/attribute_decorators.rb +3 -2
- data/lib/active_record/attribute_methods.rb +65 -24
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
- data/lib/active_record/attribute_methods/dirty.rb +33 -216
- 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 +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 +22 -19
- data/lib/active_record/attributes.rb +7 -6
- data/lib/active_record/autosave_association.rb +15 -13
- 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 +2 -0
- data/lib/active_record/collection_cache_key.rb +15 -11
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +120 -39
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +192 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +13 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -25
- 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 +65 -7
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +158 -87
- data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
- data/lib/active_record/connection_adapters/abstract_adapter.rb +86 -98
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +126 -189
- 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 +13 -2
- data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -15
- 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.rb +3 -1
- 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 +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 +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/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 +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 +258 -129
- 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 +75 -87
- 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 +24 -1
- 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 +90 -96
- 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 +41 -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 +4 -2
- 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 +30 -42
- data/lib/active_record/locking/pessimistic.rb +10 -7
- data/lib/active_record/log_subscriber.rb +46 -4
- data/lib/active_record/migration.rb +189 -139
- data/lib/active_record/migration/command_recorder.rb +11 -9
- data/lib/active_record/migration/compatibility.rb +81 -29
- data/lib/active_record/migration/join_table.rb +2 -0
- data/lib/active_record/model_schema.rb +74 -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 +199 -54
- data/lib/active_record/query_cache.rb +8 -10
- data/lib/active_record/querying.rb +5 -3
- data/lib/active_record/railtie.rb +62 -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 +48 -38
- data/lib/active_record/readonly_attributes.rb +3 -2
- data/lib/active_record/reflection.rb +137 -207
- data/lib/active_record/relation.rb +132 -207
- data/lib/active_record/relation/batches.rb +32 -17
- data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
- data/lib/active_record/relation/calculations.rb +66 -25
- data/lib/active_record/relation/delegation.rb +45 -29
- data/lib/active_record/relation/finder_methods.rb +76 -85
- 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.rb +60 -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 +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/query_attribute.rb +28 -2
- data/lib/active_record/relation/query_methods.rb +135 -103
- 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 -67
- data/lib/active_record/relation/where_clause_factory.rb +5 -48
- 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.rb +12 -10
- data/lib/active_record/scoping/default.rb +10 -7
- data/lib/active_record/scoping/named.rb +40 -12
- 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 +38 -26
- 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 +13 -6
- data/lib/active_record/touch_later.rb +2 -0
- data/lib/active_record/transactions.rb +32 -27
- 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 +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_caster.rb +2 -0
- data/lib/active_record/type_caster/connection.rb +2 -0
- data/lib/active_record/type_caster/map.rb +3 -1
- 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 +24 -36
- 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 -113
- data/lib/active_record/attribute_set.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/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
@@ -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,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
|
@@ -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
|
|
@@ -347,8 +327,8 @@ module ActiveRecord
|
|
347
327
|
end
|
348
328
|
|
349
329
|
VALID_UNSCOPING_VALUES = Set.new([:where, :select, :group, :order, :lock,
|
350
|
-
:limit, :offset, :joins, :
|
351
|
-
:readonly, :having])
|
330
|
+
:limit, :offset, :joins, :left_outer_joins,
|
331
|
+
:includes, :from, :readonly, :having])
|
352
332
|
|
353
333
|
# Removes an unwanted relation that is already defined on a chain of relations.
|
354
334
|
# This is useful when passing around chains of relations and would like to
|
@@ -395,10 +375,11 @@ module ActiveRecord
|
|
395
375
|
args.each do |scope|
|
396
376
|
case scope
|
397
377
|
when Symbol
|
378
|
+
scope = :left_outer_joins if scope == :left_joins
|
398
379
|
if !VALID_UNSCOPING_VALUES.include?(scope)
|
399
380
|
raise ArgumentError, "Called unscope() with invalid unscoping argument ':#{scope}'. Valid arguments are :#{VALID_UNSCOPING_VALUES.to_a.join(", :")}."
|
400
381
|
end
|
401
|
-
set_value(scope,
|
382
|
+
set_value(scope, DEFAULT_VALUES[scope])
|
402
383
|
when Hash
|
403
384
|
scope.each do |key, target_value|
|
404
385
|
if key != :where
|
@@ -463,16 +444,14 @@ module ActiveRecord
|
|
463
444
|
# => SELECT "users".* FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
|
464
445
|
#
|
465
446
|
def left_outer_joins(*args)
|
466
|
-
check_if_method_has_arguments!(
|
467
|
-
|
468
|
-
args.compact!
|
469
|
-
args.flatten!
|
470
|
-
|
447
|
+
check_if_method_has_arguments!(__callee__, args)
|
471
448
|
spawn.left_outer_joins!(*args)
|
472
449
|
end
|
473
450
|
alias :left_joins :left_outer_joins
|
474
451
|
|
475
452
|
def left_outer_joins!(*args) # :nodoc:
|
453
|
+
args.compact!
|
454
|
+
args.flatten!
|
476
455
|
self.left_outer_joins_values += args
|
477
456
|
self
|
478
457
|
end
|
@@ -657,6 +636,7 @@ module ActiveRecord
|
|
657
636
|
|
658
637
|
self.where_clause = self.where_clause.or(other.where_clause)
|
659
638
|
self.having_clause = having_clause.or(other.having_clause)
|
639
|
+
self.references_values += other.references_values
|
660
640
|
|
661
641
|
self
|
662
642
|
end
|
@@ -797,7 +777,7 @@ module ActiveRecord
|
|
797
777
|
value = sanitize_forbidden_attributes(value)
|
798
778
|
self.create_with_value = create_with_value.merge(value)
|
799
779
|
else
|
800
|
-
self.create_with_value =
|
780
|
+
self.create_with_value = FROZEN_EMPTY_HASH
|
801
781
|
end
|
802
782
|
|
803
783
|
self
|
@@ -913,21 +893,28 @@ module ActiveRecord
|
|
913
893
|
self
|
914
894
|
end
|
915
895
|
|
896
|
+
def skip_query_cache!(value = true) # :nodoc:
|
897
|
+
self.skip_query_cache_value = value
|
898
|
+
self
|
899
|
+
end
|
900
|
+
|
916
901
|
# Returns the Arel object associated with the relation.
|
917
|
-
def arel # :nodoc:
|
918
|
-
@arel ||= build_arel
|
902
|
+
def arel(aliases = nil) # :nodoc:
|
903
|
+
@arel ||= build_arel(aliases)
|
919
904
|
end
|
920
905
|
|
921
906
|
# Returns a relation value with a given name
|
922
907
|
def get_value(name) # :nodoc:
|
923
|
-
@values[name]
|
908
|
+
@values.fetch(name, DEFAULT_VALUES[name])
|
924
909
|
end
|
925
910
|
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
911
|
+
protected
|
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,20 +975,22 @@ 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
|
978
982
|
:association_join
|
983
|
+
when ActiveRecord::Associations::JoinDependency
|
984
|
+
:stashed_join
|
979
985
|
else
|
980
986
|
raise ArgumentError, "only Hash, Symbol and Array are allowed"
|
981
987
|
end
|
982
988
|
end
|
983
989
|
|
984
|
-
build_join_query(manager, buckets, Arel::Nodes::OuterJoin)
|
990
|
+
build_join_query(manager, buckets, Arel::Nodes::OuterJoin, aliases)
|
985
991
|
end
|
986
992
|
|
987
|
-
def build_joins(manager, joins)
|
993
|
+
def build_joins(manager, joins, aliases)
|
988
994
|
buckets = joins.group_by do |join|
|
989
995
|
case join
|
990
996
|
when String
|
@@ -1000,38 +1006,33 @@ module ActiveRecord
|
|
1000
1006
|
end
|
1001
1007
|
end
|
1002
1008
|
|
1003
|
-
build_join_query(manager, buckets, Arel::Nodes::InnerJoin)
|
1009
|
+
build_join_query(manager, buckets, Arel::Nodes::InnerJoin, aliases)
|
1004
1010
|
end
|
1005
1011
|
|
1006
|
-
def build_join_query(manager, buckets, join_type)
|
1012
|
+
def build_join_query(manager, buckets, join_type, aliases)
|
1007
1013
|
buckets.default = []
|
1008
1014
|
|
1009
|
-
association_joins
|
1010
|
-
|
1011
|
-
join_nodes
|
1012
|
-
string_joins
|
1015
|
+
association_joins = buckets[:association_join]
|
1016
|
+
stashed_joins = buckets[:stashed_join]
|
1017
|
+
join_nodes = buckets[:join_node].uniq
|
1018
|
+
string_joins = buckets[:string_join].map(&:strip).uniq
|
1013
1019
|
|
1014
|
-
join_list = join_nodes + convert_join_strings_to_ast(
|
1020
|
+
join_list = join_nodes + convert_join_strings_to_ast(string_joins)
|
1021
|
+
alias_tracker = alias_tracker(join_list, aliases)
|
1015
1022
|
|
1016
1023
|
join_dependency = ActiveRecord::Associations::JoinDependency.new(
|
1017
|
-
|
1018
|
-
association_joins,
|
1019
|
-
join_list
|
1024
|
+
klass, table, association_joins
|
1020
1025
|
)
|
1021
1026
|
|
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
|
1027
|
+
joins = join_dependency.join_constraints(stashed_joins, join_type, alias_tracker)
|
1028
|
+
joins.each { |join| manager.from(join) }
|
1028
1029
|
|
1029
1030
|
manager.join_sources.concat(join_list)
|
1030
1031
|
|
1031
|
-
|
1032
|
+
alias_tracker.aliases
|
1032
1033
|
end
|
1033
1034
|
|
1034
|
-
def convert_join_strings_to_ast(
|
1035
|
+
def convert_join_strings_to_ast(joins)
|
1035
1036
|
joins
|
1036
1037
|
.flatten
|
1037
1038
|
.reject(&:blank?)
|
@@ -1041,23 +1042,44 @@ module ActiveRecord
|
|
1041
1042
|
def build_select(arel)
|
1042
1043
|
if select_values.any?
|
1043
1044
|
arel.project(*arel_columns(select_values.uniq))
|
1045
|
+
elsif klass.ignored_columns.any?
|
1046
|
+
arel.project(*klass.column_names.map { |field| arel_attribute(field) })
|
1044
1047
|
else
|
1045
|
-
arel.project(
|
1048
|
+
arel.project(table[Arel.star])
|
1046
1049
|
end
|
1047
1050
|
end
|
1048
1051
|
|
1049
1052
|
def arel_columns(columns)
|
1050
|
-
columns.
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
connection.quote_table_name(field
|
1053
|
+
columns.flat_map do |field|
|
1054
|
+
case field
|
1055
|
+
when Symbol
|
1056
|
+
field = field.to_s
|
1057
|
+
arel_column(field) { connection.quote_table_name(field) }
|
1058
|
+
when String
|
1059
|
+
arel_column(field) { field }
|
1060
|
+
when Proc
|
1061
|
+
field.call
|
1055
1062
|
else
|
1056
1063
|
field
|
1057
1064
|
end
|
1058
1065
|
end
|
1059
1066
|
end
|
1060
1067
|
|
1068
|
+
def arel_column(field)
|
1069
|
+
field = klass.attribute_alias(field) if klass.attribute_alias?(field)
|
1070
|
+
from = from_clause.name || from_clause.value
|
1071
|
+
|
1072
|
+
if klass.columns_hash.key?(field) && (!from || table_name_matches?(from))
|
1073
|
+
arel_attribute(field)
|
1074
|
+
else
|
1075
|
+
yield
|
1076
|
+
end
|
1077
|
+
end
|
1078
|
+
|
1079
|
+
def table_name_matches?(from)
|
1080
|
+
/(?:\A|(?<!FROM)\s)(?:\b#{table.name}\b|#{connection.quote_table_name(table.name)})(?!\.)/i.match?(from.to_s)
|
1081
|
+
end
|
1082
|
+
|
1061
1083
|
def reverse_sql_order(order_query)
|
1062
1084
|
if order_query.empty?
|
1063
1085
|
return [arel_attribute(primary_key).desc] if primary_key
|
@@ -1077,7 +1099,7 @@ module ActiveRecord
|
|
1077
1099
|
end
|
1078
1100
|
o.split(",").map! do |s|
|
1079
1101
|
s.strip!
|
1080
|
-
s.gsub!(/\sasc\Z/i, " DESC") || s.gsub!(/\sdesc\Z/i, " ASC") || s
|
1102
|
+
s.gsub!(/\sasc\Z/i, " DESC") || s.gsub!(/\sdesc\Z/i, " ASC") || (s << " DESC")
|
1081
1103
|
end
|
1082
1104
|
else
|
1083
1105
|
o
|
@@ -1086,6 +1108,10 @@ module ActiveRecord
|
|
1086
1108
|
end
|
1087
1109
|
|
1088
1110
|
def does_not_support_reverse?(order)
|
1111
|
+
# Account for String subclasses like Arel::Nodes::SqlLiteral that
|
1112
|
+
# override methods like #count.
|
1113
|
+
order = String.new(order) unless order.instance_of?(String)
|
1114
|
+
|
1089
1115
|
# Uses SQL function with multiple arguments.
|
1090
1116
|
(order.include?(",") && order.split(",").find { |section| section.count("(") != section.count(")") }) ||
|
1091
1117
|
# Uses "nulls first" like construction.
|
@@ -1100,41 +1126,55 @@ module ActiveRecord
|
|
1100
1126
|
end
|
1101
1127
|
|
1102
1128
|
VALID_DIRECTIONS = [:asc, :desc, :ASC, :DESC,
|
1103
|
-
"asc", "desc", "ASC", "DESC"] # :nodoc:
|
1129
|
+
"asc", "desc", "ASC", "DESC"].to_set # :nodoc:
|
1104
1130
|
|
1105
1131
|
def validate_order_args(args)
|
1106
1132
|
args.each do |arg|
|
1107
1133
|
next unless arg.is_a?(Hash)
|
1108
1134
|
arg.each do |_key, value|
|
1109
|
-
|
1110
|
-
|
1135
|
+
unless VALID_DIRECTIONS.include?(value)
|
1136
|
+
raise ArgumentError,
|
1137
|
+
"Direction \"#{value}\" is invalid. Valid directions are: #{VALID_DIRECTIONS.to_a.inspect}"
|
1138
|
+
end
|
1111
1139
|
end
|
1112
1140
|
end
|
1113
1141
|
end
|
1114
1142
|
|
1115
1143
|
def preprocess_order_args(order_args)
|
1116
1144
|
order_args.map! do |arg|
|
1117
|
-
klass.
|
1145
|
+
klass.sanitize_sql_for_order(arg)
|
1118
1146
|
end
|
1119
1147
|
order_args.flatten!
|
1148
|
+
|
1149
|
+
@klass.enforce_raw_sql_whitelist(
|
1150
|
+
order_args.flat_map { |a| a.is_a?(Hash) ? a.keys : a },
|
1151
|
+
whitelist: AttributeMethods::ClassMethods::COLUMN_NAME_ORDER_WHITELIST
|
1152
|
+
)
|
1153
|
+
|
1120
1154
|
validate_order_args(order_args)
|
1121
1155
|
|
1122
1156
|
references = order_args.grep(String)
|
1123
|
-
references.map! { |arg| arg =~
|
1157
|
+
references.map! { |arg| arg =~ /^\W?(\w+)\W?\./ && $1 }.compact!
|
1124
1158
|
references!(references) if references.any?
|
1125
1159
|
|
1126
1160
|
# if a symbol is given we prepend the quoted table name
|
1127
1161
|
order_args.map! do |arg|
|
1128
1162
|
case arg
|
1129
1163
|
when Symbol
|
1130
|
-
|
1164
|
+
arg = arg.to_s
|
1165
|
+
arel_column(arg) {
|
1166
|
+
Arel.sql(connection.quote_table_name(arg))
|
1167
|
+
}.asc
|
1131
1168
|
when Hash
|
1132
1169
|
arg.map { |field, dir|
|
1133
1170
|
case field
|
1134
1171
|
when Arel::Nodes::SqlLiteral
|
1135
1172
|
field.send(dir.downcase)
|
1136
1173
|
else
|
1137
|
-
|
1174
|
+
field = field.to_s
|
1175
|
+
arel_column(field) {
|
1176
|
+
Arel.sql(connection.quote_table_name(field))
|
1177
|
+
}.send(dir.downcase)
|
1138
1178
|
end
|
1139
1179
|
}
|
1140
1180
|
else
|
@@ -1165,7 +1205,7 @@ module ActiveRecord
|
|
1165
1205
|
end
|
1166
1206
|
end
|
1167
1207
|
|
1168
|
-
STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having]
|
1208
|
+
STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having, :unscope, :references]
|
1169
1209
|
def structurally_incompatible_values_for_or(other)
|
1170
1210
|
STRUCTURAL_OR_METHODS.reject do |method|
|
1171
1211
|
get_value(method) == other.get_value(method)
|
@@ -1177,23 +1217,15 @@ module ActiveRecord
|
|
1177
1217
|
end
|
1178
1218
|
alias having_clause_factory where_clause_factory
|
1179
1219
|
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
Relation::FromClause.empty
|
1190
|
-
when *Relation::MULTI_VALUE_METHODS
|
1191
|
-
FROZEN_EMPTY_ARRAY
|
1192
|
-
when *Relation::SINGLE_VALUE_METHODS
|
1193
|
-
nil
|
1194
|
-
else
|
1195
|
-
raise ArgumentError, "unknown relation value #{name.inspect}"
|
1196
|
-
end
|
1220
|
+
DEFAULT_VALUES = {
|
1221
|
+
create_with: FROZEN_EMPTY_HASH,
|
1222
|
+
where: Relation::WhereClause.empty,
|
1223
|
+
having: Relation::WhereClause.empty,
|
1224
|
+
from: Relation::FromClause.empty
|
1225
|
+
}
|
1226
|
+
|
1227
|
+
Relation::MULTI_VALUE_METHODS.each do |value|
|
1228
|
+
DEFAULT_VALUES[value] ||= FROZEN_EMPTY_ARRAY
|
1197
1229
|
end
|
1198
1230
|
end
|
1199
1231
|
end
|