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,41 +1,67 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "active_support/core_ext/enumerable"
|
|
4
|
+
|
|
3
5
|
module ActiveRecord
|
|
4
6
|
class InsertAll # :nodoc:
|
|
5
7
|
attr_reader :model, :connection, :inserts, :keys
|
|
6
|
-
attr_reader :on_duplicate, :returning, :unique_by
|
|
8
|
+
attr_reader :on_duplicate, :update_only, :returning, :unique_by, :update_sql
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
class << self
|
|
11
|
+
def execute(relation, ...)
|
|
12
|
+
relation.model.with_connection do |c|
|
|
13
|
+
new(relation, c, ...).execute
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
10
17
|
|
|
11
|
-
|
|
12
|
-
@
|
|
18
|
+
def initialize(relation, connection, inserts, on_duplicate:, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil)
|
|
19
|
+
@relation = relation
|
|
20
|
+
@model, @connection, @inserts = relation.model, connection, inserts.map(&:stringify_keys)
|
|
21
|
+
@on_duplicate, @update_only, @returning, @unique_by = on_duplicate, update_only, returning, unique_by
|
|
22
|
+
@record_timestamps = record_timestamps.nil? ? model.record_timestamps : record_timestamps
|
|
23
|
+
|
|
24
|
+
disallow_raw_sql!(on_duplicate)
|
|
25
|
+
disallow_raw_sql!(returning)
|
|
26
|
+
|
|
27
|
+
if @inserts.empty?
|
|
28
|
+
@keys = []
|
|
29
|
+
else
|
|
30
|
+
resolve_sti
|
|
31
|
+
resolve_attribute_aliases
|
|
32
|
+
@keys = @inserts.first.keys
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
@scope_attributes = relation.scope_for_create.except(@model.inheritance_column)
|
|
36
|
+
@keys |= @scope_attributes.keys
|
|
37
|
+
@keys = @keys.to_set
|
|
13
38
|
|
|
14
39
|
@returning = (connection.supports_insert_returning? ? primary_keys : false) if @returning.nil?
|
|
15
40
|
@returning = false if @returning == []
|
|
16
41
|
|
|
17
|
-
@unique_by = find_unique_index_for(unique_by)
|
|
18
|
-
@on_duplicate = :skip if @on_duplicate == :update && updatable_columns.empty?
|
|
42
|
+
@unique_by = find_unique_index_for(@unique_by)
|
|
19
43
|
|
|
44
|
+
configure_on_duplicate_update_logic
|
|
20
45
|
ensure_valid_options_for_connection!
|
|
21
46
|
end
|
|
22
47
|
|
|
23
48
|
def execute
|
|
49
|
+
return ActiveRecord::Result.empty if inserts.empty?
|
|
50
|
+
|
|
24
51
|
message = +"#{model} "
|
|
25
52
|
message << "Bulk " if inserts.many?
|
|
26
53
|
message << (on_duplicate == :update ? "Upsert" : "Insert")
|
|
27
|
-
connection.
|
|
54
|
+
connection.exec_insert_all to_sql, message
|
|
28
55
|
end
|
|
29
56
|
|
|
30
57
|
def updatable_columns
|
|
31
|
-
keys - readonly_columns - unique_by_columns
|
|
58
|
+
@updatable_columns ||= keys - readonly_columns - unique_by_columns
|
|
32
59
|
end
|
|
33
60
|
|
|
34
61
|
def primary_keys
|
|
35
|
-
Array(model.
|
|
62
|
+
Array(@model.schema_cache.primary_keys(model.table_name))
|
|
36
63
|
end
|
|
37
64
|
|
|
38
|
-
|
|
39
65
|
def skip_duplicates?
|
|
40
66
|
on_duplicate == :skip
|
|
41
67
|
end
|
|
@@ -47,30 +73,103 @@ module ActiveRecord
|
|
|
47
73
|
def map_key_with_value
|
|
48
74
|
inserts.map do |attributes|
|
|
49
75
|
attributes = attributes.stringify_keys
|
|
76
|
+
attributes.merge!(@scope_attributes)
|
|
77
|
+
attributes.reverse_merge!(timestamps_for_create) if record_timestamps?
|
|
78
|
+
|
|
50
79
|
verify_attributes(attributes)
|
|
51
80
|
|
|
52
|
-
|
|
81
|
+
keys_including_timestamps.map do |key|
|
|
53
82
|
yield key, attributes[key]
|
|
54
83
|
end
|
|
55
84
|
end
|
|
56
85
|
end
|
|
57
86
|
|
|
87
|
+
def record_timestamps?
|
|
88
|
+
@record_timestamps
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# TODO: Consider renaming this method, as it only conditionally extends keys, not always
|
|
92
|
+
def keys_including_timestamps
|
|
93
|
+
@keys_including_timestamps ||= if record_timestamps?
|
|
94
|
+
keys + model.all_timestamp_attributes_in_model
|
|
95
|
+
else
|
|
96
|
+
keys
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
58
100
|
private
|
|
101
|
+
def has_attribute_aliases?(attributes)
|
|
102
|
+
attributes.keys.any? { |attribute| model.attribute_alias?(attribute) }
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def resolve_sti
|
|
106
|
+
return if model.descends_from_active_record?
|
|
107
|
+
|
|
108
|
+
sti_type = model.sti_name
|
|
109
|
+
@inserts = @inserts.map do |insert|
|
|
110
|
+
insert.reverse_merge(model.inheritance_column.to_s => sti_type)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def resolve_attribute_aliases
|
|
115
|
+
return unless has_attribute_aliases?(@inserts.first)
|
|
116
|
+
|
|
117
|
+
@inserts = @inserts.map do |insert|
|
|
118
|
+
insert.transform_keys { |attribute| resolve_attribute_alias(attribute) }
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
@update_only = Array(@update_only).map { |attribute| resolve_attribute_alias(attribute) } if @update_only
|
|
122
|
+
@unique_by = Array(@unique_by).map { |attribute| resolve_attribute_alias(attribute) } if @unique_by
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def resolve_attribute_alias(attribute)
|
|
126
|
+
model.attribute_alias(attribute) || attribute
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def configure_on_duplicate_update_logic
|
|
130
|
+
if custom_update_sql_provided? && update_only.present?
|
|
131
|
+
raise ArgumentError, "You can't set :update_only and provide custom update SQL via :on_duplicate at the same time"
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
if update_only.present?
|
|
135
|
+
@updatable_columns = Array(update_only)
|
|
136
|
+
@on_duplicate = :update
|
|
137
|
+
elsif custom_update_sql_provided?
|
|
138
|
+
@update_sql = on_duplicate
|
|
139
|
+
@on_duplicate = :update
|
|
140
|
+
elsif @on_duplicate == :update && updatable_columns.empty?
|
|
141
|
+
@on_duplicate = :skip
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def custom_update_sql_provided?
|
|
146
|
+
@custom_update_sql_provided ||= Arel.arel_node?(on_duplicate)
|
|
147
|
+
end
|
|
148
|
+
|
|
59
149
|
def find_unique_index_for(unique_by)
|
|
60
|
-
|
|
150
|
+
if !connection.supports_insert_conflict_target?
|
|
151
|
+
return if unique_by.nil?
|
|
152
|
+
|
|
153
|
+
raise ArgumentError, "#{connection.class} does not support :unique_by"
|
|
154
|
+
end
|
|
61
155
|
|
|
62
|
-
|
|
156
|
+
name_or_columns = unique_by || model.primary_key
|
|
157
|
+
match = Array(name_or_columns).map(&:to_s)
|
|
158
|
+
sorted_match = match.sort
|
|
159
|
+
|
|
160
|
+
if index = unique_indexes.find { |i| match.include?(i.name) || Array(i.columns).sort == sorted_match }
|
|
63
161
|
index
|
|
162
|
+
elsif match == primary_keys
|
|
163
|
+
unique_by.nil? ? nil : ActiveRecord::ConnectionAdapters::IndexDefinition.new(model.table_name, "#{model.table_name}_primary_key", true, match)
|
|
64
164
|
else
|
|
65
|
-
raise ArgumentError, "No unique index found for #{
|
|
165
|
+
raise ArgumentError, "No unique index found for #{name_or_columns}"
|
|
66
166
|
end
|
|
67
167
|
end
|
|
68
168
|
|
|
69
169
|
def unique_indexes
|
|
70
|
-
|
|
170
|
+
@model.schema_cache.indexes(model.table_name).select(&:unique)
|
|
71
171
|
end
|
|
72
172
|
|
|
73
|
-
|
|
74
173
|
def ensure_valid_options_for_connection!
|
|
75
174
|
if returning && !connection.supports_insert_returning?
|
|
76
175
|
raise ArgumentError, "#{connection.class} does not support :returning"
|
|
@@ -96,7 +195,7 @@ module ActiveRecord
|
|
|
96
195
|
|
|
97
196
|
|
|
98
197
|
def readonly_columns
|
|
99
|
-
primary_keys + model.readonly_attributes
|
|
198
|
+
primary_keys + model.readonly_attributes
|
|
100
199
|
end
|
|
101
200
|
|
|
102
201
|
def unique_by_columns
|
|
@@ -105,36 +204,62 @@ module ActiveRecord
|
|
|
105
204
|
|
|
106
205
|
|
|
107
206
|
def verify_attributes(attributes)
|
|
108
|
-
if
|
|
207
|
+
if keys_including_timestamps != attributes.keys.to_set
|
|
109
208
|
raise ArgumentError, "All objects being inserted must have the same keys"
|
|
110
209
|
end
|
|
111
210
|
end
|
|
112
211
|
|
|
212
|
+
def disallow_raw_sql!(value)
|
|
213
|
+
return if !value.is_a?(String) || Arel.arel_node?(value)
|
|
214
|
+
|
|
215
|
+
raise ArgumentError, "Dangerous query method (method whose arguments are used as raw " \
|
|
216
|
+
"SQL) called: #{value}. " \
|
|
217
|
+
"Known-safe values can be passed " \
|
|
218
|
+
"by wrapping them in Arel.sql()."
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def timestamps_for_create
|
|
222
|
+
model.all_timestamp_attributes_in_model.index_with(connection.high_precision_current_timestamp)
|
|
223
|
+
end
|
|
224
|
+
|
|
113
225
|
class Builder # :nodoc:
|
|
114
226
|
attr_reader :model
|
|
115
227
|
|
|
116
|
-
delegate :skip_duplicates?, :update_duplicates?, :keys, to: :insert_all
|
|
228
|
+
delegate :skip_duplicates?, :update_duplicates?, :keys, :keys_including_timestamps, :record_timestamps?, to: :insert_all
|
|
117
229
|
|
|
118
230
|
def initialize(insert_all)
|
|
119
231
|
@insert_all, @model, @connection = insert_all, insert_all.model, insert_all.connection
|
|
120
232
|
end
|
|
121
233
|
|
|
122
234
|
def into
|
|
123
|
-
"INTO #{model.quoted_table_name}(#{columns_list})"
|
|
235
|
+
"INTO #{model.quoted_table_name} (#{columns_list})"
|
|
124
236
|
end
|
|
125
237
|
|
|
126
238
|
def values_list
|
|
127
|
-
types = extract_types_from_columns_on(model.table_name, keys:
|
|
239
|
+
types = extract_types_from_columns_on(model.table_name, keys: keys_including_timestamps)
|
|
128
240
|
|
|
129
241
|
values_list = insert_all.map_key_with_value do |key, value|
|
|
242
|
+
next value if Arel::Nodes::SqlLiteral === value
|
|
130
243
|
connection.with_yaml_fallback(types[key].serialize(value))
|
|
131
244
|
end
|
|
132
245
|
|
|
133
|
-
Arel::
|
|
246
|
+
connection.visitor.compile(Arel::Nodes::ValuesList.new(values_list))
|
|
134
247
|
end
|
|
135
248
|
|
|
136
249
|
def returning
|
|
137
|
-
|
|
250
|
+
return unless insert_all.returning
|
|
251
|
+
|
|
252
|
+
if insert_all.returning.is_a?(String)
|
|
253
|
+
insert_all.returning
|
|
254
|
+
else
|
|
255
|
+
Array(insert_all.returning).map do |attribute|
|
|
256
|
+
if model.attribute_alias?(attribute)
|
|
257
|
+
"#{quote_column(model.attribute_alias(attribute))} AS #{quote_column(attribute)}"
|
|
258
|
+
else
|
|
259
|
+
quote_column(attribute)
|
|
260
|
+
end
|
|
261
|
+
end.join(",")
|
|
262
|
+
end
|
|
138
263
|
end
|
|
139
264
|
|
|
140
265
|
def conflict_target
|
|
@@ -151,28 +276,52 @@ module ActiveRecord
|
|
|
151
276
|
quote_columns(insert_all.updatable_columns)
|
|
152
277
|
end
|
|
153
278
|
|
|
279
|
+
def touch_model_timestamps_unless(&block)
|
|
280
|
+
return "" unless update_duplicates? && record_timestamps?
|
|
281
|
+
|
|
282
|
+
model.timestamp_attributes_for_update_in_model.filter_map do |column_name|
|
|
283
|
+
if touch_timestamp_attribute?(column_name)
|
|
284
|
+
"#{column_name}=(CASE WHEN (#{updatable_columns.map(&block).join(" AND ")}) THEN #{model.quoted_table_name}.#{column_name} ELSE #{connection.high_precision_current_timestamp} END),"
|
|
285
|
+
end
|
|
286
|
+
end.join
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def raw_update_sql
|
|
290
|
+
insert_all.update_sql
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
alias raw_update_sql? raw_update_sql
|
|
294
|
+
|
|
154
295
|
private
|
|
155
296
|
attr_reader :connection, :insert_all
|
|
156
297
|
|
|
298
|
+
def touch_timestamp_attribute?(column_name)
|
|
299
|
+
insert_all.updatable_columns.exclude?(column_name)
|
|
300
|
+
end
|
|
301
|
+
|
|
157
302
|
def columns_list
|
|
158
|
-
format_columns(insert_all.
|
|
303
|
+
format_columns(insert_all.keys_including_timestamps)
|
|
159
304
|
end
|
|
160
305
|
|
|
161
306
|
def extract_types_from_columns_on(table_name, keys:)
|
|
162
|
-
columns =
|
|
307
|
+
columns = @model.schema_cache.columns_hash(table_name)
|
|
163
308
|
|
|
164
309
|
unknown_column = (keys - columns.keys).first
|
|
165
310
|
raise UnknownAttributeError.new(model.new, unknown_column) if unknown_column
|
|
166
311
|
|
|
167
|
-
keys.
|
|
312
|
+
keys.index_with { |key| model.type_for_attribute(key) }
|
|
168
313
|
end
|
|
169
314
|
|
|
170
315
|
def format_columns(columns)
|
|
171
|
-
quote_columns(columns).join(",")
|
|
316
|
+
columns.respond_to?(:map) ? quote_columns(columns).join(",") : columns
|
|
172
317
|
end
|
|
173
318
|
|
|
174
319
|
def quote_columns(columns)
|
|
175
|
-
columns.map(
|
|
320
|
+
columns.map { |column| quote_column(column) }
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
def quote_column(column)
|
|
324
|
+
connection.quote_column_name(column)
|
|
176
325
|
end
|
|
177
326
|
end
|
|
178
327
|
end
|
|
@@ -10,7 +10,7 @@ module ActiveRecord
|
|
|
10
10
|
##
|
|
11
11
|
# :singleton-method:
|
|
12
12
|
# Indicates the format used to generate the timestamp in the cache key, if
|
|
13
|
-
# versioning is off. Accepts any of the symbols in
|
|
13
|
+
# versioning is off. Accepts any of the symbols in +Time::DATE_FORMATS+.
|
|
14
14
|
#
|
|
15
15
|
# This is +:usec+, by default.
|
|
16
16
|
class_attribute :cache_timestamp_format, instance_writer: false, default: :usec
|
|
@@ -20,7 +20,7 @@ module ActiveRecord
|
|
|
20
20
|
# Indicates whether to use a stable #cache_key method that is accompanied
|
|
21
21
|
# by a changing version in the #cache_version method.
|
|
22
22
|
#
|
|
23
|
-
# This is +true+, by default on Rails 5.2 and above.
|
|
23
|
+
# This is +true+, by default on \Rails 5.2 and above.
|
|
24
24
|
class_attribute :cache_versioning, instance_writer: false, default: false
|
|
25
25
|
|
|
26
26
|
##
|
|
@@ -28,7 +28,7 @@ module ActiveRecord
|
|
|
28
28
|
# Indicates whether to use a stable #cache_key method that is accompanied
|
|
29
29
|
# by a changing version in the #cache_version method on collections.
|
|
30
30
|
#
|
|
31
|
-
# This is +false+, by default until Rails 6.1.
|
|
31
|
+
# This is +false+, by default until \Rails 6.1.
|
|
32
32
|
class_attribute :collection_cache_versioning, instance_writer: false, default: false
|
|
33
33
|
end
|
|
34
34
|
|
|
@@ -55,8 +55,8 @@ module ActiveRecord
|
|
|
55
55
|
# user = User.find_by(name: 'Phusion')
|
|
56
56
|
# user_path(user) # => "/users/Phusion"
|
|
57
57
|
def to_param
|
|
58
|
-
|
|
59
|
-
id
|
|
58
|
+
return unless id
|
|
59
|
+
Array(id).join(self.class.param_delimiter)
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
# Returns a stable cache key that can be used to identify this record.
|
|
@@ -64,7 +64,7 @@ module ActiveRecord
|
|
|
64
64
|
# Product.new.cache_key # => "products/new"
|
|
65
65
|
# Product.find(5).cache_key # => "products/5"
|
|
66
66
|
#
|
|
67
|
-
# If ActiveRecord::Base.cache_versioning is turned off, as it was in Rails 5.1 and earlier,
|
|
67
|
+
# If ActiveRecord::Base.cache_versioning is turned off, as it was in \Rails 5.1 and earlier,
|
|
68
68
|
# the cache key will also include a version.
|
|
69
69
|
#
|
|
70
70
|
# Product.cache_versioning = false
|
|
@@ -79,7 +79,7 @@ module ActiveRecord
|
|
|
79
79
|
timestamp = max_updated_column_timestamp
|
|
80
80
|
|
|
81
81
|
if timestamp
|
|
82
|
-
timestamp = timestamp.utc.
|
|
82
|
+
timestamp = timestamp.utc.to_fs(cache_timestamp_format)
|
|
83
83
|
"#{model_name.cache_key}/#{id}-#{timestamp}"
|
|
84
84
|
else
|
|
85
85
|
"#{model_name.cache_key}/#{id}"
|
|
@@ -93,7 +93,7 @@ module ActiveRecord
|
|
|
93
93
|
# cache_version, but this method can be overwritten to return something else.
|
|
94
94
|
#
|
|
95
95
|
# Note, this method will return nil if ActiveRecord::Base.cache_versioning is set to
|
|
96
|
-
# +false
|
|
96
|
+
# +false+.
|
|
97
97
|
def cache_version
|
|
98
98
|
return unless cache_versioning
|
|
99
99
|
|
|
@@ -101,13 +101,12 @@ module ActiveRecord
|
|
|
101
101
|
timestamp = updated_at_before_type_cast
|
|
102
102
|
if can_use_fast_cache_version?(timestamp)
|
|
103
103
|
raw_timestamp_to_cache_version(timestamp)
|
|
104
|
+
|
|
104
105
|
elsif timestamp = updated_at
|
|
105
|
-
timestamp.utc.
|
|
106
|
-
end
|
|
107
|
-
else
|
|
108
|
-
if self.class.has_attribute?("updated_at")
|
|
109
|
-
raise ActiveModel::MissingAttributeError, "missing attribute: updated_at"
|
|
106
|
+
timestamp.utc.to_fs(cache_timestamp_format)
|
|
110
107
|
end
|
|
108
|
+
elsif self.class.has_attribute?("updated_at")
|
|
109
|
+
raise ActiveModel::MissingAttributeError, "missing attribute 'updated_at' for #{self.class}"
|
|
111
110
|
end
|
|
112
111
|
end
|
|
113
112
|
|
|
@@ -179,7 +178,10 @@ module ActiveRecord
|
|
|
179
178
|
def can_use_fast_cache_version?(timestamp)
|
|
180
179
|
timestamp.is_a?(String) &&
|
|
181
180
|
cache_timestamp_format == :usec &&
|
|
182
|
-
|
|
181
|
+
# FIXME: checking out a connection for this is wasteful
|
|
182
|
+
# we should store/cache this information in the schema cache
|
|
183
|
+
# or similar.
|
|
184
|
+
self.class.with_connection(&:default_timezone) == :utc &&
|
|
183
185
|
!updated_at_came_from_user?
|
|
184
186
|
end
|
|
185
187
|
|
|
@@ -6,48 +6,159 @@ require "active_record/scoping/named"
|
|
|
6
6
|
module ActiveRecord
|
|
7
7
|
# This class is used to create a table that keeps track of values and keys such
|
|
8
8
|
# as which environment migrations were run in.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
#
|
|
10
|
+
# This is enabled by default. To disable this functionality set
|
|
11
|
+
# `use_metadata_table` to false in your database configuration.
|
|
12
|
+
class InternalMetadata # :nodoc:
|
|
13
|
+
class NullInternalMetadata # :nodoc:
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
attr_reader :arel_table
|
|
17
|
+
|
|
18
|
+
def initialize(pool)
|
|
19
|
+
@pool = pool
|
|
20
|
+
@arel_table = Arel::Table.new(table_name)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def primary_key
|
|
24
|
+
"key"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def value_key
|
|
28
|
+
"value"
|
|
29
|
+
end
|
|
14
30
|
|
|
15
|
-
|
|
16
|
-
|
|
31
|
+
def table_name
|
|
32
|
+
"#{ActiveRecord::Base.table_name_prefix}#{ActiveRecord::Base.internal_metadata_table_name}#{ActiveRecord::Base.table_name_suffix}"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def enabled?
|
|
36
|
+
@pool.db_config.use_metadata_table?
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def []=(key, value)
|
|
40
|
+
return unless enabled?
|
|
41
|
+
|
|
42
|
+
@pool.with_connection do |connection|
|
|
43
|
+
update_or_create_entry(connection, key, value)
|
|
17
44
|
end
|
|
45
|
+
end
|
|
18
46
|
|
|
19
|
-
|
|
20
|
-
|
|
47
|
+
def [](key)
|
|
48
|
+
return unless enabled?
|
|
49
|
+
|
|
50
|
+
@pool.with_connection do |connection|
|
|
51
|
+
if entry = select_entry(connection, key)
|
|
52
|
+
entry[value_key]
|
|
53
|
+
end
|
|
21
54
|
end
|
|
55
|
+
end
|
|
22
56
|
|
|
23
|
-
|
|
24
|
-
|
|
57
|
+
def delete_all_entries
|
|
58
|
+
dm = Arel::DeleteManager.new(arel_table)
|
|
59
|
+
|
|
60
|
+
@pool.with_connection do |connection|
|
|
61
|
+
connection.delete(dm, "#{self.class} Destroy")
|
|
25
62
|
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def count
|
|
66
|
+
sm = Arel::SelectManager.new(arel_table)
|
|
67
|
+
sm.project(*Arel::Nodes::Count.new([Arel.star]))
|
|
26
68
|
|
|
27
|
-
|
|
28
|
-
|
|
69
|
+
@pool.with_connection do |connection|
|
|
70
|
+
connection.select_values(sm, "#{self.class} Count").first
|
|
29
71
|
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def create_table_and_set_flags(environment, schema_sha1 = nil)
|
|
75
|
+
return unless enabled?
|
|
30
76
|
|
|
31
|
-
|
|
32
|
-
|
|
77
|
+
@pool.with_connection do |connection|
|
|
78
|
+
create_table
|
|
79
|
+
update_or_create_entry(connection, :environment, environment)
|
|
80
|
+
update_or_create_entry(connection, :schema_sha1, schema_sha1) if schema_sha1
|
|
33
81
|
end
|
|
82
|
+
end
|
|
34
83
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
key_options = connection.internal_string_options_for_primary_key
|
|
84
|
+
# Creates an internal metadata table with columns +key+ and +value+
|
|
85
|
+
def create_table
|
|
86
|
+
return unless enabled?
|
|
39
87
|
|
|
88
|
+
@pool.with_connection do |connection|
|
|
89
|
+
unless connection.table_exists?(table_name)
|
|
40
90
|
connection.create_table(table_name, id: false) do |t|
|
|
41
|
-
t.string :key,
|
|
91
|
+
t.string :key, **connection.internal_string_options_for_primary_key
|
|
42
92
|
t.string :value
|
|
43
93
|
t.timestamps
|
|
44
94
|
end
|
|
45
95
|
end
|
|
46
96
|
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def drop_table
|
|
100
|
+
return unless enabled?
|
|
47
101
|
|
|
48
|
-
|
|
102
|
+
@pool.with_connection do |connection|
|
|
49
103
|
connection.drop_table table_name, if_exists: true
|
|
50
104
|
end
|
|
51
105
|
end
|
|
106
|
+
|
|
107
|
+
def table_exists?
|
|
108
|
+
@pool.schema_cache.data_source_exists?(table_name)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
private
|
|
112
|
+
def update_or_create_entry(connection, key, value)
|
|
113
|
+
entry = select_entry(connection, key)
|
|
114
|
+
|
|
115
|
+
if entry
|
|
116
|
+
if entry[value_key] != value
|
|
117
|
+
update_entry(connection, key, value)
|
|
118
|
+
else
|
|
119
|
+
entry[value_key]
|
|
120
|
+
end
|
|
121
|
+
else
|
|
122
|
+
create_entry(connection, key, value)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def current_time(connection)
|
|
127
|
+
connection.default_timezone == :utc ? Time.now.utc : Time.now
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def create_entry(connection, key, value)
|
|
131
|
+
im = Arel::InsertManager.new(arel_table)
|
|
132
|
+
im.insert [
|
|
133
|
+
[arel_table[primary_key], key],
|
|
134
|
+
[arel_table[value_key], value],
|
|
135
|
+
[arel_table[:created_at], current_time(connection)],
|
|
136
|
+
[arel_table[:updated_at], current_time(connection)]
|
|
137
|
+
]
|
|
138
|
+
|
|
139
|
+
connection.insert(im, "#{self.class} Create", primary_key, key)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def update_entry(connection, key, new_value)
|
|
143
|
+
um = Arel::UpdateManager.new(arel_table)
|
|
144
|
+
um.set [
|
|
145
|
+
[arel_table[value_key], new_value],
|
|
146
|
+
[arel_table[:updated_at], current_time(connection)]
|
|
147
|
+
]
|
|
148
|
+
|
|
149
|
+
um.where(arel_table[primary_key].eq(key))
|
|
150
|
+
|
|
151
|
+
connection.update(um, "#{self.class} Update")
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def select_entry(connection, key)
|
|
155
|
+
sm = Arel::SelectManager.new(arel_table)
|
|
156
|
+
sm.project(Arel::Nodes::SqlLiteral.new("*", retryable: true))
|
|
157
|
+
sm.where(arel_table[primary_key].eq(Arel::Nodes::BindParam.new(key)))
|
|
158
|
+
sm.order(arel_table[primary_key].asc)
|
|
159
|
+
sm.limit = 1
|
|
160
|
+
|
|
161
|
+
connection.select_all(sm, "#{self.class} Load").first
|
|
162
|
+
end
|
|
52
163
|
end
|
|
53
164
|
end
|
|
@@ -1,47 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module ActiveRecord
|
|
4
|
-
module LegacyYamlAdapter
|
|
5
|
-
def self.convert(
|
|
4
|
+
module LegacyYamlAdapter # :nodoc:
|
|
5
|
+
def self.convert(coder)
|
|
6
6
|
return coder unless coder.is_a?(Psych::Coder)
|
|
7
7
|
|
|
8
8
|
case coder["active_record_yaml_version"]
|
|
9
9
|
when 1, 2 then coder
|
|
10
10
|
else
|
|
11
|
-
|
|
12
|
-
Rails420.convert(klass, coder)
|
|
13
|
-
else
|
|
14
|
-
Rails41.convert(klass, coder)
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
module Rails420
|
|
20
|
-
def self.convert(klass, coder)
|
|
21
|
-
attribute_set = coder["attributes"]
|
|
22
|
-
|
|
23
|
-
klass.attribute_names.each do |attr_name|
|
|
24
|
-
attribute = attribute_set[attr_name]
|
|
25
|
-
if attribute.type.is_a?(Delegator)
|
|
26
|
-
type_from_klass = klass.type_for_attribute(attr_name)
|
|
27
|
-
attribute_set[attr_name] = attribute.with_type(type_from_klass)
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
coder
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
module Rails41
|
|
36
|
-
def self.convert(klass, coder)
|
|
37
|
-
attributes = klass.attributes_builder
|
|
38
|
-
.build_from_database(coder["attributes"])
|
|
39
|
-
new_record = coder["attributes"][klass.primary_key].blank?
|
|
40
|
-
|
|
41
|
-
{
|
|
42
|
-
"attributes" => attributes,
|
|
43
|
-
"new_record" => new_record,
|
|
44
|
-
}
|
|
11
|
+
raise("Active Record doesn't know how to load YAML with this format.")
|
|
45
12
|
end
|
|
46
13
|
end
|
|
47
14
|
end
|