activerecord 6.1.7 → 7.2.2
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 +616 -1290
- data/MIT-LICENSE +1 -1
- data/README.rdoc +31 -31
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +17 -14
- data/lib/active_record/association_relation.rb +2 -12
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +60 -21
- data/lib/active_record/associations/association_scope.rb +17 -12
- data/lib/active_record/associations/belongs_to_association.rb +37 -11
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -4
- data/lib/active_record/associations/builder/association.rb +11 -5
- data/lib/active_record/associations/builder/belongs_to.rb +41 -14
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +4 -4
- data/lib/active_record/associations/builder/singular_association.rb +6 -2
- data/lib/active_record/associations/collection_association.rb +46 -36
- data/lib/active_record/associations/collection_proxy.rb +44 -16
- 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 +10 -3
- data/lib/active_record/associations/has_many_association.rb +29 -19
- data/lib/active_record/associations/has_many_through_association.rb +19 -8
- data/lib/active_record/associations/has_one_association.rb +20 -10
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +30 -27
- data/lib/active_record/associations/join_dependency.rb +28 -20
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +212 -53
- 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 +50 -16
- data/lib/active_record/associations/preloader.rb +50 -121
- data/lib/active_record/associations/singular_association.rb +15 -3
- data/lib/active_record/associations/through_association.rb +25 -14
- data/lib/active_record/associations.rb +429 -522
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -5
- data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +73 -22
- data/lib/active_record/attribute_methods/primary_key.rb +47 -27
- data/lib/active_record/attribute_methods/query.rb +31 -19
- data/lib/active_record/attribute_methods/read.rb +14 -11
- data/lib/active_record/attribute_methods/serialization.rb +174 -37
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +15 -9
- data/lib/active_record/attribute_methods/write.rb +12 -15
- data/lib/active_record/attribute_methods.rb +164 -52
- data/lib/active_record/attributes.rb +57 -54
- data/lib/active_record/autosave_association.rb +74 -57
- data/lib/active_record/base.rb +27 -5
- data/lib/active_record/callbacks.rb +19 -35
- 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 -46
- 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 +325 -604
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -60
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +230 -64
- data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -131
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +378 -143
- data/lib/active_record/connection_adapters/abstract/transaction.rb +361 -76
- data/lib/active_record/connection_adapters/abstract_adapter.rb +624 -163
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +348 -165
- data/lib/active_record/connection_adapters/column.rb +13 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +29 -130
- data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -55
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +45 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +107 -68
- data/lib/active_record/connection_adapters/pool_config.rb +26 -16
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +114 -54
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
- 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 +14 -4
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +137 -104
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +173 -3
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +403 -77
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +520 -253
- data/lib/active_record/connection_adapters/schema_cache.rb +326 -102
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +78 -55
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +68 -54
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- 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 +66 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +372 -130
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- 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 +130 -6
- data/lib/active_record/connection_handling.rb +132 -146
- data/lib/active_record/core.rb +310 -253
- data/lib/active_record/counter_cache.rb +68 -34
- data/lib/active_record/database_configurations/connection_url_resolver.rb +10 -4
- data/lib/active_record/database_configurations/database_config.rb +34 -10
- data/lib/active_record/database_configurations/hash_config.rb +107 -31
- data/lib/active_record/database_configurations/url_config.rb +38 -13
- data/lib/active_record/database_configurations.rb +96 -60
- data/lib/active_record/delegated_type.rb +90 -20
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +4 -2
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +3 -3
- 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 +170 -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 +170 -62
- data/lib/active_record/errors.rb +210 -27
- data/lib/active_record/explain.rb +21 -12
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +70 -14
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +179 -112
- data/lib/active_record/future_result.rb +178 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +85 -31
- data/lib/active_record/insert_all.rb +148 -32
- data/lib/active_record/integration.rb +14 -10
- data/lib/active_record/internal_metadata.rb +123 -23
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +43 -27
- data/lib/active_record/locking/pessimistic.rb +15 -6
- data/lib/active_record/log_subscriber.rb +41 -29
- 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.rb +10 -10
- data/lib/active_record/middleware/database_selector.rb +23 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +113 -16
- data/lib/active_record/migration/compatibility.rb +235 -46
- 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 -1
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +374 -177
- data/lib/active_record/model_schema.rb +145 -158
- data/lib/active_record/nested_attributes.rb +61 -23
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +282 -283
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +18 -25
- data/lib/active_record/query_logs.rb +189 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +44 -9
- data/lib/active_record/railtie.rb +229 -71
- data/lib/active_record/railties/controller_runtime.rb +25 -11
- data/lib/active_record/railties/databases.rake +189 -256
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +41 -3
- data/lib/active_record/reflection.rb +332 -103
- data/lib/active_record/relation/batches/batch_enumerator.rb +38 -9
- data/lib/active_record/relation/batches.rb +200 -65
- data/lib/active_record/relation/calculations.rb +301 -112
- data/lib/active_record/relation/delegation.rb +33 -22
- data/lib/active_record/relation/finder_methods.rb +123 -52
- data/lib/active_record/relation/merger.rb +26 -19
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +38 -4
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +29 -22
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +870 -163
- data/lib/active_record/relation/record_fetch_warning.rb +10 -9
- data/lib/active_record/relation/spawn_methods.rb +7 -6
- data/lib/active_record/relation/where_clause.rb +15 -36
- data/lib/active_record/relation.rb +736 -145
- data/lib/active_record/result.rb +67 -54
- data/lib/active_record/runtime_registry.rb +71 -13
- data/lib/active_record/sanitization.rb +84 -34
- data/lib/active_record/schema.rb +39 -23
- data/lib/active_record/schema_dumper.rb +90 -31
- data/lib/active_record/schema_migration.rb +74 -23
- data/lib/active_record/scoping/default.rb +72 -15
- data/lib/active_record/scoping/named.rb +6 -13
- data/lib/active_record/scoping.rb +65 -34
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +30 -9
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/store.rb +10 -10
- data/lib/active_record/suppressor.rb +13 -15
- data/lib/active_record/table_metadata.rb +7 -3
- data/lib/active_record/tasks/database_tasks.rb +288 -149
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
- data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +173 -155
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +32 -19
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +12 -7
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +118 -41
- data/lib/active_record/translation.rb +3 -5
- data/lib/active_record/type/adapter_specific_registry.rb +32 -14
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +9 -7
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +13 -7
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +65 -15
- data/lib/active_record/validations.rb +12 -5
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +444 -32
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/collectors/bind.rb +2 -0
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -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 +6 -7
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +12 -13
- 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/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/insert_statement.rb +2 -2
- 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 +115 -5
- 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 +13 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +7 -2
- data/lib/arel/predications.rb +14 -4
- data/lib/arel/select_manager.rb +11 -5
- data/lib/arel/table.rb +9 -6
- data/lib/arel/tree_manager.rb +8 -15
- data/lib/arel/update_manager.rb +20 -5
- data/lib/arel/visitors/dot.rb +81 -90
- data/lib/arel/visitors/mysql.rb +23 -5
- data/lib/arel/visitors/postgresql.rb +1 -22
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +170 -36
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +23 -4
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- 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 +103 -17
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -67
data/lib/active_record/result.rb
CHANGED
@@ -2,11 +2,13 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
###
|
5
|
+
# = Active Record \Result
|
6
|
+
#
|
5
7
|
# This class encapsulates a result returned from calling
|
6
8
|
# {#exec_query}[rdoc-ref:ConnectionAdapters::DatabaseStatements#exec_query]
|
7
9
|
# on any database connection adapter. For example:
|
8
10
|
#
|
9
|
-
# result = ActiveRecord::Base.
|
11
|
+
# result = ActiveRecord::Base.lease_connection.exec_query('SELECT id, title, body FROM posts')
|
10
12
|
# result # => #<ActiveRecord::Result:0xdeadbeef>
|
11
13
|
#
|
12
14
|
# # Get the column names of the result:
|
@@ -36,11 +38,22 @@ module ActiveRecord
|
|
36
38
|
|
37
39
|
attr_reader :columns, :rows, :column_types
|
38
40
|
|
39
|
-
def
|
40
|
-
|
41
|
+
def self.empty(async: false) # :nodoc:
|
42
|
+
if async
|
43
|
+
EMPTY_ASYNC
|
44
|
+
else
|
45
|
+
EMPTY
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def initialize(columns, rows, column_types = nil)
|
50
|
+
# We freeze the strings to prevent them getting duped when
|
51
|
+
# used as keys in ActiveRecord::Base's @attributes hash
|
52
|
+
@columns = columns.each(&:-@).freeze
|
41
53
|
@rows = rows
|
42
54
|
@hash_rows = nil
|
43
|
-
@column_types = column_types
|
55
|
+
@column_types = column_types || EMPTY_HASH
|
56
|
+
@column_indexes = nil
|
44
57
|
end
|
45
58
|
|
46
59
|
# Returns true if this result set includes the column named +name+
|
@@ -57,19 +70,14 @@ module ActiveRecord
|
|
57
70
|
# row as parameter.
|
58
71
|
#
|
59
72
|
# Returns an +Enumerator+ if no block is given.
|
60
|
-
def each
|
73
|
+
def each(&block)
|
61
74
|
if block_given?
|
62
|
-
hash_rows.each
|
75
|
+
hash_rows.each(&block)
|
63
76
|
else
|
64
77
|
hash_rows.to_enum { @rows.size }
|
65
78
|
end
|
66
79
|
end
|
67
80
|
|
68
|
-
alias :map! :map
|
69
|
-
alias :collect! :map
|
70
|
-
deprecate "map!": :map
|
71
|
-
deprecate "collect!": :map
|
72
|
-
|
73
81
|
# Returns true if there are no records, otherwise false.
|
74
82
|
def empty?
|
75
83
|
rows.empty?
|
@@ -91,6 +99,14 @@ module ActiveRecord
|
|
91
99
|
n ? hash_rows.last(n) : hash_rows.last
|
92
100
|
end
|
93
101
|
|
102
|
+
def result # :nodoc:
|
103
|
+
self
|
104
|
+
end
|
105
|
+
|
106
|
+
def cancel # :nodoc:
|
107
|
+
self
|
108
|
+
end
|
109
|
+
|
94
110
|
def cast_values(type_overrides = {}) # :nodoc:
|
95
111
|
if columns.one?
|
96
112
|
# Separated to avoid allocating an array per row
|
@@ -98,7 +114,7 @@ module ActiveRecord
|
|
98
114
|
type = if type_overrides.is_a?(Array)
|
99
115
|
type_overrides.first
|
100
116
|
else
|
101
|
-
column_type(columns.first, type_overrides)
|
117
|
+
column_type(columns.first, 0, type_overrides)
|
102
118
|
end
|
103
119
|
|
104
120
|
rows.map do |(value)|
|
@@ -108,7 +124,7 @@ module ActiveRecord
|
|
108
124
|
types = if type_overrides.is_a?(Array)
|
109
125
|
type_overrides
|
110
126
|
else
|
111
|
-
columns.map { |name| column_type(name, type_overrides) }
|
127
|
+
columns.map.with_index { |name, i| column_type(name, i, type_overrides) }
|
112
128
|
end
|
113
129
|
|
114
130
|
rows.map do |values|
|
@@ -118,58 +134,55 @@ module ActiveRecord
|
|
118
134
|
end
|
119
135
|
|
120
136
|
def initialize_copy(other)
|
121
|
-
@columns = columns
|
137
|
+
@columns = columns
|
122
138
|
@rows = rows.dup
|
123
139
|
@column_types = column_types.dup
|
124
140
|
@hash_rows = nil
|
125
141
|
end
|
126
142
|
|
143
|
+
def freeze # :nodoc:
|
144
|
+
hash_rows.freeze
|
145
|
+
super
|
146
|
+
end
|
147
|
+
|
148
|
+
def column_indexes # :nodoc:
|
149
|
+
@column_indexes ||= begin
|
150
|
+
index = 0
|
151
|
+
hash = {}
|
152
|
+
length = columns.length
|
153
|
+
while index < length
|
154
|
+
hash[columns[index]] = index
|
155
|
+
index += 1
|
156
|
+
end
|
157
|
+
hash
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
127
161
|
private
|
128
|
-
def column_type(name, type_overrides
|
162
|
+
def column_type(name, index, type_overrides)
|
129
163
|
type_overrides.fetch(name) do
|
130
|
-
column_types.fetch(
|
164
|
+
column_types.fetch(index) do
|
165
|
+
column_types.fetch(name, Type.default_value)
|
166
|
+
end
|
131
167
|
end
|
132
168
|
end
|
133
169
|
|
134
170
|
def hash_rows
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
length = columns.length
|
141
|
-
template = nil
|
142
|
-
|
143
|
-
@rows.map { |row|
|
144
|
-
if template
|
145
|
-
# We use transform_values to build subsequent rows from the
|
146
|
-
# hash of the first row. This is faster because we avoid any
|
147
|
-
# reallocs and in Ruby 2.7+ avoid hashing entirely.
|
148
|
-
index = -1
|
149
|
-
template.transform_values do
|
150
|
-
row[index += 1]
|
151
|
-
end
|
152
|
-
else
|
153
|
-
# In the past we used Hash[columns.zip(row)]
|
154
|
-
# though elegant, the verbose way is much more efficient
|
155
|
-
# both time and memory wise cause it avoids a big array allocation
|
156
|
-
# this method is called a lot and needs to be micro optimised
|
157
|
-
hash = {}
|
158
|
-
|
159
|
-
index = 0
|
160
|
-
while index < length
|
161
|
-
hash[columns[index]] = row[index]
|
162
|
-
index += 1
|
163
|
-
end
|
164
|
-
|
165
|
-
# It's possible to select the same column twice, in which case
|
166
|
-
# we can't use a template
|
167
|
-
template = hash if hash.length == length
|
168
|
-
|
169
|
-
hash
|
170
|
-
end
|
171
|
-
}
|
172
|
-
end
|
171
|
+
# We use transform_values to rows.
|
172
|
+
# This is faster because we avoid any reallocs and avoid hashing entirely.
|
173
|
+
@hash_rows ||= @rows.map do |row|
|
174
|
+
column_indexes.transform_values { |index| row[index] }
|
175
|
+
end
|
173
176
|
end
|
177
|
+
|
178
|
+
empty_array = [].freeze
|
179
|
+
EMPTY_HASH = {}.freeze
|
180
|
+
private_constant :EMPTY_HASH
|
181
|
+
|
182
|
+
EMPTY = new(empty_array, empty_array, EMPTY_HASH).freeze
|
183
|
+
private_constant :EMPTY
|
184
|
+
|
185
|
+
EMPTY_ASYNC = FutureResult.wrap(EMPTY).freeze
|
186
|
+
private_constant :EMPTY_ASYNC
|
174
187
|
end
|
175
188
|
end
|
@@ -1,24 +1,82 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/per_thread_registry"
|
4
|
-
|
5
3
|
module ActiveRecord
|
6
4
|
# This is a thread locals registry for Active Record. For example:
|
7
5
|
#
|
8
|
-
# ActiveRecord::RuntimeRegistry.
|
9
|
-
#
|
10
|
-
# returns the connection handler local to the current thread.
|
6
|
+
# ActiveRecord::RuntimeRegistry.sql_runtime
|
11
7
|
#
|
12
|
-
#
|
13
|
-
|
14
|
-
|
15
|
-
|
8
|
+
# returns the connection handler local to the current unit of execution (either thread of fiber).
|
9
|
+
module RuntimeRegistry # :nodoc:
|
10
|
+
extend self
|
11
|
+
|
12
|
+
def sql_runtime
|
13
|
+
ActiveSupport::IsolatedExecutionState[:active_record_sql_runtime] ||= 0.0
|
14
|
+
end
|
15
|
+
|
16
|
+
def sql_runtime=(runtime)
|
17
|
+
ActiveSupport::IsolatedExecutionState[:active_record_sql_runtime] = runtime
|
18
|
+
end
|
19
|
+
|
20
|
+
def async_sql_runtime
|
21
|
+
ActiveSupport::IsolatedExecutionState[:active_record_async_sql_runtime] ||= 0.0
|
22
|
+
end
|
16
23
|
|
17
|
-
|
24
|
+
def async_sql_runtime=(runtime)
|
25
|
+
ActiveSupport::IsolatedExecutionState[:active_record_async_sql_runtime] = runtime
|
26
|
+
end
|
27
|
+
|
28
|
+
def queries_count
|
29
|
+
ActiveSupport::IsolatedExecutionState[:active_record_queries_count] ||= 0
|
30
|
+
end
|
31
|
+
|
32
|
+
def queries_count=(count)
|
33
|
+
ActiveSupport::IsolatedExecutionState[:active_record_queries_count] = count
|
34
|
+
end
|
35
|
+
|
36
|
+
def cached_queries_count
|
37
|
+
ActiveSupport::IsolatedExecutionState[:active_record_cached_queries_count] ||= 0
|
38
|
+
end
|
18
39
|
|
19
|
-
|
20
|
-
|
21
|
-
class_eval %{ def self.#{val}=(x); instance.#{val}=x; end }, __FILE__, __LINE__
|
40
|
+
def cached_queries_count=(count)
|
41
|
+
ActiveSupport::IsolatedExecutionState[:active_record_cached_queries_count] = count
|
22
42
|
end
|
43
|
+
|
44
|
+
def reset
|
45
|
+
reset_runtimes
|
46
|
+
reset_queries_count
|
47
|
+
reset_cached_queries_count
|
48
|
+
end
|
49
|
+
|
50
|
+
def reset_runtimes
|
51
|
+
rt, self.sql_runtime = sql_runtime, 0.0
|
52
|
+
self.async_sql_runtime = 0.0
|
53
|
+
rt
|
54
|
+
end
|
55
|
+
|
56
|
+
def reset_queries_count
|
57
|
+
qc = queries_count
|
58
|
+
self.queries_count = 0
|
59
|
+
qc
|
60
|
+
end
|
61
|
+
|
62
|
+
def reset_cached_queries_count
|
63
|
+
qc = cached_queries_count
|
64
|
+
self.cached_queries_count = 0
|
65
|
+
qc
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
ActiveSupport::Notifications.monotonic_subscribe("sql.active_record") do |name, start, finish, id, payload|
|
71
|
+
unless ["SCHEMA", "TRANSACTION"].include?(payload[:name])
|
72
|
+
ActiveRecord::RuntimeRegistry.queries_count += 1
|
73
|
+
ActiveRecord::RuntimeRegistry.cached_queries_count += 1 if payload[:cached]
|
74
|
+
end
|
75
|
+
|
76
|
+
runtime = (finish - start) * 1_000.0
|
77
|
+
|
78
|
+
if payload[:async]
|
79
|
+
ActiveRecord::RuntimeRegistry.async_sql_runtime += (runtime - payload[:lock_wait])
|
23
80
|
end
|
81
|
+
ActiveRecord::RuntimeRegistry.sql_runtime += runtime
|
24
82
|
end
|
@@ -5,8 +5,8 @@ module ActiveRecord
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
module ClassMethods
|
8
|
-
# Accepts an array
|
9
|
-
#
|
8
|
+
# Accepts an array of SQL conditions and sanitizes them into a valid
|
9
|
+
# SQL fragment for a WHERE clause.
|
10
10
|
#
|
11
11
|
# sanitize_sql_for_conditions(["name=? and group_id=?", "foo'bar", 4])
|
12
12
|
# # => "name='foo''bar' and group_id=4"
|
@@ -17,8 +17,19 @@ module ActiveRecord
|
|
17
17
|
# sanitize_sql_for_conditions(["name='%s' and group_id='%s'", "foo'bar", 4])
|
18
18
|
# # => "name='foo''bar' and group_id='4'"
|
19
19
|
#
|
20
|
+
# This method will NOT sanitize an SQL string since it won't contain
|
21
|
+
# any conditions in it and will return the string as is.
|
22
|
+
#
|
20
23
|
# sanitize_sql_for_conditions("name='foo''bar' and group_id='4'")
|
21
24
|
# # => "name='foo''bar' and group_id='4'"
|
25
|
+
#
|
26
|
+
# Note that this sanitization method is not schema-aware, hence won't do any type casting
|
27
|
+
# and will directly use the database adapter's +quote+ method.
|
28
|
+
# For MySQL specifically this means that numeric parameters will be quoted as strings
|
29
|
+
# to prevent query manipulation attacks.
|
30
|
+
#
|
31
|
+
# sanitize_sql_for_conditions(["role = ?", 0])
|
32
|
+
# # => "role = '0'"
|
22
33
|
def sanitize_sql_for_conditions(condition)
|
23
34
|
return nil if condition.blank?
|
24
35
|
|
@@ -29,8 +40,8 @@ module ActiveRecord
|
|
29
40
|
end
|
30
41
|
alias :sanitize_sql :sanitize_sql_for_conditions
|
31
42
|
|
32
|
-
# Accepts an array
|
33
|
-
#
|
43
|
+
# Accepts an array or hash of SQL conditions and sanitizes them into
|
44
|
+
# a valid SQL fragment for a SET clause.
|
34
45
|
#
|
35
46
|
# sanitize_sql_for_assignment(["name=? and group_id=?", nil, 4])
|
36
47
|
# # => "name=NULL and group_id=4"
|
@@ -41,8 +52,19 @@ module ActiveRecord
|
|
41
52
|
# Post.sanitize_sql_for_assignment({ name: nil, group_id: 4 })
|
42
53
|
# # => "`posts`.`name` = NULL, `posts`.`group_id` = 4"
|
43
54
|
#
|
55
|
+
# This method will NOT sanitize an SQL string since it won't contain
|
56
|
+
# any conditions in it and will return the string as is.
|
57
|
+
#
|
44
58
|
# sanitize_sql_for_assignment("name=NULL and group_id='4'")
|
45
59
|
# # => "name=NULL and group_id='4'"
|
60
|
+
#
|
61
|
+
# Note that this sanitization method is not schema-aware, hence won't do any type casting
|
62
|
+
# and will directly use the database adapter's +quote+ method.
|
63
|
+
# For MySQL specifically this means that numeric parameters will be quoted as strings
|
64
|
+
# to prevent query manipulation attacks.
|
65
|
+
#
|
66
|
+
# sanitize_sql_for_assignment(["role = ?", 0])
|
67
|
+
# # => "role = '0'"
|
46
68
|
def sanitize_sql_for_assignment(assignments, default_table_name = table_name)
|
47
69
|
case assignments
|
48
70
|
when Array; sanitize_sql_array(assignments)
|
@@ -54,7 +76,7 @@ module ActiveRecord
|
|
54
76
|
# Accepts an array, or string of SQL conditions and sanitizes
|
55
77
|
# them into a valid SQL fragment for an ORDER clause.
|
56
78
|
#
|
57
|
-
# sanitize_sql_for_order(["field(id, ?)", [1,3,2]])
|
79
|
+
# sanitize_sql_for_order([Arel.sql("field(id, ?)"), [1,3,2]])
|
58
80
|
# # => "field(id, 1,3,2)"
|
59
81
|
#
|
60
82
|
# sanitize_sql_for_order("id ASC")
|
@@ -63,7 +85,7 @@ module ActiveRecord
|
|
63
85
|
if condition.is_a?(Array) && condition.first.to_s.include?("?")
|
64
86
|
disallow_raw_sql!(
|
65
87
|
[condition.first],
|
66
|
-
permit:
|
88
|
+
permit: adapter_class.column_name_with_order_matcher
|
67
89
|
)
|
68
90
|
|
69
91
|
# Ensure we aren't dealing with a subclass of String that might
|
@@ -92,26 +114,32 @@ module ActiveRecord
|
|
92
114
|
end
|
93
115
|
|
94
116
|
# Sanitizes a +string+ so that it is safe to use within an SQL
|
95
|
-
# LIKE statement. This method uses +escape_character+ to escape all
|
117
|
+
# LIKE statement. This method uses +escape_character+ to escape all
|
118
|
+
# occurrences of itself, "_" and "%".
|
96
119
|
#
|
97
|
-
# sanitize_sql_like("100%")
|
98
|
-
# # => "100\\%"
|
120
|
+
# sanitize_sql_like("100% true!")
|
121
|
+
# # => "100\\% true!"
|
99
122
|
#
|
100
123
|
# sanitize_sql_like("snake_cased_string")
|
101
124
|
# # => "snake\\_cased\\_string"
|
102
125
|
#
|
103
|
-
# sanitize_sql_like("100%", "!")
|
104
|
-
# # => "100!%"
|
126
|
+
# sanitize_sql_like("100% true!", "!")
|
127
|
+
# # => "100!% true!!"
|
105
128
|
#
|
106
129
|
# sanitize_sql_like("snake_cased_string", "!")
|
107
130
|
# # => "snake!_cased!_string"
|
108
131
|
def sanitize_sql_like(string, escape_character = "\\")
|
109
|
-
|
110
|
-
|
132
|
+
if string.include?(escape_character) && escape_character != "%" && escape_character != "_"
|
133
|
+
string = string.gsub(escape_character, '\0\0')
|
134
|
+
end
|
135
|
+
|
136
|
+
string.gsub(/(?=[%_])/, escape_character)
|
111
137
|
end
|
112
138
|
|
113
139
|
# Accepts an array of conditions. The array has each value
|
114
|
-
# sanitized and interpolated into the SQL statement.
|
140
|
+
# sanitized and interpolated into the SQL statement. If using named bind
|
141
|
+
# variables in SQL statements where a colon is required verbatim use a
|
142
|
+
# backslash to escape.
|
115
143
|
#
|
116
144
|
# sanitize_sql_array(["name=? and group_id=?", "foo'bar", 4])
|
117
145
|
# # => "name='foo''bar' and group_id=4"
|
@@ -119,77 +147,99 @@ module ActiveRecord
|
|
119
147
|
# sanitize_sql_array(["name=:name and group_id=:group_id", name: "foo'bar", group_id: 4])
|
120
148
|
# # => "name='foo''bar' and group_id=4"
|
121
149
|
#
|
150
|
+
# sanitize_sql_array(["TO_TIMESTAMP(:date, 'YYYY/MM/DD HH12\\:MI\\:SS')", date: "foo"])
|
151
|
+
# # => "TO_TIMESTAMP('foo', 'YYYY/MM/DD HH12:MI:SS')"
|
152
|
+
#
|
122
153
|
# sanitize_sql_array(["name='%s' and group_id='%s'", "foo'bar", 4])
|
123
154
|
# # => "name='foo''bar' and group_id='4'"
|
155
|
+
#
|
156
|
+
# Note that this sanitization method is not schema-aware, hence won't do any type casting
|
157
|
+
# and will directly use the database adapter's +quote+ method.
|
158
|
+
# For MySQL specifically this means that numeric parameters will be quoted as strings
|
159
|
+
# to prevent query manipulation attacks.
|
160
|
+
#
|
161
|
+
# sanitize_sql_array(["role = ?", 0])
|
162
|
+
# # => "role = '0'"
|
124
163
|
def sanitize_sql_array(ary)
|
125
164
|
statement, *values = ary
|
126
165
|
if values.first.is_a?(Hash) && /:\w+/.match?(statement)
|
127
|
-
|
166
|
+
with_connection do |c|
|
167
|
+
replace_named_bind_variables(c, statement, values.first)
|
168
|
+
end
|
128
169
|
elsif statement.include?("?")
|
129
|
-
|
170
|
+
with_connection do |c|
|
171
|
+
replace_bind_variables(c, statement, values)
|
172
|
+
end
|
130
173
|
elsif statement.blank?
|
131
174
|
statement
|
132
175
|
else
|
133
|
-
|
176
|
+
with_connection do |c|
|
177
|
+
statement % values.collect { |value| c.quote_string(value.to_s) }
|
178
|
+
end
|
134
179
|
end
|
135
180
|
end
|
136
181
|
|
137
|
-
def disallow_raw_sql!(args, permit:
|
182
|
+
def disallow_raw_sql!(args, permit: adapter_class.column_name_matcher) # :nodoc:
|
138
183
|
unexpected = nil
|
139
184
|
args.each do |arg|
|
140
|
-
next if arg.is_a?(Symbol) || Arel.arel_node?(arg) || permit.match?(arg.to_s)
|
185
|
+
next if arg.is_a?(Symbol) || Arel.arel_node?(arg) || permit.match?(arg.to_s.strip)
|
141
186
|
(unexpected ||= []) << arg
|
142
187
|
end
|
143
188
|
|
144
189
|
if unexpected
|
145
190
|
raise(ActiveRecord::UnknownAttributeReference,
|
146
|
-
"
|
147
|
-
|
191
|
+
"Dangerous query method (method whose arguments are used as raw " \
|
192
|
+
"SQL) called with non-attribute argument(s): " \
|
193
|
+
"#{unexpected.map(&:inspect).join(", ")}." \
|
194
|
+
"This method should not be called with user-provided values, such as request " \
|
195
|
+
"parameters or model attributes. Known-safe values can be passed " \
|
196
|
+
"by wrapping them in Arel.sql()."
|
148
197
|
)
|
149
198
|
end
|
150
199
|
end
|
151
200
|
|
152
201
|
private
|
153
|
-
def replace_bind_variables(statement, values)
|
202
|
+
def replace_bind_variables(connection, statement, values)
|
154
203
|
raise_if_bind_arity_mismatch(statement, statement.count("?"), values.size)
|
155
204
|
bound = values.dup
|
156
|
-
c = connection
|
157
205
|
statement.gsub(/\?/) do
|
158
|
-
replace_bind_variable(bound.shift
|
206
|
+
replace_bind_variable(connection, bound.shift)
|
159
207
|
end
|
160
208
|
end
|
161
209
|
|
162
|
-
def replace_bind_variable(
|
210
|
+
def replace_bind_variable(connection, value)
|
163
211
|
if ActiveRecord::Relation === value
|
164
212
|
value.to_sql
|
165
213
|
else
|
166
|
-
quote_bound_value(
|
214
|
+
quote_bound_value(connection, value)
|
167
215
|
end
|
168
216
|
end
|
169
217
|
|
170
|
-
def replace_named_bind_variables(statement, bind_vars)
|
171
|
-
statement.gsub(/(
|
172
|
-
if $1 == ":" # skip
|
218
|
+
def replace_named_bind_variables(connection, statement, bind_vars)
|
219
|
+
statement.gsub(/([:\\]?):([a-zA-Z]\w*)/) do |match|
|
220
|
+
if $1 == ":" # skip PostgreSQL casts
|
173
221
|
match # return the whole match
|
222
|
+
elsif $1 == "\\" # escaped literal colon
|
223
|
+
match[1..-1] # return match with escaping backlash char removed
|
174
224
|
elsif bind_vars.include?(match = $2.to_sym)
|
175
|
-
replace_bind_variable(bind_vars[match])
|
225
|
+
replace_bind_variable(connection, bind_vars[match])
|
176
226
|
else
|
177
227
|
raise PreparedStatementInvalid, "missing value for :#{match} in #{statement}"
|
178
228
|
end
|
179
229
|
end
|
180
230
|
end
|
181
231
|
|
182
|
-
def quote_bound_value(
|
232
|
+
def quote_bound_value(connection, value)
|
183
233
|
if value.respond_to?(:map) && !value.acts_like?(:string)
|
184
234
|
values = value.map { |v| v.respond_to?(:id_for_database) ? v.id_for_database : v }
|
185
235
|
if values.empty?
|
186
|
-
|
236
|
+
connection.quote(connection.cast_bound_value(nil))
|
187
237
|
else
|
188
|
-
values.map! { |v|
|
238
|
+
values.map! { |v| connection.quote(connection.cast_bound_value(v)) }.join(",")
|
189
239
|
end
|
190
240
|
else
|
191
241
|
value = value.id_for_database if value.respond_to?(:id_for_database)
|
192
|
-
|
242
|
+
connection.quote(connection.cast_bound_value(value))
|
193
243
|
end
|
194
244
|
end
|
195
245
|
|
data/lib/active_record/schema.rb
CHANGED
@@ -10,7 +10,7 @@ module ActiveRecord
|
|
10
10
|
#
|
11
11
|
# Usage:
|
12
12
|
#
|
13
|
-
# ActiveRecord::Schema.define do
|
13
|
+
# ActiveRecord::Schema[7.0].define do
|
14
14
|
# create_table :authors do |t|
|
15
15
|
# t.string :name, null: false
|
16
16
|
# end
|
@@ -30,32 +30,48 @@ module ActiveRecord
|
|
30
30
|
# ActiveRecord::Schema is only supported by database adapters that also
|
31
31
|
# support migrations, the two features being very similar.
|
32
32
|
class Schema < Migration::Current
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
33
|
+
module Definition
|
34
|
+
extend ActiveSupport::Concern
|
35
|
+
|
36
|
+
module ClassMethods
|
37
|
+
# Eval the given block. All methods available to the current connection
|
38
|
+
# adapter are available within the block, so you can easily use the
|
39
|
+
# database definition DSL to build up your schema (
|
40
|
+
# {create_table}[rdoc-ref:ConnectionAdapters::SchemaStatements#create_table],
|
41
|
+
# {add_index}[rdoc-ref:ConnectionAdapters::SchemaStatements#add_index], etc.).
|
42
|
+
#
|
43
|
+
# The +info+ hash is optional, and if given is used to define metadata
|
44
|
+
# about the current schema (currently, only the schema's version):
|
45
|
+
#
|
46
|
+
# ActiveRecord::Schema[7.0].define(version: 2038_01_19_000001) do
|
47
|
+
# ...
|
48
|
+
# end
|
49
|
+
def define(info = {}, &block)
|
50
|
+
new.define(info, &block)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def define(info, &block) # :nodoc:
|
55
|
+
connection_pool.with_connection do |connection|
|
56
|
+
instance_eval(&block)
|
48
57
|
|
49
|
-
|
50
|
-
|
58
|
+
connection_pool.schema_migration.create_table
|
59
|
+
if info[:version].present?
|
60
|
+
connection.assume_migrated_upto_version(info[:version])
|
61
|
+
end
|
51
62
|
|
52
|
-
|
53
|
-
|
54
|
-
connection.assume_migrated_upto_version(info[:version])
|
63
|
+
connection_pool.internal_metadata.create_table_and_set_flags(connection_pool.migration_context.current_environment)
|
64
|
+
end
|
55
65
|
end
|
66
|
+
end
|
67
|
+
|
68
|
+
include Definition
|
56
69
|
|
57
|
-
|
58
|
-
|
70
|
+
def self.[](version)
|
71
|
+
@class_for_version ||= {}
|
72
|
+
@class_for_version[version] ||= Class.new(Migration::Compatibility.find(version)) do
|
73
|
+
include Definition
|
74
|
+
end
|
59
75
|
end
|
60
76
|
end
|
61
77
|
end
|