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,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module ConnectionAdapters
|
|
5
|
+
class PoolManager # :nodoc:
|
|
6
|
+
def initialize
|
|
7
|
+
@role_to_shard_mapping = Hash.new { |h, k| h[k] = {} }
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def shard_names
|
|
11
|
+
@role_to_shard_mapping.values.flat_map { |shard_map| shard_map.keys }.uniq
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def role_names
|
|
15
|
+
@role_to_shard_mapping.keys
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def pool_configs(role = nil)
|
|
19
|
+
if role
|
|
20
|
+
@role_to_shard_mapping[role].values
|
|
21
|
+
else
|
|
22
|
+
@role_to_shard_mapping.flat_map { |_, shard_map| shard_map.values }
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def each_pool_config(role = nil, &block)
|
|
27
|
+
if role
|
|
28
|
+
@role_to_shard_mapping[role].each_value(&block)
|
|
29
|
+
else
|
|
30
|
+
@role_to_shard_mapping.each_value do |shard_map|
|
|
31
|
+
shard_map.each_value(&block)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def remove_role(role)
|
|
37
|
+
@role_to_shard_mapping.delete(role)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def remove_pool_config(role, shard)
|
|
41
|
+
@role_to_shard_mapping[role].delete(shard)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def get_pool_config(role, shard)
|
|
45
|
+
@role_to_shard_mapping[role][shard]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def set_pool_config(role, shard, pool_config)
|
|
49
|
+
if pool_config
|
|
50
|
+
@role_to_shard_mapping[role][shard] = pool_config
|
|
51
|
+
else
|
|
52
|
+
raise ArgumentError, "The `pool_config` for the :#{role} role and :#{shard} shard was `nil`. Please check your configuration. If you want your writing role to be something other than `:writing` set `config.active_record.writing_role` in your application configuration. The same setting should be applied for the `reading_role` if applicable."
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -6,22 +6,74 @@ module ActiveRecord
|
|
|
6
6
|
class Column < ConnectionAdapters::Column # :nodoc:
|
|
7
7
|
delegate :oid, :fmod, to: :sql_type_metadata
|
|
8
8
|
|
|
9
|
-
def initialize(*, serial: nil, **)
|
|
9
|
+
def initialize(*, serial: nil, identity: nil, generated: nil, **)
|
|
10
10
|
super
|
|
11
11
|
@serial = serial
|
|
12
|
+
@identity = identity
|
|
13
|
+
@generated = generated
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def identity?
|
|
17
|
+
@identity
|
|
12
18
|
end
|
|
13
19
|
|
|
14
20
|
def serial?
|
|
15
21
|
@serial
|
|
16
22
|
end
|
|
17
23
|
|
|
24
|
+
def auto_incremented_by_db?
|
|
25
|
+
serial? || identity?
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def virtual?
|
|
29
|
+
# We assume every generated column is virtual, no matter the concrete type
|
|
30
|
+
@generated.present?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def has_default?
|
|
34
|
+
super && !virtual?
|
|
35
|
+
end
|
|
36
|
+
|
|
18
37
|
def array
|
|
19
38
|
sql_type_metadata.sql_type.end_with?("[]")
|
|
20
39
|
end
|
|
21
40
|
alias :array? :array
|
|
22
41
|
|
|
42
|
+
def enum?
|
|
43
|
+
type == :enum
|
|
44
|
+
end
|
|
45
|
+
|
|
23
46
|
def sql_type
|
|
24
|
-
super.
|
|
47
|
+
super.delete_suffix("[]")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def init_with(coder)
|
|
51
|
+
@serial = coder["serial"]
|
|
52
|
+
@identity = coder["identity"]
|
|
53
|
+
@generated = coder["generated"]
|
|
54
|
+
super
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def encode_with(coder)
|
|
58
|
+
coder["serial"] = @serial
|
|
59
|
+
coder["identity"] = @identity
|
|
60
|
+
coder["generated"] = @generated
|
|
61
|
+
super
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def ==(other)
|
|
65
|
+
other.is_a?(Column) &&
|
|
66
|
+
super &&
|
|
67
|
+
identity? == other.identity? &&
|
|
68
|
+
serial? == other.serial?
|
|
69
|
+
end
|
|
70
|
+
alias :eql? :==
|
|
71
|
+
|
|
72
|
+
def hash
|
|
73
|
+
Column.hash ^
|
|
74
|
+
super.hash ^
|
|
75
|
+
identity?.hash ^
|
|
76
|
+
serial?.hash
|
|
25
77
|
end
|
|
26
78
|
end
|
|
27
79
|
end
|
|
@@ -4,132 +4,87 @@ module ActiveRecord
|
|
|
4
4
|
module ConnectionAdapters
|
|
5
5
|
module PostgreSQL
|
|
6
6
|
module DatabaseStatements
|
|
7
|
-
def explain(arel, binds = [])
|
|
8
|
-
sql
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
# The internal PostgreSQL identifier of the money data type.
|
|
13
|
-
MONEY_COLUMN_TYPE_OID = 790 #:nodoc:
|
|
14
|
-
# The internal PostgreSQL identifier of the BYTEA data type.
|
|
15
|
-
BYTEA_COLUMN_TYPE_OID = 17 #:nodoc:
|
|
16
|
-
|
|
17
|
-
# create a 2D array representing the result set
|
|
18
|
-
def result_as_array(res) #:nodoc:
|
|
19
|
-
# check if we have any binary column and if they need escaping
|
|
20
|
-
ftypes = Array.new(res.nfields) do |i|
|
|
21
|
-
[i, res.ftype(i)]
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
rows = res.values
|
|
25
|
-
return rows unless ftypes.any? { |_, x|
|
|
26
|
-
x == BYTEA_COLUMN_TYPE_OID || x == MONEY_COLUMN_TYPE_OID
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
typehash = ftypes.group_by { |_, type| type }
|
|
30
|
-
binaries = typehash[BYTEA_COLUMN_TYPE_OID] || []
|
|
31
|
-
monies = typehash[MONEY_COLUMN_TYPE_OID] || []
|
|
32
|
-
|
|
33
|
-
rows.each do |row|
|
|
34
|
-
# unescape string passed BYTEA field (OID == 17)
|
|
35
|
-
binaries.each do |index, _|
|
|
36
|
-
row[index] = unescape_bytea(row[index])
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
# If this is a money type column and there are any currency symbols,
|
|
40
|
-
# then strip them off. Indeed it would be prettier to do this in
|
|
41
|
-
# PostgreSQLColumn.string_to_decimal but would break form input
|
|
42
|
-
# fields that call value_before_type_cast.
|
|
43
|
-
monies.each do |index, _|
|
|
44
|
-
data = row[index]
|
|
45
|
-
# Because money output is formatted according to the locale, there are two
|
|
46
|
-
# cases to consider (note the decimal separators):
|
|
47
|
-
# (1) $12,345,678.12
|
|
48
|
-
# (2) $12.345.678,12
|
|
49
|
-
case data
|
|
50
|
-
when /^-?\D+[\d,]+\.\d{2}$/ # (1)
|
|
51
|
-
data.gsub!(/[^-\d.]/, "")
|
|
52
|
-
when /^-?\D+[\d.]+,\d{2}$/ # (2)
|
|
53
|
-
data.gsub!(/[^-\d,]/, "").sub!(/,/, ".")
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
7
|
+
def explain(arel, binds = [], options = [])
|
|
8
|
+
sql = build_explain_clause(options) + " " + to_sql(arel, binds)
|
|
9
|
+
result = internal_exec_query(sql, "EXPLAIN", binds)
|
|
10
|
+
PostgreSQL::ExplainPrettyPrinter.new.pp(result)
|
|
57
11
|
end
|
|
58
12
|
|
|
59
13
|
# Queries the database and returns the results in an Array-like object
|
|
60
|
-
def query(sql, name = nil)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
log(sql, name) do
|
|
64
|
-
|
|
65
|
-
|
|
14
|
+
def query(sql, name = nil) # :nodoc:
|
|
15
|
+
mark_transaction_written_if_write(sql)
|
|
16
|
+
|
|
17
|
+
log(sql, name) do |notification_payload|
|
|
18
|
+
with_raw_connection do |conn|
|
|
19
|
+
result = conn.async_exec(sql).map_types!(@type_map_for_results).values
|
|
20
|
+
verified!
|
|
21
|
+
notification_payload[:row_count] = result.count
|
|
22
|
+
result
|
|
66
23
|
end
|
|
67
24
|
end
|
|
68
25
|
end
|
|
69
26
|
|
|
70
|
-
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
|
27
|
+
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
|
28
|
+
:close, :declare, :fetch, :move, :set, :show
|
|
29
|
+
) # :nodoc:
|
|
71
30
|
private_constant :READ_QUERY
|
|
72
31
|
|
|
73
32
|
def write_query?(sql) # :nodoc:
|
|
74
33
|
!READ_QUERY.match?(sql)
|
|
34
|
+
rescue ArgumentError # Invalid encoding
|
|
35
|
+
!READ_QUERY.match?(sql.b)
|
|
75
36
|
end
|
|
76
37
|
|
|
77
38
|
# Executes an SQL statement, returning a PG::Result object on success
|
|
78
39
|
# or raising a PG::Error exception otherwise.
|
|
40
|
+
#
|
|
41
|
+
# Setting +allow_retry+ to true causes the db to reconnect and retry
|
|
42
|
+
# executing the SQL statement in case of a connection-related exception.
|
|
43
|
+
# This option should only be enabled for known idempotent queries.
|
|
44
|
+
#
|
|
79
45
|
# Note: the PG::Result object is manually memory managed; if you don't
|
|
80
46
|
# need it specifically, you may want consider the <tt>exec_query</tt> wrapper.
|
|
81
|
-
def execute(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
materialize_transactions
|
|
47
|
+
def execute(...) # :nodoc:
|
|
48
|
+
super
|
|
49
|
+
ensure
|
|
50
|
+
@notice_receiver_sql_warnings = []
|
|
51
|
+
end
|
|
87
52
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
53
|
+
def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: true)
|
|
54
|
+
log(sql, name, async: async) do |notification_payload|
|
|
55
|
+
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
|
56
|
+
result = conn.async_exec(sql)
|
|
57
|
+
verified!
|
|
58
|
+
handle_warnings(result)
|
|
59
|
+
notification_payload[:row_count] = result.count
|
|
60
|
+
result
|
|
91
61
|
end
|
|
92
62
|
end
|
|
93
63
|
end
|
|
94
64
|
|
|
95
|
-
def
|
|
96
|
-
execute_and_clear(sql, name, binds, prepare: prepare) do |result|
|
|
65
|
+
def internal_exec_query(sql, name = "SQL", binds = [], prepare: false, async: false, allow_retry: false, materialize_transactions: true) # :nodoc:
|
|
66
|
+
execute_and_clear(sql, name, binds, prepare: prepare, async: async, allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |result|
|
|
97
67
|
types = {}
|
|
98
68
|
fields = result.fields
|
|
99
69
|
fields.each_with_index do |fname, i|
|
|
100
70
|
ftype = result.ftype i
|
|
101
71
|
fmod = result.fmod i
|
|
102
|
-
types[fname] = get_oid_type(ftype, fmod, fname)
|
|
72
|
+
types[fname] = types[i] = get_oid_type(ftype, fmod, fname)
|
|
103
73
|
end
|
|
104
|
-
|
|
74
|
+
build_result(columns: fields, rows: result.values, column_types: types.freeze)
|
|
105
75
|
end
|
|
106
76
|
end
|
|
107
77
|
|
|
108
|
-
def exec_delete(sql, name = nil, binds = [])
|
|
78
|
+
def exec_delete(sql, name = nil, binds = []) # :nodoc:
|
|
109
79
|
execute_and_clear(sql, name, binds) { |result| result.cmd_tuples }
|
|
110
80
|
end
|
|
111
81
|
alias :exec_update :exec_delete
|
|
112
82
|
|
|
113
|
-
def
|
|
114
|
-
if pk.nil?
|
|
115
|
-
# Extract the table from the insert sql. Yuck.
|
|
116
|
-
table_ref = extract_table_ref_from_insert_sql(sql)
|
|
117
|
-
pk = primary_key(table_ref) if table_ref
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
if pk = suppress_composite_primary_key(pk)
|
|
121
|
-
sql = "#{sql} RETURNING #{quote_column_name(pk)}"
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
super
|
|
125
|
-
end
|
|
126
|
-
private :sql_for_insert
|
|
127
|
-
|
|
128
|
-
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
|
|
83
|
+
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil, returning: nil) # :nodoc:
|
|
129
84
|
if use_insert_returning? || pk == false
|
|
130
85
|
super
|
|
131
86
|
else
|
|
132
|
-
result =
|
|
87
|
+
result = internal_exec_query(sql, name, binds)
|
|
133
88
|
unless sequence_name
|
|
134
89
|
table_ref = extract_table_ref_from_insert_sql(sql)
|
|
135
90
|
if table_ref
|
|
@@ -144,38 +99,110 @@ module ActiveRecord
|
|
|
144
99
|
end
|
|
145
100
|
|
|
146
101
|
# Begins a transaction.
|
|
147
|
-
def begin_db_transaction
|
|
148
|
-
|
|
102
|
+
def begin_db_transaction # :nodoc:
|
|
103
|
+
internal_execute("BEGIN", "TRANSACTION", allow_retry: true, materialize_transactions: false)
|
|
149
104
|
end
|
|
150
105
|
|
|
151
|
-
def begin_isolated_db_transaction(isolation)
|
|
152
|
-
|
|
153
|
-
execute "SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}"
|
|
106
|
+
def begin_isolated_db_transaction(isolation) # :nodoc:
|
|
107
|
+
internal_execute("BEGIN ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}", "TRANSACTION", allow_retry: true, materialize_transactions: false)
|
|
154
108
|
end
|
|
155
109
|
|
|
156
110
|
# Commits a transaction.
|
|
157
|
-
def commit_db_transaction
|
|
158
|
-
|
|
111
|
+
def commit_db_transaction # :nodoc:
|
|
112
|
+
internal_execute("COMMIT", "TRANSACTION", allow_retry: false, materialize_transactions: true)
|
|
159
113
|
end
|
|
160
114
|
|
|
161
115
|
# Aborts a transaction.
|
|
162
|
-
def exec_rollback_db_transaction
|
|
163
|
-
|
|
116
|
+
def exec_rollback_db_transaction # :nodoc:
|
|
117
|
+
cancel_any_running_query
|
|
118
|
+
internal_execute("ROLLBACK", "TRANSACTION", allow_retry: false, materialize_transactions: true)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def exec_restart_db_transaction # :nodoc:
|
|
122
|
+
cancel_any_running_query
|
|
123
|
+
internal_execute("ROLLBACK AND CHAIN", "TRANSACTION", allow_retry: false, materialize_transactions: true)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# From https://www.postgresql.org/docs/current/functions-datetime.html#FUNCTIONS-DATETIME-CURRENT
|
|
127
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("CURRENT_TIMESTAMP", retryable: true).freeze # :nodoc:
|
|
128
|
+
private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
|
|
129
|
+
|
|
130
|
+
def high_precision_current_timestamp
|
|
131
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def build_explain_clause(options = [])
|
|
135
|
+
return "EXPLAIN" if options.empty?
|
|
136
|
+
|
|
137
|
+
"EXPLAIN (#{options.join(", ").upcase})"
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Set when constraints will be checked for the current transaction.
|
|
141
|
+
#
|
|
142
|
+
# Not passing any specific constraint names will set the value for all deferrable constraints.
|
|
143
|
+
#
|
|
144
|
+
# [<tt>deferred</tt>]
|
|
145
|
+
# Valid values are +:deferred+ or +:immediate+.
|
|
146
|
+
#
|
|
147
|
+
# See https://www.postgresql.org/docs/current/sql-set-constraints.html
|
|
148
|
+
def set_constraints(deferred, *constraints)
|
|
149
|
+
unless %i[deferred immediate].include?(deferred)
|
|
150
|
+
raise ArgumentError, "deferred must be :deferred or :immediate"
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
constraints = if constraints.empty?
|
|
154
|
+
"ALL"
|
|
155
|
+
else
|
|
156
|
+
constraints.map { |c| quote_table_name(c) }.join(", ")
|
|
157
|
+
end
|
|
158
|
+
execute("SET CONSTRAINTS #{constraints} #{deferred.to_s.upcase}")
|
|
164
159
|
end
|
|
165
160
|
|
|
166
161
|
private
|
|
167
|
-
|
|
168
|
-
|
|
162
|
+
IDLE_TRANSACTION_STATUSES = [PG::PQTRANS_IDLE, PG::PQTRANS_INTRANS, PG::PQTRANS_INERROR]
|
|
163
|
+
private_constant :IDLE_TRANSACTION_STATUSES
|
|
164
|
+
|
|
165
|
+
def cancel_any_running_query
|
|
166
|
+
return if @raw_connection.nil? || IDLE_TRANSACTION_STATUSES.include?(@raw_connection.transaction_status)
|
|
167
|
+
|
|
168
|
+
@raw_connection.cancel
|
|
169
|
+
@raw_connection.block
|
|
170
|
+
rescue PG::Error
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def execute_batch(statements, name = nil)
|
|
174
|
+
execute(combine_multi_statements(statements))
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def build_truncate_statements(table_names)
|
|
178
|
+
["TRUNCATE TABLE #{table_names.map(&method(:quote_table_name)).join(", ")}"]
|
|
169
179
|
end
|
|
170
180
|
|
|
171
181
|
# Returns the current ID of a table's sequence.
|
|
172
182
|
def last_insert_id_result(sequence_name)
|
|
173
|
-
|
|
183
|
+
internal_exec_query("SELECT currval(#{quote(sequence_name)})", "SQL")
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def returning_column_values(result)
|
|
187
|
+
result.rows.first
|
|
174
188
|
end
|
|
175
189
|
|
|
176
190
|
def suppress_composite_primary_key(pk)
|
|
177
191
|
pk unless pk.is_a?(Array)
|
|
178
192
|
end
|
|
193
|
+
|
|
194
|
+
def handle_warnings(sql)
|
|
195
|
+
@notice_receiver_sql_warnings.each do |warning|
|
|
196
|
+
next if warning_ignored?(warning)
|
|
197
|
+
|
|
198
|
+
warning.sql = sql
|
|
199
|
+
ActiveRecord.db_warnings_action.call(warning)
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def warning_ignored?(warning)
|
|
204
|
+
["WARNING", "ERROR", "FATAL", "PANIC"].exclude?(warning.level) || super
|
|
205
|
+
end
|
|
179
206
|
end
|
|
180
207
|
end
|
|
181
208
|
end
|
|
@@ -65,7 +65,7 @@ module ActiveRecord
|
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
def map(value, &block)
|
|
68
|
-
value.map(&block)
|
|
68
|
+
value.map { |v| subtype.map(v, &block) }
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
def changed_in_place?(raw_old_value, new_value)
|
|
@@ -77,7 +77,6 @@ module ActiveRecord
|
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
private
|
|
80
|
-
|
|
81
80
|
def type_cast_array(value, method)
|
|
82
81
|
if value.is_a?(::Array)
|
|
83
82
|
value.map { |item| type_cast_array(item, method) }
|
|
@@ -12,24 +12,28 @@ module ActiveRecord
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def type_cast_for_schema(value)
|
|
15
|
-
subnet_mask = value.instance_variable_get(:@mask_addr)
|
|
16
|
-
|
|
17
15
|
# If the subnet mask is equal to /32, don't output it
|
|
18
|
-
if
|
|
16
|
+
if value.prefix == 32
|
|
19
17
|
"\"#{value}\""
|
|
20
18
|
else
|
|
21
|
-
"\"#{value}/#{
|
|
19
|
+
"\"#{value}/#{value.prefix}\""
|
|
22
20
|
end
|
|
23
21
|
end
|
|
24
22
|
|
|
25
23
|
def serialize(value)
|
|
26
24
|
if IPAddr === value
|
|
27
|
-
"#{value}/#{value.
|
|
25
|
+
"#{value}/#{value.prefix}"
|
|
28
26
|
else
|
|
29
27
|
value
|
|
30
28
|
end
|
|
31
29
|
end
|
|
32
30
|
|
|
31
|
+
# TODO: Remove when IPAddr#== compares IPAddr#prefix. See
|
|
32
|
+
# https://github.com/ruby/ipaddr/issues/21
|
|
33
|
+
def changed?(old_value, new_value, _new_value_before_type_cast)
|
|
34
|
+
!old_value.eql?(new_value) || !old_value.nil? && old_value.prefix != new_value.prefix
|
|
35
|
+
end
|
|
36
|
+
|
|
33
37
|
def cast_value(value)
|
|
34
38
|
if value.nil?
|
|
35
39
|
nil
|
|
@@ -10,12 +10,20 @@ module ActiveRecord
|
|
|
10
10
|
when "infinity" then ::Float::INFINITY
|
|
11
11
|
when "-infinity" then -::Float::INFINITY
|
|
12
12
|
when / BC$/
|
|
13
|
-
|
|
14
|
-
super(value.
|
|
13
|
+
value = value.sub(/^\d+/) { |year| format("%04d", -year.to_i + 1) }
|
|
14
|
+
super(value.delete_suffix!(" BC"))
|
|
15
15
|
else
|
|
16
16
|
super
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
|
+
|
|
20
|
+
def type_cast_for_schema(value)
|
|
21
|
+
case value
|
|
22
|
+
when ::Float::INFINITY then "::Float::INFINITY"
|
|
23
|
+
when -::Float::INFINITY then "-::Float::INFINITY"
|
|
24
|
+
else super
|
|
25
|
+
end
|
|
26
|
+
end
|
|
19
27
|
end
|
|
20
28
|
end
|
|
21
29
|
end
|
|
@@ -10,12 +10,25 @@ module ActiveRecord
|
|
|
10
10
|
when "infinity" then ::Float::INFINITY
|
|
11
11
|
when "-infinity" then -::Float::INFINITY
|
|
12
12
|
when / BC$/
|
|
13
|
-
|
|
14
|
-
super(value.
|
|
13
|
+
value = value.sub(/^\d+/) { |year| format("%04d", -year.to_i + 1) }
|
|
14
|
+
super(value.delete_suffix!(" BC"))
|
|
15
15
|
else
|
|
16
16
|
super
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
|
+
|
|
20
|
+
def type_cast_for_schema(value)
|
|
21
|
+
case value
|
|
22
|
+
when ::Float::INFINITY then "::Float::INFINITY"
|
|
23
|
+
when -::Float::INFINITY then "-::Float::INFINITY"
|
|
24
|
+
else super
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
protected
|
|
29
|
+
def real_type_unless_aliased(real_type)
|
|
30
|
+
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.datetime_type == real_type ? :datetime : real_type
|
|
31
|
+
end
|
|
19
32
|
end
|
|
20
33
|
end
|
|
21
34
|
end
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "strscan"
|
|
4
|
+
|
|
3
5
|
module ActiveRecord
|
|
4
6
|
module ConnectionAdapters
|
|
5
7
|
module PostgreSQL
|
|
6
8
|
module OID # :nodoc:
|
|
7
9
|
class Hstore < Type::Value # :nodoc:
|
|
10
|
+
ERROR = "Invalid Hstore document: %s"
|
|
11
|
+
|
|
8
12
|
include ActiveModel::Type::Helpers::Mutable
|
|
9
13
|
|
|
10
14
|
def type
|
|
@@ -12,15 +16,56 @@ module ActiveRecord
|
|
|
12
16
|
end
|
|
13
17
|
|
|
14
18
|
def deserialize(value)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
return value unless value.is_a?(::String)
|
|
20
|
+
|
|
21
|
+
scanner = StringScanner.new(value)
|
|
22
|
+
hash = {}
|
|
23
|
+
|
|
24
|
+
until scanner.eos?
|
|
25
|
+
unless scanner.skip(/"/)
|
|
26
|
+
raise(ArgumentError, ERROR % scanner.string.inspect)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
unless key = scanner.scan(/^(\\[\\"]|[^\\"])*?(?=")/)
|
|
30
|
+
raise(ArgumentError, ERROR % scanner.string.inspect)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
unless scanner.skip(/"=>?/)
|
|
34
|
+
raise(ArgumentError, ERROR % scanner.string.inspect)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
if scanner.scan(/NULL/)
|
|
38
|
+
value = nil
|
|
39
|
+
else
|
|
40
|
+
unless scanner.skip(/"/)
|
|
41
|
+
raise(ArgumentError, ERROR % scanner.string.inspect)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
unless value = scanner.scan(/^(\\[\\"]|[^\\"])*?(?=")/)
|
|
45
|
+
raise(ArgumentError, ERROR % scanner.string.inspect)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
unless scanner.skip(/"/)
|
|
49
|
+
raise(ArgumentError, ERROR % scanner.string.inspect)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
key.gsub!('\"', '"')
|
|
54
|
+
key.gsub!("\\\\", "\\")
|
|
55
|
+
|
|
56
|
+
if value
|
|
57
|
+
value.gsub!('\"', '"')
|
|
58
|
+
value.gsub!("\\\\", "\\")
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
hash[key] = value
|
|
62
|
+
|
|
63
|
+
unless scanner.skip(/, /) || scanner.eos?
|
|
64
|
+
raise(ArgumentError, ERROR % scanner.string.inspect)
|
|
65
|
+
end
|
|
23
66
|
end
|
|
67
|
+
|
|
68
|
+
hash
|
|
24
69
|
end
|
|
25
70
|
|
|
26
71
|
def serialize(value)
|
|
@@ -46,13 +91,6 @@ module ActiveRecord
|
|
|
46
91
|
end
|
|
47
92
|
|
|
48
93
|
private
|
|
49
|
-
|
|
50
|
-
HstorePair = begin
|
|
51
|
-
quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/
|
|
52
|
-
unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/
|
|
53
|
-
/(#{quoted_string}|#{unquoted_string})\s*=>\s*(#{quoted_string}|#{unquoted_string})/
|
|
54
|
-
end
|
|
55
|
-
|
|
56
94
|
def escape_hstore(value)
|
|
57
95
|
if value.nil?
|
|
58
96
|
"NULL"
|