activerecord 7.0.8.7 → 7.1.0.beta1
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 +1339 -1572
- data/MIT-LICENSE +1 -1
- data/README.rdoc +15 -16
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/association.rb +18 -3
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +14 -6
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +21 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +17 -9
- data/lib/active_record/associations/collection_proxy.rb +16 -11
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +20 -13
- data/lib/active_record/associations/has_many_through_association.rb +10 -6
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency.rb +10 -8
- data/lib/active_record/associations/preloader/association.rb +27 -6
- data/lib/active_record/associations/preloader.rb +12 -9
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +193 -97
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/dirty.rb +40 -26
- data/lib/active_record/attribute_methods/primary_key.rb +76 -24
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +18 -5
- data/lib/active_record/attribute_methods/serialization.rb +150 -31
- data/lib/active_record/attribute_methods/write.rb +3 -3
- data/lib/active_record/attribute_methods.rb +105 -21
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +55 -9
- data/lib/active_record/base.rb +7 -2
- data/lib/active_record/callbacks.rb +10 -24
- 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 +163 -88
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +3 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +63 -43
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +109 -32
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +60 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +41 -6
- 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 +289 -122
- data/lib/active_record/connection_adapters/abstract/transaction.rb +280 -58
- data/lib/active_record/connection_adapters/abstract_adapter.rb +502 -91
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +200 -108
- 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 +22 -143
- data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -12
- 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 +17 -12
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +98 -53
- data/lib/active_record/connection_adapters/pool_config.rb +14 -5
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +76 -29
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +9 -6
- 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 +131 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +351 -54
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +336 -168
- data/lib/active_record/connection_adapters/schema_cache.rb +287 -59
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +42 -36
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +4 -3
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +1 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +26 -7
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +162 -77
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +98 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +254 -0
- data/lib/active_record/connection_adapters.rb +3 -1
- data/lib/active_record/connection_handling.rb +71 -94
- data/lib/active_record/core.rb +128 -138
- data/lib/active_record/counter_cache.rb +46 -25
- data/lib/active_record/database_configurations/database_config.rb +9 -3
- data/lib/active_record/database_configurations/hash_config.rb +22 -12
- data/lib/active_record/database_configurations/url_config.rb +17 -11
- data/lib/active_record/database_configurations.rb +86 -33
- data/lib/active_record/delegated_type.rb +8 -3
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +2 -0
- 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 +36 -18
- data/lib/active_record/encryption/encrypted_attribute_type.rb +17 -6
- data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -54
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +2 -2
- data/lib/active_record/encryption/key_generator.rb +12 -1
- data/lib/active_record/encryption/message_serializer.rb +2 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/scheme.rb +19 -22
- data/lib/active_record/encryption.rb +1 -0
- data/lib/active_record/enum.rb +113 -26
- data/lib/active_record/errors.rb +89 -15
- data/lib/active_record/explain.rb +23 -3
- 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 +119 -71
- data/lib/active_record/future_result.rb +30 -5
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +30 -16
- data/lib/active_record/insert_all.rb +55 -8
- data/lib/active_record/integration.rb +8 -8
- data/lib/active_record/internal_metadata.rb +118 -30
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +29 -12
- data/lib/active_record/marshalling.rb +56 -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 +5 -7
- data/lib/active_record/middleware/shard_selector.rb +3 -1
- data/lib/active_record/migration/command_recorder.rb +100 -4
- data/lib/active_record/migration/compatibility.rb +131 -5
- data/lib/active_record/migration/default_strategy.rb +23 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration.rb +213 -109
- data/lib/active_record/model_schema.rb +47 -27
- data/lib/active_record/nested_attributes.rb +28 -3
- data/lib/active_record/normalization.rb +158 -0
- data/lib/active_record/persistence.rb +183 -33
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +3 -21
- data/lib/active_record/query_logs.rb +77 -52
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +15 -2
- data/lib/active_record/railtie.rb +107 -45
- data/lib/active_record/railties/controller_runtime.rb +10 -5
- data/lib/active_record/railties/databases.rake +139 -145
- 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 +169 -45
- data/lib/active_record/relation/batches/batch_enumerator.rb +5 -3
- data/lib/active_record/relation/batches.rb +190 -61
- data/lib/active_record/relation/calculations.rb +152 -63
- data/lib/active_record/relation/delegation.rb +22 -8
- data/lib/active_record/relation/finder_methods.rb +85 -15
- data/lib/active_record/relation/merger.rb +2 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -2
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +26 -14
- data/lib/active_record/relation/query_attribute.rb +2 -1
- data/lib/active_record/relation/query_methods.rb +351 -62
- data/lib/active_record/relation/spawn_methods.rb +18 -1
- data/lib/active_record/relation.rb +76 -35
- data/lib/active_record/result.rb +19 -5
- data/lib/active_record/runtime_registry.rb +10 -1
- data/lib/active_record/sanitization.rb +51 -11
- data/lib/active_record/schema.rb +2 -3
- data/lib/active_record/schema_dumper.rb +41 -7
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +2 -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 +7 -5
- data/lib/active_record/store.rb +8 -8
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +10 -1
- data/lib/active_record/tasks/database_tasks.rb +127 -105
- 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 +14 -7
- data/lib/active_record/test_fixtures.rb +113 -96
- data/lib/active_record/timestamp.rb +26 -14
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +36 -10
- 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/time.rb +4 -0
- data/lib/active_record/validations/absence.rb +1 -1
- 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 +47 -2
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +121 -16
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -1
- data/lib/arel/nodes/bound_sql_literal.rb +61 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/homogeneous_in.rb +0 -8
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/node.rb +111 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes.rb +4 -0
- data/lib/arel/predications.rb +2 -0
- data/lib/arel/table.rb +9 -5
- data/lib/arel/visitors/mysql.rb +8 -1
- data/lib/arel/visitors/to_sql.rb +81 -17
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +16 -2
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- 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 +52 -17
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
@@ -1,13 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/core_ext/module/attribute_accessors_per_thread"
|
4
|
+
require "active_record/query_logs_formatter"
|
4
5
|
|
5
6
|
module ActiveRecord
|
6
7
|
# = Active Record Query Logs
|
7
8
|
#
|
8
|
-
# Automatically
|
9
|
+
# Automatically append comments to SQL queries with runtime information tags. This can be used to trace troublesome
|
10
|
+
# SQL statements back to the application code that generated these statements.
|
9
11
|
#
|
10
|
-
#
|
12
|
+
# Query logs can be enabled via \Rails configuration in <tt>config/application.rb</tt> or an initializer:
|
13
|
+
#
|
14
|
+
# config.active_record.query_log_tags_enabled = true
|
15
|
+
#
|
16
|
+
# By default the name of the application, the name and action of the controller, or the name of the job are logged.
|
17
|
+
# The default format is {SQLCommenter}[https://open-telemetry.github.io/opentelemetry-sqlcommenter/].
|
18
|
+
# The tags shown in a query comment can be configured via \Rails configuration:
|
19
|
+
#
|
20
|
+
# config.active_record.query_log_tags = [ :application, :controller, :action, :job ]
|
21
|
+
#
|
22
|
+
# Active Record defines default tags available for use:
|
11
23
|
#
|
12
24
|
# * +application+
|
13
25
|
# * +pid+
|
@@ -15,48 +27,40 @@ module ActiveRecord
|
|
15
27
|
# * +db_host+
|
16
28
|
# * +database+
|
17
29
|
#
|
18
|
-
#
|
30
|
+
# Action Controller adds default tags when loaded:
|
19
31
|
#
|
20
32
|
# * +controller+
|
21
33
|
# * +action+
|
22
|
-
# * +
|
23
|
-
#
|
24
|
-
# The tags used in a query can be configured directly:
|
34
|
+
# * +namespaced_controller+
|
25
35
|
#
|
26
|
-
#
|
36
|
+
# Active Job adds default tags when loaded:
|
27
37
|
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
# config.active_record.query_log_tags = [ :application, :controller, :action, :job ]
|
38
|
+
# * +job+
|
31
39
|
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
40
|
+
# New comment tags can be defined by adding them in a +Hash+ to the tags +Array+. Tags can have dynamic content by
|
41
|
+
# setting a +Proc+ or lambda value in the +Hash+, and can reference any value stored by \Rails in the +context+ object.
|
42
|
+
# ActiveSupport::CurrentAttributes can be used to store application values. Tags with +nil+ values are
|
43
|
+
# omitted from the query comment.
|
35
44
|
#
|
36
45
|
# Escaping is performed on the string returned, however untrusted user input should not be used.
|
37
46
|
#
|
38
47
|
# Example:
|
39
48
|
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
# end
|
56
|
-
#
|
57
|
-
# Direct updates to a context value:
|
58
|
-
#
|
59
|
-
# ActiveSupport::ExecutionContext[:foo] = Bar.new
|
49
|
+
# config.active_record.query_log_tags = [
|
50
|
+
# :namespaced_controller,
|
51
|
+
# :action,
|
52
|
+
# :job,
|
53
|
+
# {
|
54
|
+
# request_id: ->(context) { context[:controller]&.request&.request_id },
|
55
|
+
# job_id: ->(context) { context[:job]&.job_id },
|
56
|
+
# tenant_id: -> { Current.tenant&.id },
|
57
|
+
# static: "value",
|
58
|
+
# },
|
59
|
+
# ]
|
60
|
+
#
|
61
|
+
# By default the name of the application, the name and action of the controller, or the name of the job are logged
|
62
|
+
# using the {SQLCommenter}[https://open-telemetry.github.io/opentelemetry-sqlcommenter/] format. This can be changed
|
63
|
+
# via {config.active_record.query_log_tags_format}[https://guides.rubyonrails.org/configuring.html#config-active-record-query-log-tags-format]
|
60
64
|
#
|
61
65
|
# Tag comments can be prepended to the query:
|
62
66
|
#
|
@@ -65,46 +69,65 @@ module ActiveRecord
|
|
65
69
|
# For applications where the content will not change during the lifetime of
|
66
70
|
# the request or job execution, the tags can be cached for reuse in every query:
|
67
71
|
#
|
68
|
-
# ActiveRecord::QueryLogs.cache_query_log_tags = true
|
69
|
-
#
|
70
|
-
# This option can be set during application configuration or in a Rails initializer:
|
71
|
-
#
|
72
72
|
# config.active_record.cache_query_log_tags = true
|
73
73
|
module QueryLogs
|
74
74
|
mattr_accessor :taggings, instance_accessor: false, default: {}
|
75
75
|
mattr_accessor :tags, instance_accessor: false, default: [ :application ]
|
76
76
|
mattr_accessor :prepend_comment, instance_accessor: false, default: false
|
77
77
|
mattr_accessor :cache_query_log_tags, instance_accessor: false, default: false
|
78
|
+
mattr_accessor :tags_formatter, instance_accessor: false
|
78
79
|
thread_mattr_accessor :cached_comment, instance_accessor: false
|
79
80
|
|
80
81
|
class << self
|
81
|
-
def call(sql) # :nodoc:
|
82
|
-
|
83
|
-
|
82
|
+
def call(sql, connection) # :nodoc:
|
83
|
+
comment = self.comment(connection)
|
84
|
+
|
85
|
+
if comment.blank?
|
86
|
+
sql
|
87
|
+
elsif prepend_comment
|
88
|
+
"#{comment} #{sql}"
|
84
89
|
else
|
85
|
-
"#{sql} #{
|
86
|
-
end
|
90
|
+
"#{sql} #{comment}"
|
91
|
+
end
|
87
92
|
end
|
88
93
|
|
89
94
|
def clear_cache # :nodoc:
|
90
95
|
self.cached_comment = nil
|
91
96
|
end
|
92
97
|
|
98
|
+
# Updates the formatter to be what the passed in format is.
|
99
|
+
def update_formatter(format)
|
100
|
+
self.tags_formatter =
|
101
|
+
case format
|
102
|
+
when :legacy
|
103
|
+
LegacyFormatter.new
|
104
|
+
when :sqlcommenter
|
105
|
+
SQLCommenter.new
|
106
|
+
else
|
107
|
+
raise ArgumentError, "Formatter is unsupported: #{formatter}"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
93
111
|
ActiveSupport::ExecutionContext.after_change { ActiveRecord::QueryLogs.clear_cache }
|
94
112
|
|
95
113
|
private
|
96
114
|
# Returns an SQL comment +String+ containing the query log tags.
|
97
115
|
# Sets and returns a cached comment if <tt>cache_query_log_tags</tt> is +true+.
|
98
|
-
def comment
|
116
|
+
def comment(connection)
|
99
117
|
if cache_query_log_tags
|
100
|
-
self.cached_comment ||= uncached_comment
|
118
|
+
self.cached_comment ||= uncached_comment(connection)
|
101
119
|
else
|
102
|
-
uncached_comment
|
120
|
+
uncached_comment(connection)
|
103
121
|
end
|
104
122
|
end
|
105
123
|
|
106
|
-
def
|
107
|
-
|
124
|
+
def formatter
|
125
|
+
self.tags_formatter || self.update_formatter(:legacy)
|
126
|
+
end
|
127
|
+
|
128
|
+
def uncached_comment(connection)
|
129
|
+
content = tag_content(connection)
|
130
|
+
|
108
131
|
if content.present?
|
109
132
|
"/*#{escape_sql_comment(content)}*/"
|
110
133
|
end
|
@@ -113,7 +136,7 @@ module ActiveRecord
|
|
113
136
|
def escape_sql_comment(content)
|
114
137
|
# Sanitize a string to appear within a SQL comment
|
115
138
|
# For compatibility, this also surrounding "/*+", "/*", and "*/"
|
116
|
-
#
|
139
|
+
# characters, possibly with single surrounding space.
|
117
140
|
# Then follows that by replacing any internal "*/" or "/ *" with
|
118
141
|
# "* /" or "/ *"
|
119
142
|
comment = content.to_s.dup
|
@@ -123,10 +146,11 @@ module ActiveRecord
|
|
123
146
|
comment
|
124
147
|
end
|
125
148
|
|
126
|
-
def tag_content
|
149
|
+
def tag_content(connection)
|
127
150
|
context = ActiveSupport::ExecutionContext.to_h
|
151
|
+
context[:connection] ||= connection
|
128
152
|
|
129
|
-
tags.flat_map { |i| [*i] }.filter_map do |tag|
|
153
|
+
pairs = tags.flat_map { |i| [*i] }.filter_map do |tag|
|
130
154
|
key, handler = tag
|
131
155
|
handler ||= taggings[key]
|
132
156
|
|
@@ -141,8 +165,9 @@ module ActiveRecord
|
|
141
165
|
else
|
142
166
|
handler
|
143
167
|
end
|
144
|
-
|
145
|
-
end
|
168
|
+
[key, val] unless val.nil?
|
169
|
+
end
|
170
|
+
self.formatter.format(pairs)
|
146
171
|
end
|
147
172
|
end
|
148
173
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module QueryLogs
|
5
|
+
class LegacyFormatter # :nodoc:
|
6
|
+
def initialize
|
7
|
+
@key_value_separator = ":"
|
8
|
+
end
|
9
|
+
|
10
|
+
# Formats the key value pairs into a string.
|
11
|
+
def format(pairs)
|
12
|
+
pairs.map! do |key, value|
|
13
|
+
"#{key}#{key_value_separator}#{format_value(value)}"
|
14
|
+
end.join(",")
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
attr_reader :key_value_separator
|
19
|
+
|
20
|
+
def format_value(value)
|
21
|
+
value
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class SQLCommenter < LegacyFormatter # :nodoc:
|
26
|
+
def initialize
|
27
|
+
@key_value_separator = "="
|
28
|
+
end
|
29
|
+
|
30
|
+
def format(pairs)
|
31
|
+
pairs.sort_by!(&:first)
|
32
|
+
super
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def format_value(value)
|
37
|
+
"'#{ERB::Util.url_encode(value)}'"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -12,12 +12,13 @@ module ActiveRecord
|
|
12
12
|
:create_or_find_by, :create_or_find_by!,
|
13
13
|
:destroy_all, :delete_all, :update_all, :touch_all, :destroy_by, :delete_by,
|
14
14
|
:find_each, :find_in_batches, :in_batches,
|
15
|
-
:select, :reselect, :order, :in_order_of, :reorder, :group, :limit, :offset, :joins, :left_joins, :left_outer_joins,
|
15
|
+
:select, :reselect, :order, :regroup, :in_order_of, :reorder, :group, :limit, :offset, :joins, :left_joins, :left_outer_joins,
|
16
16
|
:where, :rewhere, :invert_where, :preload, :extract_associated, :eager_load, :includes, :from, :lock, :readonly,
|
17
17
|
:and, :or, :annotate, :optimizer_hints, :extending,
|
18
18
|
:having, :create_with, :distinct, :references, :none, :unscope, :merge, :except, :only,
|
19
19
|
:count, :average, :minimum, :maximum, :sum, :calculate,
|
20
|
-
:pluck, :pick, :ids, :strict_loading, :excluding, :without
|
20
|
+
:pluck, :pick, :ids, :async_ids, :strict_loading, :excluding, :without, :with,
|
21
|
+
:async_count, :async_average, :async_minimum, :async_maximum, :async_sum, :async_pluck, :async_pick,
|
21
22
|
].freeze # :nodoc:
|
22
23
|
delegate(*QUERYING_METHODS, to: :all)
|
23
24
|
|
@@ -50,6 +51,13 @@ module ActiveRecord
|
|
50
51
|
_load_from_sql(_query_by_sql(sql, binds, preparable: preparable), &block)
|
51
52
|
end
|
52
53
|
|
54
|
+
# Same as <tt>#find_by_sql</tt> but perform the query asynchronously and returns an ActiveRecord::Promise
|
55
|
+
def async_find_by_sql(sql, binds = [], preparable: nil, &block)
|
56
|
+
_query_by_sql(sql, binds, preparable: preparable, async: true).then do |result|
|
57
|
+
_load_from_sql(result, &block)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
53
61
|
def _query_by_sql(sql, binds = [], preparable: nil, async: false) # :nodoc:
|
54
62
|
connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable, async: async)
|
55
63
|
end
|
@@ -93,5 +101,10 @@ module ActiveRecord
|
|
93
101
|
def count_by_sql(sql)
|
94
102
|
connection.select_value(sanitize_sql(sql), "#{name} Count").to_i
|
95
103
|
end
|
104
|
+
|
105
|
+
# Same as <tt>#count_by_sql</tt> but perform the query asynchronously and returns an ActiveRecord::Promise
|
106
|
+
def async_count_by_sql(sql)
|
107
|
+
connection.select_value(sanitize_sql(sql), "#{name} Count", async: true).then(&:to_i)
|
108
|
+
end
|
96
109
|
end
|
97
110
|
end
|
@@ -34,7 +34,11 @@ module ActiveRecord
|
|
34
34
|
config.active_record.sqlite3_production_warning = true
|
35
35
|
config.active_record.query_log_tags_enabled = false
|
36
36
|
config.active_record.query_log_tags = [ :application ]
|
37
|
+
config.active_record.query_log_tags_format = :legacy
|
37
38
|
config.active_record.cache_query_log_tags = false
|
39
|
+
config.active_record.raise_on_assign_to_attr_readonly = false
|
40
|
+
config.active_record.belongs_to_required_validates_foreign_key = true
|
41
|
+
config.active_record.generate_secure_token_on = :create
|
38
42
|
|
39
43
|
config.active_record.queues = ActiveSupport::InheritableOptions.new
|
40
44
|
|
@@ -72,6 +76,10 @@ module ActiveRecord
|
|
72
76
|
require "active_record/base"
|
73
77
|
end
|
74
78
|
|
79
|
+
initializer "active_record.deprecator", before: :load_environment_config do |app|
|
80
|
+
app.deprecators[:active_record] = ActiveRecord.deprecator
|
81
|
+
end
|
82
|
+
|
75
83
|
initializer "active_record.initialize_timezone" do
|
76
84
|
ActiveSupport.on_load(:active_record) do
|
77
85
|
self.time_zone_aware_attributes = true
|
@@ -100,7 +108,7 @@ module ActiveRecord
|
|
100
108
|
end
|
101
109
|
end
|
102
110
|
|
103
|
-
initializer "
|
111
|
+
initializer "active_record.cache_versioning_support" do
|
104
112
|
config.after_initialize do |app|
|
105
113
|
ActiveSupport.on_load(:active_record) do
|
106
114
|
if app.config.active_record.cache_versioning && Rails.cache
|
@@ -125,9 +133,15 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
125
133
|
end
|
126
134
|
end
|
127
135
|
|
136
|
+
initializer "active_record.use_schema_cache_dump" do
|
137
|
+
ActiveRecord::ConnectionAdapters::SchemaReflection.use_schema_cache_dump = config.active_record.use_schema_cache_dump
|
138
|
+
end
|
139
|
+
|
128
140
|
initializer "active_record.check_schema_cache_dump" do
|
129
141
|
check_schema_cache_dump_version = config.active_record.check_schema_cache_dump_version
|
130
142
|
|
143
|
+
ActiveRecord::ConnectionAdapters::SchemaReflection.check_schema_cache_dump_version = check_schema_cache_dump_version
|
144
|
+
|
131
145
|
if config.active_record.use_schema_cache_dump && !config.active_record.lazily_load_schema_cache
|
132
146
|
config.after_initialize do |app|
|
133
147
|
ActiveSupport.on_load(:active_record) do
|
@@ -135,10 +149,10 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
135
149
|
|
136
150
|
filename = ActiveRecord::Tasks::DatabaseTasks.cache_dump_filename(
|
137
151
|
db_config.name,
|
138
|
-
schema_cache_path: db_config
|
152
|
+
schema_cache_path: db_config.schema_cache_path
|
139
153
|
)
|
140
154
|
|
141
|
-
cache = ActiveRecord::ConnectionAdapters::SchemaCache.
|
155
|
+
cache = ActiveRecord::ConnectionAdapters::SchemaCache._load_from(filename)
|
142
156
|
next if cache.nil?
|
143
157
|
|
144
158
|
if check_schema_cache_dump_version
|
@@ -150,34 +164,47 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
150
164
|
end
|
151
165
|
next if current_version.nil?
|
152
166
|
|
153
|
-
if cache.
|
154
|
-
warn "Ignoring #{filename} because it has expired. The current schema version is #{current_version}, but the one in the schema cache file is #{cache.
|
167
|
+
if cache.schema_version != current_version
|
168
|
+
warn "Ignoring #{filename} because it has expired. The current schema version is #{current_version}, but the one in the schema cache file is #{cache.schema_version}."
|
155
169
|
next
|
156
170
|
end
|
157
171
|
end
|
158
172
|
|
159
173
|
Rails.logger.info("Using schema cache file #{filename}")
|
160
|
-
connection_pool.set_schema_cache(cache)
|
174
|
+
connection_pool.schema_reflection.set_schema_cache(cache)
|
161
175
|
end
|
162
176
|
end
|
163
177
|
end
|
164
178
|
end
|
165
179
|
|
166
180
|
initializer "active_record.define_attribute_methods" do |app|
|
181
|
+
# For resiliency, it is critical that a Rails application should be
|
182
|
+
# able to boot without depending on the database (or any other service)
|
183
|
+
# being responsive.
|
184
|
+
#
|
185
|
+
# Otherwise a bad deploy adding a lot of load on the database may require to
|
186
|
+
# entirely shutdown the application so the database can recover before a fixed
|
187
|
+
# version can be deployed again.
|
188
|
+
#
|
189
|
+
# This is why this initializer tries hard not to query the database, and if it
|
190
|
+
# does, it makes sure to rescue any possible database error.
|
191
|
+
check_schema_cache_dump_version = config.active_record.check_schema_cache_dump_version
|
167
192
|
config.after_initialize do
|
168
193
|
ActiveSupport.on_load(:active_record) do
|
169
|
-
|
194
|
+
# In development and test we shouldn't eagerly define attribute methods because
|
195
|
+
# db:test:prepare will trigger later and might change the schema.
|
196
|
+
#
|
197
|
+
# Additionally if `check_schema_cache_dump_version` is enabled (which is the default),
|
198
|
+
# loading the schema cache dump trigger a database connection to compare the schema
|
199
|
+
# versions.
|
200
|
+
# This means the attribute methods will be lazily defined whent the model is accessed,
|
201
|
+
# likely as part of the first few requests or jobs. This isn't good for performance
|
202
|
+
# but we unfortunately have to arbitrate between resiliency and performance, and chose
|
203
|
+
# resiliency.
|
204
|
+
if !check_schema_cache_dump_version && app.config.eager_load && !Rails.env.local?
|
170
205
|
begin
|
171
206
|
descendants.each do |model|
|
172
|
-
|
173
|
-
schema_cache = model.connection_pool.schema_cache
|
174
|
-
|
175
|
-
# If there's no connection yet, we avoid connecting.
|
176
|
-
schema_cache ||= model.connected? && model.connection.schema_cache
|
177
|
-
|
178
|
-
# If the schema cache doesn't have the columns
|
179
|
-
# hash for the model cached, `define_attribute_methods` would trigger a query.
|
180
|
-
if schema_cache && schema_cache.columns_hash?(model.table_name)
|
207
|
+
if model.connection_pool.schema_reflection.cached?(model.table_name)
|
181
208
|
model.define_attribute_methods
|
182
209
|
end
|
183
210
|
end
|
@@ -210,6 +237,16 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
210
237
|
end
|
211
238
|
end
|
212
239
|
|
240
|
+
initializer "active_record.sqlite3_adapter_strict_strings_by_default" do
|
241
|
+
config.after_initialize do
|
242
|
+
if config.active_record.sqlite3_adapter_strict_strings_by_default
|
243
|
+
ActiveSupport.on_load(:active_record_sqlite3adapter) do
|
244
|
+
self.strict_strings_by_default = true
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
213
250
|
initializer "active_record.set_configs" do |app|
|
214
251
|
configs = app.config.active_record
|
215
252
|
|
@@ -234,8 +271,10 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
234
271
|
:shard_resolver,
|
235
272
|
:query_log_tags_enabled,
|
236
273
|
:query_log_tags,
|
274
|
+
:query_log_tags_format,
|
237
275
|
:cache_query_log_tags,
|
238
276
|
:sqlite3_production_warning,
|
277
|
+
:sqlite3_adapter_strict_strings_by_default,
|
239
278
|
:check_schema_cache_dump_version,
|
240
279
|
:use_schema_cache_dump
|
241
280
|
)
|
@@ -260,21 +299,23 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
260
299
|
# and then establishes the connection.
|
261
300
|
initializer "active_record.initialize_database" do
|
262
301
|
ActiveSupport.on_load(:active_record) do
|
263
|
-
if ActiveRecord.legacy_connection_handling
|
264
|
-
self.connection_handlers = { ActiveRecord.writing_role => ActiveRecord::Base.default_connection_handler }
|
265
|
-
end
|
266
302
|
self.configurations = Rails.application.config.database_configuration
|
267
303
|
|
268
304
|
establish_connection
|
269
305
|
end
|
270
306
|
end
|
271
307
|
|
272
|
-
# Expose database runtime
|
308
|
+
# Expose database runtime for logging.
|
273
309
|
initializer "active_record.log_runtime" do
|
274
310
|
require "active_record/railties/controller_runtime"
|
275
311
|
ActiveSupport.on_load(:action_controller) do
|
276
312
|
include ActiveRecord::Railties::ControllerRuntime
|
277
313
|
end
|
314
|
+
|
315
|
+
require "active_record/railties/job_runtime"
|
316
|
+
ActiveSupport.on_load(:active_job) do
|
317
|
+
include ActiveRecord::Railties::JobRuntime
|
318
|
+
end
|
278
319
|
end
|
279
320
|
|
280
321
|
initializer "active_record.set_reloader_hooks" do
|
@@ -282,7 +323,7 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
282
323
|
ActiveSupport::Reloader.before_class_unload do
|
283
324
|
if ActiveRecord::Base.connected?
|
284
325
|
ActiveRecord::Base.clear_cache!
|
285
|
-
ActiveRecord::Base.clear_reloadable_connections!
|
326
|
+
ActiveRecord::Base.connection_handler.clear_reloadable_connections!(:all)
|
286
327
|
end
|
287
328
|
end
|
288
329
|
end
|
@@ -309,8 +350,8 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
309
350
|
# this connection is trivial: the rest of the pool would need to be
|
310
351
|
# populated anyway.
|
311
352
|
|
312
|
-
clear_active_connections!
|
313
|
-
flush_idle_connections!
|
353
|
+
connection_handler.clear_active_connections!(:all)
|
354
|
+
connection_handler.flush_idle_connections!(:all)
|
314
355
|
end
|
315
356
|
end
|
316
357
|
end
|
@@ -327,18 +368,32 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
327
368
|
end
|
328
369
|
end
|
329
370
|
|
371
|
+
initializer "active_record.generated_token_verifier" do
|
372
|
+
config.after_initialize do |app|
|
373
|
+
ActiveSupport.on_load(:active_record) do
|
374
|
+
self.generated_token_verifier ||= app.message_verifier("active_record/token_for")
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
330
379
|
initializer "active_record_encryption.configuration" do |app|
|
331
|
-
ActiveRecord::Encryption.
|
332
|
-
primary_key: app.credentials.dig(:active_record_encryption, :primary_key),
|
333
|
-
deterministic_key: app.credentials.dig(:active_record_encryption, :deterministic_key),
|
334
|
-
key_derivation_salt: app.credentials.dig(:active_record_encryption, :key_derivation_salt),
|
335
|
-
**config.active_record.encryption
|
380
|
+
auto_filtered_parameters = ActiveRecord::Encryption::AutoFilteredParameters.new(app)
|
336
381
|
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
382
|
+
config.after_initialize do |app|
|
383
|
+
ActiveRecord::Encryption.configure \
|
384
|
+
primary_key: app.credentials.dig(:active_record_encryption, :primary_key),
|
385
|
+
deterministic_key: app.credentials.dig(:active_record_encryption, :deterministic_key),
|
386
|
+
key_derivation_salt: app.credentials.dig(:active_record_encryption, :key_derivation_salt),
|
387
|
+
**config.active_record.encryption
|
388
|
+
|
389
|
+
auto_filtered_parameters.enable if ActiveRecord::Encryption.config.add_to_filter_parameters
|
390
|
+
|
391
|
+
ActiveSupport.on_load(:active_record) do
|
392
|
+
# Support extended queries for deterministic attributes and validations
|
393
|
+
if ActiveRecord::Encryption.config.extend_queries
|
394
|
+
ActiveRecord::Encryption::ExtendedDeterministicQueries.install_support
|
395
|
+
ActiveRecord::Encryption::ExtendedDeterministicUniquenessValidator.install_support
|
396
|
+
end
|
342
397
|
end
|
343
398
|
end
|
344
399
|
|
@@ -348,13 +403,6 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
348
403
|
ActiveRecord::Fixture.prepend ActiveRecord::Encryption::EncryptedFixtures
|
349
404
|
end
|
350
405
|
end
|
351
|
-
|
352
|
-
# Filtered params
|
353
|
-
ActiveSupport.on_load(:action_controller, run_once: true) do
|
354
|
-
if ActiveRecord::Encryption.config.add_to_filter_parameters
|
355
|
-
ActiveRecord::Encryption.install_auto_filtered_parameters_hook(app)
|
356
|
-
end
|
357
|
-
end
|
358
406
|
end
|
359
407
|
|
360
408
|
initializer "active_record.query_log_tags_config" do |app|
|
@@ -363,16 +411,21 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
363
411
|
ActiveRecord.query_transformers << ActiveRecord::QueryLogs
|
364
412
|
ActiveRecord::QueryLogs.taggings.merge!(
|
365
413
|
application: Rails.application.class.name.split("::").first,
|
366
|
-
pid: -> { Process.pid },
|
367
|
-
socket: -> {
|
368
|
-
db_host: -> {
|
369
|
-
database: -> {
|
414
|
+
pid: -> { Process.pid.to_s },
|
415
|
+
socket: ->(context) { context[:connection].pool.db_config.socket },
|
416
|
+
db_host: ->(context) { context[:connection].pool.db_config.host },
|
417
|
+
database: ->(context) { context[:connection].pool.db_config.database }
|
370
418
|
)
|
419
|
+
ActiveRecord.disable_prepared_statements = true
|
371
420
|
|
372
421
|
if app.config.active_record.query_log_tags.present?
|
373
422
|
ActiveRecord::QueryLogs.tags = app.config.active_record.query_log_tags
|
374
423
|
end
|
375
424
|
|
425
|
+
if app.config.active_record.query_log_tags_format
|
426
|
+
ActiveRecord::QueryLogs.update_formatter(app.config.active_record.query_log_tags_format)
|
427
|
+
end
|
428
|
+
|
376
429
|
if app.config.active_record.cache_query_log_tags
|
377
430
|
ActiveRecord::QueryLogs.cache_query_log_tags = true
|
378
431
|
end
|
@@ -382,7 +435,7 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
382
435
|
|
383
436
|
initializer "active_record.unregister_current_scopes_on_unload" do |app|
|
384
437
|
config.after_initialize do
|
385
|
-
|
438
|
+
if app.config.reloading_enabled?
|
386
439
|
Rails.autoloaders.main.on_unload do |_cpath, value, _abspath|
|
387
440
|
# Conditions are written this way to be robust against custom
|
388
441
|
# implementations of value#is_a? or value#<.
|
@@ -393,5 +446,14 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
393
446
|
end
|
394
447
|
end
|
395
448
|
end
|
449
|
+
|
450
|
+
initializer "active_record.message_pack" do
|
451
|
+
ActiveSupport.on_load(:message_pack) do
|
452
|
+
ActiveSupport.on_load(:active_record) do
|
453
|
+
require "active_record/message_pack"
|
454
|
+
ActiveRecord::MessagePack::Extensions.install(ActiveSupport::MessagePack::CacheSerializer)
|
455
|
+
end
|
456
|
+
end
|
457
|
+
end
|
396
458
|
end
|
397
459
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/core_ext/module/attr_internal"
|
4
|
-
require "active_record/
|
4
|
+
require "active_record/runtime_registry"
|
5
5
|
|
6
6
|
module ActiveRecord
|
7
7
|
module Railties # :nodoc:
|
@@ -16,6 +16,11 @@ module ActiveRecord
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
def initialize(...) # :nodoc:
|
20
|
+
super
|
21
|
+
self.db_runtime = nil
|
22
|
+
end
|
23
|
+
|
19
24
|
private
|
20
25
|
attr_internal :db_runtime
|
21
26
|
|
@@ -23,16 +28,16 @@ module ActiveRecord
|
|
23
28
|
# We also need to reset the runtime before each action
|
24
29
|
# because of queries in middleware or in cases we are streaming
|
25
30
|
# and it won't be cleaned up by the method below.
|
26
|
-
ActiveRecord::
|
31
|
+
ActiveRecord::RuntimeRegistry.reset
|
27
32
|
super
|
28
33
|
end
|
29
34
|
|
30
35
|
def cleanup_view_runtime
|
31
36
|
if logger && logger.info?
|
32
|
-
db_rt_before_render = ActiveRecord::
|
37
|
+
db_rt_before_render = ActiveRecord::RuntimeRegistry.reset
|
33
38
|
self.db_runtime = (db_runtime || 0) + db_rt_before_render
|
34
39
|
runtime = super
|
35
|
-
db_rt_after_render = ActiveRecord::
|
40
|
+
db_rt_after_render = ActiveRecord::RuntimeRegistry.reset
|
36
41
|
self.db_runtime += db_rt_after_render
|
37
42
|
runtime - db_rt_after_render
|
38
43
|
else
|
@@ -43,7 +48,7 @@ module ActiveRecord
|
|
43
48
|
def append_info_to_payload(payload)
|
44
49
|
super
|
45
50
|
|
46
|
-
payload[:db_runtime] = (db_runtime || 0) + ActiveRecord::
|
51
|
+
payload[:db_runtime] = (db_runtime || 0) + ActiveRecord::RuntimeRegistry.reset
|
47
52
|
end
|
48
53
|
end
|
49
54
|
end
|