activerecord 7.0.8.7 → 7.2.2.1
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 +631 -1944
- data/MIT-LICENSE +1 -1
- data/README.rdoc +29 -29
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +2 -2
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +35 -12
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +23 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +22 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +26 -14
- data/lib/active_record/associations/collection_proxy.rb +29 -11
- 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 +21 -14
- data/lib/active_record/associations/has_many_through_association.rb +17 -7
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +30 -27
- data/lib/active_record/associations/join_dependency.rb +10 -10
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +33 -8
- data/lib/active_record/associations/preloader/branch.rb +7 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/preloader.rb +13 -10
- data/lib/active_record/associations/singular_association.rb +7 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +354 -485
- data/lib/active_record/attribute_assignment.rb +0 -4
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +53 -35
- data/lib/active_record/attribute_methods/primary_key.rb +45 -25
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +8 -7
- data/lib/active_record/attribute_methods/serialization.rb +131 -32
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -6
- data/lib/active_record/attribute_methods/write.rb +6 -6
- data/lib/active_record/attribute_methods.rb +148 -33
- data/lib/active_record/attributes.rb +64 -50
- data/lib/active_record/autosave_association.rb +69 -37
- data/lib/active_record/base.rb +9 -5
- data/lib/active_record/callbacks.rb +11 -25
- 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 -42
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +123 -131
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +4 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +323 -88
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +160 -45
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +217 -63
- data/lib/active_record/connection_adapters/abstract/quoting.rb +72 -63
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -11
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +307 -129
- data/lib/active_record/connection_adapters/abstract/transaction.rb +367 -75
- data/lib/active_record/connection_adapters/abstract_adapter.rb +510 -111
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +278 -125
- data/lib/active_record/connection_adapters/column.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +26 -139
- data/lib/active_record/connection_adapters/mysql/quoting.rb +53 -54
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +6 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +25 -13
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +101 -68
- data/lib/active_record/connection_adapters/pool_config.rb +20 -10
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +14 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +100 -43
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- 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 +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +65 -61
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +151 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +370 -63
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +367 -201
- data/lib/active_record/connection_adapters/schema_cache.rb +302 -79
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +60 -43
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +45 -46
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +14 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +50 -8
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +290 -110
- 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 +124 -1
- data/lib/active_record/connection_handling.rb +96 -104
- data/lib/active_record/core.rb +251 -176
- data/lib/active_record/counter_cache.rb +68 -34
- data/lib/active_record/database_configurations/connection_url_resolver.rb +8 -3
- data/lib/active_record/database_configurations/database_config.rb +26 -5
- data/lib/active_record/database_configurations/hash_config.rb +52 -34
- data/lib/active_record/database_configurations/url_config.rb +37 -12
- data/lib/active_record/database_configurations.rb +87 -34
- data/lib/active_record/delegated_type.rb +39 -10
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +3 -1
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
- data/lib/active_record/encryption/config.rb +25 -1
- data/lib/active_record/encryption/configurable.rb +12 -19
- data/lib/active_record/encryption/context.rb +10 -3
- data/lib/active_record/encryption/contexts.rb +5 -1
- data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
- data/lib/active_record/encryption/encryptable_record.rb +45 -21
- data/lib/active_record/encryption/encrypted_attribute_type.rb +47 -12
- data/lib/active_record/encryption/encryptor.rb +18 -3
- data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -69
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +3 -3
- data/lib/active_record/encryption/key_generator.rb +12 -1
- data/lib/active_record/encryption/key_provider.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +6 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption/scheme.rb +22 -21
- data/lib/active_record/encryption.rb +3 -0
- data/lib/active_record/enum.rb +129 -28
- data/lib/active_record/errors.rb +151 -31
- data/lib/active_record/explain.rb +21 -12
- 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 +29 -8
- data/lib/active_record/fixtures.rb +167 -97
- data/lib/active_record/future_result.rb +47 -8
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +34 -18
- data/lib/active_record/insert_all.rb +72 -22
- data/lib/active_record/integration.rb +11 -8
- data/lib/active_record/internal_metadata.rb +124 -20
- data/lib/active_record/locking/optimistic.rb +8 -7
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +18 -22
- 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 +4 -0
- data/lib/active_record/middleware/database_selector.rb +6 -8
- data/lib/active_record/middleware/shard_selector.rb +3 -1
- data/lib/active_record/migration/command_recorder.rb +106 -8
- data/lib/active_record/migration/compatibility.rb +147 -5
- 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/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +234 -117
- data/lib/active_record/model_schema.rb +90 -102
- data/lib/active_record/nested_attributes.rb +48 -11
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +168 -339
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +18 -25
- data/lib/active_record/query_logs.rb +92 -52
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +33 -8
- data/lib/active_record/railtie.rb +129 -85
- data/lib/active_record/railties/controller_runtime.rb +22 -7
- data/lib/active_record/railties/databases.rake +145 -154
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +32 -5
- data/lib/active_record/reflection.rb +267 -69
- data/lib/active_record/relation/batches/batch_enumerator.rb +20 -5
- data/lib/active_record/relation/batches.rb +198 -63
- data/lib/active_record/relation/calculations.rb +250 -93
- data/lib/active_record/relation/delegation.rb +30 -19
- data/lib/active_record/relation/finder_methods.rb +93 -18
- data/lib/active_record/relation/merger.rb +6 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +18 -3
- 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 +28 -16
- data/lib/active_record/relation/query_attribute.rb +2 -1
- data/lib/active_record/relation/query_methods.rb +576 -107
- data/lib/active_record/relation/record_fetch_warning.rb +3 -0
- data/lib/active_record/relation/spawn_methods.rb +5 -4
- data/lib/active_record/relation/where_clause.rb +7 -19
- data/lib/active_record/relation.rb +580 -90
- data/lib/active_record/result.rb +49 -48
- data/lib/active_record/runtime_registry.rb +63 -1
- data/lib/active_record/sanitization.rb +70 -25
- data/lib/active_record/schema.rb +8 -7
- data/lib/active_record/schema_dumper.rb +63 -14
- data/lib/active_record/schema_migration.rb +75 -24
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +3 -2
- data/lib/active_record/scoping.rb +2 -1
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/signed_id.rb +27 -6
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/store.rb +8 -8
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +1 -1
- data/lib/active_record/tasks/database_tasks.rb +190 -118
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +16 -13
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
- data/lib/active_record/test_fixtures.rb +170 -155
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +31 -17
- 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 +106 -24
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +1 -3
- data/lib/active_record/type/time.rb +4 -0
- 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 +9 -3
- 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 +61 -11
- data/lib/active_record/validations.rb +12 -5
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +247 -33
- data/lib/arel/alias_predication.rb +1 -1
- 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/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -7
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +115 -5
- data/lib/arel/nodes/sql_literal.rb +13 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes.rb +6 -2
- data/lib/arel/predications.rb +3 -1
- data/lib/arel/select_manager.rb +1 -1
- data/lib/arel/table.rb +9 -5
- data/lib/arel/tree_manager.rb +8 -3
- data/lib/arel/update_manager.rb +2 -1
- data/lib/arel/visitors/dot.rb +1 -0
- data/lib/arel/visitors/mysql.rb +17 -5
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +112 -34
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +21 -3
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- 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
- metadata +54 -12
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
@@ -6,19 +6,6 @@ module ActiveRecord
|
|
6
6
|
|
7
7
|
class_attribute :backtrace_cleaner, default: ActiveSupport::BacktraceCleaner.new
|
8
8
|
|
9
|
-
def self.runtime=(value)
|
10
|
-
ActiveRecord::RuntimeRegistry.sql_runtime = value
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.runtime
|
14
|
-
ActiveRecord::RuntimeRegistry.sql_runtime ||= 0
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.reset_runtime
|
18
|
-
rt, self.runtime = runtime, 0
|
19
|
-
rt
|
20
|
-
end
|
21
|
-
|
22
9
|
def strict_loading_violation(event)
|
23
10
|
debug do
|
24
11
|
owner = event.payload[:owner]
|
@@ -26,11 +13,9 @@ module ActiveRecord
|
|
26
13
|
color(reflection.strict_loading_violation_message(owner), RED)
|
27
14
|
end
|
28
15
|
end
|
16
|
+
subscribe_log_level :strict_loading_violation, :debug
|
29
17
|
|
30
18
|
def sql(event)
|
31
|
-
self.class.runtime += event.duration
|
32
|
-
return unless logger.debug?
|
33
|
-
|
34
19
|
payload = event.payload
|
35
20
|
|
36
21
|
return if IGNORE_PAYLOAD_NAMES.include?(payload[:name])
|
@@ -66,10 +51,11 @@ module ActiveRecord
|
|
66
51
|
end
|
67
52
|
|
68
53
|
name = colorize_payload_name(name, payload[:name])
|
69
|
-
sql = color(sql, sql_color(sql), true) if colorize_logging
|
54
|
+
sql = color(sql, sql_color(sql), bold: true) if colorize_logging
|
70
55
|
|
71
56
|
debug " #{name} #{sql}#{binds}"
|
72
57
|
end
|
58
|
+
subscribe_log_level :sql, :debug
|
73
59
|
|
74
60
|
private
|
75
61
|
def type_casted_binds(casted_binds)
|
@@ -93,9 +79,9 @@ module ActiveRecord
|
|
93
79
|
|
94
80
|
def colorize_payload_name(name, payload_name)
|
95
81
|
if payload_name.blank? || payload_name == "SQL" # SQL vs Model Load/Exists
|
96
|
-
color(name, MAGENTA, true)
|
82
|
+
color(name, MAGENTA, bold: true)
|
97
83
|
else
|
98
|
-
color(name, CYAN, true)
|
84
|
+
color(name, CYAN, bold: true)
|
99
85
|
end
|
100
86
|
end
|
101
87
|
|
@@ -133,15 +119,25 @@ module ActiveRecord
|
|
133
119
|
end
|
134
120
|
|
135
121
|
def log_query_source
|
136
|
-
source =
|
122
|
+
source = query_source_location
|
137
123
|
|
138
124
|
if source
|
139
125
|
logger.debug(" ↳ #{source}")
|
140
126
|
end
|
141
127
|
end
|
142
128
|
|
143
|
-
|
144
|
-
|
129
|
+
if Thread.respond_to?(:each_caller_location)
|
130
|
+
def query_source_location
|
131
|
+
Thread.each_caller_location do |location|
|
132
|
+
frame = backtrace_cleaner.clean_frame(location)
|
133
|
+
return frame if frame
|
134
|
+
end
|
135
|
+
nil
|
136
|
+
end
|
137
|
+
else
|
138
|
+
def query_source_location
|
139
|
+
backtrace_cleaner.clean(caller(1).lazy).first
|
140
|
+
end
|
145
141
|
end
|
146
142
|
|
147
143
|
def filter(name, value)
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Marshalling
|
5
|
+
@format_version = 6.1
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_reader :format_version
|
9
|
+
|
10
|
+
def format_version=(version)
|
11
|
+
case version
|
12
|
+
when 6.1
|
13
|
+
Methods.remove_method(:marshal_dump) if Methods.method_defined?(:marshal_dump)
|
14
|
+
when 7.1
|
15
|
+
Methods.alias_method(:marshal_dump, :_marshal_dump_7_1)
|
16
|
+
else
|
17
|
+
raise ArgumentError, "Unknown marshalling format: #{version.inspect}"
|
18
|
+
end
|
19
|
+
@format_version = version
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module Methods
|
24
|
+
def _marshal_dump_7_1
|
25
|
+
payload = [attributes_for_database, new_record?]
|
26
|
+
|
27
|
+
cached_associations = self.class.reflect_on_all_associations.select do |reflection|
|
28
|
+
if association_cached?(reflection.name)
|
29
|
+
association = association(reflection.name)
|
30
|
+
association.loaded? || association.target.present?
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
unless cached_associations.empty?
|
35
|
+
payload << cached_associations.map do |reflection|
|
36
|
+
[reflection.name, association(reflection.name).target]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
payload
|
41
|
+
end
|
42
|
+
|
43
|
+
def marshal_load(state)
|
44
|
+
attributes_from_database, new_record, associations = state
|
45
|
+
|
46
|
+
attributes = self.class.attributes_builder.build_from_database(attributes_from_database)
|
47
|
+
init_with_attributes(attributes, new_record)
|
48
|
+
|
49
|
+
if associations
|
50
|
+
associations.each do |name, target|
|
51
|
+
association(name).target = target
|
52
|
+
rescue ActiveRecord::AssociationNotFoundError
|
53
|
+
# the association no longer exist, we can just skip it.
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module MessagePack # :nodoc:
|
5
|
+
FORMAT_VERSION = 1
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def dump(input)
|
9
|
+
encoder = Encoder.new
|
10
|
+
[FORMAT_VERSION, encoder.encode(input), encoder.entries]
|
11
|
+
end
|
12
|
+
|
13
|
+
def load(dumped)
|
14
|
+
format_version, top_level, entries = dumped
|
15
|
+
unless format_version == FORMAT_VERSION
|
16
|
+
raise "Invalid format version: #{format_version.inspect}"
|
17
|
+
end
|
18
|
+
Decoder.new(entries).decode(top_level)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module Extensions
|
23
|
+
extend self
|
24
|
+
|
25
|
+
def install(registry)
|
26
|
+
registry.register_type 119, ActiveModel::Type::Binary::Data,
|
27
|
+
packer: :to_s,
|
28
|
+
unpacker: :new
|
29
|
+
|
30
|
+
registry.register_type 120, ActiveRecord::Base,
|
31
|
+
packer: method(:write_record),
|
32
|
+
unpacker: method(:read_record),
|
33
|
+
recursive: true
|
34
|
+
end
|
35
|
+
|
36
|
+
def write_record(record, packer)
|
37
|
+
packer.write(ActiveRecord::MessagePack.dump(record))
|
38
|
+
end
|
39
|
+
|
40
|
+
def read_record(unpacker)
|
41
|
+
ActiveRecord::MessagePack.load(unpacker.read)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Encoder
|
46
|
+
attr_reader :entries
|
47
|
+
|
48
|
+
def initialize
|
49
|
+
@entries = []
|
50
|
+
@refs = {}.compare_by_identity
|
51
|
+
end
|
52
|
+
|
53
|
+
def encode(input)
|
54
|
+
if input.is_a?(Array)
|
55
|
+
input.map { |record| encode_record(record) }
|
56
|
+
elsif input
|
57
|
+
encode_record(input)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def encode_record(record)
|
62
|
+
ref = @refs[record]
|
63
|
+
|
64
|
+
if !ref
|
65
|
+
ref = @refs[record] = @entries.size
|
66
|
+
@entries << build_entry(record)
|
67
|
+
add_cached_associations(record, @entries.last)
|
68
|
+
end
|
69
|
+
|
70
|
+
ref
|
71
|
+
end
|
72
|
+
|
73
|
+
def build_entry(record)
|
74
|
+
[
|
75
|
+
ActiveSupport::MessagePack::Extensions.dump_class(record.class),
|
76
|
+
record.attributes_for_database,
|
77
|
+
record.new_record?
|
78
|
+
]
|
79
|
+
end
|
80
|
+
|
81
|
+
def add_cached_associations(record, entry)
|
82
|
+
record.class.normalized_reflections.each_value do |reflection|
|
83
|
+
if record.association_cached?(reflection.name) && record.association(reflection.name).loaded?
|
84
|
+
entry << reflection.name << encode(record.association(reflection.name).target)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class Decoder
|
91
|
+
def initialize(entries)
|
92
|
+
@records = entries.map { |entry| build_record(entry) }
|
93
|
+
@records.zip(entries) { |record, entry| resolve_cached_associations(record, entry) }
|
94
|
+
end
|
95
|
+
|
96
|
+
def decode(ref)
|
97
|
+
if ref.is_a?(Array)
|
98
|
+
ref.map { |r| @records[r] }
|
99
|
+
elsif ref
|
100
|
+
@records[ref]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def build_record(entry)
|
105
|
+
class_name, attributes_hash, is_new_record, * = entry
|
106
|
+
klass = ActiveSupport::MessagePack::Extensions.load_class(class_name)
|
107
|
+
attributes = klass.attributes_builder.build_from_database(attributes_hash)
|
108
|
+
klass.allocate.init_with_attributes(attributes, is_new_record)
|
109
|
+
end
|
110
|
+
|
111
|
+
def resolve_cached_associations(record, entry)
|
112
|
+
i = 3 # entry == [class_name, attributes_hash, is_new_record, *associations]
|
113
|
+
while i < entry.length
|
114
|
+
begin
|
115
|
+
record.association(entry[i]).target = decode(entry[i + 1])
|
116
|
+
rescue ActiveRecord::AssociationNotFoundError
|
117
|
+
# The association no longer exists, so just skip it.
|
118
|
+
end
|
119
|
+
i += 2
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -48,6 +48,10 @@ module ActiveRecord
|
|
48
48
|
context.save(response)
|
49
49
|
end
|
50
50
|
|
51
|
+
def reading_request?(request)
|
52
|
+
request.get? || request.head?
|
53
|
+
end
|
54
|
+
|
51
55
|
private
|
52
56
|
def read_from_primary(&blk)
|
53
57
|
ActiveRecord::Base.connected_to(role: ActiveRecord.writing_role, prevent_writes: true) do
|
@@ -4,8 +4,10 @@ require "active_record/middleware/database_selector/resolver"
|
|
4
4
|
|
5
5
|
module ActiveRecord
|
6
6
|
module Middleware
|
7
|
+
# = Database Selector \Middleware
|
8
|
+
#
|
7
9
|
# The DatabaseSelector Middleware provides a framework for automatically
|
8
|
-
# swapping from the primary to the replica database connection. Rails
|
10
|
+
# swapping from the primary to the replica database connection. \Rails
|
9
11
|
# provides a basic framework to determine when to swap and allows for
|
10
12
|
# applications to write custom strategy classes to override the default
|
11
13
|
# behavior.
|
@@ -15,14 +17,14 @@ module ActiveRecord
|
|
15
17
|
# resolver context class that sets a value that helps the resolver class
|
16
18
|
# decide when to switch.
|
17
19
|
#
|
18
|
-
# Rails default middleware uses the request's session to set a timestamp
|
20
|
+
# \Rails default middleware uses the request's session to set a timestamp
|
19
21
|
# that informs the application when to read from a primary or read from a
|
20
22
|
# replica.
|
21
23
|
#
|
22
24
|
# To use the DatabaseSelector in your application with default settings,
|
23
25
|
# run the provided generator.
|
24
26
|
#
|
25
|
-
# bin/rails g active_record:multi_db
|
27
|
+
# $ bin/rails g active_record:multi_db
|
26
28
|
#
|
27
29
|
# This will create a file named +config/initializers/multi_db.rb+ with the
|
28
30
|
# following contents:
|
@@ -71,7 +73,7 @@ module ActiveRecord
|
|
71
73
|
context = context_klass.call(request)
|
72
74
|
resolver = resolver_klass.call(context, options)
|
73
75
|
|
74
|
-
response = if reading_request?(request)
|
76
|
+
response = if resolver.reading_request?(request)
|
75
77
|
resolver.read(&blk)
|
76
78
|
else
|
77
79
|
resolver.write(&blk)
|
@@ -80,10 +82,6 @@ module ActiveRecord
|
|
80
82
|
resolver.update_context(response)
|
81
83
|
response
|
82
84
|
end
|
83
|
-
|
84
|
-
def reading_request?(request)
|
85
|
-
request.get? || request.head?
|
86
|
-
end
|
87
85
|
end
|
88
86
|
end
|
89
87
|
end
|
@@ -2,8 +2,10 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
module Middleware
|
5
|
+
# = Shard Selector \Middleware
|
6
|
+
#
|
5
7
|
# The ShardSelector Middleware provides a framework for automatically
|
6
|
-
# swapping shards. Rails provides a basic framework to determine which
|
8
|
+
# swapping shards. \Rails provides a basic framework to determine which
|
7
9
|
# shard to switch to and allows for applications to write custom strategies
|
8
10
|
# for swapping if needed.
|
9
11
|
#
|
@@ -2,13 +2,17 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
class Migration
|
5
|
-
#
|
5
|
+
# = \Migration Command Recorder
|
6
|
+
#
|
7
|
+
# +ActiveRecord::Migration::CommandRecorder+ records commands done during
|
6
8
|
# a migration and knows how to reverse those commands. The CommandRecorder
|
7
9
|
# knows how to invert the following commands:
|
8
10
|
#
|
9
11
|
# * add_column
|
10
12
|
# * add_foreign_key
|
11
13
|
# * add_check_constraint
|
14
|
+
# * add_exclusion_constraint
|
15
|
+
# * add_unique_constraint
|
12
16
|
# * add_index
|
13
17
|
# * add_reference
|
14
18
|
# * add_timestamps
|
@@ -16,9 +20,11 @@ module ActiveRecord
|
|
16
20
|
# * change_column_null
|
17
21
|
# * change_column_comment (must supply a +:from+ and +:to+ option)
|
18
22
|
# * change_table_comment (must supply a +:from+ and +:to+ option)
|
23
|
+
# * create_enum
|
19
24
|
# * create_join_table
|
20
25
|
# * create_table
|
21
26
|
# * disable_extension
|
27
|
+
# * drop_enum (must supply a list of values)
|
22
28
|
# * drop_join_table
|
23
29
|
# * drop_table (must supply a block)
|
24
30
|
# * enable_extension
|
@@ -26,10 +32,14 @@ module ActiveRecord
|
|
26
32
|
# * remove_columns (must supply a +:type+ option)
|
27
33
|
# * remove_foreign_key (must supply a second table)
|
28
34
|
# * remove_check_constraint
|
35
|
+
# * remove_exclusion_constraint
|
36
|
+
# * remove_unique_constraint
|
29
37
|
# * remove_index
|
30
38
|
# * remove_reference
|
31
39
|
# * remove_timestamps
|
32
40
|
# * rename_column
|
41
|
+
# * rename_enum (must supply a +:to+ option)
|
42
|
+
# * rename_enum_value (must supply a +:from+ and +:to+ option)
|
33
43
|
# * rename_index
|
34
44
|
# * rename_table
|
35
45
|
class CommandRecorder
|
@@ -41,7 +51,10 @@ module ActiveRecord
|
|
41
51
|
:change_column, :execute, :remove_columns, :change_column_null,
|
42
52
|
:add_foreign_key, :remove_foreign_key,
|
43
53
|
:change_column_comment, :change_table_comment,
|
44
|
-
:add_check_constraint, :remove_check_constraint
|
54
|
+
:add_check_constraint, :remove_check_constraint,
|
55
|
+
:add_exclusion_constraint, :remove_exclusion_constraint,
|
56
|
+
:add_unique_constraint, :remove_unique_constraint,
|
57
|
+
:create_enum, :drop_enum, :rename_enum, :add_enum_value, :rename_enum_value,
|
45
58
|
]
|
46
59
|
include JoinTable
|
47
60
|
|
@@ -117,7 +130,15 @@ module ActiveRecord
|
|
117
130
|
alias :remove_belongs_to :remove_reference
|
118
131
|
|
119
132
|
def change_table(table_name, **options) # :nodoc:
|
120
|
-
|
133
|
+
if delegate.supports_bulk_alter? && options[:bulk]
|
134
|
+
recorder = self.class.new(self.delegate)
|
135
|
+
recorder.reverting = @reverting
|
136
|
+
yield recorder.delegate.update_table_definition(table_name, recorder)
|
137
|
+
commands = recorder.commands
|
138
|
+
@commands << [:change_table, [table_name], -> t { bulk_change_table(table_name, commands) }]
|
139
|
+
else
|
140
|
+
yield delegate.update_table_definition(table_name, self)
|
141
|
+
end
|
121
142
|
end
|
122
143
|
|
123
144
|
def replay(migration)
|
@@ -139,7 +160,10 @@ module ActiveRecord
|
|
139
160
|
add_reference: :remove_reference,
|
140
161
|
add_foreign_key: :remove_foreign_key,
|
141
162
|
add_check_constraint: :remove_check_constraint,
|
142
|
-
|
163
|
+
add_exclusion_constraint: :remove_exclusion_constraint,
|
164
|
+
add_unique_constraint: :remove_unique_constraint,
|
165
|
+
enable_extension: :disable_extension,
|
166
|
+
create_enum: :drop_enum
|
143
167
|
}.each do |cmd, inv|
|
144
168
|
[[inv, cmd], [cmd, inv]].uniq.each do |method, inverse|
|
145
169
|
class_eval <<-EOV, __FILE__, __LINE__ + 1
|
@@ -164,7 +188,17 @@ module ActiveRecord
|
|
164
188
|
[:transaction, args, invertions_proc]
|
165
189
|
end
|
166
190
|
|
191
|
+
def invert_create_table(args, &block)
|
192
|
+
if args.last.is_a?(Hash)
|
193
|
+
args.last.delete(:if_not_exists)
|
194
|
+
end
|
195
|
+
super
|
196
|
+
end
|
197
|
+
|
167
198
|
def invert_drop_table(args, &block)
|
199
|
+
if args.last.is_a?(Hash)
|
200
|
+
args.last.delete(:if_exists)
|
201
|
+
end
|
168
202
|
if args.size == 1 && block == nil
|
169
203
|
raise ActiveRecord::IrreversibleMigration, "To avoid mistakes, drop_table is only reversible if given options or a block (can be empty)."
|
170
204
|
end
|
@@ -172,7 +206,10 @@ module ActiveRecord
|
|
172
206
|
end
|
173
207
|
|
174
208
|
def invert_rename_table(args)
|
175
|
-
|
209
|
+
old_name, new_name, options = args
|
210
|
+
args = [new_name, old_name]
|
211
|
+
args << options if options
|
212
|
+
[:rename_table, args]
|
176
213
|
end
|
177
214
|
|
178
215
|
def invert_remove_column(args)
|
@@ -234,6 +271,11 @@ module ActiveRecord
|
|
234
271
|
[:change_column_null, args]
|
235
272
|
end
|
236
273
|
|
274
|
+
def invert_add_foreign_key(args)
|
275
|
+
args.last.delete(:validate) if args.last.is_a?(Hash)
|
276
|
+
super
|
277
|
+
end
|
278
|
+
|
237
279
|
def invert_remove_foreign_key(args)
|
238
280
|
options = args.extract_options!
|
239
281
|
from_table, to_table = args
|
@@ -268,24 +310,80 @@ module ActiveRecord
|
|
268
310
|
[:change_table_comment, [table, from: options[:to], to: options[:from]]]
|
269
311
|
end
|
270
312
|
|
313
|
+
def invert_add_check_constraint(args)
|
314
|
+
if (options = args.last).is_a?(Hash)
|
315
|
+
options.delete(:validate)
|
316
|
+
options[:if_exists] = options.delete(:if_not_exists) if options.key?(:if_not_exists)
|
317
|
+
end
|
318
|
+
super
|
319
|
+
end
|
320
|
+
|
271
321
|
def invert_remove_check_constraint(args)
|
272
322
|
raise ActiveRecord::IrreversibleMigration, "remove_check_constraint is only reversible if given an expression." if args.size < 2
|
323
|
+
|
324
|
+
if (options = args.last).is_a?(Hash)
|
325
|
+
options[:if_not_exists] = options.delete(:if_exists) if options.key?(:if_exists)
|
326
|
+
end
|
327
|
+
super
|
328
|
+
end
|
329
|
+
|
330
|
+
def invert_remove_exclusion_constraint(args)
|
331
|
+
raise ActiveRecord::IrreversibleMigration, "remove_exclusion_constraint is only reversible if given an expression." if args.size < 2
|
332
|
+
super
|
333
|
+
end
|
334
|
+
|
335
|
+
def invert_add_unique_constraint(args)
|
336
|
+
options = args.dup.extract_options!
|
337
|
+
|
338
|
+
raise ActiveRecord::IrreversibleMigration, "add_unique_constraint is not reversible if given an using_index." if options[:using_index]
|
273
339
|
super
|
274
340
|
end
|
275
341
|
|
342
|
+
def invert_remove_unique_constraint(args)
|
343
|
+
_table, columns = args.dup.tap(&:extract_options!)
|
344
|
+
|
345
|
+
raise ActiveRecord::IrreversibleMigration, "remove_unique_constraint is only reversible if given an column_name." if columns.blank?
|
346
|
+
super
|
347
|
+
end
|
348
|
+
|
349
|
+
def invert_drop_enum(args)
|
350
|
+
_enum, values = args.dup.tap(&:extract_options!)
|
351
|
+
raise ActiveRecord::IrreversibleMigration, "drop_enum is only reversible if given a list of enum values." unless values
|
352
|
+
super
|
353
|
+
end
|
354
|
+
|
355
|
+
def invert_rename_enum(args)
|
356
|
+
name, options = args
|
357
|
+
|
358
|
+
unless options.is_a?(Hash) && options.has_key?(:to)
|
359
|
+
raise ActiveRecord::IrreversibleMigration, "rename_enum is only reversible if given a :to option."
|
360
|
+
end
|
361
|
+
|
362
|
+
[:rename_enum, [options[:to], to: name]]
|
363
|
+
end
|
364
|
+
|
365
|
+
def invert_rename_enum_value(args)
|
366
|
+
type_name, options = args
|
367
|
+
|
368
|
+
unless options.is_a?(Hash) && options.has_key?(:from) && options.has_key?(:to)
|
369
|
+
raise ActiveRecord::IrreversibleMigration, "rename_enum_value is only reversible if given a :from and :to option."
|
370
|
+
end
|
371
|
+
|
372
|
+
[:rename_enum_value, [type_name, from: options[:to], to: options[:from]]]
|
373
|
+
end
|
374
|
+
|
276
375
|
def respond_to_missing?(method, _)
|
277
376
|
super || delegate.respond_to?(method)
|
278
377
|
end
|
279
378
|
|
280
379
|
# Forwards any missing method call to the \target.
|
281
|
-
def method_missing(method,
|
380
|
+
def method_missing(method, ...)
|
282
381
|
if delegate.respond_to?(method)
|
283
|
-
delegate.public_send(method,
|
382
|
+
delegate.public_send(method, ...)
|
284
383
|
else
|
285
384
|
super
|
286
385
|
end
|
287
386
|
end
|
288
|
-
ruby2_keywords(:method_missing)
|
289
387
|
end
|
290
388
|
end
|
291
389
|
end
|