activerecord 6.0.0 → 7.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +996 -594
- data/MIT-LICENSE +1 -1
- data/README.rdoc +34 -34
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +22 -20
- data/lib/active_record/association_relation.rb +22 -12
- data/lib/active_record/associations/alias_tracker.rb +41 -30
- data/lib/active_record/associations/association.rb +106 -41
- data/lib/active_record/associations/association_scope.rb +30 -21
- data/lib/active_record/associations/belongs_to_association.rb +69 -14
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +20 -6
- data/lib/active_record/associations/builder/association.rb +39 -6
- data/lib/active_record/associations/builder/belongs_to.rb +47 -17
- data/lib/active_record/associations/builder/collection_association.rb +14 -6
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -10
- data/lib/active_record/associations/builder/has_many.rb +7 -3
- data/lib/active_record/associations/builder/has_one.rb +13 -16
- data/lib/active_record/associations/builder/singular_association.rb +7 -3
- data/lib/active_record/associations/collection_association.rb +90 -53
- data/lib/active_record/associations/collection_proxy.rb +54 -19
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/foreign_association.rb +21 -1
- data/lib/active_record/associations/has_many_association.rb +41 -10
- data/lib/active_record/associations/has_many_through_association.rb +29 -12
- data/lib/active_record/associations/has_one_association.rb +33 -9
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +41 -17
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/join_dependency.rb +97 -54
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +237 -54
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +153 -0
- data/lib/active_record/associations/preloader/through_association.rb +51 -17
- data/lib/active_record/associations/preloader.rb +55 -121
- data/lib/active_record/associations/singular_association.rb +16 -4
- data/lib/active_record/associations/through_association.rb +26 -15
- data/lib/active_record/associations.rb +454 -440
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +11 -14
- data/lib/active_record/attribute_methods/before_type_cast.rb +36 -11
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +75 -34
- data/lib/active_record/attribute_methods/primary_key.rb +53 -31
- data/lib/active_record/attribute_methods/query.rb +31 -22
- data/lib/active_record/attribute_methods/read.rb +16 -17
- data/lib/active_record/attribute_methods/serialization.rb +177 -35
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +18 -15
- data/lib/active_record/attribute_methods/write.rb +16 -28
- data/lib/active_record/attribute_methods.rb +227 -100
- data/lib/active_record/attributes.rb +94 -56
- data/lib/active_record/autosave_association.rb +119 -73
- data/lib/active_record/base.rb +31 -21
- data/lib/active_record/callbacks.rb +168 -55
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -25
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +79 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +367 -565
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -57
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +277 -89
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +241 -69
- data/lib/active_record/connection_adapters/abstract/quoting.rb +122 -134
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +324 -72
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +611 -211
- data/lib/active_record/connection_adapters/abstract/transaction.rb +425 -82
- data/lib/active_record/connection_adapters/abstract_adapter.rb +698 -211
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +464 -239
- data/lib/active_record/connection_adapters/column.rb +28 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +2 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +32 -137
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +90 -43
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +41 -7
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +18 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +13 -4
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +53 -15
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +127 -63
- data/lib/active_record/connection_adapters/pool_config.rb +83 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +57 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +54 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +127 -100
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +9 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +15 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -15
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -4
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +35 -8
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +23 -4
- data/lib/active_record/connection_adapters/postgresql/oid.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +139 -106
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +98 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +176 -4
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +462 -118
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -11
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +585 -295
- data/lib/active_record/connection_adapters/schema_cache.rb +399 -60
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +99 -48
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +80 -54
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +27 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +102 -24
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +425 -174
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -1
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
- data/lib/active_record/connection_adapters.rb +176 -0
- data/lib/active_record/connection_handling.rb +243 -115
- data/lib/active_record/core.rb +481 -199
- data/lib/active_record/counter_cache.rb +69 -32
- data/lib/active_record/database_configurations/connection_url_resolver.rb +107 -0
- data/lib/active_record/database_configurations/database_config.rb +77 -10
- data/lib/active_record/database_configurations/hash_config.rb +148 -26
- data/lib/active_record/database_configurations/url_config.rb +44 -45
- data/lib/active_record/database_configurations.rb +190 -114
- data/lib/active_record/delegated_type.rb +279 -0
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +38 -0
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +5 -6
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +68 -0
- data/lib/active_record/encryption/configurable.rb +60 -0
- data/lib/active_record/encryption/context.rb +42 -0
- data/lib/active_record/encryption/contexts.rb +76 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +230 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +175 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +171 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +53 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +96 -0
- data/lib/active_record/encryption/null_encryptor.rb +25 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
- data/lib/active_record/encryption/scheme.rb +100 -0
- data/lib/active_record/encryption.rb +58 -0
- data/lib/active_record/enum.rb +224 -73
- data/lib/active_record/errors.rb +254 -36
- data/lib/active_record/explain.rb +30 -17
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +2 -2
- data/lib/active_record/fixture_set/file.rb +22 -15
- data/lib/active_record/fixture_set/model_metadata.rb +15 -6
- data/lib/active_record/fixture_set/render_context.rb +3 -1
- data/lib/active_record/fixture_set/table_row.rb +88 -16
- data/lib/active_record/fixture_set/table_rows.rb +4 -5
- data/lib/active_record/fixtures.rb +229 -116
- data/lib/active_record/future_result.rb +178 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +121 -48
- data/lib/active_record/insert_all.rb +178 -29
- data/lib/active_record/integration.rb +16 -14
- data/lib/active_record/internal_metadata.rb +132 -21
- data/lib/active_record/legacy_yaml_adapter.rb +3 -36
- data/lib/active_record/locking/optimistic.rb +64 -33
- data/lib/active_record/locking/pessimistic.rb +21 -8
- data/lib/active_record/log_subscriber.rb +61 -30
- data/lib/active_record/marshalling.rb +59 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +19 -19
- data/lib/active_record/middleware/database_selector.rb +25 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +160 -55
- data/lib/active_record/migration/compatibility.rb +286 -43
- data/lib/active_record/migration/default_strategy.rb +22 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/join_table.rb +1 -2
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +421 -193
- data/lib/active_record/model_schema.rb +217 -125
- data/lib/active_record/nested_attributes.rb +62 -27
- data/lib/active_record/no_touching.rb +4 -4
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +322 -319
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +18 -15
- data/lib/active_record/query_logs.rb +193 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +54 -14
- data/lib/active_record/railtie.rb +250 -72
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/controller_runtime.rb +25 -11
- data/lib/active_record/railties/databases.rake +312 -197
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +45 -3
- data/lib/active_record/reflection.rb +389 -146
- data/lib/active_record/relation/batches/batch_enumerator.rb +61 -16
- data/lib/active_record/relation/batches.rb +214 -73
- data/lib/active_record/relation/calculations.rb +379 -124
- data/lib/active_record/relation/delegation.rb +36 -23
- data/lib/active_record/relation/finder_methods.rb +159 -49
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +41 -33
- data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -11
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -7
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +20 -13
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +79 -53
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +1156 -279
- data/lib/active_record/relation/record_fetch_warning.rb +12 -11
- data/lib/active_record/relation/spawn_methods.rb +10 -9
- data/lib/active_record/relation/where_clause.rb +100 -66
- data/lib/active_record/relation.rb +829 -194
- data/lib/active_record/result.rb +76 -56
- data/lib/active_record/runtime_registry.rb +71 -13
- data/lib/active_record/sanitization.rb +86 -47
- data/lib/active_record/schema.rb +39 -23
- data/lib/active_record/schema_dumper.rb +140 -33
- data/lib/active_record/schema_migration.rb +74 -29
- data/lib/active_record/scoping/default.rb +73 -19
- data/lib/active_record/scoping/named.rb +10 -28
- data/lib/active_record/scoping.rb +65 -35
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +34 -8
- data/lib/active_record/serialization.rb +11 -4
- data/lib/active_record/signed_id.rb +138 -0
- data/lib/active_record/statement_cache.rb +26 -10
- data/lib/active_record/store.rb +19 -14
- data/lib/active_record/suppressor.rb +15 -17
- data/lib/active_record/table_metadata.rb +46 -36
- data/lib/active_record/tasks/database_tasks.rb +371 -205
- data/lib/active_record/tasks/mysql_database_tasks.rb +43 -36
- data/lib/active_record/tasks/postgresql_database_tasks.rb +54 -41
- data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -13
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +189 -104
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +35 -25
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +31 -27
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +131 -99
- data/lib/active_record/translation.rb +3 -5
- data/lib/active_record/type/adapter_specific_registry.rb +33 -18
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -2
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +11 -6
- data/lib/active_record/type/time.rb +14 -0
- data/lib/active_record/type/type_map.rb +17 -21
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +7 -2
- data/lib/active_record/type_caster/connection.rb +4 -5
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +13 -8
- data/lib/active_record/validations/numericality.rb +36 -0
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +88 -18
- data/lib/active_record/validations.rb +15 -8
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +446 -40
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/attributes/attribute.rb +4 -8
- data/lib/arel/collectors/bind.rb +8 -1
- data/lib/arel/collectors/composite.rb +15 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/crud.rb +30 -22
- data/lib/arel/delete_manager.rb +23 -4
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/binary.rb +82 -9
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/casted.rb +22 -10
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +14 -13
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +68 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
- data/lib/arel/nodes/node.rb +122 -11
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/table_alias.rb +11 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes/update_statement.rb +11 -4
- data/lib/arel/nodes.rb +10 -3
- data/lib/arel/predications.rb +31 -28
- data/lib/arel/select_manager.rb +18 -9
- data/lib/arel/table.rb +21 -10
- data/lib/arel/tree_manager.rb +8 -15
- data/lib/arel/update_manager.rb +25 -5
- data/lib/arel/visitors/dot.rb +94 -90
- data/lib/arel/visitors/mysql.rb +34 -6
- data/lib/arel/visitors/postgresql.rb +5 -16
- data/lib/arel/visitors/sqlite.rb +25 -1
- data/lib/arel/visitors/to_sql.rb +227 -81
- data/lib/arel/visitors/visitor.rb +2 -3
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +37 -15
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +6 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
- data/lib/rails/generators/active_record/migration.rb +9 -3
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +49 -4
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +117 -30
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/null_relation.rb +0 -68
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -204
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -157
- data/lib/arel/visitors/oracle.rb +0 -159
- data/lib/arel/visitors/oracle12.rb +0 -66
- data/lib/arel/visitors/where_sql.rb +0 -23
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "active_support/core_ext/enumerable"
|
|
4
|
+
|
|
3
5
|
module ActiveRecord
|
|
4
6
|
module TestFixtures
|
|
5
7
|
extend ActiveSupport::Concern
|
|
@@ -11,18 +13,31 @@ module ActiveRecord
|
|
|
11
13
|
|
|
12
14
|
def after_teardown # :nodoc:
|
|
13
15
|
super
|
|
16
|
+
ensure
|
|
14
17
|
teardown_fixtures
|
|
15
18
|
end
|
|
16
19
|
|
|
17
20
|
included do
|
|
18
|
-
|
|
21
|
+
##
|
|
22
|
+
# :singleton-method: fixture_paths
|
|
23
|
+
#
|
|
24
|
+
# Returns the ActiveRecord::FixtureSet collection
|
|
25
|
+
|
|
26
|
+
##
|
|
27
|
+
# :singleton-method: fixture_paths=
|
|
28
|
+
#
|
|
29
|
+
# :call-seq:
|
|
30
|
+
# fixture_paths=(fixture_paths)
|
|
31
|
+
class_attribute :fixture_paths, instance_writer: false, default: []
|
|
19
32
|
class_attribute :fixture_table_names, default: []
|
|
20
33
|
class_attribute :fixture_class_names, default: {}
|
|
21
34
|
class_attribute :use_transactional_tests, default: true
|
|
22
35
|
class_attribute :use_instantiated_fixtures, default: false # true, false, or :no_instances
|
|
23
36
|
class_attribute :pre_loaded_fixtures, default: false
|
|
24
|
-
class_attribute :config, default: ActiveRecord::Base
|
|
25
37
|
class_attribute :lock_threads, default: true
|
|
38
|
+
class_attribute :fixture_sets, default: {}
|
|
39
|
+
|
|
40
|
+
ActiveSupport.run_load_hooks(:active_record_fixtures, self)
|
|
26
41
|
end
|
|
27
42
|
|
|
28
43
|
module ClassMethods
|
|
@@ -40,50 +55,36 @@ module ActiveRecord
|
|
|
40
55
|
|
|
41
56
|
def fixtures(*fixture_set_names)
|
|
42
57
|
if fixture_set_names.first == :all
|
|
43
|
-
raise StandardError, "No fixture path found. Please set `#{self}.
|
|
44
|
-
fixture_set_names =
|
|
45
|
-
|
|
58
|
+
raise StandardError, "No fixture path found. Please set `#{self}.fixture_paths`." if fixture_paths.blank?
|
|
59
|
+
fixture_set_names = fixture_paths.flat_map do |path|
|
|
60
|
+
names = Dir[::File.join(path, "{**,*}/*.{yml}")].uniq
|
|
61
|
+
names.reject! { |f| f.start_with?(file_fixture_path.to_s) } if defined?(file_fixture_path) && file_fixture_path
|
|
62
|
+
names.map! { |f| f[path.to_s.size..-5].delete_prefix("/") }
|
|
63
|
+
end.uniq
|
|
46
64
|
else
|
|
47
65
|
fixture_set_names = fixture_set_names.flatten.map(&:to_s)
|
|
48
66
|
end
|
|
49
67
|
|
|
50
|
-
self.fixture_table_names
|
|
68
|
+
self.fixture_table_names = (fixture_table_names | fixture_set_names).sort
|
|
51
69
|
setup_fixture_accessors(fixture_set_names)
|
|
52
70
|
end
|
|
53
71
|
|
|
54
72
|
def setup_fixture_accessors(fixture_set_names = nil)
|
|
55
73
|
fixture_set_names = Array(fixture_set_names || fixture_table_names)
|
|
56
|
-
|
|
74
|
+
unless fixture_set_names.empty?
|
|
75
|
+
self.fixture_sets = fixture_sets.dup
|
|
57
76
|
fixture_set_names.each do |fs_name|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
|
|
63
|
-
return_single_record = fixture_names.size == 1
|
|
64
|
-
fixture_names = @loaded_fixtures[fs_name].fixtures.keys if fixture_names.empty?
|
|
65
|
-
|
|
66
|
-
@fixture_cache[fs_name] ||= {}
|
|
67
|
-
|
|
68
|
-
instances = fixture_names.map do |f_name|
|
|
69
|
-
f_name = f_name.to_s if f_name.is_a?(Symbol)
|
|
70
|
-
@fixture_cache[fs_name].delete(f_name) if force_reload
|
|
71
|
-
|
|
72
|
-
if @loaded_fixtures[fs_name][f_name]
|
|
73
|
-
@fixture_cache[fs_name][f_name] ||= @loaded_fixtures[fs_name][f_name].find
|
|
74
|
-
else
|
|
75
|
-
raise StandardError, "No fixture named '#{f_name}' found for fixture set '#{fs_name}'"
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
return_single_record ? instances.first : instances
|
|
80
|
-
end
|
|
81
|
-
private accessor_name
|
|
77
|
+
key = fs_name.to_s.include?("/") ? -fs_name.to_s.tr("/", "_") : fs_name
|
|
78
|
+
key = -key.to_s if key.is_a?(Symbol)
|
|
79
|
+
fs_name = -fs_name.to_s if fs_name.is_a?(Symbol)
|
|
80
|
+
fixture_sets[key] = fs_name
|
|
82
81
|
end
|
|
83
82
|
end
|
|
84
|
-
include methods
|
|
85
83
|
end
|
|
86
84
|
|
|
85
|
+
# Prevents automatically wrapping each specified test in a transaction,
|
|
86
|
+
# to allow application logic transactions to be tested in a top-level
|
|
87
|
+
# (non-nested) context.
|
|
87
88
|
def uses_transaction(*methods)
|
|
88
89
|
@uses_transaction = [] unless defined?(@uses_transaction)
|
|
89
90
|
@uses_transaction.concat methods.map(&:to_s)
|
|
@@ -95,91 +96,109 @@ module ActiveRecord
|
|
|
95
96
|
end
|
|
96
97
|
end
|
|
97
98
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
# Generic fixture accessor for fixture names that may conflict with other methods.
|
|
100
|
+
#
|
|
101
|
+
# assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
|
|
102
|
+
# assert_equal "Ruby on Rails", fixture(:web_sites, :rubyonrails).name
|
|
103
|
+
def fixture(fixture_set_name, *fixture_names)
|
|
104
|
+
active_record_fixture(fixture_set_name, *fixture_names)
|
|
101
105
|
end
|
|
102
106
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
107
|
+
private
|
|
108
|
+
def run_in_transaction?
|
|
109
|
+
use_transactional_tests &&
|
|
110
|
+
!self.class.uses_transaction?(name)
|
|
106
111
|
end
|
|
107
112
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
113
|
+
def setup_fixtures(config = ActiveRecord::Base)
|
|
114
|
+
if pre_loaded_fixtures && !use_transactional_tests
|
|
115
|
+
raise RuntimeError, "pre_loaded_fixtures requires use_transactional_tests"
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
@fixture_cache = {}
|
|
119
|
+
@fixture_cache_key = [self.class.fixture_table_names.dup, self.class.fixture_paths.dup, self.class.fixture_class_names.dup]
|
|
120
|
+
@fixture_connection_pools = []
|
|
121
|
+
@@already_loaded_fixtures ||= {}
|
|
122
|
+
@connection_subscriber = nil
|
|
123
|
+
@saved_pool_configs = Hash.new { |hash, key| hash[key] = {} }
|
|
124
|
+
|
|
125
|
+
if run_in_transaction?
|
|
126
|
+
# Load fixtures once and begin transaction.
|
|
127
|
+
@loaded_fixtures = @@already_loaded_fixtures[@fixture_cache_key]
|
|
128
|
+
unless @loaded_fixtures
|
|
129
|
+
@@already_loaded_fixtures.clear
|
|
130
|
+
@loaded_fixtures = @@already_loaded_fixtures[@fixture_cache_key] = load_fixtures(config)
|
|
131
|
+
end
|
|
112
132
|
|
|
113
|
-
|
|
114
|
-
if run_in_transaction?
|
|
115
|
-
if @@already_loaded_fixtures[self.class]
|
|
116
|
-
@loaded_fixtures = @@already_loaded_fixtures[self.class]
|
|
133
|
+
setup_transactional_fixtures
|
|
117
134
|
else
|
|
135
|
+
# Load fixtures for every test.
|
|
136
|
+
ActiveRecord::FixtureSet.reset_cache
|
|
137
|
+
invalidate_already_loaded_fixtures
|
|
118
138
|
@loaded_fixtures = load_fixtures(config)
|
|
119
|
-
@@already_loaded_fixtures[self.class] = @loaded_fixtures
|
|
120
139
|
end
|
|
121
140
|
|
|
141
|
+
# Instantiate fixtures for every test if requested.
|
|
142
|
+
instantiate_fixtures if use_instantiated_fixtures
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def teardown_fixtures
|
|
146
|
+
# Rollback changes if a transaction is active.
|
|
147
|
+
if run_in_transaction?
|
|
148
|
+
teardown_transactional_fixtures
|
|
149
|
+
else
|
|
150
|
+
ActiveRecord::FixtureSet.reset_cache
|
|
151
|
+
invalidate_already_loaded_fixtures
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def invalidate_already_loaded_fixtures
|
|
158
|
+
@@already_loaded_fixtures.clear
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def setup_transactional_fixtures
|
|
162
|
+
setup_shared_connection_pool
|
|
163
|
+
|
|
122
164
|
# Begin transactions for connections already established
|
|
123
|
-
@
|
|
124
|
-
@
|
|
125
|
-
|
|
126
|
-
|
|
165
|
+
@fixture_connection_pools = ActiveRecord::Base.connection_handler.connection_pool_list(:writing)
|
|
166
|
+
@fixture_connection_pools.each do |pool|
|
|
167
|
+
pool.pin_connection!(lock_threads)
|
|
168
|
+
pool.lease_connection
|
|
127
169
|
end
|
|
128
170
|
|
|
129
171
|
# When connections are established in the future, begin a transaction too
|
|
130
172
|
@connection_subscriber = ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
173
|
+
connection_name = payload[:connection_name] if payload.key?(:connection_name)
|
|
174
|
+
shard = payload[:shard] if payload.key?(:shard)
|
|
175
|
+
|
|
176
|
+
if connection_name
|
|
177
|
+
pool = ActiveRecord::Base.connection_handler.retrieve_connection_pool(connection_name, shard: shard)
|
|
178
|
+
if pool
|
|
179
|
+
setup_shared_connection_pool
|
|
180
|
+
|
|
181
|
+
unless @fixture_connection_pools.include?(pool)
|
|
182
|
+
pool.pin_connection!(lock_threads)
|
|
183
|
+
pool.lease_connection
|
|
184
|
+
@fixture_connection_pools << pool
|
|
185
|
+
end
|
|
144
186
|
end
|
|
145
187
|
end
|
|
146
188
|
end
|
|
147
|
-
|
|
148
|
-
# Load fixtures for every test.
|
|
149
|
-
else
|
|
150
|
-
ActiveRecord::FixtureSet.reset_cache
|
|
151
|
-
@@already_loaded_fixtures[self.class] = nil
|
|
152
|
-
@loaded_fixtures = load_fixtures(config)
|
|
153
189
|
end
|
|
154
190
|
|
|
155
|
-
|
|
156
|
-
instantiate_fixtures if use_instantiated_fixtures
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
def teardown_fixtures
|
|
160
|
-
# Rollback changes if a transaction is active.
|
|
161
|
-
if run_in_transaction?
|
|
191
|
+
def teardown_transactional_fixtures
|
|
162
192
|
ActiveSupport::Notifications.unsubscribe(@connection_subscriber) if @connection_subscriber
|
|
163
|
-
@
|
|
164
|
-
|
|
165
|
-
|
|
193
|
+
unless @fixture_connection_pools.map(&:unpin_connection!).all?
|
|
194
|
+
# Something caused the transaction to be committed or rolled back
|
|
195
|
+
# We can no longer trust the database is in a clean state.
|
|
196
|
+
@@already_loaded_fixtures.clear
|
|
166
197
|
end
|
|
167
|
-
@
|
|
168
|
-
|
|
169
|
-
ActiveRecord::FixtureSet.reset_cache
|
|
198
|
+
@fixture_connection_pools.clear
|
|
199
|
+
teardown_shared_connection_pool
|
|
170
200
|
end
|
|
171
201
|
|
|
172
|
-
ActiveRecord::Base.clear_active_connections!
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
def enlist_fixture_connections
|
|
176
|
-
setup_shared_connection_pool
|
|
177
|
-
|
|
178
|
-
ActiveRecord::Base.connection_handler.connection_pool_list.map(&:connection)
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
private
|
|
182
|
-
|
|
183
202
|
# Shares the writing connection pool with connections on
|
|
184
203
|
# other handlers.
|
|
185
204
|
#
|
|
@@ -187,22 +206,43 @@ module ActiveRecord
|
|
|
187
206
|
# need to share a connection pool so that the reading connection
|
|
188
207
|
# can see data in the open transaction on the writing connection.
|
|
189
208
|
def setup_shared_connection_pool
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
209
|
+
handler = ActiveRecord::Base.connection_handler
|
|
210
|
+
|
|
211
|
+
handler.connection_pool_names.each do |name|
|
|
212
|
+
pool_manager = handler.send(:connection_name_to_pool_manager)[name]
|
|
213
|
+
pool_manager.shard_names.each do |shard_name|
|
|
214
|
+
writing_pool_config = pool_manager.get_pool_config(ActiveRecord.writing_role, shard_name)
|
|
215
|
+
@saved_pool_configs[name][shard_name] ||= {}
|
|
216
|
+
pool_manager.role_names.each do |role|
|
|
217
|
+
next unless pool_config = pool_manager.get_pool_config(role, shard_name)
|
|
218
|
+
next if pool_config == writing_pool_config
|
|
219
|
+
|
|
220
|
+
@saved_pool_configs[name][shard_name][role] = pool_config
|
|
221
|
+
pool_manager.set_pool_config(role, shard_name, writing_pool_config)
|
|
198
222
|
end
|
|
199
223
|
end
|
|
200
224
|
end
|
|
201
225
|
end
|
|
202
226
|
|
|
227
|
+
def teardown_shared_connection_pool
|
|
228
|
+
handler = ActiveRecord::Base.connection_handler
|
|
229
|
+
|
|
230
|
+
@saved_pool_configs.each_pair do |name, shards|
|
|
231
|
+
pool_manager = handler.send(:connection_name_to_pool_manager)[name]
|
|
232
|
+
shards.each_pair do |shard_name, roles|
|
|
233
|
+
roles.each_pair do |role, pool_config|
|
|
234
|
+
next unless pool_manager.get_pool_config(role, shard_name)
|
|
235
|
+
|
|
236
|
+
pool_manager.set_pool_config(role, shard_name, pool_config)
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
@saved_pool_configs.clear
|
|
242
|
+
end
|
|
243
|
+
|
|
203
244
|
def load_fixtures(config)
|
|
204
|
-
|
|
205
|
-
Hash[fixtures.map { |f| [f.name, f] }]
|
|
245
|
+
ActiveRecord::FixtureSet.create_fixtures(fixture_paths, fixture_table_names, fixture_class_names, config).index_by(&:name)
|
|
206
246
|
end
|
|
207
247
|
|
|
208
248
|
def instantiate_fixtures
|
|
@@ -220,5 +260,50 @@ module ActiveRecord
|
|
|
220
260
|
def load_instances?
|
|
221
261
|
use_instantiated_fixtures != :no_instances
|
|
222
262
|
end
|
|
263
|
+
|
|
264
|
+
def method_missing(method, ...)
|
|
265
|
+
if fixture_sets.key?(method.name)
|
|
266
|
+
active_record_fixture(method, ...)
|
|
267
|
+
else
|
|
268
|
+
super
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def respond_to_missing?(method, include_private = false)
|
|
273
|
+
if include_private && fixture_sets.key?(method.name)
|
|
274
|
+
true
|
|
275
|
+
else
|
|
276
|
+
super
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def active_record_fixture(fixture_set_name, *fixture_names)
|
|
281
|
+
if fs_name = fixture_sets[fixture_set_name.name]
|
|
282
|
+
access_fixture(fs_name, *fixture_names)
|
|
283
|
+
else
|
|
284
|
+
raise StandardError, "No fixture set named '#{fixture_set_name.inspect}'"
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def access_fixture(fs_name, *fixture_names)
|
|
289
|
+
force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
|
|
290
|
+
return_single_record = fixture_names.size == 1
|
|
291
|
+
|
|
292
|
+
fixture_names = @loaded_fixtures[fs_name].fixtures.keys if fixture_names.empty?
|
|
293
|
+
@fixture_cache[fs_name] ||= {}
|
|
294
|
+
|
|
295
|
+
instances = fixture_names.map do |f_name|
|
|
296
|
+
f_name = f_name.to_s if f_name.is_a?(Symbol)
|
|
297
|
+
@fixture_cache[fs_name].delete(f_name) if force_reload
|
|
298
|
+
|
|
299
|
+
if @loaded_fixtures[fs_name][f_name]
|
|
300
|
+
@fixture_cache[fs_name][f_name] ||= @loaded_fixtures[fs_name][f_name].find
|
|
301
|
+
else
|
|
302
|
+
raise StandardError, "No fixture named '#{f_name}' found for fixture set '#{fs_name}'"
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
return_single_record ? instances.first : instances
|
|
307
|
+
end
|
|
223
308
|
end
|
|
224
309
|
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module Assertions
|
|
5
|
+
module QueryAssertions
|
|
6
|
+
# Asserts that the number of SQL queries executed in the given block matches the expected count.
|
|
7
|
+
#
|
|
8
|
+
# # Check for exact number of queries
|
|
9
|
+
# assert_queries_count(1) { Post.first }
|
|
10
|
+
#
|
|
11
|
+
# # Check for any number of queries
|
|
12
|
+
# assert_queries_count { Post.first }
|
|
13
|
+
#
|
|
14
|
+
# If the +:include_schema+ option is provided, any queries (including schema related) are counted.
|
|
15
|
+
#
|
|
16
|
+
# assert_queries_count(1, include_schema: true) { Post.columns }
|
|
17
|
+
#
|
|
18
|
+
def assert_queries_count(count = nil, include_schema: false, &block)
|
|
19
|
+
ActiveRecord::Base.lease_connection.materialize_transactions
|
|
20
|
+
|
|
21
|
+
counter = SQLCounter.new
|
|
22
|
+
ActiveSupport::Notifications.subscribed(counter, "sql.active_record") do
|
|
23
|
+
result = _assert_nothing_raised_or_warn("assert_queries_count", &block)
|
|
24
|
+
queries = include_schema ? counter.log_all : counter.log
|
|
25
|
+
if count
|
|
26
|
+
assert_equal count, queries.size, "#{queries.size} instead of #{count} queries were executed. Queries: #{queries.join("\n\n")}"
|
|
27
|
+
else
|
|
28
|
+
assert_operator queries.size, :>=, 1, "1 or more queries expected, but none were executed.#{queries.empty? ? '' : "\nQueries:\n#{queries.join("\n")}"}"
|
|
29
|
+
end
|
|
30
|
+
result
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Asserts that no SQL queries are executed in the given block.
|
|
35
|
+
#
|
|
36
|
+
# assert_no_queries { post.comments }
|
|
37
|
+
#
|
|
38
|
+
# If the +:include_schema+ option is provided, any queries (including schema related) are counted.
|
|
39
|
+
#
|
|
40
|
+
# assert_no_queries(include_schema: true) { Post.columns }
|
|
41
|
+
#
|
|
42
|
+
def assert_no_queries(include_schema: false, &block)
|
|
43
|
+
assert_queries_count(0, include_schema: include_schema, &block)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Asserts that the SQL queries executed in the given block match expected pattern.
|
|
47
|
+
#
|
|
48
|
+
# # Check for exact number of queries
|
|
49
|
+
# assert_queries_match(/LIMIT \?/, count: 1) { Post.first }
|
|
50
|
+
#
|
|
51
|
+
# # Check for any number of queries
|
|
52
|
+
# assert_queries_match(/LIMIT \?/) { Post.first }
|
|
53
|
+
#
|
|
54
|
+
# If the +:include_schema+ option is provided, any queries (including schema related)
|
|
55
|
+
# that match the matcher are considered.
|
|
56
|
+
#
|
|
57
|
+
# assert_queries_match(/FROM pg_attribute/i, include_schema: true) { Post.columns }
|
|
58
|
+
#
|
|
59
|
+
def assert_queries_match(match, count: nil, include_schema: false, &block)
|
|
60
|
+
ActiveRecord::Base.lease_connection.materialize_transactions
|
|
61
|
+
|
|
62
|
+
counter = SQLCounter.new
|
|
63
|
+
ActiveSupport::Notifications.subscribed(counter, "sql.active_record") do
|
|
64
|
+
result = _assert_nothing_raised_or_warn("assert_queries_match", &block)
|
|
65
|
+
queries = include_schema ? counter.log_all : counter.log
|
|
66
|
+
matched_queries = queries.select { |query| match === query }
|
|
67
|
+
|
|
68
|
+
if count
|
|
69
|
+
assert_equal count, matched_queries.size, "#{matched_queries.size} instead of #{count} queries were executed.#{queries.empty? ? '' : "\nQueries:\n#{queries.join("\n")}"}"
|
|
70
|
+
else
|
|
71
|
+
assert_operator matched_queries.size, :>=, 1, "1 or more queries expected, but none were executed.#{queries.empty? ? '' : "\nQueries:\n#{queries.join("\n")}"}"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
result
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Asserts that no SQL queries matching the pattern are executed in the given block.
|
|
79
|
+
#
|
|
80
|
+
# assert_no_queries_match(/SELECT/i) { post.comments }
|
|
81
|
+
#
|
|
82
|
+
# If the +:include_schema+ option is provided, any queries (including schema related)
|
|
83
|
+
# that match the matcher are counted.
|
|
84
|
+
#
|
|
85
|
+
# assert_no_queries_match(/FROM pg_attribute/i, include_schema: true) { Post.columns }
|
|
86
|
+
#
|
|
87
|
+
def assert_no_queries_match(match, include_schema: false, &block)
|
|
88
|
+
assert_queries_match(match, count: 0, include_schema: include_schema, &block)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
class SQLCounter # :nodoc:
|
|
92
|
+
attr_reader :log_full, :log_all
|
|
93
|
+
|
|
94
|
+
def initialize
|
|
95
|
+
@log_full = []
|
|
96
|
+
@log_all = []
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def log
|
|
100
|
+
@log_full.map(&:first)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def call(*, payload)
|
|
104
|
+
return if payload[:cached]
|
|
105
|
+
|
|
106
|
+
sql = payload[:sql]
|
|
107
|
+
@log_all << sql
|
|
108
|
+
|
|
109
|
+
unless payload[:name] == "SCHEMA"
|
|
110
|
+
bound_values = (payload[:binds] || []).map do |value|
|
|
111
|
+
value = value.value_for_database if value.respond_to?(:value_for_database)
|
|
112
|
+
value
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
@log_full << [sql, bound_values]
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -30,7 +30,7 @@ module ActiveRecord
|
|
|
30
30
|
#
|
|
31
31
|
# ActiveRecord::Base.time_zone_aware_types = [:datetime]
|
|
32
32
|
#
|
|
33
|
-
# You can also add database
|
|
33
|
+
# You can also add database-specific timezone aware types. For example, for PostgreSQL:
|
|
34
34
|
#
|
|
35
35
|
# ActiveRecord::Base.time_zone_aware_types += [:tsrange, :tstzrange]
|
|
36
36
|
#
|
|
@@ -54,8 +54,10 @@ module ActiveRecord
|
|
|
54
54
|
|
|
55
55
|
module ClassMethods # :nodoc:
|
|
56
56
|
def touch_attributes_with_time(*names, time: nil)
|
|
57
|
+
names = names.map(&:to_s)
|
|
58
|
+
names = names.map { |name| attribute_aliases[name] || name }
|
|
57
59
|
attribute_names = timestamp_attributes_for_update_in_model
|
|
58
|
-
attribute_names |= names
|
|
60
|
+
attribute_names |= names
|
|
59
61
|
attribute_names.index_with(time || current_time_from_proper_timezone)
|
|
60
62
|
end
|
|
61
63
|
|
|
@@ -75,36 +77,39 @@ module ActiveRecord
|
|
|
75
77
|
end
|
|
76
78
|
|
|
77
79
|
def current_time_from_proper_timezone
|
|
78
|
-
default_timezone == :utc ? Time.now.utc : Time.now
|
|
80
|
+
with_connection { |c| c.default_timezone == :utc ? Time.now.utc : Time.now }
|
|
79
81
|
end
|
|
80
82
|
|
|
83
|
+
protected
|
|
84
|
+
def reload_schema_from_cache(recursive = true)
|
|
85
|
+
@timestamp_attributes_for_create_in_model = nil
|
|
86
|
+
@timestamp_attributes_for_update_in_model = nil
|
|
87
|
+
@all_timestamp_attributes_in_model = nil
|
|
88
|
+
super
|
|
89
|
+
end
|
|
90
|
+
|
|
81
91
|
private
|
|
82
92
|
def timestamp_attributes_for_create
|
|
83
|
-
["created_at", "created_on"]
|
|
93
|
+
["created_at", "created_on"].map! { |name| attribute_aliases[name] || name }
|
|
84
94
|
end
|
|
85
95
|
|
|
86
96
|
def timestamp_attributes_for_update
|
|
87
|
-
["updated_at", "updated_on"]
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def reload_schema_from_cache
|
|
91
|
-
@timestamp_attributes_for_create_in_model = nil
|
|
92
|
-
@timestamp_attributes_for_update_in_model = nil
|
|
93
|
-
@all_timestamp_attributes_in_model = nil
|
|
94
|
-
super
|
|
97
|
+
["updated_at", "updated_on"].map! { |name| attribute_aliases[name] || name }
|
|
95
98
|
end
|
|
96
99
|
end
|
|
97
100
|
|
|
98
101
|
private
|
|
102
|
+
def init_internals
|
|
103
|
+
super
|
|
104
|
+
@_touch_record = nil
|
|
105
|
+
end
|
|
99
106
|
|
|
100
107
|
def _create_record
|
|
101
108
|
if record_timestamps
|
|
102
109
|
current_time = current_time_from_proper_timezone
|
|
103
110
|
|
|
104
111
|
all_timestamp_attributes_in_model.each do |column|
|
|
105
|
-
|
|
106
|
-
_write_attribute(column, current_time)
|
|
107
|
-
end
|
|
112
|
+
_write_attribute(column, current_time) unless _read_attribute(column)
|
|
108
113
|
end
|
|
109
114
|
end
|
|
110
115
|
|
|
@@ -112,6 +117,17 @@ module ActiveRecord
|
|
|
112
117
|
end
|
|
113
118
|
|
|
114
119
|
def _update_record
|
|
120
|
+
record_update_timestamps
|
|
121
|
+
|
|
122
|
+
super
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def create_or_update(touch: true, **)
|
|
126
|
+
@_touch_record = touch
|
|
127
|
+
super
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def record_update_timestamps
|
|
115
131
|
if @_touch_record && should_record_timestamps?
|
|
116
132
|
current_time = current_time_from_proper_timezone
|
|
117
133
|
|
|
@@ -121,16 +137,11 @@ module ActiveRecord
|
|
|
121
137
|
end
|
|
122
138
|
end
|
|
123
139
|
|
|
124
|
-
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
def create_or_update(touch: true, **)
|
|
128
|
-
@_touch_record = touch
|
|
129
|
-
super
|
|
140
|
+
yield if block_given?
|
|
130
141
|
end
|
|
131
142
|
|
|
132
143
|
def should_record_timestamps?
|
|
133
|
-
record_timestamps && (!
|
|
144
|
+
record_timestamps && (!partial_updates? || has_changes_to_save?)
|
|
134
145
|
end
|
|
135
146
|
|
|
136
147
|
def timestamp_attributes_for_create_in_model
|
|
@@ -151,8 +162,7 @@ module ActiveRecord
|
|
|
151
162
|
|
|
152
163
|
def max_updated_column_timestamp
|
|
153
164
|
timestamp_attributes_for_update_in_model
|
|
154
|
-
.
|
|
155
|
-
.compact
|
|
165
|
+
.filter_map { |attr| (v = self[attr]) && (v.is_a?(::Time) ? v : v.to_time) }
|
|
156
166
|
.max
|
|
157
167
|
end
|
|
158
168
|
|
|
@@ -160,7 +170,7 @@ module ActiveRecord
|
|
|
160
170
|
def clear_timestamp_attributes
|
|
161
171
|
all_timestamp_attributes_in_model.each do |attribute_name|
|
|
162
172
|
self[attribute_name] = nil
|
|
163
|
-
|
|
173
|
+
clear_attribute_change(attribute_name)
|
|
164
174
|
end
|
|
165
175
|
end
|
|
166
176
|
end
|