activerecord 6.0.0 → 6.1.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1178 -600
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- data/lib/active_record/aggregations.rb +5 -6
- data/lib/active_record/association_relation.rb +30 -10
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +55 -29
- data/lib/active_record/associations/association_scope.rb +19 -15
- data/lib/active_record/associations/belongs_to_association.rb +23 -10
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
- data/lib/active_record/associations/builder/association.rb +32 -5
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -3
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +25 -8
- data/lib/active_record/associations/collection_proxy.rb +14 -7
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -3
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +39 -16
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/join_dependency.rb +77 -42
- data/lib/active_record/associations/preloader/association.rb +51 -25
- data/lib/active_record/associations/preloader/through_association.rb +2 -2
- data/lib/active_record/associations/preloader.rb +13 -8
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +120 -13
- data/lib/active_record/attribute_assignment.rb +10 -9
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
- data/lib/active_record/attribute_methods/dirty.rb +3 -13
- data/lib/active_record/attribute_methods/primary_key.rb +6 -4
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -12
- data/lib/active_record/attribute_methods/serialization.rb +11 -6
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +12 -21
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attributes.rb +33 -9
- data/lib/active_record/autosave_association.rb +63 -44
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +153 -24
- data/lib/active_record/coders/yaml_column.rb +12 -3
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +202 -138
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +87 -38
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +5 -10
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +152 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +141 -52
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +267 -105
- data/lib/active_record/connection_adapters/abstract/transaction.rb +94 -36
- data/lib/active_record/connection_adapters/abstract_adapter.rb +76 -79
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -115
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +30 -36
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +17 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
- data/lib/active_record/connection_adapters/pool_config.rb +73 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +21 -56
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
- 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 +2 -2
- 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 +24 -6
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +83 -65
- data/lib/active_record/connection_adapters/schema_cache.rb +106 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +38 -12
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -57
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_adapters.rb +52 -0
- data/lib/active_record/connection_handling.rb +219 -81
- data/lib/active_record/core.rb +268 -71
- data/lib/active_record/counter_cache.rb +4 -1
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -41
- data/lib/active_record/database_configurations.rb +124 -85
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +2 -3
- data/lib/active_record/enum.rb +80 -38
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -5
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -3
- data/lib/active_record/fixture_set/table_rows.rb +0 -1
- data/lib/active_record/fixtures.rb +58 -12
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +40 -21
- data/lib/active_record/insert_all.rb +43 -10
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +16 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +33 -18
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +28 -9
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +14 -14
- data/lib/active_record/middleware/database_selector.rb +4 -2
- data/lib/active_record/migration/command_recorder.rb +53 -45
- data/lib/active_record/migration/compatibility.rb +71 -20
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +115 -85
- data/lib/active_record/model_schema.rb +120 -15
- data/lib/active_record/nested_attributes.rb +2 -5
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +50 -46
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +12 -7
- data/lib/active_record/railtie.rb +65 -45
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/databases.rake +280 -99
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +77 -63
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -32
- data/lib/active_record/relation/calculations.rb +106 -45
- data/lib/active_record/relation/delegation.rb +9 -7
- data/lib/active_record/relation/finder_methods.rb +55 -17
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +27 -26
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +59 -40
- data/lib/active_record/relation/query_methods.rb +344 -181
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -8
- data/lib/active_record/relation/where_clause.rb +111 -62
- data/lib/active_record/relation.rb +116 -82
- data/lib/active_record/result.rb +41 -34
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +2 -8
- data/lib/active_record/scoping/default.rb +1 -4
- data/lib/active_record/scoping/named.rb +7 -18
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +20 -4
- data/lib/active_record/store.rb +3 -3
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +42 -36
- data/lib/active_record/tasks/database_tasks.rb +140 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +79 -16
- data/lib/active_record/timestamp.rb +4 -7
- data/lib/active_record/touch_later.rb +20 -21
- data/lib/active_record/transactions.rb +26 -73
- data/lib/active_record/type/adapter_specific_registry.rb +2 -5
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +6 -3
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +8 -2
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record.rb +7 -13
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +76 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/predications.rb +17 -24
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors/dot.rb +14 -3
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -5
- data/lib/arel/visitors/sqlite.rb +0 -1
- data/lib/arel/visitors/to_sql.rb +89 -79
- data/lib/arel/visitors/visitor.rb +0 -1
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +15 -12
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -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 +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
- data/lib/rails/generators/active_record/migration.rb +6 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +27 -24
- 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/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
@@ -60,6 +60,15 @@ module ActiveRecord
|
|
60
60
|
self.class.locking_enabled?
|
61
61
|
end
|
62
62
|
|
63
|
+
def increment!(*, **) #:nodoc:
|
64
|
+
super.tap do
|
65
|
+
if locking_enabled?
|
66
|
+
self[self.class.locking_column] += 1
|
67
|
+
clear_attribute_change(self.class.locking_column)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
63
72
|
private
|
64
73
|
def _create_record(attribute_names = self.attribute_names)
|
65
74
|
if locking_enabled?
|
@@ -80,7 +89,10 @@ module ActiveRecord
|
|
80
89
|
|
81
90
|
begin
|
82
91
|
locking_column = self.class.locking_column
|
83
|
-
|
92
|
+
lock_attribute_was = @attributes[locking_column]
|
93
|
+
lock_value_for_database = _lock_value_for_database(locking_column)
|
94
|
+
|
95
|
+
attribute_names = attribute_names.dup if attribute_names.frozen?
|
84
96
|
attribute_names << locking_column
|
85
97
|
|
86
98
|
self[locking_column] += 1
|
@@ -88,7 +100,7 @@ module ActiveRecord
|
|
88
100
|
affected_rows = self.class._update_record(
|
89
101
|
attributes_with_values(attribute_names),
|
90
102
|
@primary_key => id_in_database,
|
91
|
-
locking_column =>
|
103
|
+
locking_column => lock_value_for_database
|
92
104
|
)
|
93
105
|
|
94
106
|
if affected_rows != 1
|
@@ -99,7 +111,7 @@ module ActiveRecord
|
|
99
111
|
|
100
112
|
# If something went wrong, revert the locking_column value.
|
101
113
|
rescue Exception
|
102
|
-
|
114
|
+
@attributes[locking_column] = lock_attribute_was
|
103
115
|
raise
|
104
116
|
end
|
105
117
|
end
|
@@ -111,7 +123,7 @@ module ActiveRecord
|
|
111
123
|
|
112
124
|
affected_rows = self.class._delete_record(
|
113
125
|
@primary_key => id_in_database,
|
114
|
-
locking_column =>
|
126
|
+
locking_column => _lock_value_for_database(locking_column)
|
115
127
|
)
|
116
128
|
|
117
129
|
if affected_rows != 1
|
@@ -121,6 +133,14 @@ module ActiveRecord
|
|
121
133
|
affected_rows
|
122
134
|
end
|
123
135
|
|
136
|
+
def _lock_value_for_database(locking_column)
|
137
|
+
if will_save_change_to_attribute?(locking_column)
|
138
|
+
@attributes[locking_column].value_for_database
|
139
|
+
else
|
140
|
+
@attributes[locking_column].original_value_for_database
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
124
144
|
module ClassMethods
|
125
145
|
DEFAULT_LOCKING_COLUMN = "lock_version"
|
126
146
|
|
@@ -155,21 +175,12 @@ module ActiveRecord
|
|
155
175
|
super
|
156
176
|
end
|
157
177
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
# created by the matcher would otherwise evaluate for `ActiveRecord::Base`, not the
|
162
|
-
# sub class being decorated. As such, changes to `lock_optimistically`, or
|
163
|
-
# `locking_column` would not be picked up.
|
164
|
-
def inherited(subclass)
|
165
|
-
subclass.class_eval do
|
166
|
-
is_lock_column = ->(name, _) { lock_optimistically && name == locking_column }
|
167
|
-
decorate_matching_attribute_types(is_lock_column, "_optimistic_locking") do |type|
|
168
|
-
LockingType.new(type)
|
169
|
-
end
|
170
|
-
end
|
171
|
-
super
|
178
|
+
def define_attribute(name, cast_type, **) # :nodoc:
|
179
|
+
if lock_optimistically && name == locking_column
|
180
|
+
cast_type = LockingType.new(cast_type)
|
172
181
|
end
|
182
|
+
super
|
183
|
+
end
|
173
184
|
end
|
174
185
|
end
|
175
186
|
|
@@ -177,6 +188,10 @@ module ActiveRecord
|
|
177
188
|
# `nil` values to `lock_version`, and not result in `ActiveRecord::StaleObjectError`
|
178
189
|
# during update record.
|
179
190
|
class LockingType < DelegateClass(Type::Value) # :nodoc:
|
191
|
+
def self.new(subtype)
|
192
|
+
self === subtype ? subtype : super
|
193
|
+
end
|
194
|
+
|
180
195
|
def deserialize(value)
|
181
196
|
super.to_i
|
182
197
|
end
|
@@ -53,8 +53,12 @@ module ActiveRecord
|
|
53
53
|
# end
|
54
54
|
#
|
55
55
|
# Database-specific information on row locking:
|
56
|
-
#
|
57
|
-
#
|
56
|
+
#
|
57
|
+
# [MySQL]
|
58
|
+
# https://dev.mysql.com/doc/refman/en/innodb-locking-reads.html
|
59
|
+
#
|
60
|
+
# [PostgreSQL]
|
61
|
+
# https://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE
|
58
62
|
module Pessimistic
|
59
63
|
# Obtain a row lock on this record. Reloads the record to obtain the requested
|
60
64
|
# lock. Pass an SQL locking clause to append the end of the SELECT statement
|
@@ -19,6 +19,16 @@ module ActiveRecord
|
|
19
19
|
rt
|
20
20
|
end
|
21
21
|
|
22
|
+
def strict_loading_violation(event)
|
23
|
+
debug do
|
24
|
+
owner = event.payload[:owner]
|
25
|
+
association = event.payload[:reflection].klass
|
26
|
+
name = event.payload[:reflection].name
|
27
|
+
|
28
|
+
color("Strict loading violation: #{owner} is marked for strict loading. The #{association} association named :#{name} cannot be lazily loaded.", RED)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
22
32
|
def sql(event)
|
23
33
|
self.class.runtime += event.duration
|
24
34
|
return unless logger.debug?
|
@@ -32,15 +42,19 @@ module ActiveRecord
|
|
32
42
|
sql = payload[:sql]
|
33
43
|
binds = nil
|
34
44
|
|
35
|
-
|
45
|
+
if payload[:binds]&.any?
|
36
46
|
casted_params = type_casted_binds(payload[:type_casted_binds])
|
37
|
-
|
38
|
-
|
39
|
-
|
47
|
+
|
48
|
+
binds = []
|
49
|
+
payload[:binds].each_with_index do |attr, i|
|
50
|
+
binds << render_bind(attr, casted_params[i])
|
51
|
+
end
|
52
|
+
binds = binds.inspect
|
53
|
+
binds.prepend(" ")
|
40
54
|
end
|
41
55
|
|
42
56
|
name = colorize_payload_name(name, payload[:name])
|
43
|
-
sql = color(sql, sql_color(sql), true)
|
57
|
+
sql = color(sql, sql_color(sql), true) if colorize_logging
|
44
58
|
|
45
59
|
debug " #{name} #{sql}#{binds}"
|
46
60
|
end
|
@@ -51,13 +65,18 @@ module ActiveRecord
|
|
51
65
|
end
|
52
66
|
|
53
67
|
def render_bind(attr, value)
|
54
|
-
|
68
|
+
case attr
|
69
|
+
when ActiveModel::Attribute
|
70
|
+
if attr.type.binary? && attr.value
|
71
|
+
value = "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
|
72
|
+
end
|
73
|
+
when Array
|
55
74
|
attr = attr.first
|
56
|
-
|
57
|
-
|
75
|
+
else
|
76
|
+
attr = nil
|
58
77
|
end
|
59
78
|
|
60
|
-
[attr
|
79
|
+
[attr&.name, value]
|
61
80
|
end
|
62
81
|
|
63
82
|
def colorize_payload_name(name, payload_name)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_record/middleware/database_selector/resolver/session"
|
4
|
+
require "active_support/core_ext/numeric/time"
|
4
5
|
|
5
6
|
module ActiveRecord
|
6
7
|
module Middleware
|
@@ -43,20 +44,21 @@ module ActiveRecord
|
|
43
44
|
write_to_primary(&blk)
|
44
45
|
end
|
45
46
|
|
46
|
-
|
47
|
+
def update_context(response)
|
48
|
+
context.save(response)
|
49
|
+
end
|
47
50
|
|
51
|
+
private
|
48
52
|
def read_from_primary(&blk)
|
49
|
-
ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role) do
|
50
|
-
|
51
|
-
|
52
|
-
yield
|
53
|
-
end
|
53
|
+
ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role, prevent_writes: true) do
|
54
|
+
instrumenter.instrument("database_selector.active_record.read_from_primary") do
|
55
|
+
yield
|
54
56
|
end
|
55
57
|
end
|
56
58
|
end
|
57
59
|
|
58
60
|
def read_from_replica(&blk)
|
59
|
-
ActiveRecord::Base.connected_to(role: ActiveRecord::Base.reading_role) do
|
61
|
+
ActiveRecord::Base.connected_to(role: ActiveRecord::Base.reading_role, prevent_writes: true) do
|
60
62
|
instrumenter.instrument("database_selector.active_record.read_from_replica") do
|
61
63
|
yield
|
62
64
|
end
|
@@ -64,13 +66,11 @@ module ActiveRecord
|
|
64
66
|
end
|
65
67
|
|
66
68
|
def write_to_primary(&blk)
|
67
|
-
ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role) do
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
context.update_last_write_timestamp
|
73
|
-
end
|
69
|
+
ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role, prevent_writes: false) do
|
70
|
+
instrumenter.instrument("database_selector.active_record.wrote_to_primary") do
|
71
|
+
yield
|
72
|
+
ensure
|
73
|
+
context.update_last_write_timestamp
|
74
74
|
end
|
75
75
|
end
|
76
76
|
end
|
@@ -55,16 +55,18 @@ module ActiveRecord
|
|
55
55
|
end
|
56
56
|
|
57
57
|
private
|
58
|
-
|
59
58
|
def select_database(request, &blk)
|
60
59
|
context = context_klass.call(request)
|
61
60
|
resolver = resolver_klass.call(context, options)
|
62
61
|
|
63
|
-
if reading_request?(request)
|
62
|
+
response = if reading_request?(request)
|
64
63
|
resolver.read(&blk)
|
65
64
|
else
|
66
65
|
resolver.write(&blk)
|
67
66
|
end
|
67
|
+
|
68
|
+
resolver.update_context(response)
|
69
|
+
response
|
68
70
|
end
|
69
71
|
|
70
72
|
def reading_request?(request)
|
@@ -8,6 +8,7 @@ module ActiveRecord
|
|
8
8
|
#
|
9
9
|
# * add_column
|
10
10
|
# * add_foreign_key
|
11
|
+
# * add_check_constraint
|
11
12
|
# * add_index
|
12
13
|
# * add_reference
|
13
14
|
# * add_timestamps
|
@@ -25,6 +26,7 @@ module ActiveRecord
|
|
25
26
|
# * remove_column (must supply a type)
|
26
27
|
# * remove_columns (must specify at least one column name or more)
|
27
28
|
# * remove_foreign_key (must supply a second table)
|
29
|
+
# * remove_check_constraint
|
28
30
|
# * remove_index
|
29
31
|
# * remove_reference
|
30
32
|
# * remove_timestamps
|
@@ -32,13 +34,15 @@ module ActiveRecord
|
|
32
34
|
# * rename_index
|
33
35
|
# * rename_table
|
34
36
|
class CommandRecorder
|
35
|
-
ReversibleAndIrreversibleMethods = [
|
37
|
+
ReversibleAndIrreversibleMethods = [
|
38
|
+
:create_table, :create_join_table, :rename_table, :add_column, :remove_column,
|
36
39
|
:rename_index, :rename_column, :add_index, :remove_index, :add_timestamps, :remove_timestamps,
|
37
40
|
:change_column_default, :add_reference, :remove_reference, :transaction,
|
38
41
|
:drop_join_table, :drop_table, :execute_block, :enable_extension, :disable_extension,
|
39
42
|
:change_column, :execute, :remove_columns, :change_column_null,
|
40
43
|
:add_foreign_key, :remove_foreign_key,
|
41
|
-
:change_column_comment, :change_table_comment
|
44
|
+
:change_column_comment, :change_table_comment,
|
45
|
+
:add_check_constraint, :remove_check_constraint
|
42
46
|
]
|
43
47
|
include JoinTable
|
44
48
|
|
@@ -84,6 +88,11 @@ module ActiveRecord
|
|
84
88
|
# recorder.inverse_of(:rename_table, [:old, :new])
|
85
89
|
# # => [:rename_table, [:new, :old]]
|
86
90
|
#
|
91
|
+
# If the inverse of a command requires several commands, returns array of commands.
|
92
|
+
#
|
93
|
+
# recorder.inverse_of(:remove_columns, [:some_table, :foo, :bar, type: :string])
|
94
|
+
# # => [[:add_column, :some_table, :foo, :string], [:add_column, :some_table, :bar, :string]]
|
95
|
+
#
|
87
96
|
# This method will raise an +IrreversibleMigration+ exception if it cannot
|
88
97
|
# invert the +command+.
|
89
98
|
def inverse_of(command, args, &block)
|
@@ -103,11 +112,12 @@ module ActiveRecord
|
|
103
112
|
record(:"#{method}", args, &block) # record(:create_table, args, &block)
|
104
113
|
end # end
|
105
114
|
EOV
|
115
|
+
ruby2_keywords(method) if respond_to?(:ruby2_keywords, true)
|
106
116
|
end
|
107
117
|
alias :add_belongs_to :add_reference
|
108
118
|
alias :remove_belongs_to :remove_reference
|
109
119
|
|
110
|
-
def change_table(table_name, options
|
120
|
+
def change_table(table_name, **options) # :nodoc:
|
111
121
|
yield delegate.update_table_definition(table_name, self)
|
112
122
|
end
|
113
123
|
|
@@ -118,7 +128,6 @@ module ActiveRecord
|
|
118
128
|
end
|
119
129
|
|
120
130
|
private
|
121
|
-
|
122
131
|
module StraightReversions # :nodoc:
|
123
132
|
private
|
124
133
|
{
|
@@ -126,8 +135,11 @@ module ActiveRecord
|
|
126
135
|
create_table: :drop_table,
|
127
136
|
create_join_table: :drop_join_table,
|
128
137
|
add_column: :remove_column,
|
138
|
+
add_index: :remove_index,
|
129
139
|
add_timestamps: :remove_timestamps,
|
130
140
|
add_reference: :remove_reference,
|
141
|
+
add_foreign_key: :remove_foreign_key,
|
142
|
+
add_check_constraint: :remove_check_constraint,
|
131
143
|
enable_extension: :disable_extension
|
132
144
|
}.each do |cmd, inv|
|
133
145
|
[[inv, cmd], [cmd, inv]].uniq.each do |method, inverse|
|
@@ -169,44 +181,49 @@ module ActiveRecord
|
|
169
181
|
super
|
170
182
|
end
|
171
183
|
|
184
|
+
def invert_remove_columns(args)
|
185
|
+
unless args[-1].is_a?(Hash) && args[-1].has_key?(:type)
|
186
|
+
raise ActiveRecord::IrreversibleMigration, "remove_columns is only reversible if given a type."
|
187
|
+
end
|
188
|
+
|
189
|
+
[:add_columns, args]
|
190
|
+
end
|
191
|
+
|
172
192
|
def invert_rename_index(args)
|
173
|
-
|
193
|
+
table_name, old_name, new_name = args
|
194
|
+
[:rename_index, [table_name, new_name, old_name]]
|
174
195
|
end
|
175
196
|
|
176
197
|
def invert_rename_column(args)
|
177
|
-
|
198
|
+
table_name, old_name, new_name = args
|
199
|
+
[:rename_column, [table_name, new_name, old_name]]
|
178
200
|
end
|
179
201
|
|
180
|
-
def
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
options_hash = options.slice(:name, :algorithm)
|
185
|
-
options_hash[:column] = columns if !options_hash[:name]
|
202
|
+
def invert_remove_index(args)
|
203
|
+
options = args.extract_options!
|
204
|
+
table, columns = args
|
186
205
|
|
187
|
-
|
188
|
-
end
|
206
|
+
columns ||= options.delete(:column)
|
189
207
|
|
190
|
-
|
191
|
-
|
192
|
-
if (options = options_or_column).is_a?(Hash)
|
193
|
-
unless options[:column]
|
194
|
-
raise ActiveRecord::IrreversibleMigration, "remove_index is only reversible if given a :column option."
|
195
|
-
end
|
196
|
-
options = options.dup
|
197
|
-
[:add_index, [table, options.delete(:column), options]]
|
198
|
-
elsif (column = options_or_column).present?
|
199
|
-
[:add_index, [table, column]]
|
208
|
+
unless columns
|
209
|
+
raise ActiveRecord::IrreversibleMigration, "remove_index is only reversible if given a :column option."
|
200
210
|
end
|
211
|
+
|
212
|
+
options.delete(:if_exists)
|
213
|
+
|
214
|
+
args = [table, columns]
|
215
|
+
args << options unless options.empty?
|
216
|
+
|
217
|
+
[:add_index, args]
|
201
218
|
end
|
202
219
|
|
203
220
|
alias :invert_add_belongs_to :invert_add_reference
|
204
221
|
alias :invert_remove_belongs_to :invert_remove_reference
|
205
222
|
|
206
223
|
def invert_change_column_default(args)
|
207
|
-
table, column, options =
|
224
|
+
table, column, options = args
|
208
225
|
|
209
|
-
unless options
|
226
|
+
unless options.is_a?(Hash) && options.has_key?(:from) && options.has_key?(:to)
|
210
227
|
raise ActiveRecord::IrreversibleMigration, "change_column_default is only reversible if given a :from and :to option."
|
211
228
|
end
|
212
229
|
|
@@ -218,21 +235,6 @@ module ActiveRecord
|
|
218
235
|
[:change_column_null, args]
|
219
236
|
end
|
220
237
|
|
221
|
-
def invert_add_foreign_key(args)
|
222
|
-
from_table, to_table, add_options = args
|
223
|
-
add_options ||= {}
|
224
|
-
|
225
|
-
if add_options[:name]
|
226
|
-
options = { name: add_options[:name] }
|
227
|
-
elsif add_options[:column]
|
228
|
-
options = { column: add_options[:column] }
|
229
|
-
else
|
230
|
-
options = to_table
|
231
|
-
end
|
232
|
-
|
233
|
-
[:remove_foreign_key, [from_table, options]]
|
234
|
-
end
|
235
|
-
|
236
238
|
def invert_remove_foreign_key(args)
|
237
239
|
options = args.extract_options!
|
238
240
|
from_table, to_table = args
|
@@ -248,9 +250,9 @@ module ActiveRecord
|
|
248
250
|
end
|
249
251
|
|
250
252
|
def invert_change_column_comment(args)
|
251
|
-
table, column, options =
|
253
|
+
table, column, options = args
|
252
254
|
|
253
|
-
unless options
|
255
|
+
unless options.is_a?(Hash) && options.has_key?(:from) && options.has_key?(:to)
|
254
256
|
raise ActiveRecord::IrreversibleMigration, "change_column_comment is only reversible if given a :from and :to option."
|
255
257
|
end
|
256
258
|
|
@@ -258,15 +260,20 @@ module ActiveRecord
|
|
258
260
|
end
|
259
261
|
|
260
262
|
def invert_change_table_comment(args)
|
261
|
-
table, options =
|
263
|
+
table, options = args
|
262
264
|
|
263
|
-
unless options
|
265
|
+
unless options.is_a?(Hash) && options.has_key?(:from) && options.has_key?(:to)
|
264
266
|
raise ActiveRecord::IrreversibleMigration, "change_table_comment is only reversible if given a :from and :to option."
|
265
267
|
end
|
266
268
|
|
267
269
|
[:change_table_comment, [table, from: options[:to], to: options[:from]]]
|
268
270
|
end
|
269
271
|
|
272
|
+
def invert_remove_check_constraint(args)
|
273
|
+
raise ActiveRecord::IrreversibleMigration, "remove_check_constraint is only reversible if given an expression." if args.size < 2
|
274
|
+
super
|
275
|
+
end
|
276
|
+
|
270
277
|
def respond_to_missing?(method, _)
|
271
278
|
super || delegate.respond_to?(method)
|
272
279
|
end
|
@@ -279,6 +286,7 @@ module ActiveRecord
|
|
279
286
|
super
|
280
287
|
end
|
281
288
|
end
|
289
|
+
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
282
290
|
end
|
283
291
|
end
|
284
292
|
end
|
@@ -13,7 +13,62 @@ module ActiveRecord
|
|
13
13
|
const_get(name)
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
V6_1 = Current
|
17
|
+
|
18
|
+
class V6_0 < V6_1
|
19
|
+
class ReferenceDefinition < ConnectionAdapters::ReferenceDefinition
|
20
|
+
def index_options(table_name)
|
21
|
+
as_options(index)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module TableDefinition
|
26
|
+
def references(*args, **options)
|
27
|
+
args.each do |ref_name|
|
28
|
+
ReferenceDefinition.new(ref_name, **options).add_to(self)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
alias :belongs_to :references
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_table(table_name, **options)
|
35
|
+
if block_given?
|
36
|
+
super { |t| yield compatible_table_definition(t) }
|
37
|
+
else
|
38
|
+
super
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def change_table(table_name, **options)
|
43
|
+
if block_given?
|
44
|
+
super { |t| yield compatible_table_definition(t) }
|
45
|
+
else
|
46
|
+
super
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def create_join_table(table_1, table_2, **options)
|
51
|
+
if block_given?
|
52
|
+
super { |t| yield compatible_table_definition(t) }
|
53
|
+
else
|
54
|
+
super
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def add_reference(table_name, ref_name, **options)
|
59
|
+
ReferenceDefinition.new(ref_name, **options)
|
60
|
+
.add_to(connection.update_table_definition(table_name, self))
|
61
|
+
end
|
62
|
+
alias :add_belongs_to :add_reference
|
63
|
+
|
64
|
+
private
|
65
|
+
def compatible_table_definition(t)
|
66
|
+
class << t
|
67
|
+
prepend TableDefinition
|
68
|
+
end
|
69
|
+
t
|
70
|
+
end
|
71
|
+
end
|
17
72
|
|
18
73
|
class V5_2 < V6_0
|
19
74
|
module TableDefinition
|
@@ -29,13 +84,11 @@ module ActiveRecord
|
|
29
84
|
end
|
30
85
|
|
31
86
|
def invert_change_column_comment(args)
|
32
|
-
|
33
|
-
[:change_column_comment, [table_name, column_name, from: comment, to: comment]]
|
87
|
+
[:change_column_comment, args]
|
34
88
|
end
|
35
89
|
|
36
90
|
def invert_change_table_comment(args)
|
37
|
-
|
38
|
-
[:change_table_comment, [table_name, from: comment, to: comment]]
|
91
|
+
[:change_table_comment, args]
|
39
92
|
end
|
40
93
|
end
|
41
94
|
|
@@ -86,9 +139,9 @@ module ActiveRecord
|
|
86
139
|
end
|
87
140
|
|
88
141
|
class V5_1 < V5_2
|
89
|
-
def change_column(table_name, column_name, type, options
|
142
|
+
def change_column(table_name, column_name, type, **options)
|
90
143
|
if connection.adapter_name == "PostgreSQL"
|
91
|
-
super(table_name, column_name, type, options.except(:default, :null, :comment))
|
144
|
+
super(table_name, column_name, type, **options.except(:default, :null, :comment))
|
92
145
|
connection.change_column_default(table_name, column_name, options[:default]) if options.key?(:default)
|
93
146
|
connection.change_column_null(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
|
94
147
|
connection.change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
|
@@ -97,7 +150,7 @@ module ActiveRecord
|
|
97
150
|
end
|
98
151
|
end
|
99
152
|
|
100
|
-
def create_table(table_name, options
|
153
|
+
def create_table(table_name, **options)
|
101
154
|
if connection.adapter_name == "Mysql2"
|
102
155
|
super(table_name, options: "ENGINE=InnoDB", **options)
|
103
156
|
else
|
@@ -119,7 +172,7 @@ module ActiveRecord
|
|
119
172
|
alias :belongs_to :references
|
120
173
|
end
|
121
174
|
|
122
|
-
def create_table(table_name, options
|
175
|
+
def create_table(table_name, **options)
|
123
176
|
if connection.adapter_name == "PostgreSQL"
|
124
177
|
if options[:id] == :uuid && !options.key?(:default)
|
125
178
|
options[:default] = "uuid_generate_v4()"
|
@@ -147,7 +200,7 @@ module ActiveRecord
|
|
147
200
|
super
|
148
201
|
end
|
149
202
|
|
150
|
-
def add_column(table_name, column_name, type, options
|
203
|
+
def add_column(table_name, column_name, type, **options)
|
151
204
|
if type == :primary_key
|
152
205
|
type = :integer
|
153
206
|
options[:primary_key] = true
|
@@ -194,7 +247,7 @@ module ActiveRecord
|
|
194
247
|
super
|
195
248
|
end
|
196
249
|
|
197
|
-
def index_exists?(table_name, column_name, options
|
250
|
+
def index_exists?(table_name, column_name, **options)
|
198
251
|
column_names = Array(column_name).map(&:to_s)
|
199
252
|
options[:name] =
|
200
253
|
if options[:name].present?
|
@@ -205,10 +258,9 @@ module ActiveRecord
|
|
205
258
|
super
|
206
259
|
end
|
207
260
|
|
208
|
-
def remove_index(table_name,
|
209
|
-
options =
|
210
|
-
|
211
|
-
super(table_name, options)
|
261
|
+
def remove_index(table_name, column_name = nil, **options)
|
262
|
+
options[:name] = index_name_for_remove(table_name, column_name, options)
|
263
|
+
super
|
212
264
|
end
|
213
265
|
|
214
266
|
private
|
@@ -219,13 +271,12 @@ module ActiveRecord
|
|
219
271
|
super
|
220
272
|
end
|
221
273
|
|
222
|
-
def index_name_for_remove(table_name, options
|
223
|
-
index_name = connection.index_name(table_name, options)
|
274
|
+
def index_name_for_remove(table_name, column_name, options)
|
275
|
+
index_name = connection.index_name(table_name, column_name || options)
|
224
276
|
|
225
277
|
unless connection.index_name_exists?(table_name, index_name)
|
226
|
-
if options.
|
227
|
-
options_without_column = options.
|
228
|
-
options_without_column.delete :column
|
278
|
+
if options.key?(:name)
|
279
|
+
options_without_column = options.except(:column)
|
229
280
|
index_name_without_column = connection.index_name(table_name, options_without_column)
|
230
281
|
|
231
282
|
if connection.index_name_exists?(table_name, index_name_without_column)
|