activerecord 4.2.11.1 → 6.0.3.5
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 +721 -1522
- data/MIT-LICENSE +4 -2
- data/README.rdoc +14 -13
- data/examples/performance.rb +33 -32
- data/examples/simple.rb +5 -4
- data/lib/active_record/advisory_lock_base.rb +18 -0
- data/lib/active_record/aggregations.rb +266 -251
- data/lib/active_record/association_relation.rb +20 -13
- data/lib/active_record/associations/alias_tracker.rb +29 -36
- data/lib/active_record/associations/association.rb +128 -57
- data/lib/active_record/associations/association_scope.rb +103 -132
- data/lib/active_record/associations/belongs_to_association.rb +65 -60
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
- data/lib/active_record/associations/builder/association.rb +27 -40
- data/lib/active_record/associations/builder/belongs_to.rb +69 -55
- data/lib/active_record/associations/builder/collection_association.rb +10 -33
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +50 -66
- data/lib/active_record/associations/builder/has_many.rb +8 -4
- data/lib/active_record/associations/builder/has_one.rb +46 -5
- data/lib/active_record/associations/builder/singular_association.rb +16 -10
- data/lib/active_record/associations/collection_association.rb +136 -288
- data/lib/active_record/associations/collection_proxy.rb +241 -147
- data/lib/active_record/associations/foreign_association.rb +10 -1
- data/lib/active_record/associations/has_many_association.rb +34 -98
- data/lib/active_record/associations/has_many_through_association.rb +60 -87
- data/lib/active_record/associations/has_one_association.rb +61 -49
- data/lib/active_record/associations/has_one_through_association.rb +20 -11
- data/lib/active_record/associations/join_dependency/join_association.rb +38 -86
- data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
- data/lib/active_record/associations/join_dependency.rb +149 -166
- data/lib/active_record/associations/preloader/association.rb +90 -123
- data/lib/active_record/associations/preloader/through_association.rb +85 -65
- data/lib/active_record/associations/preloader.rb +90 -93
- data/lib/active_record/associations/singular_association.rb +18 -39
- data/lib/active_record/associations/through_association.rb +38 -18
- data/lib/active_record/associations.rb +1737 -1597
- data/lib/active_record/attribute_assignment.rb +57 -185
- data/lib/active_record/attribute_decorators.rb +39 -17
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
- data/lib/active_record/attribute_methods/dirty.rb +174 -144
- data/lib/active_record/attribute_methods/primary_key.rb +90 -84
- data/lib/active_record/attribute_methods/query.rb +6 -5
- data/lib/active_record/attribute_methods/read.rb +20 -77
- data/lib/active_record/attribute_methods/serialization.rb +40 -21
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +57 -37
- data/lib/active_record/attribute_methods/write.rb +32 -55
- data/lib/active_record/attribute_methods.rb +120 -135
- data/lib/active_record/attributes.rb +213 -82
- data/lib/active_record/autosave_association.rb +97 -41
- data/lib/active_record/base.rb +57 -45
- data/lib/active_record/callbacks.rb +101 -76
- data/lib/active_record/coders/json.rb +3 -1
- data/lib/active_record/coders/yaml_column.rb +23 -12
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +804 -297
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +26 -8
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +240 -115
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +83 -24
- data/lib/active_record/connection_adapters/abstract/quoting.rb +170 -53
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +74 -47
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +371 -242
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +694 -256
- data/lib/active_record/connection_adapters/abstract/transaction.rb +190 -83
- data/lib/active_record/connection_adapters/abstract_adapter.rb +473 -202
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +507 -639
- data/lib/active_record/connection_adapters/column.rb +56 -43
- data/lib/active_record/connection_adapters/connection_specification.rb +174 -153
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +29 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +196 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +71 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +95 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +88 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +58 -181
- data/lib/active_record/connection_adapters/postgresql/column.rb +21 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +70 -114
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +49 -58
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -22
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -20
- 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 +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
- data/lib/active_record/connection_adapters/postgresql/oid/{infinity.rb → oid.rb} +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +32 -11
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +51 -34
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -5
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +9 -5
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +144 -47
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +462 -296
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +11 -8
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +558 -356
- data/lib/active_record/connection_adapters/schema_cache.rb +72 -25
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +37 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +119 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +102 -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 +137 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +299 -349
- data/lib/active_record/connection_adapters/statement_pool.rb +33 -13
- data/lib/active_record/connection_handling.rb +167 -41
- data/lib/active_record/core.rb +252 -230
- data/lib/active_record/counter_cache.rb +70 -49
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +78 -0
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +87 -106
- data/lib/active_record/enum.rb +163 -86
- data/lib/active_record/errors.rb +188 -53
- data/lib/active_record/explain.rb +22 -11
- data/lib/active_record/explain_registry.rb +4 -2
- data/lib/active_record/explain_subscriber.rb +10 -5
- data/lib/active_record/fixture_set/file.rb +35 -9
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +152 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +227 -501
- data/lib/active_record/gem_version.rb +6 -4
- data/lib/active_record/inheritance.rb +158 -115
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +123 -29
- data/lib/active_record/internal_metadata.rb +53 -0
- data/lib/active_record/legacy_yaml_adapter.rb +21 -3
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +86 -96
- data/lib/active_record/locking/pessimistic.rb +18 -6
- data/lib/active_record/log_subscriber.rb +76 -33
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
- data/lib/active_record/middleware/database_selector.rb +74 -0
- data/lib/active_record/migration/command_recorder.rb +166 -91
- data/lib/active_record/migration/compatibility.rb +244 -0
- data/lib/active_record/migration/join_table.rb +8 -7
- data/lib/active_record/migration.rb +623 -305
- data/lib/active_record/model_schema.rb +313 -112
- data/lib/active_record/nested_attributes.rb +263 -223
- data/lib/active_record/no_touching.rb +15 -2
- data/lib/active_record/null_relation.rb +24 -38
- data/lib/active_record/persistence.rb +557 -126
- data/lib/active_record/query_cache.rb +19 -23
- data/lib/active_record/querying.rb +44 -30
- data/lib/active_record/railtie.rb +143 -44
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +34 -33
- data/lib/active_record/railties/databases.rake +331 -185
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +430 -281
- data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
- data/lib/active_record/relation/batches.rb +206 -55
- data/lib/active_record/relation/calculations.rb +268 -254
- data/lib/active_record/relation/delegation.rb +75 -84
- data/lib/active_record/relation/finder_methods.rb +285 -241
- data/lib/active_record/relation/from_clause.rb +30 -0
- data/lib/active_record/relation/merger.rb +78 -88
- data/lib/active_record/relation/predicate_builder/array_handler.rb +27 -26
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +18 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
- data/lib/active_record/relation/predicate_builder.rb +110 -119
- data/lib/active_record/relation/query_attribute.rb +50 -0
- data/lib/active_record/relation/query_methods.rb +603 -397
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +11 -14
- data/lib/active_record/relation/where_clause.rb +189 -0
- data/lib/active_record/relation/where_clause_factory.rb +33 -0
- data/lib/active_record/relation.rb +530 -341
- data/lib/active_record/result.rb +79 -43
- data/lib/active_record/runtime_registry.rb +6 -4
- data/lib/active_record/sanitization.rb +144 -121
- data/lib/active_record/schema.rb +21 -24
- data/lib/active_record/schema_dumper.rb +112 -93
- data/lib/active_record/schema_migration.rb +24 -17
- data/lib/active_record/scoping/default.rb +98 -83
- data/lib/active_record/scoping/named.rb +86 -33
- data/lib/active_record/scoping.rb +45 -27
- data/lib/active_record/secure_token.rb +40 -0
- data/lib/active_record/serialization.rb +5 -5
- data/lib/active_record/statement_cache.rb +73 -36
- data/lib/active_record/store.rb +127 -42
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +90 -0
- data/lib/active_record/tasks/database_tasks.rb +307 -100
- data/lib/active_record/tasks/mysql_database_tasks.rb +55 -100
- data/lib/active_record/tasks/postgresql_database_tasks.rb +80 -41
- data/lib/active_record/tasks/sqlite_database_tasks.rb +37 -16
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +225 -0
- data/lib/active_record/timestamp.rb +86 -41
- data/lib/active_record/touch_later.rb +65 -0
- data/lib/active_record/transactions.rb +223 -157
- data/lib/active_record/translation.rb +3 -1
- data/lib/active_record/type/adapter_specific_registry.rb +126 -0
- data/lib/active_record/type/date.rb +4 -45
- data/lib/active_record/type/date_time.rb +4 -49
- data/lib/active_record/type/decimal_without_scale.rb +6 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
- 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 +23 -15
- data/lib/active_record/type/text.rb +2 -2
- data/lib/active_record/type/time.rb +11 -16
- data/lib/active_record/type/type_map.rb +16 -19
- data/lib/active_record/type/unsigned_integer.rb +9 -8
- data/lib/active_record/type.rb +77 -23
- data/lib/active_record/type_caster/connection.rb +34 -0
- data/lib/active_record/type_caster/map.rb +20 -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 +12 -4
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/presence.rb +14 -13
- data/lib/active_record/validations/uniqueness.rb +42 -55
- data/lib/active_record/validations.rb +38 -35
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +42 -22
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/nodes.rb +68 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +256 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/depth_first.rb +203 -0
- data/lib/arel/visitors/dot.rb +296 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +156 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +158 -0
- data/lib/arel/visitors/oracle12.rb +65 -0
- data/lib/arel/visitors/postgresql.rb +109 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +888 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors/where_sql.rb +22 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +62 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -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 +42 -37
- 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 → migration.rb.tt} +11 -2
- data/lib/rails/generators/active_record/migration.rb +30 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +18 -22
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +168 -59
- 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_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- 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.rb +0 -163
- data/lib/active_record/attribute_set/builder.rb +0 -106
- data/lib/active_record/attribute_set.rb +0 -81
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- 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 -31
- data/lib/active_record/type/decimal.rb +0 -64
- 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 -59
- 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 -40
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/value.rb +0 -110
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -19
- data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module Calculations
|
3
5
|
# Count the records.
|
@@ -14,127 +16,134 @@ module ActiveRecord
|
|
14
16
|
# Person.distinct.count(:age)
|
15
17
|
# # => counts the number of different age values
|
16
18
|
#
|
17
|
-
# If
|
19
|
+
# If #count is used with {Relation#group}[rdoc-ref:QueryMethods#group],
|
20
|
+
# it returns a Hash whose keys represent the aggregated column,
|
18
21
|
# and the values are the respective amounts:
|
19
22
|
#
|
20
23
|
# Person.group(:city).count
|
21
24
|
# # => { 'Rome' => 5, 'Paris' => 3 }
|
22
25
|
#
|
23
|
-
# If
|
26
|
+
# If #count is used with {Relation#group}[rdoc-ref:QueryMethods#group] for multiple columns, it returns a Hash whose
|
24
27
|
# keys are an array containing the individual values of each column and the value
|
25
|
-
# of each key would be the
|
28
|
+
# of each key would be the #count.
|
26
29
|
#
|
27
30
|
# Article.group(:status, :category).count
|
28
31
|
# # => {["draft", "business"]=>10, ["draft", "technology"]=>4,
|
29
32
|
# ["published", "business"]=>0, ["published", "technology"]=>2}
|
30
33
|
#
|
31
|
-
# If
|
34
|
+
# If #count is used with {Relation#select}[rdoc-ref:QueryMethods#select], it will count the selected columns:
|
32
35
|
#
|
33
36
|
# Person.select(:age).count
|
34
37
|
# # => counts the number of different age values
|
35
38
|
#
|
36
|
-
# Note: not all valid
|
39
|
+
# Note: not all valid {Relation#select}[rdoc-ref:QueryMethods#select] expressions are valid #count expressions. The specifics differ
|
37
40
|
# between databases. In invalid cases, an error from the database is thrown.
|
38
|
-
def count(column_name = nil
|
39
|
-
if
|
40
|
-
|
41
|
-
|
42
|
-
|
41
|
+
def count(column_name = nil)
|
42
|
+
if block_given?
|
43
|
+
unless column_name.nil?
|
44
|
+
raise ArgumentError, "Column name argument is not supported when a block is passed."
|
45
|
+
end
|
43
46
|
|
47
|
+
super()
|
48
|
+
else
|
49
|
+
calculate(:count, column_name)
|
44
50
|
end
|
45
|
-
|
46
|
-
# TODO: Remove options argument as soon we remove support to
|
47
|
-
# activerecord-deprecated_finders.
|
48
|
-
calculate(:count, column_name, options)
|
49
51
|
end
|
50
52
|
|
51
53
|
# Calculates the average value on a given column. Returns +nil+ if there's
|
52
|
-
# no row. See
|
54
|
+
# no row. See #calculate for examples with options.
|
53
55
|
#
|
54
56
|
# Person.average(:age) # => 35.8
|
55
|
-
def average(column_name
|
56
|
-
|
57
|
-
# activerecord-deprecated_finders.
|
58
|
-
calculate(:average, column_name, options)
|
57
|
+
def average(column_name)
|
58
|
+
calculate(:average, column_name)
|
59
59
|
end
|
60
60
|
|
61
61
|
# Calculates the minimum value on a given column. The value is returned
|
62
62
|
# with the same data type of the column, or +nil+ if there's no row. See
|
63
|
-
#
|
63
|
+
# #calculate for examples with options.
|
64
64
|
#
|
65
65
|
# Person.minimum(:age) # => 7
|
66
|
-
def minimum(column_name
|
67
|
-
|
68
|
-
# activerecord-deprecated_finders.
|
69
|
-
calculate(:minimum, column_name, options)
|
66
|
+
def minimum(column_name)
|
67
|
+
calculate(:minimum, column_name)
|
70
68
|
end
|
71
69
|
|
72
70
|
# Calculates the maximum value on a given column. The value is returned
|
73
71
|
# with the same data type of the column, or +nil+ if there's no row. See
|
74
|
-
#
|
72
|
+
# #calculate for examples with options.
|
75
73
|
#
|
76
74
|
# Person.maximum(:age) # => 93
|
77
|
-
def maximum(column_name
|
78
|
-
|
79
|
-
# activerecord-deprecated_finders.
|
80
|
-
calculate(:maximum, column_name, options)
|
75
|
+
def maximum(column_name)
|
76
|
+
calculate(:maximum, column_name)
|
81
77
|
end
|
82
78
|
|
83
79
|
# Calculates the sum of values on a given column. The value is returned
|
84
|
-
# with the same data type of the column, 0 if there's no row. See
|
85
|
-
#
|
80
|
+
# with the same data type of the column, +0+ if there's no row. See
|
81
|
+
# #calculate for examples with options.
|
86
82
|
#
|
87
83
|
# Person.sum(:age) # => 4562
|
88
|
-
def sum(
|
89
|
-
|
84
|
+
def sum(column_name = nil)
|
85
|
+
if block_given?
|
86
|
+
unless column_name.nil?
|
87
|
+
raise ArgumentError, "Column name argument is not supported when a block is passed."
|
88
|
+
end
|
89
|
+
|
90
|
+
super()
|
91
|
+
else
|
92
|
+
calculate(:sum, column_name)
|
93
|
+
end
|
90
94
|
end
|
91
95
|
|
92
|
-
# This calculates aggregate values in the given column. Methods for count, sum, average,
|
93
|
-
# minimum, and maximum have been added as shortcuts.
|
96
|
+
# This calculates aggregate values in the given column. Methods for #count, #sum, #average,
|
97
|
+
# #minimum, and #maximum have been added as shortcuts.
|
94
98
|
#
|
95
|
-
#
|
99
|
+
# Person.calculate(:count, :all) # The same as Person.count
|
100
|
+
# Person.average(:age) # SELECT AVG(age) FROM people...
|
96
101
|
#
|
97
|
-
#
|
98
|
-
#
|
102
|
+
# # Selects the minimum age for any family without any minors
|
103
|
+
# Person.group(:last_name).having("min(age) > 17").minimum(:age)
|
99
104
|
#
|
100
|
-
# *
|
101
|
-
# takes either a column name, or the name of a belongs_to association.
|
105
|
+
# Person.sum("2 * age")
|
102
106
|
#
|
103
|
-
#
|
104
|
-
# puts values["Drake"]
|
105
|
-
# # => 43
|
107
|
+
# There are two basic forms of output:
|
106
108
|
#
|
107
|
-
#
|
108
|
-
#
|
109
|
-
# puts values[drake]
|
110
|
-
# # => 43
|
109
|
+
# * Single aggregate value: The single value is type cast to Integer for COUNT, Float
|
110
|
+
# for AVG, and the given column's type for everything else.
|
111
111
|
#
|
112
|
-
#
|
113
|
-
#
|
114
|
-
# end
|
112
|
+
# * Grouped values: This returns an ordered hash of the values and groups them. It
|
113
|
+
# takes either a column name, or the name of a belongs_to association.
|
115
114
|
#
|
116
|
-
#
|
117
|
-
#
|
115
|
+
# values = Person.group('last_name').maximum(:age)
|
116
|
+
# puts values["Drake"]
|
117
|
+
# # => 43
|
118
118
|
#
|
119
|
-
#
|
120
|
-
#
|
119
|
+
# drake = Family.find_by(last_name: 'Drake')
|
120
|
+
# values = Person.group(:family).maximum(:age) # Person belongs_to :family
|
121
|
+
# puts values[drake]
|
122
|
+
# # => 43
|
121
123
|
#
|
122
|
-
#
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
if column_name.is_a?(Symbol) && attribute_alias?(column_name)
|
127
|
-
column_name = attribute_alias(column_name)
|
128
|
-
end
|
129
|
-
|
124
|
+
# values.each do |family, max_age|
|
125
|
+
# ...
|
126
|
+
# end
|
127
|
+
def calculate(operation, column_name)
|
130
128
|
if has_include?(column_name)
|
131
|
-
|
129
|
+
relation = apply_join_dependency
|
130
|
+
|
131
|
+
if operation.to_s.downcase == "count"
|
132
|
+
unless distinct_value || distinct_select?(column_name || select_for_count)
|
133
|
+
relation.distinct!
|
134
|
+
relation.select_values = [ klass.primary_key || table[Arel.star] ]
|
135
|
+
end
|
136
|
+
# PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
|
137
|
+
relation.order_values = []
|
138
|
+
end
|
139
|
+
|
140
|
+
relation.calculate(operation, column_name)
|
132
141
|
else
|
133
|
-
perform_calculation(operation, column_name
|
142
|
+
perform_calculation(operation, column_name)
|
134
143
|
end
|
135
144
|
end
|
136
145
|
|
137
|
-
# Use
|
146
|
+
# Use #pluck as a shortcut to select one or more attributes without
|
138
147
|
# loading a bunch of records just to grab the attributes you want.
|
139
148
|
#
|
140
149
|
# Person.pluck(:name)
|
@@ -143,19 +152,19 @@ module ActiveRecord
|
|
143
152
|
#
|
144
153
|
# Person.all.map(&:name)
|
145
154
|
#
|
146
|
-
# Pluck returns an
|
155
|
+
# Pluck returns an Array of attribute values type-casted to match
|
147
156
|
# the plucked column names, if they can be deduced. Plucking an SQL fragment
|
148
157
|
# returns String values by default.
|
149
158
|
#
|
150
|
-
# Person.pluck(:
|
151
|
-
# # SELECT people.
|
152
|
-
# # => [
|
159
|
+
# Person.pluck(:name)
|
160
|
+
# # SELECT people.name FROM people
|
161
|
+
# # => ['David', 'Jeremy', 'Jose']
|
153
162
|
#
|
154
163
|
# Person.pluck(:id, :name)
|
155
164
|
# # SELECT people.id, people.name FROM people
|
156
165
|
# # => [[1, 'David'], [2, 'Jeremy'], [3, 'Jose']]
|
157
166
|
#
|
158
|
-
# Person.pluck(
|
167
|
+
# Person.distinct.pluck(:role)
|
159
168
|
# # SELECT DISTINCT role FROM people
|
160
169
|
# # => ['admin', 'member', 'guest']
|
161
170
|
#
|
@@ -163,31 +172,47 @@ module ActiveRecord
|
|
163
172
|
# # SELECT people.id FROM people WHERE people.age = 21 LIMIT 5
|
164
173
|
# # => [2, 3]
|
165
174
|
#
|
166
|
-
# Person.pluck('DATEDIFF(updated_at, created_at)')
|
175
|
+
# Person.pluck(Arel.sql('DATEDIFF(updated_at, created_at)'))
|
167
176
|
# # SELECT DATEDIFF(updated_at, created_at) FROM people
|
168
177
|
# # => ['0', '27761', '173']
|
169
178
|
#
|
179
|
+
# See also #ids.
|
180
|
+
#
|
170
181
|
def pluck(*column_names)
|
171
|
-
column_names.map
|
172
|
-
|
173
|
-
attribute_alias(column_name)
|
174
|
-
else
|
175
|
-
column_name.to_s
|
176
|
-
end
|
182
|
+
if loaded? && (column_names.map(&:to_s) - @klass.attribute_names - @klass.attribute_aliases.keys).empty?
|
183
|
+
return records.pluck(*column_names)
|
177
184
|
end
|
178
185
|
|
179
186
|
if has_include?(column_names.first)
|
180
|
-
|
187
|
+
relation = apply_join_dependency
|
188
|
+
relation.pluck(*column_names)
|
181
189
|
else
|
190
|
+
klass.disallow_raw_sql!(column_names)
|
182
191
|
relation = spawn
|
183
|
-
relation.select_values = column_names
|
184
|
-
|
185
|
-
|
186
|
-
result = klass.connection.select_all(relation.arel, nil, relation.arel.bind_values + bind_values)
|
187
|
-
result.cast_values(klass.column_types)
|
192
|
+
relation.select_values = column_names
|
193
|
+
result = skip_query_cache_if_necessary { klass.connection.select_all(relation.arel, nil) }
|
194
|
+
result.cast_values(klass.attribute_types)
|
188
195
|
end
|
189
196
|
end
|
190
197
|
|
198
|
+
# Pick the value(s) from the named column(s) in the current relation.
|
199
|
+
# This is short-hand for <tt>relation.limit(1).pluck(*column_names).first</tt>, and is primarily useful
|
200
|
+
# when you have a relation that's already narrowed down to a single row.
|
201
|
+
#
|
202
|
+
# Just like #pluck, #pick will only load the actual value, not the entire record object, so it's also
|
203
|
+
# more efficient. The value is, again like with pluck, typecast by the column type.
|
204
|
+
#
|
205
|
+
# Person.where(id: 1).pick(:name)
|
206
|
+
# # SELECT people.name FROM people WHERE id = 1 LIMIT 1
|
207
|
+
# # => 'David'
|
208
|
+
#
|
209
|
+
# Person.where(id: 1).pick(:name, :email_address)
|
210
|
+
# # SELECT people.name, people.email_address FROM people WHERE id = 1 LIMIT 1
|
211
|
+
# # => [ 'David', 'david@loudthinking.com' ]
|
212
|
+
def pick(*column_names)
|
213
|
+
limit(1).pluck(*column_names).first
|
214
|
+
end
|
215
|
+
|
191
216
|
# Pluck all the ID's for the relation using the table's primary key
|
192
217
|
#
|
193
218
|
# Person.ids # SELECT people.id FROM people
|
@@ -197,214 +222,203 @@ module ActiveRecord
|
|
197
222
|
end
|
198
223
|
|
199
224
|
private
|
225
|
+
def has_include?(column_name)
|
226
|
+
eager_loading? || (includes_values.present? && column_name && column_name != :all)
|
227
|
+
end
|
200
228
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
229
|
+
def perform_calculation(operation, column_name)
|
230
|
+
operation = operation.to_s.downcase
|
231
|
+
|
232
|
+
# If #count is used with #distinct (i.e. `relation.distinct.count`) it is
|
233
|
+
# considered distinct.
|
234
|
+
distinct = distinct_value
|
235
|
+
|
236
|
+
if operation == "count"
|
237
|
+
column_name ||= select_for_count
|
238
|
+
if column_name == :all
|
239
|
+
if !distinct
|
240
|
+
distinct = distinct_select?(select_for_count) if group_values.empty?
|
241
|
+
elsif group_values.any? || select_values.empty? && order_values.empty?
|
242
|
+
column_name = primary_key
|
243
|
+
end
|
244
|
+
elsif distinct_select?(column_name)
|
245
|
+
distinct = nil
|
246
|
+
end
|
218
247
|
end
|
219
248
|
|
220
|
-
|
221
|
-
|
249
|
+
if group_values.any?
|
250
|
+
execute_grouped_calculation(operation, column_name, distinct)
|
251
|
+
else
|
252
|
+
execute_simple_calculation(operation, column_name, distinct)
|
253
|
+
end
|
222
254
|
end
|
223
255
|
|
224
|
-
|
225
|
-
|
226
|
-
else
|
227
|
-
execute_simple_calculation(operation, column_name, distinct)
|
256
|
+
def distinct_select?(column_name)
|
257
|
+
column_name.is_a?(::String) && /\bDISTINCT[\s(]/i.match?(column_name)
|
228
258
|
end
|
229
|
-
end
|
230
259
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
260
|
+
def aggregate_column(column_name)
|
261
|
+
return column_name if Arel::Expressions === column_name
|
262
|
+
|
263
|
+
arel_column(column_name.to_s) do |name|
|
264
|
+
Arel.sql(column_name == :all ? "*" : name)
|
265
|
+
end
|
236
266
|
end
|
237
|
-
end
|
238
267
|
|
239
|
-
|
240
|
-
|
241
|
-
|
268
|
+
def operation_over_aggregate_column(column, operation, distinct)
|
269
|
+
operation == "count" ? column.count(distinct) : column.send(operation)
|
270
|
+
end
|
242
271
|
|
243
|
-
|
244
|
-
|
245
|
-
relation = unscope(:order)
|
272
|
+
def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
|
273
|
+
column_alias = column_name
|
246
274
|
|
247
|
-
|
275
|
+
if operation == "count" && (column_name == :all && distinct || has_limit_or_offset?)
|
276
|
+
# Shortcut when limit is zero.
|
277
|
+
return 0 if limit_value == 0
|
248
278
|
|
249
|
-
|
279
|
+
query_builder = build_count_subquery(spawn, column_name, distinct)
|
280
|
+
else
|
281
|
+
# PostgreSQL doesn't like ORDER BY when there are no GROUP BY
|
282
|
+
relation = unscope(:order).distinct!(false)
|
250
283
|
|
251
|
-
|
252
|
-
# Shortcut when limit is zero.
|
253
|
-
return 0 if relation.limit_value == 0
|
284
|
+
column = aggregate_column(column_name)
|
254
285
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
286
|
+
select_value = operation_over_aggregate_column(column, operation, distinct)
|
287
|
+
if operation == "sum" && distinct
|
288
|
+
select_value.distinct = true
|
289
|
+
end
|
259
290
|
|
260
|
-
|
291
|
+
column_alias = select_value.alias
|
292
|
+
column_alias ||= @klass.connection.column_name_for_operation(operation, select_value)
|
293
|
+
relation.select_values = [select_value]
|
261
294
|
|
262
|
-
|
263
|
-
|
264
|
-
relation.select_values = [select_value]
|
295
|
+
query_builder = relation.arel
|
296
|
+
end
|
265
297
|
|
266
|
-
|
267
|
-
|
268
|
-
|
298
|
+
result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder, nil) }
|
299
|
+
row = result.first
|
300
|
+
value = row && row.values.first
|
301
|
+
type = result.column_types.fetch(column_alias) do
|
302
|
+
type_for(column_name)
|
303
|
+
end
|
269
304
|
|
270
|
-
|
271
|
-
row = result.first
|
272
|
-
value = row && row.values.first
|
273
|
-
column = result.column_types.fetch(column_alias) do
|
274
|
-
type_for(column_name)
|
305
|
+
type_cast_calculated_value(value, type, operation)
|
275
306
|
end
|
276
307
|
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
|
281
|
-
group_attrs = group_values
|
308
|
+
def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
|
309
|
+
group_fields = group_values
|
282
310
|
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
group_fields =
|
289
|
-
end
|
290
|
-
group_fields = arel_columns(group_fields)
|
311
|
+
if group_fields.size == 1 && group_fields.first.respond_to?(:to_sym)
|
312
|
+
association = klass._reflect_on_association(group_fields.first)
|
313
|
+
associated = association && association.belongs_to? # only count belongs_to associations
|
314
|
+
group_fields = Array(association.foreign_key) if associated
|
315
|
+
end
|
316
|
+
group_fields = arel_columns(group_fields)
|
291
317
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
318
|
+
group_aliases = group_fields.map { |field|
|
319
|
+
field = connection.visitor.compile(field) if Arel.arel_node?(field)
|
320
|
+
column_alias_for(field.to_s.downcase)
|
321
|
+
}
|
322
|
+
group_columns = group_aliases.zip(group_fields)
|
323
|
+
|
324
|
+
aggregate_alias = column_alias_for("#{operation} #{column_name.to_s.downcase}")
|
325
|
+
|
326
|
+
select_values = [
|
327
|
+
operation_over_aggregate_column(
|
328
|
+
aggregate_column(column_name),
|
329
|
+
operation,
|
330
|
+
distinct).as(aggregate_alias)
|
331
|
+
]
|
332
|
+
select_values += self.select_values unless having_clause.empty?
|
333
|
+
|
334
|
+
select_values.concat group_columns.map { |aliaz, field|
|
335
|
+
if field.respond_to?(:as)
|
336
|
+
field.as(aliaz)
|
337
|
+
else
|
338
|
+
"#{field} AS #{aliaz}"
|
339
|
+
end
|
340
|
+
}
|
298
341
|
|
299
|
-
|
342
|
+
relation = except(:group).distinct!(false)
|
343
|
+
relation.group_values = group_fields
|
344
|
+
relation.select_values = select_values
|
300
345
|
|
301
|
-
|
302
|
-
aggregate_alias = 'count_all'
|
303
|
-
else
|
304
|
-
aggregate_alias = column_alias_for([operation, column_name].join(' '))
|
305
|
-
end
|
346
|
+
calculated_data = skip_query_cache_if_necessary { @klass.connection.select_all(relation.arel, nil) }
|
306
347
|
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
distinct).as(aggregate_alias)
|
312
|
-
]
|
313
|
-
select_values += self.select_values unless having_values.empty?
|
314
|
-
|
315
|
-
select_values.concat group_fields.zip(group_aliases).map { |field,aliaz|
|
316
|
-
if field.respond_to?(:as)
|
317
|
-
field.as(aliaz)
|
318
|
-
else
|
319
|
-
"#{field} AS #{aliaz}"
|
348
|
+
if association
|
349
|
+
key_ids = calculated_data.collect { |row| row[group_aliases.first] }
|
350
|
+
key_records = association.klass.base_class.where(association.klass.base_class.primary_key => key_ids)
|
351
|
+
key_records = Hash[key_records.map { |r| [r.id, r] }]
|
320
352
|
end
|
321
|
-
}
|
322
|
-
|
323
|
-
relation = except(:group)
|
324
|
-
relation.group_values = group
|
325
|
-
relation.select_values = select_values
|
326
|
-
|
327
|
-
calculated_data = @klass.connection.select_all(relation, nil, relation.arel.bind_values + bind_values)
|
328
353
|
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
354
|
+
Hash[calculated_data.map do |row|
|
355
|
+
key = group_columns.map { |aliaz, col_name|
|
356
|
+
type = type_for(col_name) do
|
357
|
+
calculated_data.column_types.fetch(aliaz, Type.default_value)
|
358
|
+
end
|
359
|
+
type_cast_calculated_value(row[aliaz], type)
|
360
|
+
}
|
361
|
+
key = key.first if key.size == 1
|
362
|
+
key = key_records[key] if associated
|
363
|
+
|
364
|
+
type = calculated_data.column_types.fetch(aggregate_alias) { type_for(column_name) }
|
365
|
+
[key, type_cast_calculated_value(row[aggregate_alias], type, operation)]
|
366
|
+
end]
|
333
367
|
end
|
334
368
|
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
# Converts the given keys to the value that the database adapter returns as
|
351
|
-
# a usable column name:
|
352
|
-
#
|
353
|
-
# column_alias_for("users.id") # => "users_id"
|
354
|
-
# column_alias_for("sum(id)") # => "sum_id"
|
355
|
-
# column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
|
356
|
-
# column_alias_for("count(*)") # => "count_all"
|
357
|
-
# column_alias_for("count", "id") # => "count_id"
|
358
|
-
def column_alias_for(keys)
|
359
|
-
if keys.respond_to? :name
|
360
|
-
keys = "#{keys.relation.name}.#{keys.name}"
|
369
|
+
# Converts the given field to the value that the database adapter returns as
|
370
|
+
# a usable column name:
|
371
|
+
#
|
372
|
+
# column_alias_for("users.id") # => "users_id"
|
373
|
+
# column_alias_for("sum(id)") # => "sum_id"
|
374
|
+
# column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
|
375
|
+
# column_alias_for("count(*)") # => "count_all"
|
376
|
+
def column_alias_for(field)
|
377
|
+
column_alias = +field
|
378
|
+
column_alias.gsub!(/\*/, "all")
|
379
|
+
column_alias.gsub!(/\W+/, " ")
|
380
|
+
column_alias.strip!
|
381
|
+
column_alias.gsub!(/ +/, "_")
|
382
|
+
|
383
|
+
connection.table_alias_for(column_alias)
|
361
384
|
end
|
362
385
|
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
table_name.gsub!(/ +/, '_')
|
368
|
-
|
369
|
-
@klass.connection.table_alias_for(table_name)
|
370
|
-
end
|
371
|
-
|
372
|
-
def type_for(field)
|
373
|
-
field_name = field.respond_to?(:name) ? field.name.to_s : field.to_s.split('.').last
|
374
|
-
@klass.type_for_attribute(field_name)
|
375
|
-
end
|
386
|
+
def type_for(field, &block)
|
387
|
+
field_name = field.respond_to?(:name) ? field.name.to_s : field.to_s.split(".").last
|
388
|
+
@klass.type_for_attribute(field_name, &block)
|
389
|
+
end
|
376
390
|
|
377
|
-
|
378
|
-
|
379
|
-
when
|
380
|
-
when
|
381
|
-
when
|
382
|
-
else type.
|
391
|
+
def type_cast_calculated_value(value, type, operation = nil)
|
392
|
+
case operation
|
393
|
+
when "count" then value.to_i
|
394
|
+
when "sum" then type.deserialize(value || 0)
|
395
|
+
when "average" then value&.respond_to?(:to_d) ? value.to_d : value
|
396
|
+
else type.deserialize(value)
|
397
|
+
end
|
383
398
|
end
|
384
|
-
end
|
385
399
|
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
400
|
+
def select_for_count
|
401
|
+
if select_values.present?
|
402
|
+
return select_values.first if select_values.one?
|
403
|
+
select_values.join(", ")
|
404
|
+
else
|
405
|
+
:all
|
406
|
+
end
|
392
407
|
end
|
393
|
-
end
|
394
408
|
|
395
|
-
|
396
|
-
|
397
|
-
|
409
|
+
def build_count_subquery(relation, column_name, distinct)
|
410
|
+
if column_name == :all
|
411
|
+
column_alias = Arel.star
|
412
|
+
relation.select_values = [ Arel.sql(FinderMethods::ONE_AS_ONE) ] unless distinct
|
413
|
+
else
|
414
|
+
column_alias = Arel.sql("count_column")
|
415
|
+
relation.select_values = [ aggregate_column(column_name).as(column_alias) ]
|
416
|
+
end
|
398
417
|
|
399
|
-
|
400
|
-
|
401
|
-
arel = relation.arel
|
402
|
-
subquery = arel.as(subquery_alias)
|
418
|
+
subquery_alias = Arel.sql("subquery_for_count")
|
419
|
+
select_value = operation_over_aggregate_column(column_alias, "count", false)
|
403
420
|
|
404
|
-
|
405
|
-
|
406
|
-
select_value = operation_over_aggregate_column(column_alias, 'count', distinct)
|
407
|
-
sm.project(select_value).from(subquery)
|
408
|
-
end
|
421
|
+
relation.build_subquery(subquery_alias, select_value)
|
422
|
+
end
|
409
423
|
end
|
410
424
|
end
|