activerecord 6.0.0.beta3 → 6.0.2.rc2
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 +466 -9
- data/README.rdoc +3 -1
- data/lib/active_record.rb +0 -1
- data/lib/active_record/association_relation.rb +15 -6
- data/lib/active_record/associations.rb +4 -3
- data/lib/active_record/associations/association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +5 -2
- data/lib/active_record/associations/builder/collection_association.rb +5 -15
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -1
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +6 -2
- data/lib/active_record/associations/collection_proxy.rb +2 -2
- data/lib/active_record/associations/has_many_through_association.rb +4 -11
- data/lib/active_record/associations/join_dependency.rb +14 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +12 -3
- data/lib/active_record/associations/preloader.rb +13 -8
- data/lib/active_record/associations/preloader/association.rb +34 -30
- data/lib/active_record/associations/preloader/through_association.rb +48 -28
- data/lib/active_record/attribute_methods.rb +3 -53
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
- data/lib/active_record/attribute_methods/dirty.rb +47 -14
- data/lib/active_record/attribute_methods/primary_key.rb +7 -15
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +3 -9
- data/lib/active_record/attribute_methods/write.rb +6 -12
- data/lib/active_record/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +21 -7
- data/lib/active_record/base.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +109 -11
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +8 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +88 -61
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +6 -4
- data/lib/active_record/connection_adapters/abstract/quoting.rb +63 -6
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -7
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +79 -22
- data/lib/active_record/connection_adapters/abstract/transaction.rb +12 -4
- data/lib/active_record/connection_adapters/abstract_adapter.rb +111 -33
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +78 -73
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +2 -2
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +48 -8
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -5
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +9 -6
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +18 -5
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -30
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +39 -2
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +34 -38
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +23 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +67 -26
- data/lib/active_record/connection_adapters/schema_cache.rb +32 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +38 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +2 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +66 -114
- data/lib/active_record/connection_handling.rb +31 -13
- data/lib/active_record/core.rb +23 -24
- data/lib/active_record/database_configurations.rb +73 -44
- data/lib/active_record/database_configurations/hash_config.rb +11 -11
- data/lib/active_record/database_configurations/url_config.rb +12 -12
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +15 -0
- data/lib/active_record/errors.rb +1 -1
- data/lib/active_record/fixtures.rb +11 -6
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +13 -1
- data/lib/active_record/internal_metadata.rb +5 -1
- data/lib/active_record/locking/optimistic.rb +3 -4
- data/lib/active_record/log_subscriber.rb +1 -1
- data/lib/active_record/middleware/database_selector.rb +3 -3
- data/lib/active_record/middleware/database_selector/resolver.rb +4 -6
- data/lib/active_record/migration.rb +62 -44
- data/lib/active_record/migration/command_recorder.rb +28 -14
- data/lib/active_record/migration/compatibility.rb +10 -0
- data/lib/active_record/model_schema.rb +3 -0
- data/lib/active_record/persistence.rb +206 -13
- data/lib/active_record/querying.rb +17 -12
- data/lib/active_record/railtie.rb +0 -1
- data/lib/active_record/railties/databases.rake +127 -25
- data/lib/active_record/reflection.rb +3 -3
- data/lib/active_record/relation.rb +99 -20
- data/lib/active_record/relation/calculations.rb +38 -40
- data/lib/active_record/relation/delegation.rb +22 -30
- data/lib/active_record/relation/finder_methods.rb +17 -12
- data/lib/active_record/relation/merger.rb +11 -16
- data/lib/active_record/relation/query_methods.rb +228 -76
- data/lib/active_record/relation/where_clause.rb +9 -5
- data/lib/active_record/sanitization.rb +33 -4
- data/lib/active_record/schema.rb +1 -1
- data/lib/active_record/schema_dumper.rb +10 -1
- data/lib/active_record/schema_migration.rb +1 -1
- data/lib/active_record/scoping/default.rb +6 -7
- data/lib/active_record/scoping/named.rb +3 -2
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/store.rb +48 -0
- data/lib/active_record/table_metadata.rb +9 -13
- data/lib/active_record/tasks/database_tasks.rb +109 -6
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -1
- data/lib/active_record/test_databases.rb +1 -16
- data/lib/active_record/test_fixtures.rb +1 -0
- data/lib/active_record/timestamp.rb +26 -16
- data/lib/active_record/touch_later.rb +4 -2
- data/lib/active_record/transactions.rb +56 -46
- data/lib/active_record/type_caster/connection.rb +16 -10
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record/validations/uniqueness.rb +3 -5
- data/lib/arel.rb +12 -5
- data/lib/arel/insert_manager.rb +3 -3
- data/lib/arel/nodes.rb +2 -1
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/select_core.rb +16 -12
- data/lib/arel/nodes/unary.rb +1 -0
- data/lib/arel/nodes/values_list.rb +2 -17
- data/lib/arel/select_manager.rb +10 -10
- data/lib/arel/visitors/depth_first.rb +7 -2
- data/lib/arel/visitors/dot.rb +7 -2
- data/lib/arel/visitors/ibm_db.rb +13 -0
- data/lib/arel/visitors/informix.rb +6 -0
- data/lib/arel/visitors/mssql.rb +15 -1
- data/lib/arel/visitors/oracle12.rb +4 -5
- data/lib/arel/visitors/postgresql.rb +4 -10
- data/lib/arel/visitors/to_sql.rb +107 -131
- data/lib/arel/visitors/visitor.rb +9 -5
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +16 -12
- data/lib/active_record/collection_cache_key.rb +0 -53
- data/lib/arel/nodes/values.rb +0 -16
@@ -85,14 +85,14 @@ module ActiveRecord
|
|
85
85
|
# based on the requested role:
|
86
86
|
#
|
87
87
|
# ActiveRecord::Base.connected_to(role: :writing) do
|
88
|
-
# Dog.create! # creates dog using dog connection
|
88
|
+
# Dog.create! # creates dog using dog writing connection
|
89
89
|
# end
|
90
90
|
#
|
91
91
|
# ActiveRecord::Base.connected_to(role: :reading) do
|
92
92
|
# Dog.create! # throws exception because we're on a replica
|
93
93
|
# end
|
94
94
|
#
|
95
|
-
# ActiveRecord::Base.connected_to(role: :
|
95
|
+
# ActiveRecord::Base.connected_to(role: :unknown_role) do
|
96
96
|
# # raises exception due to non-existent role
|
97
97
|
# end
|
98
98
|
#
|
@@ -100,31 +100,44 @@ module ActiveRecord
|
|
100
100
|
# you can use +connected_to+ with a +database+ argument. The +database+ argument
|
101
101
|
# expects a symbol that corresponds to the database key in your config.
|
102
102
|
#
|
103
|
-
# This will connect to a new database for the queries inside the block.
|
104
|
-
#
|
105
103
|
# ActiveRecord::Base.connected_to(database: :animals_slow_replica) do
|
106
104
|
# Dog.run_a_long_query # runs a long query while connected to the +animals_slow_replica+
|
107
105
|
# end
|
108
|
-
|
106
|
+
#
|
107
|
+
# This will connect to a new database for the queries inside the block. By
|
108
|
+
# default the `:writing` role will be used since all connections must be assigned
|
109
|
+
# a role. If you would like to use a different role you can pass a hash to database:
|
110
|
+
#
|
111
|
+
# ActiveRecord::Base.connected_to(database: { readonly_slow: :animals_slow_replica }) do
|
112
|
+
# # runs a long query while connected to the +animals_slow_replica+ using the readonly_slow role.
|
113
|
+
# Dog.run_a_long_query
|
114
|
+
# end
|
115
|
+
#
|
116
|
+
# When using the database key a new connection will be established every time. It is not
|
117
|
+
# recommended to use this outside of one-off scripts.
|
118
|
+
def connected_to(database: nil, role: nil, prevent_writes: false, &blk)
|
109
119
|
if database && role
|
110
120
|
raise ArgumentError, "connected_to can only accept a `database` or a `role` argument, but not both arguments."
|
111
121
|
elsif database
|
112
122
|
if database.is_a?(Hash)
|
113
123
|
role, database = database.first
|
114
124
|
role = role.to_sym
|
115
|
-
else
|
116
|
-
role = database.to_sym
|
117
125
|
end
|
118
126
|
|
119
127
|
config_hash = resolve_config_for_connection(database)
|
120
128
|
handler = lookup_connection_handler(role)
|
121
129
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
end
|
130
|
+
handler.establish_connection(config_hash)
|
131
|
+
|
132
|
+
with_handler(role, &blk)
|
126
133
|
elsif role
|
127
|
-
|
134
|
+
if role == writing_role
|
135
|
+
with_handler(role.to_sym) do
|
136
|
+
connection_handler.while_preventing_writes(prevent_writes, &blk)
|
137
|
+
end
|
138
|
+
else
|
139
|
+
with_handler(role.to_sym, &blk)
|
140
|
+
end
|
128
141
|
else
|
129
142
|
raise ArgumentError, "must provide a `database` or a `role`."
|
130
143
|
end
|
@@ -154,6 +167,7 @@ module ActiveRecord
|
|
154
167
|
end
|
155
168
|
|
156
169
|
def lookup_connection_handler(handler_key) # :nodoc:
|
170
|
+
handler_key ||= ActiveRecord::Base.writing_role
|
157
171
|
connection_handlers[handler_key] ||= ActiveRecord::ConnectionAdapters::ConnectionHandler.new
|
158
172
|
end
|
159
173
|
|
@@ -166,7 +180,7 @@ module ActiveRecord
|
|
166
180
|
raise "Anonymous class is not allowed." unless name
|
167
181
|
|
168
182
|
config_or_env ||= DEFAULT_ENV.call.to_sym
|
169
|
-
pool_name =
|
183
|
+
pool_name = primary_class? ? "primary" : name
|
170
184
|
self.connection_specification_name = pool_name
|
171
185
|
|
172
186
|
resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new(Base.configurations)
|
@@ -202,6 +216,10 @@ module ActiveRecord
|
|
202
216
|
@connection_specification_name
|
203
217
|
end
|
204
218
|
|
219
|
+
def primary_class? # :nodoc:
|
220
|
+
self == Base || defined?(ApplicationRecord) && self == ApplicationRecord
|
221
|
+
end
|
222
|
+
|
205
223
|
# Returns the configuration of the associated connection as a hash:
|
206
224
|
#
|
207
225
|
# ActiveRecord::Base.connection_config
|
data/lib/active_record/core.rb
CHANGED
@@ -101,7 +101,6 @@ module ActiveRecord
|
|
101
101
|
# environment where dumping schema is rarely needed.
|
102
102
|
mattr_accessor :dump_schema_after_migration, instance_writer: false, default: true
|
103
103
|
|
104
|
-
mattr_accessor :database_selector, instance_writer: false
|
105
104
|
##
|
106
105
|
# :singleton-method:
|
107
106
|
# Specifies which database schemas to dump when calling db:structure:dump.
|
@@ -161,7 +160,7 @@ module ActiveRecord
|
|
161
160
|
return super if block_given? ||
|
162
161
|
primary_key.nil? ||
|
163
162
|
scope_attributes? ||
|
164
|
-
columns_hash.
|
163
|
+
columns_hash.key?(inheritance_column) && !base_class?
|
165
164
|
|
166
165
|
id = ids.first
|
167
166
|
|
@@ -175,14 +174,14 @@ module ActiveRecord
|
|
175
174
|
|
176
175
|
record = statement.execute([id], connection)&.first
|
177
176
|
unless record
|
178
|
-
raise RecordNotFound.new("Couldn't find #{name} with '#{
|
179
|
-
name, primary_key, id)
|
177
|
+
raise RecordNotFound.new("Couldn't find #{name} with '#{key}'=#{id}", name, key, id)
|
180
178
|
end
|
181
179
|
record
|
182
180
|
end
|
183
181
|
|
184
182
|
def find_by(*args) # :nodoc:
|
185
|
-
return super if scope_attributes? || reflect_on_all_aggregations.any?
|
183
|
+
return super if scope_attributes? || reflect_on_all_aggregations.any? ||
|
184
|
+
columns_hash.key?(inheritance_column) && !base_class?
|
186
185
|
|
187
186
|
hash = args.first
|
188
187
|
|
@@ -269,7 +268,8 @@ module ActiveRecord
|
|
269
268
|
end
|
270
269
|
|
271
270
|
def arel_attribute(name, table = arel_table) # :nodoc:
|
272
|
-
name =
|
271
|
+
name = name.to_s
|
272
|
+
name = attribute_aliases[name] || name
|
273
273
|
table[name]
|
274
274
|
end
|
275
275
|
|
@@ -317,7 +317,7 @@ module ActiveRecord
|
|
317
317
|
# # Instantiates a single new object
|
318
318
|
# User.new(first_name: 'Jamie')
|
319
319
|
def initialize(attributes = nil)
|
320
|
-
|
320
|
+
@new_record = true
|
321
321
|
@attributes = self.class._default_attributes.deep_dup
|
322
322
|
|
323
323
|
init_internals
|
@@ -354,12 +354,10 @@ module ActiveRecord
|
|
354
354
|
# +attributes+ should be an attributes object, and unlike the
|
355
355
|
# `initialize` method, no assignment calls are made per attribute.
|
356
356
|
def init_with_attributes(attributes, new_record = false) # :nodoc:
|
357
|
-
init_internals
|
358
|
-
|
359
357
|
@new_record = new_record
|
360
358
|
@attributes = attributes
|
361
359
|
|
362
|
-
|
360
|
+
init_internals
|
363
361
|
|
364
362
|
yield self if block_given?
|
365
363
|
|
@@ -398,13 +396,13 @@ module ActiveRecord
|
|
398
396
|
##
|
399
397
|
def initialize_dup(other) # :nodoc:
|
400
398
|
@attributes = @attributes.deep_dup
|
401
|
-
@attributes.reset(
|
399
|
+
@attributes.reset(@primary_key)
|
402
400
|
|
403
401
|
_run_initialize_callbacks
|
404
402
|
|
405
403
|
@new_record = true
|
406
404
|
@destroyed = false
|
407
|
-
@_start_transaction_state =
|
405
|
+
@_start_transaction_state = nil
|
408
406
|
@transaction_state = nil
|
409
407
|
|
410
408
|
super
|
@@ -465,6 +463,7 @@ module ActiveRecord
|
|
465
463
|
|
466
464
|
# Returns +true+ if the attributes hash has been frozen.
|
467
465
|
def frozen?
|
466
|
+
sync_with_transaction_state if @transaction_state&.finalized?
|
468
467
|
@attributes.frozen?
|
469
468
|
end
|
470
469
|
|
@@ -569,34 +568,34 @@ module ActiveRecord
|
|
569
568
|
end
|
570
569
|
|
571
570
|
def init_internals
|
571
|
+
@primary_key = self.class.primary_key
|
572
572
|
@readonly = false
|
573
573
|
@destroyed = false
|
574
574
|
@marked_for_destruction = false
|
575
575
|
@destroyed_by_association = nil
|
576
|
-
@
|
577
|
-
@_start_transaction_state = {}
|
576
|
+
@_start_transaction_state = nil
|
578
577
|
@transaction_state = nil
|
579
|
-
end
|
580
578
|
|
581
|
-
|
579
|
+
self.class.define_attribute_methods
|
582
580
|
end
|
583
581
|
|
584
|
-
def
|
585
|
-
if frozen?
|
586
|
-
@attributes = @attributes.dup
|
587
|
-
end
|
582
|
+
def initialize_internals_callback
|
588
583
|
end
|
589
584
|
|
590
585
|
def custom_inspect_method_defined?
|
591
586
|
self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner
|
592
587
|
end
|
593
588
|
|
589
|
+
class InspectionMask < DelegateClass(::String)
|
590
|
+
def pretty_print(pp)
|
591
|
+
pp.text __getobj__
|
592
|
+
end
|
593
|
+
end
|
594
|
+
private_constant :InspectionMask
|
595
|
+
|
594
596
|
def inspection_filter
|
595
597
|
@inspection_filter ||= begin
|
596
|
-
mask =
|
597
|
-
def mask.pretty_print(pp)
|
598
|
-
pp.text __getobj__
|
599
|
-
end
|
598
|
+
mask = InspectionMask.new(ActiveSupport::ParameterFilter::FILTERED)
|
600
599
|
ActiveSupport::ParameterFilter.new(self.class.filter_attributes, mask: mask)
|
601
600
|
end
|
602
601
|
end
|
@@ -7,8 +7,10 @@ require "active_record/database_configurations/url_config"
|
|
7
7
|
module ActiveRecord
|
8
8
|
# ActiveRecord::DatabaseConfigurations returns an array of DatabaseConfig
|
9
9
|
# objects (either a HashConfig or UrlConfig) that are constructed from the
|
10
|
-
# application's database configuration hash or
|
10
|
+
# application's database configuration hash or URL string.
|
11
11
|
class DatabaseConfigurations
|
12
|
+
class InvalidConfigurationError < StandardError; end
|
13
|
+
|
12
14
|
attr_reader :configurations
|
13
15
|
delegate :any?, to: :configurations
|
14
16
|
|
@@ -17,22 +19,22 @@ module ActiveRecord
|
|
17
19
|
end
|
18
20
|
|
19
21
|
# Collects the configs for the environment and optionally the specification
|
20
|
-
# name passed in. To include replica configurations pass
|
22
|
+
# name passed in. To include replica configurations pass <tt>include_replicas: true</tt>.
|
21
23
|
#
|
22
24
|
# If a spec name is provided a single DatabaseConfig object will be
|
23
25
|
# returned, otherwise an array of DatabaseConfig objects will be
|
24
26
|
# returned that corresponds with the environment and type requested.
|
25
27
|
#
|
26
|
-
# Options
|
28
|
+
# ==== Options
|
27
29
|
#
|
28
|
-
# <tt>env_name:</tt> The environment name. Defaults to +nil+ which will collect
|
29
|
-
#
|
30
|
-
# <tt>spec_name:</tt> The specification name (i.e. primary, animals, etc.). Defaults
|
31
|
-
#
|
32
|
-
# <tt>include_replicas:</tt> Determines whether to include replicas in
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
30
|
+
# * <tt>env_name:</tt> The environment name. Defaults to +nil+ which will collect
|
31
|
+
# configs for all environments.
|
32
|
+
# * <tt>spec_name:</tt> The specification name (i.e. primary, animals, etc.). Defaults
|
33
|
+
# to +nil+.
|
34
|
+
# * <tt>include_replicas:</tt> Determines whether to include replicas in
|
35
|
+
# the returned list. Most of the time we're only iterating over the write
|
36
|
+
# connection (i.e. migrations don't need to run for the write and read connection).
|
37
|
+
# Defaults to +false+.
|
36
38
|
def configs_for(env_name: nil, spec_name: nil, include_replicas: false)
|
37
39
|
configs = env_with_configs(env_name)
|
38
40
|
|
@@ -53,7 +55,7 @@ module ActiveRecord
|
|
53
55
|
|
54
56
|
# Returns the config hash that corresponds with the environment
|
55
57
|
#
|
56
|
-
# If the application has multiple databases
|
58
|
+
# If the application has multiple databases +default_hash+ will
|
57
59
|
# return the first config hash for the environment.
|
58
60
|
#
|
59
61
|
# { database: "my_db", adapter: "mysql2" }
|
@@ -65,7 +67,7 @@ module ActiveRecord
|
|
65
67
|
|
66
68
|
# Returns a single DatabaseConfig object based on the requested environment.
|
67
69
|
#
|
68
|
-
# If the application has multiple databases
|
70
|
+
# If the application has multiple databases +find_db_config+ will return
|
69
71
|
# the first DatabaseConfig for the environment.
|
70
72
|
def find_db_config(env)
|
71
73
|
configurations.find do |db_config|
|
@@ -91,6 +93,19 @@ module ActiveRecord
|
|
91
93
|
end
|
92
94
|
alias :blank? :empty?
|
93
95
|
|
96
|
+
def each
|
97
|
+
throw_getter_deprecation(:each)
|
98
|
+
configurations.each { |config|
|
99
|
+
yield [config.env_name, config.config]
|
100
|
+
}
|
101
|
+
end
|
102
|
+
|
103
|
+
def first
|
104
|
+
throw_getter_deprecation(:first)
|
105
|
+
config = configurations.first
|
106
|
+
[config.env_name, config.config]
|
107
|
+
end
|
108
|
+
|
94
109
|
private
|
95
110
|
def env_with_configs(env = nil)
|
96
111
|
if env
|
@@ -104,34 +119,48 @@ module ActiveRecord
|
|
104
119
|
return configs.configurations if configs.is_a?(DatabaseConfigurations)
|
105
120
|
return configs if configs.is_a?(Array)
|
106
121
|
|
107
|
-
|
108
|
-
|
109
|
-
|
122
|
+
db_configs = configs.flat_map do |env_name, config|
|
123
|
+
if config.is_a?(Hash) && config.all? { |_, v| v.is_a?(Hash) }
|
124
|
+
walk_configs(env_name.to_s, config)
|
125
|
+
else
|
126
|
+
build_db_config_from_raw_config(env_name.to_s, "primary", config)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
current_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call.to_s
|
110
131
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
132
|
+
unless db_configs.find(&:for_current_env?)
|
133
|
+
db_configs << environment_url_config(current_env, "primary", {})
|
134
|
+
end
|
135
|
+
|
136
|
+
merge_db_environment_variables(current_env, db_configs.compact)
|
137
|
+
end
|
138
|
+
|
139
|
+
def walk_configs(env_name, config)
|
140
|
+
config.map do |spec_name, sub_config|
|
141
|
+
build_db_config_from_raw_config(env_name, spec_name.to_s, sub_config)
|
115
142
|
end
|
116
143
|
end
|
117
144
|
|
118
|
-
def
|
145
|
+
def build_db_config_from_raw_config(env_name, spec_name, config)
|
119
146
|
case config
|
120
147
|
when String
|
121
148
|
build_db_config_from_string(env_name, spec_name, config)
|
122
149
|
when Hash
|
123
150
|
build_db_config_from_hash(env_name, spec_name, config.stringify_keys)
|
151
|
+
else
|
152
|
+
raise InvalidConfigurationError, "'{ #{env_name} => #{config} }' is not a valid configuration. Expected '#{config}' to be a URL string or a Hash."
|
124
153
|
end
|
125
154
|
end
|
126
155
|
|
127
156
|
def build_db_config_from_string(env_name, spec_name, config)
|
128
157
|
url = config
|
129
158
|
uri = URI.parse(url)
|
130
|
-
if uri.
|
159
|
+
if uri.scheme
|
131
160
|
ActiveRecord::DatabaseConfigurations::UrlConfig.new(env_name, spec_name, url)
|
161
|
+
else
|
162
|
+
raise InvalidConfigurationError, "'{ #{env_name} => #{config} }' is not a valid configuration. Expected '#{config}' to be a URL string or a Hash."
|
132
163
|
end
|
133
|
-
rescue URI::InvalidURIError
|
134
|
-
ActiveRecord::DatabaseConfigurations::HashConfig.new(env_name, spec_name, config)
|
135
164
|
end
|
136
165
|
|
137
166
|
def build_db_config_from_hash(env_name, spec_name, config)
|
@@ -141,36 +170,36 @@ module ActiveRecord
|
|
141
170
|
config_without_url.delete "url"
|
142
171
|
|
143
172
|
ActiveRecord::DatabaseConfigurations::UrlConfig.new(env_name, spec_name, url, config_without_url)
|
144
|
-
elsif config["database"] || (config.size == 1 && config.values.all? { |v| v.is_a? String })
|
145
|
-
ActiveRecord::DatabaseConfigurations::HashConfig.new(env_name, spec_name, config)
|
146
173
|
else
|
147
|
-
|
148
|
-
walk_configs(env_name, sub_spec_name, sub_config)
|
149
|
-
end
|
174
|
+
ActiveRecord::DatabaseConfigurations::HashConfig.new(env_name, spec_name, config)
|
150
175
|
end
|
151
176
|
end
|
152
177
|
|
153
|
-
def
|
154
|
-
|
178
|
+
def merge_db_environment_variables(current_env, configs)
|
179
|
+
configs.map do |config|
|
180
|
+
next config if config.url_config? || config.env_name != current_env
|
155
181
|
|
156
|
-
|
157
|
-
|
158
|
-
configs
|
159
|
-
else
|
160
|
-
configs.map do |config|
|
161
|
-
ActiveRecord::DatabaseConfigurations::UrlConfig.new(config.env_name, config.spec_name, url, config.config)
|
162
|
-
end
|
163
|
-
end
|
164
|
-
else
|
165
|
-
configs + [ActiveRecord::DatabaseConfigurations::UrlConfig.new(env, "primary", url)]
|
182
|
+
url_config = environment_url_config(current_env, config.spec_name, config.config)
|
183
|
+
url_config || config
|
166
184
|
end
|
167
185
|
end
|
168
186
|
|
187
|
+
def environment_url_config(env, spec_name, config)
|
188
|
+
url = environment_value_for(spec_name)
|
189
|
+
return unless url
|
190
|
+
|
191
|
+
ActiveRecord::DatabaseConfigurations::UrlConfig.new(env, spec_name, url, config)
|
192
|
+
end
|
193
|
+
|
194
|
+
def environment_value_for(spec_name)
|
195
|
+
spec_env_key = "#{spec_name.upcase}_DATABASE_URL"
|
196
|
+
url = ENV[spec_env_key]
|
197
|
+
url ||= ENV["DATABASE_URL"] if spec_name == "primary"
|
198
|
+
url
|
199
|
+
end
|
200
|
+
|
169
201
|
def method_missing(method, *args, &blk)
|
170
202
|
case method
|
171
|
-
when :each, :first
|
172
|
-
throw_getter_deprecation(method)
|
173
|
-
configurations.send(method, *args, &blk)
|
174
203
|
when :fetch
|
175
204
|
throw_getter_deprecation(method)
|
176
205
|
configs_for(env_name: args.first)
|
@@ -14,16 +14,16 @@ module ActiveRecord
|
|
14
14
|
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10
|
15
15
|
# @env_name="development", @spec_name="primary", @config={"database"=>"db_name"}>
|
16
16
|
#
|
17
|
-
# Options
|
17
|
+
# ==== Options
|
18
18
|
#
|
19
|
-
# <tt>:env_name</tt> - The Rails environment, i.e. "development"
|
20
|
-
# <tt>:spec_name</tt> - The specification name. In a standard two-tier
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
# <tt>:config</tt> - The config hash. This is the hash that contains the
|
25
|
-
#
|
26
|
-
#
|
19
|
+
# * <tt>:env_name</tt> - The Rails environment, i.e. "development".
|
20
|
+
# * <tt>:spec_name</tt> - The specification name. In a standard two-tier
|
21
|
+
# database configuration this will default to "primary". In a multiple
|
22
|
+
# database three-tier database configuration this corresponds to the name
|
23
|
+
# used in the second tier, for example "primary_readonly".
|
24
|
+
# * <tt>:config</tt> - The config hash. This is the hash that contains the
|
25
|
+
# database adapter, name, and other important information for database
|
26
|
+
# connections.
|
27
27
|
class HashConfig < DatabaseConfig
|
28
28
|
attr_reader :config
|
29
29
|
|
@@ -33,14 +33,14 @@ module ActiveRecord
|
|
33
33
|
end
|
34
34
|
|
35
35
|
# Determines whether a database configuration is for a replica / readonly
|
36
|
-
# connection. If the
|
36
|
+
# connection. If the +replica+ key is present in the config, +replica?+ will
|
37
37
|
# return +true+.
|
38
38
|
def replica?
|
39
39
|
config["replica"]
|
40
40
|
end
|
41
41
|
|
42
42
|
# The migrations paths for a database configuration. If the
|
43
|
-
#
|
43
|
+
# +migrations_paths+ key is present in the config, +migrations_paths+
|
44
44
|
# will return its value.
|
45
45
|
def migrations_paths
|
46
46
|
config["migrations_paths"]
|