activerecord 5.2.8.1 → 6.0.0.beta1
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 +299 -816
- data/MIT-LICENSE +3 -1
- data/README.rdoc +1 -1
- data/examples/performance.rb +1 -1
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/associations/association.rb +35 -19
- data/lib/active_record/associations/association_scope.rb +4 -6
- data/lib/active_record/associations/belongs_to_association.rb +36 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
- data/lib/active_record/associations/builder/belongs_to.rb +14 -50
- data/lib/active_record/associations/builder/collection_association.rb +3 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
- data/lib/active_record/associations/collection_association.rb +11 -25
- data/lib/active_record/associations/collection_proxy.rb +32 -6
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +25 -18
- data/lib/active_record/associations/has_one_association.rb +28 -30
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +11 -26
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/join_dependency.rb +15 -20
- data/lib/active_record/associations/preloader/association.rb +1 -2
- data/lib/active_record/associations/preloader.rb +32 -29
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/associations.rb +16 -12
- data/lib/active_record/attribute_assignment.rb +7 -10
- data/lib/active_record/attribute_methods/dirty.rb +64 -26
- data/lib/active_record/attribute_methods/primary_key.rb +8 -7
- data/lib/active_record/attribute_methods/read.rb +16 -48
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
- data/lib/active_record/attribute_methods/write.rb +15 -16
- data/lib/active_record/attribute_methods.rb +34 -56
- data/lib/active_record/autosave_association.rb +7 -21
- data/lib/active_record/base.rb +2 -2
- data/lib/active_record/callbacks.rb +3 -17
- data/lib/active_record/coders/yaml_column.rb +1 -13
- data/lib/active_record/collection_cache_key.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +13 -36
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +25 -84
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +17 -14
- data/lib/active_record/connection_adapters/abstract/quoting.rb +5 -11
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +15 -11
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -13
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +0 -2
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +41 -27
- data/lib/active_record/connection_adapters/abstract/transaction.rb +81 -52
- data/lib/active_record/connection_adapters/abstract_adapter.rb +95 -31
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +65 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +52 -42
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +5 -9
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +29 -7
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +65 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -4
- data/lib/active_record/connection_adapters/postgresql/column.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +16 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +11 -36
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +9 -2
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +38 -20
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -56
- data/lib/active_record/connection_adapters/schema_cache.rb +5 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +5 -5
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +14 -9
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +95 -62
- data/lib/active_record/connection_handling.rb +132 -26
- data/lib/active_record/core.rb +75 -52
- data/lib/active_record/counter_cache.rb +4 -29
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +74 -0
- data/lib/active_record/database_configurations.rb +184 -0
- data/lib/active_record/enum.rb +22 -7
- data/lib/active_record/errors.rb +24 -21
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +140 -472
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +12 -2
- data/lib/active_record/integration.rb +56 -16
- data/lib/active_record/internal_metadata.rb +5 -1
- data/lib/active_record/locking/optimistic.rb +2 -2
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +7 -26
- data/lib/active_record/migration/command_recorder.rb +35 -5
- data/lib/active_record/migration/compatibility.rb +34 -16
- data/lib/active_record/migration.rb +38 -37
- data/lib/active_record/model_schema.rb +30 -9
- data/lib/active_record/nested_attributes.rb +2 -2
- data/lib/active_record/no_touching.rb +7 -0
- data/lib/active_record/persistence.rb +18 -7
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +19 -11
- data/lib/active_record/railtie.rb +71 -60
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +94 -43
- data/lib/active_record/reflection.rb +60 -44
- data/lib/active_record/relation/batches.rb +13 -10
- data/lib/active_record/relation/calculations.rb +38 -28
- data/lib/active_record/relation/delegation.rb +4 -13
- data/lib/active_record/relation/finder_methods.rb +12 -25
- data/lib/active_record/relation/merger.rb +2 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/predicate_builder.rb +4 -6
- data/lib/active_record/relation/query_attribute.rb +15 -12
- data/lib/active_record/relation/query_methods.rb +29 -52
- data/lib/active_record/relation/where_clause.rb +4 -0
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/relation.rb +150 -69
- data/lib/active_record/result.rb +30 -11
- data/lib/active_record/sanitization.rb +2 -39
- data/lib/active_record/schema.rb +1 -10
- data/lib/active_record/schema_dumper.rb +12 -6
- data/lib/active_record/schema_migration.rb +4 -0
- data/lib/active_record/scoping/default.rb +10 -3
- data/lib/active_record/scoping/named.rb +10 -14
- data/lib/active_record/scoping.rb +9 -8
- data/lib/active_record/statement_cache.rb +32 -5
- data/lib/active_record/store.rb +39 -8
- data/lib/active_record/table_metadata.rb +1 -4
- data/lib/active_record/tasks/database_tasks.rb +89 -23
- data/lib/active_record/tasks/mysql_database_tasks.rb +2 -4
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
- data/lib/active_record/test_databases.rb +38 -0
- data/lib/active_record/test_fixtures.rb +224 -0
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/transactions.rb +3 -22
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type.rb +3 -4
- data/lib/active_record/type_caster/connection.rb +1 -6
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations/uniqueness.rb +13 -25
- data/lib/active_record.rb +2 -1
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +63 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +44 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values.rb +16 -0
- data/lib/arel/nodes/values_list.rb +24 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/nodes.rb +67 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +257 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/depth_first.rb +199 -0
- data/lib/arel/visitors/dot.rb +292 -0
- data/lib/arel/visitors/ibm_db.rb +21 -0
- data/lib/arel/visitors/informix.rb +56 -0
- data/lib/arel/visitors/mssql.rb +143 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +67 -0
- data/lib/arel/visitors/postgresql.rb +116 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +913 -0
- data/lib/arel/visitors/visitor.rb +42 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +44 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
- data/lib/rails/generators/active_record/migration.rb +14 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
- metadata +107 -29
@@ -44,7 +44,7 @@ module ActiveRecord
|
|
44
44
|
def initialize(values)
|
45
45
|
@values = values
|
46
46
|
@indexes = values.each_with_index.find_all { |thing, i|
|
47
|
-
|
47
|
+
Substitute === thing
|
48
48
|
}.map(&:last)
|
49
49
|
end
|
50
50
|
|
@@ -56,6 +56,28 @@ module ActiveRecord
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
+
class PartialQueryCollector
|
60
|
+
def initialize
|
61
|
+
@parts = []
|
62
|
+
@binds = []
|
63
|
+
end
|
64
|
+
|
65
|
+
def <<(str)
|
66
|
+
@parts << str
|
67
|
+
self
|
68
|
+
end
|
69
|
+
|
70
|
+
def add_bind(obj)
|
71
|
+
@binds << obj
|
72
|
+
@parts << Substitute.new
|
73
|
+
self
|
74
|
+
end
|
75
|
+
|
76
|
+
def value
|
77
|
+
[@parts, @binds]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
59
81
|
def self.query(sql)
|
60
82
|
Query.new(sql)
|
61
83
|
end
|
@@ -64,6 +86,10 @@ module ActiveRecord
|
|
64
86
|
PartialQuery.new(values)
|
65
87
|
end
|
66
88
|
|
89
|
+
def self.partial_query_collector
|
90
|
+
PartialQueryCollector.new
|
91
|
+
end
|
92
|
+
|
67
93
|
class Params # :nodoc:
|
68
94
|
def bind; Substitute.new; end
|
69
95
|
end
|
@@ -87,8 +113,8 @@ module ActiveRecord
|
|
87
113
|
end
|
88
114
|
end
|
89
115
|
|
90
|
-
def self.create(connection,
|
91
|
-
relation =
|
116
|
+
def self.create(connection, block = Proc.new)
|
117
|
+
relation = block.call Params.new
|
92
118
|
query_builder, binds = connection.cacheable_query(self, relation.arel)
|
93
119
|
bind_map = BindMap.new(binds)
|
94
120
|
new(query_builder, bind_map, relation.klass)
|
@@ -106,6 +132,8 @@ module ActiveRecord
|
|
106
132
|
sql = query_builder.sql_for bind_values, connection
|
107
133
|
|
108
134
|
klass.find_by_sql(sql, bind_values, preparable: true, &block)
|
135
|
+
rescue ::RangeError
|
136
|
+
nil
|
109
137
|
end
|
110
138
|
|
111
139
|
def self.unsupported_value?(value)
|
@@ -114,8 +142,7 @@ module ActiveRecord
|
|
114
142
|
end
|
115
143
|
end
|
116
144
|
|
117
|
-
|
118
|
-
|
145
|
+
private
|
119
146
|
attr_reader :query_builder, :bind_map, :klass
|
120
147
|
end
|
121
148
|
end
|
data/lib/active_record/store.rb
CHANGED
@@ -17,8 +17,8 @@ module ActiveRecord
|
|
17
17
|
# You can set custom coder to encode/decode your serialized attributes to/from different formats.
|
18
18
|
# JSON, YAML, Marshal are supported out of the box. Generally it can be any wrapper that provides +load+ and +dump+.
|
19
19
|
#
|
20
|
-
# NOTE: If you are using
|
21
|
-
# the serialization provided by {.store}[rdoc-ref:rdoc-ref:ClassMethods#store].
|
20
|
+
# NOTE: If you are using structured database data types (eg. PostgreSQL +hstore+/+json+, or MySQL 5.7+
|
21
|
+
# +json+) there is no need for the serialization provided by {.store}[rdoc-ref:rdoc-ref:ClassMethods#store].
|
22
22
|
# Simply use {.store_accessor}[rdoc-ref:ClassMethods#store_accessor] instead to generate
|
23
23
|
# the accessor methods. Be aware that these columns use a string keyed hash and do not allow access
|
24
24
|
# using a symbol.
|
@@ -31,10 +31,18 @@ module ActiveRecord
|
|
31
31
|
#
|
32
32
|
# class User < ActiveRecord::Base
|
33
33
|
# store :settings, accessors: [ :color, :homepage ], coder: JSON
|
34
|
+
# store :parent, accessors: [ :name ], coder: JSON, prefix: true
|
35
|
+
# store :spouse, accessors: [ :name ], coder: JSON, prefix: :partner
|
36
|
+
# store :settings, accessors: [ :two_factor_auth ], suffix: true
|
37
|
+
# store :settings, accessors: [ :login_retry ], suffix: :config
|
34
38
|
# end
|
35
39
|
#
|
36
|
-
# u = User.new(color: 'black', homepage: '37signals.com')
|
40
|
+
# u = User.new(color: 'black', homepage: '37signals.com', parent_name: 'Mary', partner_name: 'Lily')
|
37
41
|
# u.color # Accessor stored attribute
|
42
|
+
# u.parent_name # Accessor stored attribute with prefix
|
43
|
+
# u.partner_name # Accessor stored attribute with custom prefix
|
44
|
+
# u.two_factor_auth_settings # Accessor stored attribute with suffix
|
45
|
+
# u.login_retry_config # Accessor stored attribute with custom suffix
|
38
46
|
# u.settings[:country] = 'Denmark' # Any attribute, even if not specified with an accessor
|
39
47
|
#
|
40
48
|
# # There is no difference between strings and symbols for accessing custom attributes
|
@@ -44,11 +52,13 @@ module ActiveRecord
|
|
44
52
|
# # Add additional accessors to an existing store through store_accessor
|
45
53
|
# class SuperUser < User
|
46
54
|
# store_accessor :settings, :privileges, :servants
|
55
|
+
# store_accessor :parent, :birthday, prefix: true
|
56
|
+
# store_accessor :settings, :secret_question, suffix: :config
|
47
57
|
# end
|
48
58
|
#
|
49
59
|
# The stored attribute names can be retrieved using {.stored_attributes}[rdoc-ref:rdoc-ref:ClassMethods#stored_attributes].
|
50
60
|
#
|
51
|
-
# User.stored_attributes[:settings] # [:color, :homepage]
|
61
|
+
# User.stored_attributes[:settings] # [:color, :homepage, :two_factor_auth, :login_retry]
|
52
62
|
#
|
53
63
|
# == Overwriting default accessors
|
54
64
|
#
|
@@ -81,19 +91,40 @@ module ActiveRecord
|
|
81
91
|
module ClassMethods
|
82
92
|
def store(store_attribute, options = {})
|
83
93
|
serialize store_attribute, IndifferentCoder.new(store_attribute, options[:coder])
|
84
|
-
store_accessor(store_attribute, options[:accessors]) if options.has_key? :accessors
|
94
|
+
store_accessor(store_attribute, options[:accessors], options.slice(:prefix, :suffix)) if options.has_key? :accessors
|
85
95
|
end
|
86
96
|
|
87
|
-
def store_accessor(store_attribute, *keys)
|
97
|
+
def store_accessor(store_attribute, *keys, prefix: nil, suffix: nil)
|
88
98
|
keys = keys.flatten
|
89
99
|
|
100
|
+
accessor_prefix =
|
101
|
+
case prefix
|
102
|
+
when String, Symbol
|
103
|
+
"#{prefix}_"
|
104
|
+
when TrueClass
|
105
|
+
"#{store_attribute}_"
|
106
|
+
else
|
107
|
+
""
|
108
|
+
end
|
109
|
+
accessor_suffix =
|
110
|
+
case suffix
|
111
|
+
when String, Symbol
|
112
|
+
"_#{suffix}"
|
113
|
+
when TrueClass
|
114
|
+
"_#{store_attribute}"
|
115
|
+
else
|
116
|
+
""
|
117
|
+
end
|
118
|
+
|
90
119
|
_store_accessors_module.module_eval do
|
91
120
|
keys.each do |key|
|
92
|
-
|
121
|
+
accessor_key = "#{accessor_prefix}#{key}#{accessor_suffix}"
|
122
|
+
|
123
|
+
define_method("#{accessor_key}=") do |value|
|
93
124
|
write_store_attribute(store_attribute, key, value)
|
94
125
|
end
|
95
126
|
|
96
|
-
define_method(
|
127
|
+
define_method(accessor_key) do
|
97
128
|
read_store_attribute(store_attribute, key)
|
98
129
|
end
|
99
130
|
end
|
@@ -73,10 +73,7 @@ module ActiveRecord
|
|
73
73
|
klass.reflect_on_aggregation(aggregation_name)
|
74
74
|
end
|
75
75
|
|
76
|
-
|
77
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
78
|
-
protected
|
79
|
-
|
76
|
+
private
|
80
77
|
attr_reader :klass, :arel_table, :association
|
81
78
|
end
|
82
79
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_record/database_configurations"
|
4
|
+
|
3
5
|
module ActiveRecord
|
4
6
|
module Tasks # :nodoc:
|
5
7
|
class DatabaseAlreadyExists < StandardError; end # :nodoc:
|
@@ -8,7 +10,7 @@ module ActiveRecord
|
|
8
10
|
# ActiveRecord::Tasks::DatabaseTasks is a utility class, which encapsulates
|
9
11
|
# logic behind common tasks used to manage database and migrations.
|
10
12
|
#
|
11
|
-
# The tasks defined here are used with
|
13
|
+
# The tasks defined here are used with Rails commands provided by Active Record.
|
12
14
|
#
|
13
15
|
# In order to use DatabaseTasks, a few config values need to be set. All the needed
|
14
16
|
# config values are set by Rails already, so it's necessary to do it only if you
|
@@ -101,25 +103,30 @@ module ActiveRecord
|
|
101
103
|
@env ||= Rails.env
|
102
104
|
end
|
103
105
|
|
106
|
+
def spec
|
107
|
+
@spec ||= "primary"
|
108
|
+
end
|
109
|
+
|
104
110
|
def seed_loader
|
105
111
|
@seed_loader ||= Rails.application
|
106
112
|
end
|
107
113
|
|
108
114
|
def current_config(options = {})
|
109
115
|
options.reverse_merge! env: env
|
116
|
+
options[:spec] ||= "primary"
|
110
117
|
if options.has_key?(:config)
|
111
118
|
@current_config = options[:config]
|
112
119
|
else
|
113
|
-
@current_config ||= ActiveRecord::Base.configurations
|
120
|
+
@current_config ||= ActiveRecord::Base.configurations.configs_for(env_name: options[:env], spec_name: options[:spec]).config
|
114
121
|
end
|
115
122
|
end
|
116
123
|
|
117
124
|
def create(*arguments)
|
118
125
|
configuration = arguments.first
|
119
126
|
class_for_adapter(configuration["adapter"]).new(*arguments).create
|
120
|
-
$stdout.puts "Created database '#{configuration['database']}'"
|
127
|
+
$stdout.puts "Created database '#{configuration['database']}'" if verbose?
|
121
128
|
rescue DatabaseAlreadyExists
|
122
|
-
$stderr.puts "Database '#{configuration['database']}' already exists"
|
129
|
+
$stderr.puts "Database '#{configuration['database']}' already exists" if verbose?
|
123
130
|
rescue Exception => error
|
124
131
|
$stderr.puts error
|
125
132
|
$stderr.puts "Couldn't create '#{configuration['database']}' database. Please check your configuration."
|
@@ -134,6 +141,18 @@ module ActiveRecord
|
|
134
141
|
end
|
135
142
|
end
|
136
143
|
|
144
|
+
def for_each
|
145
|
+
databases = Rails.application.config.database_configuration
|
146
|
+
database_configs = ActiveRecord::DatabaseConfigurations.new(databases).configs_for(env_name: Rails.env)
|
147
|
+
|
148
|
+
# if this is a single database application we don't want tasks for each primary database
|
149
|
+
return if database_configs.count == 1
|
150
|
+
|
151
|
+
database_configs.each do |db_config|
|
152
|
+
yield db_config.spec_name
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
137
156
|
def create_current(environment = env)
|
138
157
|
each_current_configuration(environment) { |configuration|
|
139
158
|
create configuration
|
@@ -144,7 +163,7 @@ module ActiveRecord
|
|
144
163
|
def drop(*arguments)
|
145
164
|
configuration = arguments.first
|
146
165
|
class_for_adapter(configuration["adapter"]).new(*arguments).drop
|
147
|
-
$stdout.puts "Dropped database '#{configuration['database']}'"
|
166
|
+
$stdout.puts "Dropped database '#{configuration['database']}'" if verbose?
|
148
167
|
rescue ActiveRecord::NoDatabaseError
|
149
168
|
$stderr.puts "Database '#{configuration['database']}' does not exist"
|
150
169
|
rescue Exception => error
|
@@ -166,17 +185,33 @@ module ActiveRecord
|
|
166
185
|
def migrate
|
167
186
|
check_target_version
|
168
187
|
|
169
|
-
verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] != "false" : true
|
170
188
|
scope = ENV["SCOPE"]
|
171
|
-
verbose_was, Migration.verbose = Migration.verbose, verbose
|
189
|
+
verbose_was, Migration.verbose = Migration.verbose, verbose?
|
190
|
+
|
172
191
|
Base.connection.migration_context.migrate(target_version) do |migration|
|
173
192
|
scope.blank? || scope == migration.scope
|
174
193
|
end
|
194
|
+
|
175
195
|
ActiveRecord::Base.clear_cache!
|
176
196
|
ensure
|
177
197
|
Migration.verbose = verbose_was
|
178
198
|
end
|
179
199
|
|
200
|
+
def migrate_status
|
201
|
+
unless ActiveRecord::SchemaMigration.table_exists?
|
202
|
+
Kernel.abort "Schema migrations table does not exist yet."
|
203
|
+
end
|
204
|
+
|
205
|
+
# output
|
206
|
+
puts "\ndatabase: #{ActiveRecord::Base.connection_config[:database]}\n\n"
|
207
|
+
puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
|
208
|
+
puts "-" * 50
|
209
|
+
ActiveRecord::Base.connection.migration_context.migrations_status.each do |status, version, name|
|
210
|
+
puts "#{status.center(8)} #{version.ljust(14)} #{name}"
|
211
|
+
end
|
212
|
+
puts
|
213
|
+
end
|
214
|
+
|
180
215
|
def check_target_version
|
181
216
|
if target_version && !(Migration::MigrationFilenameRegexp.match?(ENV["VERSION"]) || /\A\d+\z/.match?(ENV["VERSION"]))
|
182
217
|
raise "Invalid format of target version: `VERSION=#{ENV['VERSION']}`"
|
@@ -187,8 +222,8 @@ module ActiveRecord
|
|
187
222
|
ENV["VERSION"].to_i if ENV["VERSION"] && !ENV["VERSION"].empty?
|
188
223
|
end
|
189
224
|
|
190
|
-
def charset_current(environment = env)
|
191
|
-
charset ActiveRecord::Base.configurations
|
225
|
+
def charset_current(environment = env, specification_name = spec)
|
226
|
+
charset ActiveRecord::Base.configurations.configs_for(env_name: environment, spec_name: specification_name).config
|
192
227
|
end
|
193
228
|
|
194
229
|
def charset(*arguments)
|
@@ -196,8 +231,8 @@ module ActiveRecord
|
|
196
231
|
class_for_adapter(configuration["adapter"]).new(*arguments).charset
|
197
232
|
end
|
198
233
|
|
199
|
-
def collation_current(environment = env)
|
200
|
-
collation ActiveRecord::Base.configurations
|
234
|
+
def collation_current(environment = env, specification_name = spec)
|
235
|
+
collation ActiveRecord::Base.configurations.configs_for(env_name: environment, spec_name: specification_name).config
|
201
236
|
end
|
202
237
|
|
203
238
|
def collation(*arguments)
|
@@ -234,9 +269,10 @@ module ActiveRecord
|
|
234
269
|
class_for_adapter(configuration["adapter"]).new(*arguments).structure_load(filename, structure_load_flags)
|
235
270
|
end
|
236
271
|
|
237
|
-
def load_schema(configuration, format = ActiveRecord::Base.schema_format, file = nil, environment = env) # :nodoc:
|
238
|
-
file ||=
|
272
|
+
def load_schema(configuration, format = ActiveRecord::Base.schema_format, file = nil, environment = env, spec_name = "primary") # :nodoc:
|
273
|
+
file ||= dump_filename(spec_name, format)
|
239
274
|
|
275
|
+
verbose_was, Migration.verbose = Migration.verbose, verbose? && ENV["VERBOSE"]
|
240
276
|
check_schema_file(file)
|
241
277
|
ActiveRecord::Base.establish_connection(configuration)
|
242
278
|
|
@@ -250,27 +286,53 @@ module ActiveRecord
|
|
250
286
|
end
|
251
287
|
ActiveRecord::InternalMetadata.create_table
|
252
288
|
ActiveRecord::InternalMetadata[:environment] = environment
|
289
|
+
ensure
|
290
|
+
Migration.verbose = verbose_was
|
253
291
|
end
|
254
292
|
|
255
293
|
def schema_file(format = ActiveRecord::Base.schema_format)
|
294
|
+
File.join(db_dir, schema_file_type(format))
|
295
|
+
end
|
296
|
+
|
297
|
+
def schema_file_type(format = ActiveRecord::Base.schema_format)
|
256
298
|
case format
|
257
299
|
when :ruby
|
258
|
-
|
300
|
+
"schema.rb"
|
259
301
|
when :sql
|
260
|
-
|
302
|
+
"structure.sql"
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
def dump_filename(namespace, format = ActiveRecord::Base.schema_format)
|
307
|
+
filename = if namespace == "primary"
|
308
|
+
schema_file_type(format)
|
309
|
+
else
|
310
|
+
"#{namespace}_#{schema_file_type(format)}"
|
311
|
+
end
|
312
|
+
|
313
|
+
ENV["SCHEMA"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, filename)
|
314
|
+
end
|
315
|
+
|
316
|
+
def cache_dump_filename(namespace)
|
317
|
+
filename = if namespace == "primary"
|
318
|
+
"schema_cache.yml"
|
319
|
+
else
|
320
|
+
"#{namespace}_schema_cache.yml"
|
261
321
|
end
|
322
|
+
|
323
|
+
ENV["SCHEMA_CACHE"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, filename)
|
262
324
|
end
|
263
325
|
|
264
326
|
def load_schema_current(format = ActiveRecord::Base.schema_format, file = nil, environment = env)
|
265
|
-
each_current_configuration(environment) { |configuration,
|
266
|
-
load_schema
|
327
|
+
each_current_configuration(environment) { |configuration, spec_name, env|
|
328
|
+
load_schema(configuration, format, file, env, spec_name)
|
267
329
|
}
|
268
330
|
ActiveRecord::Base.establish_connection(environment.to_sym)
|
269
331
|
end
|
270
332
|
|
271
333
|
def check_schema_file(filename)
|
272
334
|
unless File.exist?(filename)
|
273
|
-
message =
|
335
|
+
message = +%{#{filename} doesn't exist yet. Run `rails db:migrate` to create it, then try again.}
|
274
336
|
message << %{ If you do not intend to use a database, you should instead alter #{Rails.root}/config/application.rb to limit the frameworks that will be loaded.} if defined?(::Rails.root)
|
275
337
|
Kernel.abort message
|
276
338
|
end
|
@@ -297,6 +359,9 @@ module ActiveRecord
|
|
297
359
|
end
|
298
360
|
|
299
361
|
private
|
362
|
+
def verbose?
|
363
|
+
ENV["VERBOSE"] ? ENV["VERBOSE"] != "false" : true
|
364
|
+
end
|
300
365
|
|
301
366
|
def class_for_adapter(adapter)
|
302
367
|
_key, task = @tasks.each_pair.detect { |pattern, _task| adapter[pattern] }
|
@@ -310,15 +375,16 @@ module ActiveRecord
|
|
310
375
|
environments = [environment]
|
311
376
|
environments << "test" if environment == "development"
|
312
377
|
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
378
|
+
environments.each do |env|
|
379
|
+
ActiveRecord::Base.configurations.configs_for(env_name: env).each do |db_config|
|
380
|
+
yield db_config.config, db_config.spec_name, env
|
381
|
+
end
|
317
382
|
end
|
318
383
|
end
|
319
384
|
|
320
385
|
def each_local_configuration
|
321
|
-
ActiveRecord::Base.configurations.
|
386
|
+
ActiveRecord::Base.configurations.configs_for.each do |db_config|
|
387
|
+
configuration = db_config.config
|
322
388
|
next unless configuration["database"]
|
323
389
|
|
324
390
|
if local_database?(configuration)
|
@@ -68,9 +68,7 @@ module ActiveRecord
|
|
68
68
|
|
69
69
|
private
|
70
70
|
|
71
|
-
|
72
|
-
@configuration
|
73
|
-
end
|
71
|
+
attr_reader :configuration
|
74
72
|
|
75
73
|
def configuration_without_database
|
76
74
|
configuration.merge("database" => nil)
|
@@ -106,7 +104,7 @@ module ActiveRecord
|
|
106
104
|
end
|
107
105
|
|
108
106
|
def run_cmd_error(cmd, args, action)
|
109
|
-
msg = "failed to execute: `#{cmd}`\n"
|
107
|
+
msg = +"failed to execute: `#{cmd}`\n"
|
110
108
|
msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
|
111
109
|
msg
|
112
110
|
end
|
@@ -6,8 +6,8 @@ module ActiveRecord
|
|
6
6
|
module Tasks # :nodoc:
|
7
7
|
class PostgreSQLDatabaseTasks # :nodoc:
|
8
8
|
DEFAULT_ENCODING = ENV["CHARSET"] || "utf8"
|
9
|
-
ON_ERROR_STOP_1 = "ON_ERROR_STOP=1"
|
10
|
-
SQL_COMMENT_BEGIN = "--"
|
9
|
+
ON_ERROR_STOP_1 = "ON_ERROR_STOP=1"
|
10
|
+
SQL_COMMENT_BEGIN = "--"
|
11
11
|
|
12
12
|
delegate :connection, :establish_connection, :clear_active_connections!,
|
13
13
|
to: ActiveRecord::Base
|
@@ -82,7 +82,7 @@ module ActiveRecord
|
|
82
82
|
|
83
83
|
def structure_load(filename, extra_flags)
|
84
84
|
set_psql_env
|
85
|
-
args = ["-v", ON_ERROR_STOP_1, "-q", "-f", filename]
|
85
|
+
args = ["-v", ON_ERROR_STOP_1, "-q", "-X", "-f", filename]
|
86
86
|
args.concat(Array(extra_flags)) if extra_flags
|
87
87
|
args << configuration["database"]
|
88
88
|
run_cmd("psql", args, "loading")
|
@@ -90,9 +90,7 @@ module ActiveRecord
|
|
90
90
|
|
91
91
|
private
|
92
92
|
|
93
|
-
|
94
|
-
@configuration
|
95
|
-
end
|
93
|
+
attr_reader :configuration
|
96
94
|
|
97
95
|
def encoding
|
98
96
|
configuration["encoding"] || DEFAULT_ENCODING
|
@@ -117,7 +115,7 @@ module ActiveRecord
|
|
117
115
|
end
|
118
116
|
|
119
117
|
def run_cmd_error(cmd, args, action)
|
120
|
-
msg = "failed to execute:\n"
|
118
|
+
msg = +"failed to execute:\n"
|
121
119
|
msg << "#{cmd} #{args.join(' ')}\n\n"
|
122
120
|
msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
|
123
121
|
msg
|
@@ -60,20 +60,14 @@ module ActiveRecord
|
|
60
60
|
|
61
61
|
private
|
62
62
|
|
63
|
-
|
64
|
-
@configuration
|
65
|
-
end
|
66
|
-
|
67
|
-
def root
|
68
|
-
@root
|
69
|
-
end
|
63
|
+
attr_reader :configuration, :root
|
70
64
|
|
71
65
|
def run_cmd(cmd, args, out)
|
72
66
|
fail run_cmd_error(cmd, args) unless Kernel.system(cmd, *args, out: out)
|
73
67
|
end
|
74
68
|
|
75
69
|
def run_cmd_error(cmd, args)
|
76
|
-
msg = "failed to execute:\n"
|
70
|
+
msg = +"failed to execute:\n"
|
77
71
|
msg << "#{cmd} #{args.join(' ')}\n\n"
|
78
72
|
msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
|
79
73
|
msg
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/testing/parallelization"
|
4
|
+
|
5
|
+
module ActiveRecord
|
6
|
+
module TestDatabases # :nodoc:
|
7
|
+
ActiveSupport::Testing::Parallelization.after_fork_hook do |i|
|
8
|
+
create_and_load_schema(i, env_name: Rails.env)
|
9
|
+
end
|
10
|
+
|
11
|
+
ActiveSupport::Testing::Parallelization.run_cleanup_hook do
|
12
|
+
drop(env_name: Rails.env)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.create_and_load_schema(i, env_name:)
|
16
|
+
old, ENV["VERBOSE"] = ENV["VERBOSE"], "false"
|
17
|
+
|
18
|
+
ActiveRecord::Base.configurations.configs_for(env_name: env_name).each do |db_config|
|
19
|
+
db_config.config["database"] += "-#{i}"
|
20
|
+
ActiveRecord::Tasks::DatabaseTasks.create(db_config.config)
|
21
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config.config, ActiveRecord::Base.schema_format, nil, env_name, db_config.spec_name)
|
22
|
+
end
|
23
|
+
ensure
|
24
|
+
ActiveRecord::Base.establish_connection(Rails.env.to_sym)
|
25
|
+
ENV["VERBOSE"] = old
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.drop(env_name:)
|
29
|
+
old, ENV["VERBOSE"] = ENV["VERBOSE"], "false"
|
30
|
+
|
31
|
+
ActiveRecord::Base.configurations.configs_for(env_name: env_name).each do |db_config|
|
32
|
+
ActiveRecord::Tasks::DatabaseTasks.drop(db_config.config)
|
33
|
+
end
|
34
|
+
ensure
|
35
|
+
ENV["VERBOSE"] = old
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|