activerecord 3.2.22.5 → 5.2.8
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 +657 -621
- data/MIT-LICENSE +2 -2
- data/README.rdoc +41 -46
- data/examples/performance.rb +55 -42
- data/examples/simple.rb +6 -5
- data/lib/active_record/aggregations.rb +264 -236
- data/lib/active_record/association_relation.rb +40 -0
- data/lib/active_record/associations/alias_tracker.rb +47 -42
- data/lib/active_record/associations/association.rb +127 -75
- data/lib/active_record/associations/association_scope.rb +126 -92
- data/lib/active_record/associations/belongs_to_association.rb +78 -27
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +9 -4
- data/lib/active_record/associations/builder/association.rb +117 -32
- data/lib/active_record/associations/builder/belongs_to.rb +135 -60
- data/lib/active_record/associations/builder/collection_association.rb +61 -54
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +120 -42
- data/lib/active_record/associations/builder/has_many.rb +10 -64
- data/lib/active_record/associations/builder/has_one.rb +19 -51
- data/lib/active_record/associations/builder/singular_association.rb +28 -18
- data/lib/active_record/associations/collection_association.rb +226 -293
- data/lib/active_record/associations/collection_proxy.rb +1067 -69
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +83 -47
- data/lib/active_record/associations/has_many_through_association.rb +98 -65
- data/lib/active_record/associations/has_one_association.rb +57 -20
- data/lib/active_record/associations/has_one_through_association.rb +18 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +48 -126
- data/lib/active_record/associations/join_dependency/join_base.rb +11 -12
- data/lib/active_record/associations/join_dependency/join_part.rb +35 -42
- data/lib/active_record/associations/join_dependency.rb +212 -164
- data/lib/active_record/associations/preloader/association.rb +95 -89
- data/lib/active_record/associations/preloader/through_association.rb +84 -44
- data/lib/active_record/associations/preloader.rb +123 -111
- data/lib/active_record/associations/singular_association.rb +33 -24
- data/lib/active_record/associations/through_association.rb +60 -26
- data/lib/active_record/associations.rb +1759 -1506
- data/lib/active_record/attribute_assignment.rb +60 -193
- data/lib/active_record/attribute_decorators.rb +90 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +55 -8
- data/lib/active_record/attribute_methods/dirty.rb +113 -74
- data/lib/active_record/attribute_methods/primary_key.rb +106 -77
- data/lib/active_record/attribute_methods/query.rb +8 -5
- data/lib/active_record/attribute_methods/read.rb +63 -114
- data/lib/active_record/attribute_methods/serialization.rb +60 -90
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +69 -43
- data/lib/active_record/attribute_methods/write.rb +43 -45
- data/lib/active_record/attribute_methods.rb +366 -149
- data/lib/active_record/attributes.rb +266 -0
- data/lib/active_record/autosave_association.rb +312 -225
- data/lib/active_record/base.rb +114 -505
- data/lib/active_record/callbacks.rb +145 -67
- data/lib/active_record/coders/json.rb +15 -0
- data/lib/active_record/coders/yaml_column.rb +32 -23
- data/lib/active_record/collection_cache_key.rb +53 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +883 -284
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +16 -2
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +350 -200
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +82 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +150 -65
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +146 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +477 -284
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +95 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1100 -310
- data/lib/active_record/connection_adapters/abstract/transaction.rb +283 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +450 -118
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +657 -446
- data/lib/active_record/connection_adapters/column.rb +50 -255
- data/lib/active_record/connection_adapters/connection_specification.rb +287 -0
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +59 -210
- data/lib/active_record/connection_adapters/postgresql/column.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +163 -0
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +92 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +56 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +41 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +111 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +168 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +206 -0
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +774 -0
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +620 -1080
- data/lib/active_record/connection_adapters/schema_cache.rb +85 -36
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +545 -27
- data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
- data/lib/active_record/connection_handling.rb +145 -0
- data/lib/active_record/core.rb +559 -0
- data/lib/active_record/counter_cache.rb +200 -105
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +107 -69
- data/lib/active_record/enum.rb +244 -0
- data/lib/active_record/errors.rb +245 -60
- data/lib/active_record/explain.rb +35 -71
- data/lib/active_record/explain_registry.rb +32 -0
- data/lib/active_record/explain_subscriber.rb +18 -9
- data/lib/active_record/fixture_set/file.rb +82 -0
- data/lib/active_record/fixtures.rb +418 -275
- data/lib/active_record/gem_version.rb +17 -0
- data/lib/active_record/inheritance.rb +209 -100
- data/lib/active_record/integration.rb +116 -21
- data/lib/active_record/internal_metadata.rb +45 -0
- data/lib/active_record/legacy_yaml_adapter.rb +48 -0
- data/lib/active_record/locale/en.yml +9 -1
- data/lib/active_record/locking/optimistic.rb +107 -94
- data/lib/active_record/locking/pessimistic.rb +20 -8
- data/lib/active_record/log_subscriber.rb +99 -34
- data/lib/active_record/migration/command_recorder.rb +199 -64
- data/lib/active_record/migration/compatibility.rb +217 -0
- data/lib/active_record/migration/join_table.rb +17 -0
- data/lib/active_record/migration.rb +893 -296
- data/lib/active_record/model_schema.rb +328 -175
- data/lib/active_record/nested_attributes.rb +338 -242
- data/lib/active_record/no_touching.rb +58 -0
- data/lib/active_record/null_relation.rb +68 -0
- data/lib/active_record/persistence.rb +557 -170
- data/lib/active_record/query_cache.rb +14 -43
- data/lib/active_record/querying.rb +36 -24
- data/lib/active_record/railtie.rb +147 -52
- data/lib/active_record/railties/console_sandbox.rb +5 -4
- data/lib/active_record/railties/controller_runtime.rb +13 -6
- data/lib/active_record/railties/databases.rake +206 -488
- data/lib/active_record/readonly_attributes.rb +4 -6
- data/lib/active_record/reflection.rb +734 -228
- data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
- data/lib/active_record/relation/batches.rb +249 -52
- data/lib/active_record/relation/calculations.rb +330 -284
- data/lib/active_record/relation/delegation.rb +135 -37
- data/lib/active_record/relation/finder_methods.rb +450 -287
- data/lib/active_record/relation/from_clause.rb +26 -0
- data/lib/active_record/relation/merger.rb +193 -0
- data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder.rb +132 -43
- data/lib/active_record/relation/query_attribute.rb +45 -0
- data/lib/active_record/relation/query_methods.rb +1037 -221
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +48 -151
- data/lib/active_record/relation/where_clause.rb +186 -0
- data/lib/active_record/relation/where_clause_factory.rb +34 -0
- data/lib/active_record/relation.rb +451 -359
- data/lib/active_record/result.rb +129 -20
- data/lib/active_record/runtime_registry.rb +24 -0
- data/lib/active_record/sanitization.rb +164 -136
- data/lib/active_record/schema.rb +31 -19
- data/lib/active_record/schema_dumper.rb +154 -107
- data/lib/active_record/schema_migration.rb +56 -0
- data/lib/active_record/scoping/default.rb +108 -98
- data/lib/active_record/scoping/named.rb +125 -112
- data/lib/active_record/scoping.rb +77 -123
- data/lib/active_record/secure_token.rb +40 -0
- data/lib/active_record/serialization.rb +10 -6
- data/lib/active_record/statement_cache.rb +121 -0
- data/lib/active_record/store.rb +175 -16
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +82 -0
- data/lib/active_record/tasks/database_tasks.rb +337 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +143 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +83 -0
- data/lib/active_record/timestamp.rb +80 -41
- data/lib/active_record/touch_later.rb +64 -0
- data/lib/active_record/transactions.rb +240 -119
- data/lib/active_record/translation.rb +2 -0
- data/lib/active_record/type/adapter_specific_registry.rb +136 -0
- data/lib/active_record/type/date.rb +9 -0
- data/lib/active_record/type/date_time.rb +9 -0
- data/lib/active_record/type/decimal_without_scale.rb +15 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
- data/lib/active_record/type/internal/timezone.rb +17 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +71 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +21 -0
- data/lib/active_record/type/type_map.rb +62 -0
- data/lib/active_record/type/unsigned_integer.rb +17 -0
- data/lib/active_record/type.rb +79 -0
- data/lib/active_record/type_caster/connection.rb +33 -0
- data/lib/active_record/type_caster/map.rb +23 -0
- data/lib/active_record/type_caster.rb +9 -0
- data/lib/active_record/validations/absence.rb +25 -0
- data/lib/active_record/validations/associated.rb +35 -18
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/presence.rb +68 -0
- data/lib/active_record/validations/uniqueness.rb +133 -75
- data/lib/active_record/validations.rb +53 -43
- data/lib/active_record/version.rb +7 -7
- data/lib/active_record.rb +89 -57
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +61 -8
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +46 -0
- data/lib/rails/generators/active_record/migration.rb +28 -8
- data/lib/rails/generators/active_record/model/model_generator.rb +23 -22
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +13 -0
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +1 -1
- data/lib/rails/generators/active_record.rb +10 -16
- metadata +141 -62
- data/examples/associations.png +0 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
- data/lib/active_record/associations/join_helper.rb +0 -55
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -24
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -15
- data/lib/active_record/associations/preloader/has_one.rb +0 -23
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -21
- data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -441
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
- data/lib/active_record/dynamic_finder_match.rb +0 -68
- data/lib/active_record/dynamic_scope_match.rb +0 -23
- data/lib/active_record/fixtures/file.rb +0 -65
- data/lib/active_record/identity_map.rb +0 -162
- data/lib/active_record/observer.rb +0 -121
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/serializers/xml_serializer.rb +0 -203
- data/lib/active_record/session_store.rb +0 -360
- data/lib/active_record/test_case.rb +0 -73
- data/lib/rails/generators/active_record/migration/templates/migration.rb +0 -34
- data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
- data/lib/rails/generators/active_record/model/templates/model.rb +0 -12
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,372 +1,418 @@
|
|
1
|
-
|
2
|
-
require 'active_support/core_ext/object/try'
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module ActiveRecord
|
5
4
|
module Calculations
|
6
|
-
# Count
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
# Note: <tt>Person.count(:all)</tt> will not work because it will use <tt>:all</tt> as the condition.
|
55
|
-
# Use Person.count instead.
|
56
|
-
def count(column_name = nil, options = {})
|
57
|
-
column_name, options = nil, column_name if column_name.is_a?(Hash)
|
58
|
-
calculate(:count, column_name, options)
|
5
|
+
# Count the records.
|
6
|
+
#
|
7
|
+
# Person.count
|
8
|
+
# # => the total count of all people
|
9
|
+
#
|
10
|
+
# Person.count(:age)
|
11
|
+
# # => returns the total count of all people whose age is present in database
|
12
|
+
#
|
13
|
+
# Person.count(:all)
|
14
|
+
# # => performs a COUNT(*) (:all is an alias for '*')
|
15
|
+
#
|
16
|
+
# Person.distinct.count(:age)
|
17
|
+
# # => counts the number of different age values
|
18
|
+
#
|
19
|
+
# If #count is used with {Relation#group}[rdoc-ref:QueryMethods#group],
|
20
|
+
# it returns a Hash whose keys represent the aggregated column,
|
21
|
+
# and the values are the respective amounts:
|
22
|
+
#
|
23
|
+
# Person.group(:city).count
|
24
|
+
# # => { 'Rome' => 5, 'Paris' => 3 }
|
25
|
+
#
|
26
|
+
# If #count is used with {Relation#group}[rdoc-ref:QueryMethods#group] for multiple columns, it returns a Hash whose
|
27
|
+
# keys are an array containing the individual values of each column and the value
|
28
|
+
# of each key would be the #count.
|
29
|
+
#
|
30
|
+
# Article.group(:status, :category).count
|
31
|
+
# # => {["draft", "business"]=>10, ["draft", "technology"]=>4,
|
32
|
+
# ["published", "business"]=>0, ["published", "technology"]=>2}
|
33
|
+
#
|
34
|
+
# If #count is used with {Relation#select}[rdoc-ref:QueryMethods#select], it will count the selected columns:
|
35
|
+
#
|
36
|
+
# Person.select(:age).count
|
37
|
+
# # => counts the number of different age values
|
38
|
+
#
|
39
|
+
# Note: not all valid {Relation#select}[rdoc-ref:QueryMethods#select] expressions are valid #count expressions. The specifics differ
|
40
|
+
# between databases. In invalid cases, an error from the database is thrown.
|
41
|
+
def count(column_name = nil)
|
42
|
+
if block_given?
|
43
|
+
unless column_name.nil?
|
44
|
+
ActiveSupport::Deprecation.warn \
|
45
|
+
"When `count' is called with a block, it ignores other arguments. " \
|
46
|
+
"This behavior is now deprecated and will result in an ArgumentError in Rails 6.0."
|
47
|
+
end
|
48
|
+
|
49
|
+
return super()
|
50
|
+
end
|
51
|
+
|
52
|
+
calculate(:count, column_name)
|
59
53
|
end
|
60
54
|
|
61
55
|
# Calculates the average value on a given column. Returns +nil+ if there's
|
62
|
-
# no row. See
|
56
|
+
# no row. See #calculate for examples with options.
|
63
57
|
#
|
64
|
-
# Person.average(
|
65
|
-
def average(column_name
|
66
|
-
calculate(:average, column_name
|
58
|
+
# Person.average(:age) # => 35.8
|
59
|
+
def average(column_name)
|
60
|
+
calculate(:average, column_name)
|
67
61
|
end
|
68
62
|
|
69
63
|
# Calculates the minimum value on a given column. The value is returned
|
70
64
|
# with the same data type of the column, or +nil+ if there's no row. See
|
71
|
-
#
|
65
|
+
# #calculate for examples with options.
|
72
66
|
#
|
73
|
-
# Person.minimum(
|
74
|
-
def minimum(column_name
|
75
|
-
calculate(:minimum, column_name
|
67
|
+
# Person.minimum(:age) # => 7
|
68
|
+
def minimum(column_name)
|
69
|
+
calculate(:minimum, column_name)
|
76
70
|
end
|
77
71
|
|
78
72
|
# Calculates the maximum value on a given column. The value is returned
|
79
73
|
# with the same data type of the column, or +nil+ if there's no row. See
|
80
|
-
#
|
74
|
+
# #calculate for examples with options.
|
81
75
|
#
|
82
|
-
# Person.maximum(
|
83
|
-
def maximum(column_name
|
84
|
-
calculate(:maximum, column_name
|
76
|
+
# Person.maximum(:age) # => 93
|
77
|
+
def maximum(column_name)
|
78
|
+
calculate(:maximum, column_name)
|
85
79
|
end
|
86
80
|
|
87
81
|
# Calculates the sum of values on a given column. The value is returned
|
88
|
-
# with the same data type of the column, 0 if there's no row. See
|
89
|
-
#
|
82
|
+
# with the same data type of the column, +0+ if there's no row. See
|
83
|
+
# #calculate for examples with options.
|
90
84
|
#
|
91
|
-
# Person.sum(
|
92
|
-
def sum(
|
85
|
+
# Person.sum(:age) # => 4562
|
86
|
+
def sum(column_name = nil)
|
93
87
|
if block_given?
|
94
|
-
|
95
|
-
|
96
|
-
|
88
|
+
unless column_name.nil?
|
89
|
+
ActiveSupport::Deprecation.warn \
|
90
|
+
"When `sum' is called with a block, it ignores other arguments. " \
|
91
|
+
"This behavior is now deprecated and will result in an ArgumentError in Rails 6.0."
|
92
|
+
end
|
93
|
+
|
94
|
+
return super()
|
97
95
|
end
|
96
|
+
|
97
|
+
calculate(:sum, column_name)
|
98
98
|
end
|
99
99
|
|
100
|
-
# This calculates aggregate values in the given column. Methods for count, sum, average,
|
101
|
-
# minimum, and maximum have been added as shortcuts.
|
102
|
-
# <tt>:order</tt>, <tt>:group</tt>, <tt>:having</tt>, and <tt>:joins</tt> can be passed to customize the query.
|
100
|
+
# This calculates aggregate values in the given column. Methods for #count, #sum, #average,
|
101
|
+
# #minimum, and #maximum have been added as shortcuts.
|
103
102
|
#
|
104
|
-
# There are two basic forms of output:
|
105
|
-
# * Single aggregate value: The single value is type cast to Fixnum for COUNT, Float
|
106
|
-
# for AVG, and the given column's type for everything else.
|
107
|
-
# * Grouped values: This returns an ordered hash of the values and groups them by the
|
108
|
-
# <tt>:group</tt> option. It takes either a column name, or the name of a belongs_to association.
|
109
|
-
#
|
110
|
-
# values = Person.maximum(:age, :group => 'last_name')
|
111
|
-
# puts values["Drake"]
|
112
|
-
# => 43
|
113
|
-
#
|
114
|
-
# drake = Family.find_by_last_name('Drake')
|
115
|
-
# values = Person.maximum(:age, :group => :family) # Person belongs_to :family
|
116
|
-
# puts values[drake]
|
117
|
-
# => 43
|
118
|
-
#
|
119
|
-
# values.each do |family, max_age|
|
120
|
-
# ...
|
121
|
-
# end
|
122
|
-
#
|
123
|
-
# Options:
|
124
|
-
# * <tt>:conditions</tt> - An SQL fragment like "administrator = 1" or [ "user_name = ?", username ].
|
125
|
-
# See conditions in the intro to ActiveRecord::Base.
|
126
|
-
# * <tt>:include</tt>: Eager loading, see Associations for details. Since calculations don't load anything,
|
127
|
-
# the purpose of this is to access fields on joined tables in your conditions, order, or group clauses.
|
128
|
-
# * <tt>:joins</tt> - An SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id".
|
129
|
-
# (Rarely needed).
|
130
|
-
# The records will be returned read-only since they will have attributes that do not correspond to the
|
131
|
-
# table's columns.
|
132
|
-
# * <tt>:order</tt> - An SQL fragment like "created_at DESC, name" (really only used with GROUP BY calculations).
|
133
|
-
# * <tt>:group</tt> - An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.
|
134
|
-
# * <tt>:select</tt> - By default, this is * as in SELECT * FROM, but can be changed if you for example
|
135
|
-
# want to do a join, but not include the joined columns.
|
136
|
-
# * <tt>:distinct</tt> - Set this to true to make this a distinct calculation, such as
|
137
|
-
# SELECT COUNT(DISTINCT posts.id) ...
|
138
|
-
#
|
139
|
-
# Examples:
|
140
103
|
# Person.calculate(:count, :all) # The same as Person.count
|
141
104
|
# Person.average(:age) # SELECT AVG(age) FROM people...
|
142
|
-
# Person.minimum(:age, :conditions => ['last_name != ?', 'Drake']) # Selects the minimum age for
|
143
|
-
# # everyone with a last name other than 'Drake'
|
144
105
|
#
|
145
106
|
# # Selects the minimum age for any family without any minors
|
146
|
-
# Person.
|
107
|
+
# Person.group(:last_name).having("min(age) > 17").minimum(:age)
|
147
108
|
#
|
148
109
|
# Person.sum("2 * age")
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
110
|
+
#
|
111
|
+
# There are two basic forms of output:
|
112
|
+
#
|
113
|
+
# * Single aggregate value: The single value is type cast to Integer for COUNT, Float
|
114
|
+
# for AVG, and the given column's type for everything else.
|
115
|
+
#
|
116
|
+
# * Grouped values: This returns an ordered hash of the values and groups them. It
|
117
|
+
# takes either a column name, or the name of a belongs_to association.
|
118
|
+
#
|
119
|
+
# values = Person.group('last_name').maximum(:age)
|
120
|
+
# puts values["Drake"]
|
121
|
+
# # => 43
|
122
|
+
#
|
123
|
+
# drake = Family.find_by(last_name: 'Drake')
|
124
|
+
# values = Person.group(:family).maximum(:age) # Person belongs_to :family
|
125
|
+
# puts values[drake]
|
126
|
+
# # => 43
|
127
|
+
#
|
128
|
+
# values.each do |family, max_age|
|
129
|
+
# ...
|
130
|
+
# end
|
131
|
+
def calculate(operation, column_name)
|
132
|
+
if has_include?(column_name)
|
133
|
+
relation = apply_join_dependency
|
134
|
+
|
135
|
+
if operation.to_s.downcase == "count"
|
136
|
+
unless distinct_value || distinct_select?(column_name || select_for_count)
|
137
|
+
relation.distinct!
|
138
|
+
relation.select_values = [ klass.primary_key || table[Arel.star] ]
|
160
139
|
end
|
161
|
-
|
162
|
-
relation.
|
140
|
+
# PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
|
141
|
+
relation.order_values = []
|
163
142
|
end
|
143
|
+
|
144
|
+
relation.calculate(operation, column_name)
|
145
|
+
else
|
146
|
+
perform_calculation(operation, column_name)
|
164
147
|
end
|
165
|
-
rescue ThrowResult
|
166
|
-
0
|
167
148
|
end
|
168
149
|
|
169
|
-
#
|
170
|
-
#
|
171
|
-
#
|
150
|
+
# Use #pluck as a shortcut to select one or more attributes without
|
151
|
+
# loading a bunch of records just to grab the attributes you want.
|
152
|
+
#
|
153
|
+
# Person.pluck(:name)
|
154
|
+
#
|
155
|
+
# instead of
|
156
|
+
#
|
157
|
+
# Person.all.map(&:name)
|
158
|
+
#
|
159
|
+
# Pluck returns an Array of attribute values type-casted to match
|
160
|
+
# the plucked column names, if they can be deduced. Plucking an SQL fragment
|
161
|
+
# returns String values by default.
|
172
162
|
#
|
173
|
-
#
|
163
|
+
# Person.pluck(:name)
|
164
|
+
# # SELECT people.name FROM people
|
165
|
+
# # => ['David', 'Jeremy', 'Jose']
|
174
166
|
#
|
175
|
-
# Person.pluck(:id)
|
176
|
-
#
|
177
|
-
#
|
167
|
+
# Person.pluck(:id, :name)
|
168
|
+
# # SELECT people.id, people.name FROM people
|
169
|
+
# # => [[1, 'David'], [2, 'Jeremy'], [3, 'Jose']]
|
178
170
|
#
|
179
|
-
|
180
|
-
|
181
|
-
|
171
|
+
# Person.distinct.pluck(:role)
|
172
|
+
# # SELECT DISTINCT role FROM people
|
173
|
+
# # => ['admin', 'member', 'guest']
|
174
|
+
#
|
175
|
+
# Person.where(age: 21).limit(5).pluck(:id)
|
176
|
+
# # SELECT people.id FROM people WHERE people.age = 21 LIMIT 5
|
177
|
+
# # => [2, 3]
|
178
|
+
#
|
179
|
+
# Person.pluck('DATEDIFF(updated_at, created_at)')
|
180
|
+
# # SELECT DATEDIFF(updated_at, created_at) FROM people
|
181
|
+
# # => ['0', '27761', '173']
|
182
|
+
#
|
183
|
+
# See also #ids.
|
184
|
+
#
|
185
|
+
def pluck(*column_names)
|
186
|
+
if loaded? && (column_names.map(&:to_s) - @klass.attribute_names - @klass.attribute_aliases.keys).empty?
|
187
|
+
return records.pluck(*column_names)
|
182
188
|
end
|
183
189
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
klass.
|
190
|
+
if has_include?(column_names.first)
|
191
|
+
relation = apply_join_dependency
|
192
|
+
relation.pluck(*column_names)
|
193
|
+
else
|
194
|
+
klass.enforce_raw_sql_whitelist(column_names)
|
195
|
+
relation = spawn
|
196
|
+
relation.select_values = column_names
|
197
|
+
result = skip_query_cache_if_necessary { klass.connection.select_all(relation.arel, nil) }
|
198
|
+
result.cast_values(klass.attribute_types)
|
189
199
|
end
|
190
200
|
end
|
191
201
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
202
|
+
# Pluck all the ID's for the relation using the table's primary key
|
203
|
+
#
|
204
|
+
# Person.ids # SELECT people.id FROM people
|
205
|
+
# Person.joins(:companies).ids # SELECT people.id FROM people INNER JOIN companies ON companies.person_id = people.id
|
206
|
+
def ids
|
207
|
+
pluck primary_key
|
208
|
+
end
|
199
209
|
|
200
|
-
|
201
|
-
|
210
|
+
private
|
211
|
+
def has_include?(column_name)
|
212
|
+
eager_loading? || (includes_values.present? && column_name && column_name != :all)
|
213
|
+
end
|
202
214
|
|
203
|
-
|
204
|
-
|
215
|
+
def perform_calculation(operation, column_name)
|
216
|
+
operation = operation.to_s.downcase
|
217
|
+
|
218
|
+
# If #count is used with #distinct (i.e. `relation.distinct.count`) it is
|
219
|
+
# considered distinct.
|
220
|
+
distinct = distinct_value
|
221
|
+
|
222
|
+
if operation == "count"
|
223
|
+
column_name ||= select_for_count
|
224
|
+
if column_name == :all
|
225
|
+
if !distinct
|
226
|
+
distinct = distinct_select?(select_for_count) if group_values.empty?
|
227
|
+
elsif group_values.any? || select_values.empty? && order_values.empty?
|
228
|
+
column_name = primary_key
|
229
|
+
end
|
230
|
+
elsif distinct_select?(column_name)
|
231
|
+
distinct = nil
|
232
|
+
end
|
205
233
|
end
|
206
234
|
|
207
|
-
|
208
|
-
|
209
|
-
|
235
|
+
if group_values.any?
|
236
|
+
execute_grouped_calculation(operation, column_name, distinct)
|
237
|
+
else
|
238
|
+
execute_simple_calculation(operation, column_name, distinct)
|
239
|
+
end
|
210
240
|
end
|
211
241
|
|
212
|
-
|
213
|
-
|
214
|
-
else
|
215
|
-
execute_simple_calculation(operation, column_name, distinct)
|
242
|
+
def distinct_select?(column_name)
|
243
|
+
column_name.is_a?(::String) && /\bDISTINCT[\s(]/i.match?(column_name)
|
216
244
|
end
|
217
|
-
end
|
218
245
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
246
|
+
def aggregate_column(column_name)
|
247
|
+
return column_name if Arel::Expressions === column_name
|
248
|
+
|
249
|
+
if @klass.has_attribute?(column_name) || @klass.attribute_alias?(column_name)
|
250
|
+
@klass.arel_attribute(column_name)
|
251
|
+
else
|
252
|
+
Arel.sql(column_name == :all ? "*" : column_name.to_s)
|
253
|
+
end
|
224
254
|
end
|
225
|
-
end
|
226
255
|
|
227
|
-
|
228
|
-
|
229
|
-
|
256
|
+
def operation_over_aggregate_column(column, operation, distinct)
|
257
|
+
operation == "count" ? column.count(distinct) : column.send(operation)
|
258
|
+
end
|
230
259
|
|
231
|
-
|
232
|
-
|
233
|
-
relation = reorder(nil)
|
260
|
+
def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
|
261
|
+
column_alias = column_name
|
234
262
|
|
235
|
-
|
236
|
-
|
237
|
-
|
263
|
+
if operation == "count" && (column_name == :all && distinct || has_limit_or_offset?)
|
264
|
+
# Shortcut when limit is zero.
|
265
|
+
return 0 if limit_value == 0
|
238
266
|
|
239
|
-
|
240
|
-
|
241
|
-
|
267
|
+
query_builder = build_count_subquery(spawn, column_name, distinct)
|
268
|
+
else
|
269
|
+
# PostgreSQL doesn't like ORDER BY when there are no GROUP BY
|
270
|
+
relation = unscope(:order).distinct!(false)
|
242
271
|
|
243
|
-
|
272
|
+
column = aggregate_column(column_name)
|
244
273
|
|
245
|
-
|
274
|
+
select_value = operation_over_aggregate_column(column, operation, distinct)
|
275
|
+
if operation == "sum" && distinct
|
276
|
+
select_value.distinct = true
|
277
|
+
end
|
246
278
|
|
247
|
-
|
248
|
-
|
279
|
+
column_alias = select_value.alias
|
280
|
+
column_alias ||= @klass.connection.column_name_for_operation(operation, select_value)
|
281
|
+
relation.select_values = [select_value]
|
249
282
|
|
250
|
-
|
251
|
-
|
283
|
+
query_builder = relation.arel
|
284
|
+
end
|
252
285
|
|
253
|
-
|
254
|
-
|
286
|
+
result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder, nil) }
|
287
|
+
row = result.first
|
288
|
+
value = row && row.values.first
|
289
|
+
type = result.column_types.fetch(column_alias) do
|
290
|
+
type_for(column_name)
|
291
|
+
end
|
255
292
|
|
256
|
-
|
257
|
-
association = @klass.reflect_on_association(group_attrs.first.to_sym)
|
258
|
-
associated = group_attrs.size == 1 && association && association.macro == :belongs_to # only count belongs_to associations
|
259
|
-
group_fields = Array(associated ? association.foreign_key : group_attrs)
|
260
|
-
else
|
261
|
-
group_fields = group_attrs
|
293
|
+
type_cast_calculated_value(value, type, operation)
|
262
294
|
end
|
263
295
|
|
264
|
-
|
265
|
-
|
266
|
-
[aliaz, column_for(field)]
|
267
|
-
}
|
296
|
+
def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
|
297
|
+
group_attrs = group_values
|
268
298
|
|
269
|
-
|
299
|
+
if group_attrs.first.respond_to?(:to_sym)
|
300
|
+
association = @klass._reflect_on_association(group_attrs.first)
|
301
|
+
associated = group_attrs.size == 1 && association && association.belongs_to? # only count belongs_to associations
|
302
|
+
group_fields = Array(associated ? association.foreign_key : group_attrs)
|
303
|
+
else
|
304
|
+
group_fields = group_attrs
|
305
|
+
end
|
306
|
+
group_fields = arel_columns(group_fields)
|
270
307
|
|
271
|
-
|
272
|
-
|
273
|
-
else
|
274
|
-
aggregate_alias = column_alias_for(operation, column_name)
|
275
|
-
end
|
308
|
+
group_aliases = group_fields.map { |field| column_alias_for(field) }
|
309
|
+
group_columns = group_aliases.zip(group_fields)
|
276
310
|
|
277
|
-
|
278
|
-
|
279
|
-
aggregate_column(column_name),
|
280
|
-
operation,
|
281
|
-
distinct).as(aggregate_alias)
|
282
|
-
]
|
283
|
-
select_values += @select_values unless @having_values.empty?
|
284
|
-
|
285
|
-
select_values.concat group_fields.zip(group_aliases).map { |field,aliaz|
|
286
|
-
if field.respond_to?(:as)
|
287
|
-
field.as(aliaz)
|
311
|
+
if operation == "count" && column_name == :all
|
312
|
+
aggregate_alias = "count_all"
|
288
313
|
else
|
289
|
-
|
314
|
+
aggregate_alias = column_alias_for([operation, column_name].join(" "))
|
290
315
|
end
|
291
|
-
}
|
292
316
|
|
293
|
-
|
294
|
-
|
317
|
+
select_values = [
|
318
|
+
operation_over_aggregate_column(
|
319
|
+
aggregate_column(column_name),
|
320
|
+
operation,
|
321
|
+
distinct).as(aggregate_alias)
|
322
|
+
]
|
323
|
+
select_values += self.select_values unless having_clause.empty?
|
324
|
+
|
325
|
+
select_values.concat group_columns.map { |aliaz, field|
|
326
|
+
if field.respond_to?(:as)
|
327
|
+
field.as(aliaz)
|
328
|
+
else
|
329
|
+
"#{field} AS #{aliaz}"
|
330
|
+
end
|
331
|
+
}
|
332
|
+
|
333
|
+
relation = except(:group).distinct!(false)
|
334
|
+
relation.group_values = group_fields
|
335
|
+
relation.select_values = select_values
|
336
|
+
|
337
|
+
calculated_data = skip_query_cache_if_necessary { @klass.connection.select_all(relation.arel, nil) }
|
295
338
|
|
296
|
-
|
339
|
+
if association
|
340
|
+
key_ids = calculated_data.collect { |row| row[group_aliases.first] }
|
341
|
+
key_records = association.klass.base_class.where(association.klass.base_class.primary_key => key_ids)
|
342
|
+
key_records = Hash[key_records.map { |r| [r.id, r] }]
|
343
|
+
end
|
297
344
|
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
345
|
+
Hash[calculated_data.map do |row|
|
346
|
+
key = group_columns.map { |aliaz, col_name|
|
347
|
+
type = type_for(col_name) do
|
348
|
+
calculated_data.column_types.fetch(aliaz, Type.default_value)
|
349
|
+
end
|
350
|
+
type_cast_calculated_value(row[aliaz], type)
|
351
|
+
}
|
352
|
+
key = key.first if key.size == 1
|
353
|
+
key = key_records[key] if associated
|
354
|
+
|
355
|
+
type = calculated_data.column_types.fetch(aggregate_alias) { type_for(column_name) }
|
356
|
+
[key, type_cast_calculated_value(row[aggregate_alias], type, operation)]
|
357
|
+
end]
|
302
358
|
end
|
303
359
|
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
360
|
+
# Converts the given keys to the value that the database adapter returns as
|
361
|
+
# a usable column name:
|
362
|
+
#
|
363
|
+
# column_alias_for("users.id") # => "users_id"
|
364
|
+
# column_alias_for("sum(id)") # => "sum_id"
|
365
|
+
# column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
|
366
|
+
# column_alias_for("count(*)") # => "count_all"
|
367
|
+
def column_alias_for(keys)
|
368
|
+
if keys.respond_to? :name
|
369
|
+
keys = "#{keys.relation.name}.#{keys.name}"
|
370
|
+
end
|
313
371
|
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
# column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
|
320
|
-
# column_alias_for("count(*)") # => "count_all"
|
321
|
-
# column_alias_for("count", "id") # => "count_id"
|
322
|
-
def column_alias_for(*keys)
|
323
|
-
keys.map! {|k| k.respond_to?(:to_sql) ? k.to_sql : k}
|
324
|
-
table_name = keys.join(' ')
|
325
|
-
table_name.downcase!
|
326
|
-
table_name.gsub!(/\*/, 'all')
|
327
|
-
table_name.gsub!(/\W+/, ' ')
|
328
|
-
table_name.strip!
|
329
|
-
table_name.gsub!(/ +/, '_')
|
330
|
-
|
331
|
-
@klass.connection.table_alias_for(table_name)
|
332
|
-
end
|
372
|
+
table_name = keys.to_s.downcase
|
373
|
+
table_name.gsub!(/\*/, "all")
|
374
|
+
table_name.gsub!(/\W+/, " ")
|
375
|
+
table_name.strip!
|
376
|
+
table_name.gsub!(/ +/, "_")
|
333
377
|
|
334
|
-
|
335
|
-
|
336
|
-
@klass.columns.detect { |c| c.name.to_s == field_name }
|
337
|
-
end
|
378
|
+
@klass.connection.table_alias_for(table_name)
|
379
|
+
end
|
338
380
|
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
when 'sum' then type_cast_using_column(value || '0', column)
|
343
|
-
when 'average' then value.respond_to?(:to_d) ? value.to_d : value
|
344
|
-
else type_cast_using_column(value, column)
|
381
|
+
def type_for(field, &block)
|
382
|
+
field_name = field.respond_to?(:name) ? field.name.to_s : field.to_s.split(".").last
|
383
|
+
@klass.type_for_attribute(field_name, &block)
|
345
384
|
end
|
346
|
-
end
|
347
385
|
|
348
|
-
|
349
|
-
|
350
|
-
|
386
|
+
def type_cast_calculated_value(value, type, operation = nil)
|
387
|
+
case operation
|
388
|
+
when "count" then value.to_i
|
389
|
+
when "sum" then type.deserialize(value || 0)
|
390
|
+
when "average" then value && value.respond_to?(:to_d) ? value.to_d : value
|
391
|
+
else type.deserialize(value)
|
392
|
+
end
|
393
|
+
end
|
351
394
|
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
395
|
+
def select_for_count
|
396
|
+
if select_values.present?
|
397
|
+
return select_values.first if select_values.one?
|
398
|
+
select_values.join(", ")
|
399
|
+
else
|
400
|
+
:all
|
401
|
+
end
|
356
402
|
end
|
357
|
-
end
|
358
403
|
|
359
|
-
|
360
|
-
|
361
|
-
|
404
|
+
def build_count_subquery(relation, column_name, distinct)
|
405
|
+
if column_name == :all
|
406
|
+
relation.select_values = [ Arel.sql(FinderMethods::ONE_AS_ONE) ] unless distinct
|
407
|
+
else
|
408
|
+
column_alias = Arel.sql("count_column")
|
409
|
+
relation.select_values = [ aggregate_column(column_name).as(column_alias) ]
|
410
|
+
end
|
362
411
|
|
363
|
-
|
364
|
-
|
365
|
-
subquery = relation.arel.as(subquery_alias)
|
412
|
+
subquery = relation.arel.as(Arel.sql("subquery_for_count"))
|
413
|
+
select_value = operation_over_aggregate_column(column_alias || Arel.star, "count", false)
|
366
414
|
|
367
|
-
|
368
|
-
|
369
|
-
sm.project(select_value).from(subquery)
|
370
|
-
end
|
415
|
+
Arel::SelectManager.new(subquery).project(select_value)
|
416
|
+
end
|
371
417
|
end
|
372
418
|
end
|