activerecord 4.2.0 → 5.0.0
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 +4 -4
- data/CHANGELOG.md +1537 -789
- data/MIT-LICENSE +2 -2
- data/README.rdoc +7 -8
- data/examples/performance.rb +2 -3
- data/examples/simple.rb +0 -1
- data/lib/active_record/aggregations.rb +37 -23
- data/lib/active_record/association_relation.rb +16 -3
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +23 -9
- data/lib/active_record/associations/association_scope.rb +74 -102
- data/lib/active_record/associations/belongs_to_association.rb +26 -29
- data/lib/active_record/associations/builder/association.rb +28 -34
- data/lib/active_record/associations/builder/belongs_to.rb +43 -18
- data/lib/active_record/associations/builder/collection_association.rb +12 -20
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +22 -15
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +11 -6
- data/lib/active_record/associations/builder/singular_association.rb +3 -10
- data/lib/active_record/associations/collection_association.rb +61 -33
- data/lib/active_record/associations/collection_proxy.rb +81 -35
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +21 -57
- data/lib/active_record/associations/has_many_through_association.rb +15 -45
- data/lib/active_record/associations/has_one_association.rb +13 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +20 -8
- data/lib/active_record/associations/join_dependency.rb +37 -21
- data/lib/active_record/associations/preloader/association.rb +51 -53
- data/lib/active_record/associations/preloader/collection_association.rb +0 -6
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/has_one.rb +0 -8
- data/lib/active_record/associations/preloader/through_association.rb +27 -14
- data/lib/active_record/associations/preloader.rb +18 -8
- data/lib/active_record/associations/singular_association.rb +8 -8
- data/lib/active_record/associations/through_association.rb +22 -9
- data/lib/active_record/associations.rb +321 -212
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute.rb +79 -15
- data/lib/active_record/attribute_assignment.rb +20 -141
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods/before_type_cast.rb +6 -1
- data/lib/active_record/attribute_methods/dirty.rb +51 -81
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +31 -59
- data/lib/active_record/attribute_methods/serialization.rb +13 -16
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +65 -14
- data/lib/active_record/attribute_methods/write.rb +14 -38
- data/lib/active_record/attribute_methods.rb +70 -45
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set/builder.rb +37 -15
- data/lib/active_record/attribute_set.rb +34 -3
- data/lib/active_record/attributes.rb +199 -73
- data/lib/active_record/autosave_association.rb +73 -25
- data/lib/active_record/base.rb +35 -27
- data/lib/active_record/callbacks.rb +39 -43
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +20 -8
- data/lib/active_record/collection_cache_key.rb +40 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +457 -181
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +83 -59
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -9
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -4
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +246 -185
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +438 -136
- data/lib/active_record/connection_adapters/abstract/transaction.rb +53 -40
- data/lib/active_record/connection_adapters/abstract_adapter.rb +166 -66
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +429 -335
- data/lib/active_record/connection_adapters/column.rb +28 -43
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -177
- data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +11 -73
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -56
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -13
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +17 -5
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +248 -154
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +258 -170
- data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +150 -209
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +38 -15
- data/lib/active_record/core.rb +109 -114
- data/lib/active_record/counter_cache.rb +14 -25
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +115 -79
- data/lib/active_record/errors.rb +88 -48
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +2 -2
- data/lib/active_record/fixture_set/file.rb +26 -5
- data/lib/active_record/fixtures.rb +84 -46
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +32 -40
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/internal_metadata.rb +56 -0
- data/lib/active_record/legacy_yaml_adapter.rb +46 -0
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +27 -25
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +43 -21
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/migration.rb +372 -114
- data/lib/active_record/model_schema.rb +128 -38
- data/lib/active_record/nested_attributes.rb +71 -32
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/null_relation.rb +16 -8
- data/lib/active_record/persistence.rb +124 -80
- data/lib/active_record/query_cache.rb +15 -18
- data/lib/active_record/querying.rb +10 -9
- data/lib/active_record/railtie.rb +28 -19
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +67 -51
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +318 -139
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/batches.rb +139 -34
- data/lib/active_record/relation/calculations.rb +80 -102
- data/lib/active_record/relation/delegation.rb +7 -20
- data/lib/active_record/relation/finder_methods.rb +167 -97
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +38 -41
- data/lib/active_record/relation/predicate_builder/array_handler.rb +12 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +124 -82
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +323 -257
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +11 -10
- data/lib/active_record/relation/where_clause.rb +174 -0
- data/lib/active_record/relation/where_clause_factory.rb +38 -0
- data/lib/active_record/relation.rb +176 -115
- data/lib/active_record/result.rb +4 -3
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +95 -66
- data/lib/active_record/schema.rb +26 -22
- data/lib/active_record/schema_dumper.rb +62 -38
- data/lib/active_record/schema_migration.rb +11 -17
- data/lib/active_record/scoping/default.rb +24 -9
- data/lib/active_record/scoping/named.rb +49 -28
- data/lib/active_record/scoping.rb +32 -15
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +2 -4
- data/lib/active_record/statement_cache.rb +16 -14
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +58 -0
- data/lib/active_record/table_metadata.rb +68 -0
- data/lib/active_record/tasks/database_tasks.rb +59 -42
- data/lib/active_record/tasks/mysql_database_tasks.rb +32 -26
- data/lib/active_record/tasks/postgresql_database_tasks.rb +29 -9
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +20 -9
- data/lib/active_record/touch_later.rb +58 -0
- data/lib/active_record/transactions.rb +159 -67
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +2 -41
- data/lib/active_record/type/date_time.rb +2 -38
- data/lib/active_record/type/hash_lookup_type_map.rb +8 -2
- data/lib/active_record/type/internal/abstract_json.rb +29 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +21 -14
- data/lib/active_record/type/time.rb +10 -16
- data/lib/active_record/type/type_map.rb +4 -4
- data/lib/active_record/type.rb +66 -17
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/type_caster.rb +7 -0
- data/lib/active_record/validations/absence.rb +23 -0
- data/lib/active_record/validations/associated.rb +10 -3
- data/lib/active_record/validations/length.rb +24 -0
- data/lib/active_record/validations/presence.rb +11 -12
- data/lib/active_record/validations/uniqueness.rb +29 -18
- data/lib/active_record/validations.rb +33 -32
- data/lib/active_record.rb +9 -2
- data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -6
- data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -7
- data/lib/rails/generators/active_record/migration.rb +7 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
- data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
- metadata +60 -34
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -30
- data/lib/active_record/type/decimal.rb +0 -40
- data/lib/active_record/type/decimal_without_scale.rb +0 -11
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -55
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -36
- data/lib/active_record/type/text.rb +0 -11
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/unsigned_integer.rb +0 -15
- data/lib/active_record/type/value.rb +0 -101
@@ -14,121 +14,112 @@ module ActiveRecord
|
|
14
14
|
# Person.distinct.count(:age)
|
15
15
|
# # => counts the number of different age values
|
16
16
|
#
|
17
|
-
# If
|
17
|
+
# If #count is used with {Relation#group}[rdoc-ref:QueryMethods#group],
|
18
|
+
# it returns a Hash whose keys represent the aggregated column,
|
18
19
|
# and the values are the respective amounts:
|
19
20
|
#
|
20
21
|
# Person.group(:city).count
|
21
22
|
# # => { 'Rome' => 5, 'Paris' => 3 }
|
22
23
|
#
|
23
|
-
# If
|
24
|
+
# If #count is used with {Relation#group}[rdoc-ref:QueryMethods#group] for multiple columns, it returns a Hash whose
|
24
25
|
# keys are an array containing the individual values of each column and the value
|
25
|
-
# of each key would be the
|
26
|
+
# of each key would be the #count.
|
26
27
|
#
|
27
28
|
# Article.group(:status, :category).count
|
28
29
|
# # => {["draft", "business"]=>10, ["draft", "technology"]=>4,
|
29
30
|
# ["published", "business"]=>0, ["published", "technology"]=>2}
|
30
31
|
#
|
31
|
-
# If
|
32
|
+
# If #count is used with {Relation#select}[rdoc-ref:QueryMethods#select], it will count the selected columns:
|
32
33
|
#
|
33
34
|
# Person.select(:age).count
|
34
35
|
# # => counts the number of different age values
|
35
36
|
#
|
36
|
-
# Note: not all valid
|
37
|
+
# Note: not all valid {Relation#select}[rdoc-ref:QueryMethods#select] expressions are valid #count expressions. The specifics differ
|
37
38
|
# between databases. In invalid cases, an error from the database is thrown.
|
38
|
-
def count(column_name = nil
|
39
|
-
|
40
|
-
# activerecord-deprecated_finders.
|
41
|
-
column_name, options = nil, column_name if column_name.is_a?(Hash)
|
42
|
-
calculate(:count, column_name, options)
|
39
|
+
def count(column_name = nil)
|
40
|
+
calculate(:count, column_name)
|
43
41
|
end
|
44
42
|
|
45
43
|
# Calculates the average value on a given column. Returns +nil+ if there's
|
46
|
-
# no row. See
|
44
|
+
# no row. See #calculate for examples with options.
|
47
45
|
#
|
48
46
|
# Person.average(:age) # => 35.8
|
49
|
-
def average(column_name
|
50
|
-
|
51
|
-
# activerecord-deprecated_finders.
|
52
|
-
calculate(:average, column_name, options)
|
47
|
+
def average(column_name)
|
48
|
+
calculate(:average, column_name)
|
53
49
|
end
|
54
50
|
|
55
51
|
# Calculates the minimum value on a given column. The value is returned
|
56
52
|
# with the same data type of the column, or +nil+ if there's no row. See
|
57
|
-
#
|
53
|
+
# #calculate for examples with options.
|
58
54
|
#
|
59
55
|
# Person.minimum(:age) # => 7
|
60
|
-
def minimum(column_name
|
61
|
-
|
62
|
-
# activerecord-deprecated_finders.
|
63
|
-
calculate(:minimum, column_name, options)
|
56
|
+
def minimum(column_name)
|
57
|
+
calculate(:minimum, column_name)
|
64
58
|
end
|
65
59
|
|
66
60
|
# Calculates the maximum value on a given column. The value is returned
|
67
61
|
# with the same data type of the column, or +nil+ if there's no row. See
|
68
|
-
#
|
62
|
+
# #calculate for examples with options.
|
69
63
|
#
|
70
64
|
# Person.maximum(:age) # => 93
|
71
|
-
def maximum(column_name
|
72
|
-
|
73
|
-
# activerecord-deprecated_finders.
|
74
|
-
calculate(:maximum, column_name, options)
|
65
|
+
def maximum(column_name)
|
66
|
+
calculate(:maximum, column_name)
|
75
67
|
end
|
76
68
|
|
77
69
|
# Calculates the sum of values on a given column. The value is returned
|
78
|
-
# with the same data type of the column, 0 if there's no row. See
|
79
|
-
#
|
70
|
+
# with the same data type of the column, +0+ if there's no row. See
|
71
|
+
# #calculate for examples with options.
|
80
72
|
#
|
81
73
|
# Person.sum(:age) # => 4562
|
82
|
-
def sum(
|
83
|
-
|
74
|
+
def sum(column_name = nil, &block)
|
75
|
+
return super(&block) if block_given?
|
76
|
+
calculate(:sum, column_name)
|
84
77
|
end
|
85
78
|
|
86
|
-
# This calculates aggregate values in the given column. Methods for count, sum, average,
|
87
|
-
# minimum, and maximum have been added as shortcuts.
|
79
|
+
# This calculates aggregate values in the given column. Methods for #count, #sum, #average,
|
80
|
+
# #minimum, and #maximum have been added as shortcuts.
|
88
81
|
#
|
89
|
-
#
|
82
|
+
# Person.calculate(:count, :all) # The same as Person.count
|
83
|
+
# Person.average(:age) # SELECT AVG(age) FROM people...
|
90
84
|
#
|
91
|
-
#
|
92
|
-
#
|
85
|
+
# # Selects the minimum age for any family without any minors
|
86
|
+
# Person.group(:last_name).having("min(age) > 17").minimum(:age)
|
93
87
|
#
|
94
|
-
# *
|
95
|
-
# takes either a column name, or the name of a belongs_to association.
|
88
|
+
# Person.sum("2 * age")
|
96
89
|
#
|
97
|
-
#
|
98
|
-
# puts values["Drake"]
|
99
|
-
# # => 43
|
90
|
+
# There are two basic forms of output:
|
100
91
|
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
# puts values[drake]
|
104
|
-
# # => 43
|
92
|
+
# * Single aggregate value: The single value is type cast to Integer for COUNT, Float
|
93
|
+
# for AVG, and the given column's type for everything else.
|
105
94
|
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
# end
|
95
|
+
# * Grouped values: This returns an ordered hash of the values and groups them. It
|
96
|
+
# takes either a column name, or the name of a belongs_to association.
|
109
97
|
#
|
110
|
-
#
|
111
|
-
#
|
98
|
+
# values = Person.group('last_name').maximum(:age)
|
99
|
+
# puts values["Drake"]
|
100
|
+
# # => 43
|
112
101
|
#
|
113
|
-
#
|
114
|
-
#
|
102
|
+
# drake = Family.find_by(last_name: 'Drake')
|
103
|
+
# values = Person.group(:family).maximum(:age) # Person belongs_to :family
|
104
|
+
# puts values[drake]
|
105
|
+
# # => 43
|
115
106
|
#
|
116
|
-
#
|
117
|
-
|
118
|
-
|
119
|
-
|
107
|
+
# values.each do |family, max_age|
|
108
|
+
# ...
|
109
|
+
# end
|
110
|
+
def calculate(operation, column_name)
|
120
111
|
if column_name.is_a?(Symbol) && attribute_alias?(column_name)
|
121
112
|
column_name = attribute_alias(column_name)
|
122
113
|
end
|
123
114
|
|
124
115
|
if has_include?(column_name)
|
125
|
-
construct_relation_for_association_calculations.calculate(operation, column_name
|
116
|
+
construct_relation_for_association_calculations.calculate(operation, column_name)
|
126
117
|
else
|
127
|
-
perform_calculation(operation, column_name
|
118
|
+
perform_calculation(operation, column_name)
|
128
119
|
end
|
129
120
|
end
|
130
121
|
|
131
|
-
# Use
|
122
|
+
# Use #pluck as a shortcut to select one or more attributes without
|
132
123
|
# loading a bunch of records just to grab the attributes you want.
|
133
124
|
#
|
134
125
|
# Person.pluck(:name)
|
@@ -137,19 +128,19 @@ module ActiveRecord
|
|
137
128
|
#
|
138
129
|
# Person.all.map(&:name)
|
139
130
|
#
|
140
|
-
# Pluck returns an
|
131
|
+
# Pluck returns an Array of attribute values type-casted to match
|
141
132
|
# the plucked column names, if they can be deduced. Plucking an SQL fragment
|
142
133
|
# returns String values by default.
|
143
134
|
#
|
144
|
-
# Person.pluck(:
|
145
|
-
# # SELECT people.
|
146
|
-
# # => [
|
135
|
+
# Person.pluck(:name)
|
136
|
+
# # SELECT people.name FROM people
|
137
|
+
# # => ['David', 'Jeremy', 'Jose']
|
147
138
|
#
|
148
139
|
# Person.pluck(:id, :name)
|
149
140
|
# # SELECT people.id, people.name FROM people
|
150
141
|
# # => [[1, 'David'], [2, 'Jeremy'], [3, 'Jose']]
|
151
142
|
#
|
152
|
-
# Person.pluck(
|
143
|
+
# Person.distinct.pluck(:role)
|
153
144
|
# # SELECT DISTINCT role FROM people
|
154
145
|
# # => ['admin', 'member', 'guest']
|
155
146
|
#
|
@@ -161,13 +152,11 @@ module ActiveRecord
|
|
161
152
|
# # SELECT DATEDIFF(updated_at, created_at) FROM people
|
162
153
|
# # => ['0', '27761', '173']
|
163
154
|
#
|
155
|
+
# See also #ids.
|
156
|
+
#
|
164
157
|
def pluck(*column_names)
|
165
|
-
column_names.map
|
166
|
-
|
167
|
-
attribute_alias(column_name)
|
168
|
-
else
|
169
|
-
column_name.to_s
|
170
|
-
end
|
158
|
+
if loaded? && (column_names.map(&:to_s) - @klass.attribute_names - @klass.attribute_aliases.keys).empty?
|
159
|
+
return @records.pluck(*column_names)
|
171
160
|
end
|
172
161
|
|
173
162
|
if has_include?(column_names.first)
|
@@ -175,10 +164,10 @@ module ActiveRecord
|
|
175
164
|
else
|
176
165
|
relation = spawn
|
177
166
|
relation.select_values = column_names.map { |cn|
|
178
|
-
|
167
|
+
@klass.has_attribute?(cn) || @klass.attribute_alias?(cn) ? arel_attribute(cn) : cn
|
179
168
|
}
|
180
|
-
result = klass.connection.select_all(relation.arel, nil,
|
181
|
-
result.cast_values(klass.
|
169
|
+
result = klass.connection.select_all(relation.arel, nil, bound_attributes)
|
170
|
+
result.cast_values(klass.attribute_types)
|
182
171
|
end
|
183
172
|
end
|
184
173
|
|
@@ -193,15 +182,14 @@ module ActiveRecord
|
|
193
182
|
private
|
194
183
|
|
195
184
|
def has_include?(column_name)
|
196
|
-
eager_loading? || (includes_values.present? &&
|
185
|
+
eager_loading? || (includes_values.present? && column_name && column_name != :all)
|
197
186
|
end
|
198
187
|
|
199
|
-
def perform_calculation(operation, column_name
|
200
|
-
# TODO: Remove options argument as soon we remove support to
|
201
|
-
# activerecord-deprecated_finders.
|
188
|
+
def perform_calculation(operation, column_name)
|
202
189
|
operation = operation.to_s.downcase
|
203
190
|
|
204
|
-
# If #count is used with #distinct
|
191
|
+
# If #count is used with #distinct (i.e. `relation.distinct.count`) it is
|
192
|
+
# considered distinct.
|
205
193
|
distinct = self.distinct_value
|
206
194
|
|
207
195
|
if operation == "count"
|
@@ -223,6 +211,8 @@ module ActiveRecord
|
|
223
211
|
end
|
224
212
|
|
225
213
|
def aggregate_column(column_name)
|
214
|
+
return column_name if Arel::Expressions === column_name
|
215
|
+
|
226
216
|
if @klass.column_names.include?(column_name.to_s)
|
227
217
|
Arel::Attribute.new(@klass.unscoped.table, column_name)
|
228
218
|
else
|
@@ -235,19 +225,16 @@ module ActiveRecord
|
|
235
225
|
end
|
236
226
|
|
237
227
|
def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
|
238
|
-
#
|
228
|
+
# PostgreSQL doesn't like ORDER BY when there are no GROUP BY
|
239
229
|
relation = unscope(:order)
|
240
230
|
|
241
231
|
column_alias = column_name
|
242
232
|
|
243
|
-
bind_values = nil
|
244
|
-
|
245
233
|
if operation == "count" && (relation.limit_value || relation.offset_value)
|
246
234
|
# Shortcut when limit is zero.
|
247
235
|
return 0 if relation.limit_value == 0
|
248
236
|
|
249
237
|
query_builder = build_count_subquery(relation, column_name, distinct)
|
250
|
-
bind_values = query_builder.bind_values + relation.bind_values
|
251
238
|
else
|
252
239
|
column = aggregate_column(column_name)
|
253
240
|
|
@@ -258,10 +245,9 @@ module ActiveRecord
|
|
258
245
|
relation.select_values = [select_value]
|
259
246
|
|
260
247
|
query_builder = relation.arel
|
261
|
-
bind_values = query_builder.bind_values + relation.bind_values
|
262
248
|
end
|
263
249
|
|
264
|
-
result = @klass.connection.select_all(query_builder, nil,
|
250
|
+
result = @klass.connection.select_all(query_builder, nil, bound_attributes)
|
265
251
|
row = result.first
|
266
252
|
value = row && row.values.first
|
267
253
|
column = result.column_types.fetch(column_alias) do
|
@@ -281,15 +267,10 @@ module ActiveRecord
|
|
281
267
|
else
|
282
268
|
group_fields = group_attrs
|
283
269
|
end
|
270
|
+
group_fields = arel_columns(group_fields)
|
284
271
|
|
285
|
-
group_aliases = group_fields.map { |field|
|
286
|
-
|
287
|
-
}
|
288
|
-
group_columns = group_aliases.zip(group_fields).map { |aliaz,field|
|
289
|
-
[aliaz, field]
|
290
|
-
}
|
291
|
-
|
292
|
-
group = group_fields
|
272
|
+
group_aliases = group_fields.map { |field| column_alias_for(field) }
|
273
|
+
group_columns = group_aliases.zip(group_fields)
|
293
274
|
|
294
275
|
if operation == 'count' && column_name == :all
|
295
276
|
aggregate_alias = 'count_all'
|
@@ -303,9 +284,9 @@ module ActiveRecord
|
|
303
284
|
operation,
|
304
285
|
distinct).as(aggregate_alias)
|
305
286
|
]
|
306
|
-
select_values += select_values unless
|
287
|
+
select_values += select_values unless having_clause.empty?
|
307
288
|
|
308
|
-
select_values.concat
|
289
|
+
select_values.concat group_columns.map { |aliaz, field|
|
309
290
|
if field.respond_to?(:as)
|
310
291
|
field.as(aliaz)
|
311
292
|
else
|
@@ -314,14 +295,14 @@ module ActiveRecord
|
|
314
295
|
}
|
315
296
|
|
316
297
|
relation = except(:group)
|
317
|
-
relation.group_values =
|
298
|
+
relation.group_values = group_fields
|
318
299
|
relation.select_values = select_values
|
319
300
|
|
320
|
-
calculated_data = @klass.connection.select_all(relation, nil, relation.
|
301
|
+
calculated_data = @klass.connection.select_all(relation, nil, relation.bound_attributes)
|
321
302
|
|
322
303
|
if association
|
323
304
|
key_ids = calculated_data.collect { |row| row[group_aliases.first] }
|
324
|
-
key_records = association.klass.base_class.
|
305
|
+
key_records = association.klass.base_class.where(association.klass.base_class.primary_key => key_ids)
|
325
306
|
key_records = Hash[key_records.map { |r| [r.id, r] }]
|
326
307
|
end
|
327
308
|
|
@@ -347,7 +328,6 @@ module ActiveRecord
|
|
347
328
|
# column_alias_for("sum(id)") # => "sum_id"
|
348
329
|
# column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
|
349
330
|
# column_alias_for("count(*)") # => "count_all"
|
350
|
-
# column_alias_for("count", "id") # => "count_id"
|
351
331
|
def column_alias_for(keys)
|
352
332
|
if keys.respond_to? :name
|
353
333
|
keys = "#{keys.relation.name}.#{keys.name}"
|
@@ -370,15 +350,15 @@ module ActiveRecord
|
|
370
350
|
def type_cast_calculated_value(value, type, operation = nil)
|
371
351
|
case operation
|
372
352
|
when 'count' then value.to_i
|
373
|
-
when 'sum' then type.
|
353
|
+
when 'sum' then type.deserialize(value || 0)
|
374
354
|
when 'average' then value.respond_to?(:to_d) ? value.to_d : value
|
375
|
-
else type.
|
355
|
+
else type.deserialize(value)
|
376
356
|
end
|
377
357
|
end
|
378
358
|
|
379
|
-
# TODO: refactor to allow non-string `select_values` (eg. Arel nodes).
|
380
359
|
def select_for_count
|
381
360
|
if select_values.present?
|
361
|
+
return select_values.first if select_values.one?
|
382
362
|
select_values.join(", ")
|
383
363
|
else
|
384
364
|
:all
|
@@ -391,11 +371,9 @@ module ActiveRecord
|
|
391
371
|
|
392
372
|
aliased_column = aggregate_column(column_name == :all ? 1 : column_name).as(column_alias)
|
393
373
|
relation.select_values = [aliased_column]
|
394
|
-
|
395
|
-
subquery = arel.as(subquery_alias)
|
374
|
+
subquery = relation.arel.as(subquery_alias)
|
396
375
|
|
397
376
|
sm = Arel::SelectManager.new relation.engine
|
398
|
-
sm.bind_values = arel.bind_values
|
399
377
|
select_value = operation_over_aggregate_column(column_alias, 'count', distinct)
|
400
378
|
sm.project(select_value).from(subquery)
|
401
379
|
end
|
@@ -1,15 +1,13 @@
|
|
1
|
-
require 'set'
|
2
1
|
require 'active_support/concern'
|
3
|
-
require 'active_support/deprecation'
|
4
2
|
|
5
3
|
module ActiveRecord
|
6
4
|
module Delegation # :nodoc:
|
7
|
-
module DelegateCache
|
8
|
-
def relation_delegate_class(klass)
|
5
|
+
module DelegateCache # :nodoc:
|
6
|
+
def relation_delegate_class(klass)
|
9
7
|
@relation_delegate_cache[klass]
|
10
8
|
end
|
11
9
|
|
12
|
-
def initialize_relation_delegate_cache
|
10
|
+
def initialize_relation_delegate_cache
|
13
11
|
@relation_delegate_cache = cache = {}
|
14
12
|
[
|
15
13
|
ActiveRecord::Relation,
|
@@ -19,7 +17,7 @@ module ActiveRecord
|
|
19
17
|
delegate = Class.new(klass) {
|
20
18
|
include ClassSpecificRelation
|
21
19
|
}
|
22
|
-
const_set klass.name.gsub('::', '_'), delegate
|
20
|
+
const_set klass.name.gsub('::'.freeze, '_'.freeze), delegate
|
23
21
|
cache[klass] = delegate
|
24
22
|
end
|
25
23
|
end
|
@@ -37,13 +35,9 @@ module ActiveRecord
|
|
37
35
|
# may vary depending on the klass of a relation, so we create a subclass of Relation
|
38
36
|
# for each different klass, and the delegations are compiled into that subclass only.
|
39
37
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
:keep_if, :pop, :shift, :delete_at, :compact, :select!
|
44
|
-
].to_set # :nodoc:
|
45
|
-
|
46
|
-
delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to_ary, :join, to: :to_a
|
38
|
+
delegate :to_xml, :encode_with, :length, :collect, :map, :each, :all?, :include?, :to_ary, :join,
|
39
|
+
:[], :&, :|, :+, :-, :sample, :reverse, :compact, :in_groups, :in_groups_of,
|
40
|
+
:shuffle, :split, to: :records
|
47
41
|
|
48
42
|
delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key,
|
49
43
|
:connection, :columns_hash, :to => :klass
|
@@ -115,21 +109,14 @@ module ActiveRecord
|
|
115
109
|
|
116
110
|
def respond_to?(method, include_private = false)
|
117
111
|
super || @klass.respond_to?(method, include_private) ||
|
118
|
-
array_delegable?(method) ||
|
119
112
|
arel.respond_to?(method, include_private)
|
120
113
|
end
|
121
114
|
|
122
115
|
protected
|
123
116
|
|
124
|
-
def array_delegable?(method)
|
125
|
-
Array.method_defined?(method) && BLACKLISTED_ARRAY_METHODS.exclude?(method)
|
126
|
-
end
|
127
|
-
|
128
117
|
def method_missing(method, *args, &block)
|
129
118
|
if @klass.respond_to?(method)
|
130
119
|
scoping { @klass.public_send(method, *args, &block) }
|
131
|
-
elsif array_delegable?(method)
|
132
|
-
to_a.public_send(method, *args, &block)
|
133
120
|
elsif arel.respond_to?(method)
|
134
121
|
arel.public_send(method, *args, &block)
|
135
122
|
else
|