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
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/message_pack"
|
|
4
|
+
|
|
5
|
+
module ActiveRecord
|
|
6
|
+
module Encryption
|
|
7
|
+
# A message serializer that serializes +Messages+ with MessagePack.
|
|
8
|
+
#
|
|
9
|
+
# The message is converted to a hash with this structure:
|
|
10
|
+
#
|
|
11
|
+
# {
|
|
12
|
+
# p: <payload>,
|
|
13
|
+
# h: {
|
|
14
|
+
# header1: value1,
|
|
15
|
+
# header2: value2,
|
|
16
|
+
# ...
|
|
17
|
+
# }
|
|
18
|
+
# }
|
|
19
|
+
#
|
|
20
|
+
# Then it is converted to the MessagePack format.
|
|
21
|
+
class MessagePackMessageSerializer
|
|
22
|
+
def dump(message)
|
|
23
|
+
raise Errors::ForbiddenClass unless message.is_a?(Message)
|
|
24
|
+
ActiveSupport::MessagePack.dump(message_to_hash(message))
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def load(serialized_content)
|
|
28
|
+
data = ActiveSupport::MessagePack.load(serialized_content)
|
|
29
|
+
hash_to_message(data, 1)
|
|
30
|
+
rescue RuntimeError
|
|
31
|
+
raise Errors::Decryption
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def binary?
|
|
35
|
+
true
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
def message_to_hash(message)
|
|
40
|
+
{
|
|
41
|
+
"p" => message.payload,
|
|
42
|
+
"h" => headers_to_hash(message.headers)
|
|
43
|
+
}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def headers_to_hash(headers)
|
|
47
|
+
headers.transform_values do |value|
|
|
48
|
+
value.is_a?(Message) ? message_to_hash(value) : value
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def hash_to_message(data, level)
|
|
53
|
+
validate_message_data_format(data, level)
|
|
54
|
+
Message.new(payload: data["p"], headers: parse_properties(data["h"], level))
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def validate_message_data_format(data, level)
|
|
58
|
+
if level > 2
|
|
59
|
+
raise Errors::Decryption, "More than one level of hash nesting in headers is not supported"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
unless data.is_a?(Hash) && data.has_key?("p")
|
|
63
|
+
raise Errors::Decryption, "Invalid data format: hash without payload"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def parse_properties(headers, level)
|
|
68
|
+
Properties.new.tap do |properties|
|
|
69
|
+
headers&.each do |key, value|
|
|
70
|
+
properties[key] = value.is_a?(Hash) ? hash_to_message(value, level + 1) : value
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "base64"
|
|
4
|
+
|
|
5
|
+
module ActiveRecord
|
|
6
|
+
module Encryption
|
|
7
|
+
# A message serializer that serializes +Messages+ with JSON.
|
|
8
|
+
#
|
|
9
|
+
# The generated structure is pretty simple:
|
|
10
|
+
#
|
|
11
|
+
# {
|
|
12
|
+
# p: <payload>,
|
|
13
|
+
# h: {
|
|
14
|
+
# header1: value1,
|
|
15
|
+
# header2: value2,
|
|
16
|
+
# ...
|
|
17
|
+
# }
|
|
18
|
+
# }
|
|
19
|
+
#
|
|
20
|
+
# Both the payload and the header values are encoded with Base64
|
|
21
|
+
# to prevent JSON parsing errors and encoding issues when
|
|
22
|
+
# storing the resulting serialized data.
|
|
23
|
+
class MessageSerializer
|
|
24
|
+
def load(serialized_content)
|
|
25
|
+
data = JSON.parse(serialized_content)
|
|
26
|
+
parse_message(data, 1)
|
|
27
|
+
rescue JSON::ParserError
|
|
28
|
+
raise ActiveRecord::Encryption::Errors::Encoding
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def dump(message)
|
|
32
|
+
raise ActiveRecord::Encryption::Errors::ForbiddenClass unless message.is_a?(ActiveRecord::Encryption::Message)
|
|
33
|
+
JSON.dump message_to_json(message)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def binary?
|
|
37
|
+
false
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
def parse_message(data, level)
|
|
42
|
+
validate_message_data_format(data, level)
|
|
43
|
+
ActiveRecord::Encryption::Message.new(payload: decode_if_needed(data["p"]), headers: parse_properties(data["h"], level))
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def validate_message_data_format(data, level)
|
|
47
|
+
if level > 2
|
|
48
|
+
raise ActiveRecord::Encryption::Errors::Decryption, "More than one level of hash nesting in headers is not supported"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
unless data.is_a?(Hash) && data.has_key?("p")
|
|
52
|
+
raise ActiveRecord::Encryption::Errors::Decryption, "Invalid data format: hash without payload"
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def parse_properties(headers, level)
|
|
57
|
+
ActiveRecord::Encryption::Properties.new.tap do |properties|
|
|
58
|
+
headers&.each do |key, value|
|
|
59
|
+
properties[key] = value.is_a?(Hash) ? parse_message(value, level + 1) : decode_if_needed(value)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def message_to_json(message)
|
|
65
|
+
{
|
|
66
|
+
p: encode_if_needed(message.payload),
|
|
67
|
+
h: headers_to_json(message.headers)
|
|
68
|
+
}
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def headers_to_json(headers)
|
|
72
|
+
headers.transform_values do |value|
|
|
73
|
+
value.is_a?(ActiveRecord::Encryption::Message) ? message_to_json(value) : encode_if_needed(value)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def encode_if_needed(value)
|
|
78
|
+
if value.is_a?(String)
|
|
79
|
+
::Base64.strict_encode64 value
|
|
80
|
+
else
|
|
81
|
+
value
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def decode_if_needed(value)
|
|
86
|
+
if value.is_a?(String)
|
|
87
|
+
::Base64.strict_decode64(value)
|
|
88
|
+
else
|
|
89
|
+
value
|
|
90
|
+
end
|
|
91
|
+
rescue ArgumentError, TypeError
|
|
92
|
+
raise Errors::Encoding
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module Encryption
|
|
5
|
+
# An encryptor that won't decrypt or encrypt. It will just return the passed
|
|
6
|
+
# values
|
|
7
|
+
class NullEncryptor
|
|
8
|
+
def encrypt(clean_text, key_provider: nil, cipher_options: {})
|
|
9
|
+
clean_text
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def decrypt(encrypted_text, key_provider: nil, cipher_options: {})
|
|
13
|
+
encrypted_text
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def encrypted?(text)
|
|
17
|
+
false
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def binary?
|
|
21
|
+
false
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module Encryption
|
|
5
|
+
# This is a wrapper for a hash of encryption properties. It is used by
|
|
6
|
+
# +Key+ (public tags) and +Message+ (headers).
|
|
7
|
+
#
|
|
8
|
+
# Since properties are serialized in messages, it is important for storage
|
|
9
|
+
# efficiency to keep their keys as short as possible. It defines accessors
|
|
10
|
+
# for common properties that will keep these keys very short while exposing
|
|
11
|
+
# a readable name.
|
|
12
|
+
#
|
|
13
|
+
# message.headers.encrypted_data_key # instead of message.headers[:k]
|
|
14
|
+
#
|
|
15
|
+
# See +Properties::DEFAULT_PROPERTIES+, Key, Message
|
|
16
|
+
class Properties
|
|
17
|
+
ALLOWED_VALUE_CLASSES = [String, ActiveRecord::Encryption::Message, Numeric, Integer, Float, BigDecimal, TrueClass, FalseClass, Symbol, NilClass]
|
|
18
|
+
|
|
19
|
+
delegate_missing_to :data
|
|
20
|
+
delegate :==, :[], :each, :key?, to: :data
|
|
21
|
+
|
|
22
|
+
# For each entry it generates an accessor exposing the full name
|
|
23
|
+
DEFAULT_PROPERTIES = {
|
|
24
|
+
encrypted_data_key: "k",
|
|
25
|
+
encrypted_data_key_id: "i",
|
|
26
|
+
compressed: "c",
|
|
27
|
+
iv: "iv",
|
|
28
|
+
auth_tag: "at",
|
|
29
|
+
encoding: "e"
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
DEFAULT_PROPERTIES.each do |name, key|
|
|
33
|
+
define_method name do
|
|
34
|
+
self[key.to_sym]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
define_method "#{name}=" do |value|
|
|
38
|
+
self[key.to_sym] = value
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def initialize(initial_properties = {})
|
|
43
|
+
@data = {}
|
|
44
|
+
add(initial_properties)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Set a value for a given key
|
|
48
|
+
#
|
|
49
|
+
# It will raise an +EncryptedContentIntegrity+ if the value exists
|
|
50
|
+
def []=(key, value)
|
|
51
|
+
raise Errors::EncryptedContentIntegrity, "Properties can't be overridden: #{key}" if key?(key)
|
|
52
|
+
validate_value_type(value)
|
|
53
|
+
data[key] = value
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def validate_value_type(value)
|
|
57
|
+
unless ALLOWED_VALUE_CLASSES.include?(value.class) || ALLOWED_VALUE_CLASSES.any? { |klass| value.is_a?(klass) }
|
|
58
|
+
raise ActiveRecord::Encryption::Errors::ForbiddenClass, "Can't store a #{value.class}, only properties of type #{ALLOWED_VALUE_CLASSES.inspect} are allowed"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def add(other_properties)
|
|
63
|
+
other_properties.each do |key, value|
|
|
64
|
+
self[key.to_sym] = value
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def to_h
|
|
69
|
+
data
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
attr_reader :data
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module Encryption
|
|
5
|
+
# A +NullEncryptor+ that will raise an error when trying to encrypt data
|
|
6
|
+
#
|
|
7
|
+
# This is useful when you want to reveal ciphertexts for debugging purposes
|
|
8
|
+
# and you want to make sure you won't overwrite any encryptable attribute with
|
|
9
|
+
# the wrong content.
|
|
10
|
+
class ReadOnlyNullEncryptor
|
|
11
|
+
def encrypt(clean_text, key_provider: nil, cipher_options: {})
|
|
12
|
+
raise Errors::Encryption, "This encryptor is read-only"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def decrypt(encrypted_text, key_provider: nil, cipher_options: {})
|
|
16
|
+
encrypted_text
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def encrypted?(text)
|
|
20
|
+
false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def binary?
|
|
24
|
+
false
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module Encryption
|
|
5
|
+
# A container of attribute encryption options.
|
|
6
|
+
#
|
|
7
|
+
# It validates and serves attribute encryption options.
|
|
8
|
+
#
|
|
9
|
+
# See EncryptedAttributeType, Context
|
|
10
|
+
class Scheme
|
|
11
|
+
attr_accessor :previous_schemes
|
|
12
|
+
|
|
13
|
+
def initialize(key_provider: nil, key: nil, deterministic: nil, support_unencrypted_data: nil, downcase: nil, ignore_case: nil,
|
|
14
|
+
previous_schemes: nil, **context_properties)
|
|
15
|
+
# Initializing all attributes to +nil+ as we want to allow a "not set" semantics so that we
|
|
16
|
+
# can merge schemes without overriding values with defaults. See +#merge+
|
|
17
|
+
|
|
18
|
+
@key_provider_param = key_provider
|
|
19
|
+
@key = key
|
|
20
|
+
@deterministic = deterministic
|
|
21
|
+
@support_unencrypted_data = support_unencrypted_data
|
|
22
|
+
@downcase = downcase || ignore_case
|
|
23
|
+
@ignore_case = ignore_case
|
|
24
|
+
@previous_schemes_param = previous_schemes
|
|
25
|
+
@previous_schemes = Array.wrap(previous_schemes)
|
|
26
|
+
@context_properties = context_properties
|
|
27
|
+
|
|
28
|
+
validate_config!
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def ignore_case?
|
|
32
|
+
@ignore_case
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def downcase?
|
|
36
|
+
@downcase
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def deterministic?
|
|
40
|
+
!!@deterministic
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def support_unencrypted_data?
|
|
44
|
+
@support_unencrypted_data.nil? ? ActiveRecord::Encryption.config.support_unencrypted_data : @support_unencrypted_data
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def fixed?
|
|
48
|
+
# by default deterministic encryption is fixed
|
|
49
|
+
@fixed ||= @deterministic && (!@deterministic.is_a?(Hash) || @deterministic[:fixed])
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def key_provider
|
|
53
|
+
@key_provider_param || key_provider_from_key || deterministic_key_provider || default_key_provider
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def merge(other_scheme)
|
|
57
|
+
self.class.new(**to_h.merge(other_scheme.to_h))
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def to_h
|
|
61
|
+
{ key_provider: @key_provider_param, deterministic: @deterministic, downcase: @downcase, ignore_case: @ignore_case,
|
|
62
|
+
previous_schemes: @previous_schemes_param, **@context_properties }.compact
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def with_context(&block)
|
|
66
|
+
if @context_properties.present?
|
|
67
|
+
ActiveRecord::Encryption.with_encryption_context(**@context_properties, &block)
|
|
68
|
+
else
|
|
69
|
+
block.call
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def compatible_with?(other_scheme)
|
|
74
|
+
deterministic? == other_scheme.deterministic?
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
def validate_config!
|
|
79
|
+
raise Errors::Configuration, "ignore_case: can only be used with deterministic encryption" if @ignore_case && !@deterministic
|
|
80
|
+
raise Errors::Configuration, "key_provider: and key: can't be used simultaneously" if @key_provider_param && @key
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def key_provider_from_key
|
|
84
|
+
@key_provider_from_key ||= if @key.present?
|
|
85
|
+
DerivedSecretKeyProvider.new(@key)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def deterministic_key_provider
|
|
90
|
+
@deterministic_key_provider ||= if @deterministic
|
|
91
|
+
DeterministicKeyProvider.new(ActiveRecord::Encryption.config.deterministic_key)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def default_key_provider
|
|
96
|
+
ActiveRecord::Encryption.key_provider
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/core_ext/module"
|
|
4
|
+
require "active_support/core_ext/array"
|
|
5
|
+
|
|
6
|
+
module ActiveRecord
|
|
7
|
+
module Encryption
|
|
8
|
+
extend ActiveSupport::Autoload
|
|
9
|
+
|
|
10
|
+
eager_autoload do
|
|
11
|
+
autoload :AutoFilteredParameters
|
|
12
|
+
autoload :Cipher
|
|
13
|
+
autoload :Config
|
|
14
|
+
autoload :Configurable
|
|
15
|
+
autoload :Context
|
|
16
|
+
autoload :Contexts
|
|
17
|
+
autoload :DerivedSecretKeyProvider
|
|
18
|
+
autoload :EncryptableRecord
|
|
19
|
+
autoload :EncryptedAttributeType
|
|
20
|
+
autoload :EncryptedFixtures
|
|
21
|
+
autoload :EncryptingOnlyEncryptor
|
|
22
|
+
autoload :DeterministicKeyProvider
|
|
23
|
+
autoload :Encryptor
|
|
24
|
+
autoload :EnvelopeEncryptionKeyProvider
|
|
25
|
+
autoload :Errors
|
|
26
|
+
autoload :ExtendedDeterministicQueries
|
|
27
|
+
autoload :ExtendedDeterministicUniquenessValidator
|
|
28
|
+
autoload :Key
|
|
29
|
+
autoload :KeyGenerator
|
|
30
|
+
autoload :KeyProvider
|
|
31
|
+
autoload :Message
|
|
32
|
+
autoload :MessageSerializer
|
|
33
|
+
autoload :NullEncryptor
|
|
34
|
+
autoload :Properties
|
|
35
|
+
autoload :ReadOnlyNullEncryptor
|
|
36
|
+
autoload :Scheme
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class Cipher
|
|
40
|
+
extend ActiveSupport::Autoload
|
|
41
|
+
|
|
42
|
+
eager_autoload do
|
|
43
|
+
autoload :Aes256Gcm
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
include Configurable
|
|
48
|
+
include Contexts
|
|
49
|
+
|
|
50
|
+
def self.eager_load!
|
|
51
|
+
super
|
|
52
|
+
|
|
53
|
+
Cipher.eager_load!
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
ActiveSupport.run_load_hooks :active_record_encryption, Encryption
|
|
58
|
+
end
|