activerecord 6.0.0.beta1 → 6.0.0
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 +455 -9
- data/README.rdoc +3 -1
- data/lib/active_record/associations/association.rb +18 -1
- 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 +5 -6
- data/lib/active_record/associations/collection_proxy.rb +13 -42
- data/lib/active_record/associations/has_many_association.rb +1 -9
- data/lib/active_record/associations/has_many_through_association.rb +4 -11
- data/lib/active_record/associations/join_dependency/join_association.rb +21 -7
- data/lib/active_record/associations/join_dependency.rb +10 -9
- data/lib/active_record/associations/preloader/association.rb +37 -34
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- data/lib/active_record/associations/preloader.rb +11 -6
- data/lib/active_record/associations.rb +3 -2
- 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/attribute_methods.rb +3 -53
- data/lib/active_record/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +15 -5
- data/lib/active_record/base.rb +0 -1
- data/lib/active_record/callbacks.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +124 -23
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +8 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +101 -70
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +11 -5
- data/lib/active_record/connection_adapters/abstract/quoting.rb +63 -6
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +5 -2
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +51 -40
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +95 -30
- data/lib/active_record/connection_adapters/abstract/transaction.rb +17 -6
- data/lib/active_record/connection_adapters/abstract_adapter.rb +108 -39
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +93 -134
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +1 -1
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +3 -3
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -7
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +66 -5
- 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 +5 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +40 -3
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +98 -89
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +47 -63
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +23 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +91 -24
- 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 +118 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +38 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +28 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +69 -118
- data/lib/active_record/connection_handling.rb +32 -16
- data/lib/active_record/core.rb +27 -20
- data/lib/active_record/database_configurations/hash_config.rb +11 -11
- data/lib/active_record/database_configurations/url_config.rb +21 -16
- data/lib/active_record/database_configurations.rb +99 -50
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +15 -0
- data/lib/active_record/errors.rb +18 -13
- data/lib/active_record/fixtures.rb +11 -6
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/inheritance.rb +1 -1
- 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/resolver/session.rb +45 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/migration/command_recorder.rb +28 -14
- data/lib/active_record/migration/compatibility.rb +72 -63
- data/lib/active_record/migration.rb +62 -44
- data/lib/active_record/persistence.rb +212 -19
- data/lib/active_record/querying.rb +18 -14
- data/lib/active_record/railtie.rb +9 -1
- data/lib/active_record/railties/collection_cache_association_loading.rb +3 -3
- data/lib/active_record/railties/databases.rake +124 -25
- data/lib/active_record/reflection.rb +18 -32
- data/lib/active_record/relation/calculations.rb +40 -44
- data/lib/active_record/relation/delegation.rb +23 -31
- data/lib/active_record/relation/finder_methods.rb +13 -13
- data/lib/active_record/relation/merger.rb +11 -16
- data/lib/active_record/relation/query_attribute.rb +5 -3
- data/lib/active_record/relation/query_methods.rb +217 -68
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation/where_clause.rb +10 -10
- data/lib/active_record/relation.rb +184 -35
- 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 +7 -15
- data/lib/active_record/scoping/named.rb +10 -2
- data/lib/active_record/scoping.rb +6 -7
- 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 +2 -2
- data/lib/active_record/timestamp.rb +35 -19
- data/lib/active_record/touch_later.rb +4 -2
- data/lib/active_record/transactions.rb +55 -45
- data/lib/active_record/type_caster/connection.rb +16 -10
- data/lib/active_record/validations/uniqueness.rb +4 -4
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record.rb +7 -1
- data/lib/arel/insert_manager.rb +3 -3
- data/lib/arel/nodes/and.rb +1 -1
- data/lib/arel/nodes/case.rb +1 -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/nodes.rb +2 -1
- 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/arel.rb +7 -0
- 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 +17 -13
- data/lib/active_record/collection_cache_key.rb +0 -53
- data/lib/arel/nodes/values.rb +0 -16
@@ -2,18 +2,23 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
module Querying
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
5
|
+
QUERYING_METHODS = [
|
6
|
+
:find, :find_by, :find_by!, :take, :take!, :first, :first!, :last, :last!,
|
7
|
+
:second, :second!, :third, :third!, :fourth, :fourth!, :fifth, :fifth!,
|
8
|
+
:forty_two, :forty_two!, :third_to_last, :third_to_last!, :second_to_last, :second_to_last!,
|
9
|
+
:exists?, :any?, :many?, :none?, :one?,
|
10
|
+
:first_or_create, :first_or_create!, :first_or_initialize,
|
11
|
+
:find_or_create_by, :find_or_create_by!, :find_or_initialize_by,
|
12
|
+
:create_or_find_by, :create_or_find_by!,
|
13
|
+
:destroy_all, :delete_all, :update_all, :touch_all, :destroy_by, :delete_by,
|
14
|
+
:find_each, :find_in_batches, :in_batches,
|
15
|
+
:select, :reselect, :order, :reorder, :group, :limit, :offset, :joins, :left_joins, :left_outer_joins,
|
16
|
+
:where, :rewhere, :preload, :extract_associated, :eager_load, :includes, :from, :lock, :readonly, :extending, :or,
|
17
|
+
:having, :create_with, :distinct, :references, :none, :unscope, :optimizer_hints, :merge, :except, :only,
|
18
|
+
:count, :average, :minimum, :maximum, :sum, :calculate, :annotate,
|
19
|
+
:pluck, :pick, :ids
|
20
|
+
].freeze # :nodoc:
|
21
|
+
delegate(*QUERYING_METHODS, to: :all)
|
17
22
|
|
18
23
|
# Executes a custom SQL query against your database and returns all the results. The results will
|
19
24
|
# be returned as an array, with the requested columns encapsulated as attributes of the model you call
|
@@ -40,8 +45,7 @@ module ActiveRecord
|
|
40
45
|
def find_by_sql(sql, binds = [], preparable: nil, &block)
|
41
46
|
result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable)
|
42
47
|
column_types = result_set.column_types.dup
|
43
|
-
|
44
|
-
cached_columns_hash.each_key { |k| column_types.delete k }
|
48
|
+
attribute_types.each_key { |k| column_types.delete k }
|
45
49
|
message_bus = ActiveSupport::Notifications.instrumenter
|
46
50
|
|
47
51
|
payload = {
|
@@ -88,6 +88,14 @@ module ActiveRecord
|
|
88
88
|
end
|
89
89
|
end
|
90
90
|
|
91
|
+
initializer "active_record.database_selector" do
|
92
|
+
if options = config.active_record.delete(:database_selector)
|
93
|
+
resolver = config.active_record.delete(:database_resolver)
|
94
|
+
operations = config.active_record.delete(:database_resolver_context)
|
95
|
+
config.app_middleware.use ActiveRecord::Middleware::DatabaseSelector, resolver, operations, options
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
91
99
|
initializer "Check for cache versioning support" do
|
92
100
|
config.after_initialize do |app|
|
93
101
|
ActiveSupport.on_load(:active_record) do
|
@@ -126,7 +134,6 @@ end_error
|
|
126
134
|
|
127
135
|
cache = YAML.load(File.read(filename))
|
128
136
|
if cache.version == current_version
|
129
|
-
connection.schema_cache = cache
|
130
137
|
connection_pool.schema_cache = cache.dup
|
131
138
|
else
|
132
139
|
warn "Ignoring db/schema_cache.yml because it has expired. The current schema version is #{current_version}, but the one in the cache is #{cache.version}."
|
@@ -189,6 +196,7 @@ end_error
|
|
189
196
|
# and then establishes the connection.
|
190
197
|
initializer "active_record.initialize_database" do
|
191
198
|
ActiveSupport.on_load(:active_record) do
|
199
|
+
self.connection_handlers = { writing_role => ActiveRecord::Base.default_connection_handler }
|
192
200
|
self.configurations = Rails.application.config.database_configuration
|
193
201
|
establish_connection
|
194
202
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module ActiveRecord
|
4
4
|
module Railties # :nodoc:
|
5
5
|
module CollectionCacheAssociationLoading #:nodoc:
|
6
|
-
def setup(context, options, block)
|
6
|
+
def setup(context, options, as, block)
|
7
7
|
@relation = relation_from_options(options)
|
8
8
|
|
9
9
|
super
|
@@ -20,12 +20,12 @@ module ActiveRecord
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
def collection_without_template
|
23
|
+
def collection_without_template(*)
|
24
24
|
@relation.preload_associations(@collection) if @relation
|
25
25
|
super
|
26
26
|
end
|
27
27
|
|
28
|
-
def collection_with_template
|
28
|
+
def collection_with_template(*)
|
29
29
|
@relation.preload_associations(@collection) if @relation
|
30
30
|
super
|
31
31
|
end
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
require "active_record"
|
4
4
|
|
5
|
+
databases = ActiveRecord::Tasks::DatabaseTasks.setup_initial_database_yaml
|
6
|
+
|
5
7
|
db_namespace = namespace :db do
|
6
8
|
desc "Set the environment value for the database"
|
7
9
|
task "environment:set" => :load_config do
|
@@ -23,7 +25,7 @@ db_namespace = namespace :db do
|
|
23
25
|
ActiveRecord::Tasks::DatabaseTasks.create_all
|
24
26
|
end
|
25
27
|
|
26
|
-
ActiveRecord::Tasks::DatabaseTasks.for_each do |spec_name|
|
28
|
+
ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
|
27
29
|
desc "Create #{spec_name} database for current environment"
|
28
30
|
task spec_name => :load_config do
|
29
31
|
db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
|
@@ -42,7 +44,7 @@ db_namespace = namespace :db do
|
|
42
44
|
ActiveRecord::Tasks::DatabaseTasks.drop_all
|
43
45
|
end
|
44
46
|
|
45
|
-
ActiveRecord::Tasks::DatabaseTasks.for_each do |spec_name|
|
47
|
+
ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
|
46
48
|
desc "Drop #{spec_name} database for current environment"
|
47
49
|
task spec_name => [:load_config, :check_protected_environments] do
|
48
50
|
db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
|
@@ -66,6 +68,11 @@ db_namespace = namespace :db do
|
|
66
68
|
end
|
67
69
|
end
|
68
70
|
|
71
|
+
# desc "Truncates tables of each database for current environment"
|
72
|
+
task truncate_all: [:load_config, :check_protected_environments] do
|
73
|
+
ActiveRecord::Tasks::DatabaseTasks.truncate_all
|
74
|
+
end
|
75
|
+
|
69
76
|
# desc "Empty the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:purge:all to purge all databases in the config). Without RAILS_ENV it defaults to purging the development and test databases."
|
70
77
|
task purge: [:load_config, :check_protected_environments] do
|
71
78
|
ActiveRecord::Tasks::DatabaseTasks.purge_current
|
@@ -73,7 +80,7 @@ db_namespace = namespace :db do
|
|
73
80
|
|
74
81
|
desc "Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)."
|
75
82
|
task migrate: :load_config do
|
76
|
-
ActiveRecord::Base.configurations.configs_for(env_name:
|
83
|
+
ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
|
77
84
|
ActiveRecord::Base.establish_connection(db_config.config)
|
78
85
|
ActiveRecord::Tasks::DatabaseTasks.migrate
|
79
86
|
end
|
@@ -96,7 +103,7 @@ db_namespace = namespace :db do
|
|
96
103
|
end
|
97
104
|
|
98
105
|
namespace :migrate do
|
99
|
-
ActiveRecord::Tasks::DatabaseTasks.for_each do |spec_name|
|
106
|
+
ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
|
100
107
|
desc "Migrate #{spec_name} database for current environment"
|
101
108
|
task spec_name => :load_config do
|
102
109
|
db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
|
@@ -123,6 +130,8 @@ db_namespace = namespace :db do
|
|
123
130
|
|
124
131
|
# desc 'Runs the "up" for a given migration VERSION.'
|
125
132
|
task up: :load_config do
|
133
|
+
ActiveRecord::Tasks::DatabaseTasks.raise_for_multi_db(command: "db:migrate:up")
|
134
|
+
|
126
135
|
raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty?
|
127
136
|
|
128
137
|
ActiveRecord::Tasks::DatabaseTasks.check_target_version
|
@@ -134,8 +143,29 @@ db_namespace = namespace :db do
|
|
134
143
|
db_namespace["_dump"].invoke
|
135
144
|
end
|
136
145
|
|
146
|
+
namespace :up do
|
147
|
+
ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
|
148
|
+
task spec_name => :load_config do
|
149
|
+
raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty?
|
150
|
+
|
151
|
+
db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
|
152
|
+
|
153
|
+
ActiveRecord::Base.establish_connection(db_config.config)
|
154
|
+
ActiveRecord::Tasks::DatabaseTasks.check_target_version
|
155
|
+
ActiveRecord::Base.connection.migration_context.run(
|
156
|
+
:up,
|
157
|
+
ActiveRecord::Tasks::DatabaseTasks.target_version
|
158
|
+
)
|
159
|
+
|
160
|
+
db_namespace["_dump"].invoke
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
137
165
|
# desc 'Runs the "down" for a given migration VERSION.'
|
138
166
|
task down: :load_config do
|
167
|
+
ActiveRecord::Tasks::DatabaseTasks.raise_for_multi_db(command: "db:migrate:down")
|
168
|
+
|
139
169
|
raise "VERSION is required - To go down one migration, use db:rollback" if !ENV["VERSION"] || ENV["VERSION"].empty?
|
140
170
|
|
141
171
|
ActiveRecord::Tasks::DatabaseTasks.check_target_version
|
@@ -147,16 +177,35 @@ db_namespace = namespace :db do
|
|
147
177
|
db_namespace["_dump"].invoke
|
148
178
|
end
|
149
179
|
|
180
|
+
namespace :down do
|
181
|
+
ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
|
182
|
+
task spec_name => :load_config do
|
183
|
+
raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty?
|
184
|
+
|
185
|
+
db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
|
186
|
+
|
187
|
+
ActiveRecord::Base.establish_connection(db_config.config)
|
188
|
+
ActiveRecord::Tasks::DatabaseTasks.check_target_version
|
189
|
+
ActiveRecord::Base.connection.migration_context.run(
|
190
|
+
:down,
|
191
|
+
ActiveRecord::Tasks::DatabaseTasks.target_version
|
192
|
+
)
|
193
|
+
|
194
|
+
db_namespace["_dump"].invoke
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
150
199
|
desc "Display status of migrations"
|
151
200
|
task status: :load_config do
|
152
|
-
ActiveRecord::Base.configurations.configs_for(env_name:
|
201
|
+
ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
|
153
202
|
ActiveRecord::Base.establish_connection(db_config.config)
|
154
203
|
ActiveRecord::Tasks::DatabaseTasks.migrate_status
|
155
204
|
end
|
156
205
|
end
|
157
206
|
|
158
207
|
namespace :status do
|
159
|
-
ActiveRecord::Tasks::DatabaseTasks.for_each do |spec_name|
|
208
|
+
ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
|
160
209
|
desc "Display status of migrations for #{spec_name} database"
|
161
210
|
task spec_name => :load_config do
|
162
211
|
db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
|
@@ -203,7 +252,11 @@ db_namespace = namespace :db do
|
|
203
252
|
|
204
253
|
# desc "Raises an error if there are pending migrations"
|
205
254
|
task abort_if_pending_migrations: :load_config do
|
206
|
-
pending_migrations = ActiveRecord::Base.
|
255
|
+
pending_migrations = ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).flat_map do |db_config|
|
256
|
+
ActiveRecord::Base.establish_connection(db_config.config)
|
257
|
+
|
258
|
+
ActiveRecord::Base.connection.migration_context.open.pending_migrations
|
259
|
+
end
|
207
260
|
|
208
261
|
if pending_migrations.any?
|
209
262
|
puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}"
|
@@ -212,17 +265,74 @@ db_namespace = namespace :db do
|
|
212
265
|
end
|
213
266
|
abort %{Run `rails db:migrate` to update your database then try again.}
|
214
267
|
end
|
268
|
+
ensure
|
269
|
+
ActiveRecord::Base.establish_connection(ActiveRecord::Tasks::DatabaseTasks.env.to_sym)
|
270
|
+
end
|
271
|
+
|
272
|
+
namespace :abort_if_pending_migrations do
|
273
|
+
ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
|
274
|
+
# desc "Raises an error if there are pending migrations for #{spec_name} database"
|
275
|
+
task spec_name => :load_config do
|
276
|
+
db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
|
277
|
+
ActiveRecord::Base.establish_connection(db_config.config)
|
278
|
+
|
279
|
+
pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations
|
280
|
+
|
281
|
+
if pending_migrations.any?
|
282
|
+
puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}"
|
283
|
+
pending_migrations.each do |pending_migration|
|
284
|
+
puts " %4d %s" % [pending_migration.version, pending_migration.name]
|
285
|
+
end
|
286
|
+
abort %{Run `rails db:migrate:#{spec_name}` to update your database then try again.}
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
215
290
|
end
|
216
291
|
|
217
292
|
desc "Creates the database, loads the schema, and initializes with the seed data (use db:reset to also drop the database first)"
|
218
293
|
task setup: ["db:schema:load_if_ruby", "db:structure:load_if_sql", :seed]
|
219
294
|
|
295
|
+
desc "Runs setup if database does not exist, or runs migrations if it does"
|
296
|
+
task prepare: :load_config do
|
297
|
+
seed = false
|
298
|
+
|
299
|
+
ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
|
300
|
+
ActiveRecord::Base.establish_connection(db_config.config)
|
301
|
+
|
302
|
+
# Skipped when no database
|
303
|
+
ActiveRecord::Tasks::DatabaseTasks.migrate
|
304
|
+
if ActiveRecord::Base.dump_schema_after_migration
|
305
|
+
ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config.config, ActiveRecord::Base.schema_format, db_config.spec_name)
|
306
|
+
end
|
307
|
+
|
308
|
+
rescue ActiveRecord::NoDatabaseError
|
309
|
+
ActiveRecord::Tasks::DatabaseTasks.create_current(db_config.env_name, db_config.spec_name)
|
310
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema(
|
311
|
+
db_config.config,
|
312
|
+
ActiveRecord::Base.schema_format,
|
313
|
+
nil,
|
314
|
+
db_config.env_name,
|
315
|
+
db_config.spec_name
|
316
|
+
)
|
317
|
+
|
318
|
+
seed = true
|
319
|
+
end
|
320
|
+
|
321
|
+
ActiveRecord::Base.establish_connection
|
322
|
+
ActiveRecord::Tasks::DatabaseTasks.load_seed if seed
|
323
|
+
end
|
324
|
+
|
220
325
|
desc "Loads the seed data from db/seeds.rb"
|
221
326
|
task seed: :load_config do
|
222
327
|
db_namespace["abort_if_pending_migrations"].invoke
|
223
328
|
ActiveRecord::Tasks::DatabaseTasks.load_seed
|
224
329
|
end
|
225
330
|
|
331
|
+
namespace :seed do
|
332
|
+
desc "Truncates tables of each database for current environment and loads the seeds"
|
333
|
+
task replant: [:load_config, :truncate_all, :seed]
|
334
|
+
end
|
335
|
+
|
226
336
|
namespace :fixtures do
|
227
337
|
desc "Loads fixtures into the current environment's database. Load specific fixtures using FIXTURES=x,y. Load from subdirectory in test/fixtures using FIXTURES_DIR=z. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures."
|
228
338
|
task load: :load_config do
|
@@ -274,13 +384,9 @@ db_namespace = namespace :db do
|
|
274
384
|
namespace :schema do
|
275
385
|
desc "Creates a db/schema.rb file that is portable against any DB supported by Active Record"
|
276
386
|
task dump: :load_config do
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
File.open(filename, "w:utf-8") do |file|
|
281
|
-
ActiveRecord::Base.establish_connection(db_config.config)
|
282
|
-
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
|
283
|
-
end
|
387
|
+
ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
|
388
|
+
ActiveRecord::Base.establish_connection(db_config.config)
|
389
|
+
ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config.config, :ruby, db_config.spec_name)
|
284
390
|
end
|
285
391
|
|
286
392
|
db_namespace["schema:dump"].reenable
|
@@ -298,7 +404,7 @@ db_namespace = namespace :db do
|
|
298
404
|
namespace :cache do
|
299
405
|
desc "Creates a db/schema_cache.yml file."
|
300
406
|
task dump: :load_config do
|
301
|
-
ActiveRecord::Base.configurations.configs_for(env_name:
|
407
|
+
ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
|
302
408
|
ActiveRecord::Base.establish_connection(db_config.config)
|
303
409
|
filename = ActiveRecord::Tasks::DatabaseTasks.cache_dump_filename(db_config.spec_name)
|
304
410
|
ActiveRecord::Tasks::DatabaseTasks.dump_schema_cache(
|
@@ -310,7 +416,7 @@ db_namespace = namespace :db do
|
|
310
416
|
|
311
417
|
desc "Clears a db/schema_cache.yml file."
|
312
418
|
task clear: :load_config do
|
313
|
-
ActiveRecord::Base.configurations.configs_for(env_name:
|
419
|
+
ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
|
314
420
|
filename = ActiveRecord::Tasks::DatabaseTasks.cache_dump_filename(db_config.spec_name)
|
315
421
|
rm_f filename, verbose: false
|
316
422
|
end
|
@@ -321,16 +427,9 @@ db_namespace = namespace :db do
|
|
321
427
|
namespace :structure do
|
322
428
|
desc "Dumps the database structure to db/structure.sql. Specify another file with SCHEMA=db/my_structure.sql"
|
323
429
|
task dump: :load_config do
|
324
|
-
ActiveRecord::Base.configurations.configs_for(env_name:
|
430
|
+
ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
|
325
431
|
ActiveRecord::Base.establish_connection(db_config.config)
|
326
|
-
|
327
|
-
ActiveRecord::Tasks::DatabaseTasks.structure_dump(db_config.config, filename)
|
328
|
-
if ActiveRecord::SchemaMigration.table_exists?
|
329
|
-
File.open(filename, "a") do |f|
|
330
|
-
f.puts ActiveRecord::Base.connection.dump_schema_information
|
331
|
-
f.print "\n"
|
332
|
-
end
|
333
|
-
end
|
432
|
+
ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config.config, :sql, db_config.spec_name)
|
334
433
|
end
|
335
434
|
|
336
435
|
db_namespace["structure:dump"].reenable
|
@@ -21,12 +21,12 @@ module ActiveRecord
|
|
21
21
|
|
22
22
|
def add_reflection(ar, name, reflection)
|
23
23
|
ar.clear_reflections_cache
|
24
|
-
name = name.to_s
|
24
|
+
name = -name.to_s
|
25
25
|
ar._reflections = ar._reflections.except(name).merge!(name => reflection)
|
26
26
|
end
|
27
27
|
|
28
28
|
def add_aggregate_reflection(ar, name, reflection)
|
29
|
-
ar.aggregate_reflections = ar.aggregate_reflections.merge(name.to_s => reflection)
|
29
|
+
ar.aggregate_reflections = ar.aggregate_reflections.merge(-name.to_s => reflection)
|
30
30
|
end
|
31
31
|
|
32
32
|
private
|
@@ -178,28 +178,24 @@ module ActiveRecord
|
|
178
178
|
scope ? [scope] : []
|
179
179
|
end
|
180
180
|
|
181
|
-
def
|
182
|
-
key = join_keys.key
|
183
|
-
foreign_key = join_keys.foreign_key
|
184
|
-
|
185
|
-
constraint = table[key].eq(foreign_table[foreign_key])
|
186
|
-
|
187
|
-
if klass.finder_needs_type_condition?
|
188
|
-
table.create_and([constraint, klass.send(:type_condition, table)])
|
189
|
-
else
|
190
|
-
constraint
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
def join_scope(table, foreign_klass)
|
181
|
+
def join_scope(table, foreign_table, foreign_klass)
|
195
182
|
predicate_builder = predicate_builder(table)
|
196
183
|
scope_chain_items = join_scopes(table, predicate_builder)
|
197
184
|
klass_scope = klass_join_scope(table, predicate_builder)
|
198
185
|
|
186
|
+
key = join_keys.key
|
187
|
+
foreign_key = join_keys.foreign_key
|
188
|
+
|
189
|
+
klass_scope.where!(table[key].eq(foreign_table[foreign_key]))
|
190
|
+
|
199
191
|
if type
|
200
192
|
klass_scope.where!(type => foreign_klass.polymorphic_name)
|
201
193
|
end
|
202
194
|
|
195
|
+
if klass.finder_needs_type_condition?
|
196
|
+
klass_scope.where!(klass.send(:type_condition, table))
|
197
|
+
end
|
198
|
+
|
203
199
|
scope_chain_items.inject(klass_scope, &:merge!)
|
204
200
|
end
|
205
201
|
|
@@ -481,7 +477,7 @@ module ActiveRecord
|
|
481
477
|
def check_preloadable!
|
482
478
|
return unless scope
|
483
479
|
|
484
|
-
|
480
|
+
unless scope.arity == 0
|
485
481
|
raise ArgumentError, <<-MSG.squish
|
486
482
|
The association scope '#{name}' is instance dependent (the scope
|
487
483
|
block takes an argument). Preloading instance dependent scopes is
|
@@ -612,21 +608,9 @@ module ActiveRecord
|
|
612
608
|
|
613
609
|
# returns either +nil+ or the inverse association name that it finds.
|
614
610
|
def automatic_inverse_of
|
615
|
-
|
611
|
+
if can_find_inverse_of_automatically?(self)
|
612
|
+
inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name.demodulize).to_sym
|
616
613
|
|
617
|
-
inverse_name_candidates =
|
618
|
-
if options[:as]
|
619
|
-
[options[:as]]
|
620
|
-
else
|
621
|
-
active_record_name = active_record.name.demodulize
|
622
|
-
[active_record_name, ActiveSupport::Inflector.pluralize(active_record_name)]
|
623
|
-
end
|
624
|
-
|
625
|
-
inverse_name_candidates.map! do |candidate|
|
626
|
-
ActiveSupport::Inflector.underscore(candidate).to_sym
|
627
|
-
end
|
628
|
-
|
629
|
-
inverse_name_candidates.detect do |inverse_name|
|
630
614
|
begin
|
631
615
|
reflection = klass._reflect_on_association(inverse_name)
|
632
616
|
rescue NameError
|
@@ -635,7 +619,9 @@ module ActiveRecord
|
|
635
619
|
reflection = false
|
636
620
|
end
|
637
621
|
|
638
|
-
valid_inverse_reflection?(reflection)
|
622
|
+
if valid_inverse_reflection?(reflection)
|
623
|
+
return inverse_name
|
624
|
+
end
|
639
625
|
end
|
640
626
|
end
|
641
627
|
|
@@ -129,11 +129,12 @@ module ActiveRecord
|
|
129
129
|
relation = apply_join_dependency
|
130
130
|
|
131
131
|
if operation.to_s.downcase == "count"
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
relation.order_values = []
|
132
|
+
unless distinct_value || distinct_select?(column_name || select_for_count)
|
133
|
+
relation.distinct!
|
134
|
+
relation.select_values = [ klass.primary_key || table[Arel.star] ]
|
136
135
|
end
|
136
|
+
# PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
|
137
|
+
relation.order_values = []
|
137
138
|
end
|
138
139
|
|
139
140
|
relation.calculate(operation, column_name)
|
@@ -186,11 +187,9 @@ module ActiveRecord
|
|
186
187
|
relation = apply_join_dependency
|
187
188
|
relation.pluck(*column_names)
|
188
189
|
else
|
189
|
-
disallow_raw_sql!(column_names)
|
190
|
+
klass.disallow_raw_sql!(column_names)
|
190
191
|
relation = spawn
|
191
|
-
relation.select_values = column_names
|
192
|
-
@klass.has_attribute?(cn) || @klass.attribute_alias?(cn) ? arel_attribute(cn) : cn
|
193
|
-
}
|
192
|
+
relation.select_values = column_names
|
194
193
|
result = skip_query_cache_if_necessary { klass.connection.select_all(relation.arel, nil) }
|
195
194
|
result.cast_values(klass.attribute_types)
|
196
195
|
end
|
@@ -223,7 +222,6 @@ module ActiveRecord
|
|
223
222
|
end
|
224
223
|
|
225
224
|
private
|
226
|
-
|
227
225
|
def has_include?(column_name)
|
228
226
|
eager_loading? || (includes_values.present? && column_name && column_name != :all)
|
229
227
|
end
|
@@ -238,10 +236,12 @@ module ActiveRecord
|
|
238
236
|
if operation == "count"
|
239
237
|
column_name ||= select_for_count
|
240
238
|
if column_name == :all
|
241
|
-
if distinct
|
239
|
+
if !distinct
|
240
|
+
distinct = distinct_select?(select_for_count) if group_values.empty?
|
241
|
+
elsif group_values.any? || select_values.empty? && order_values.empty?
|
242
242
|
column_name = primary_key
|
243
243
|
end
|
244
|
-
elsif
|
244
|
+
elsif distinct_select?(column_name)
|
245
245
|
distinct = nil
|
246
246
|
end
|
247
247
|
end
|
@@ -253,13 +253,15 @@ module ActiveRecord
|
|
253
253
|
end
|
254
254
|
end
|
255
255
|
|
256
|
+
def distinct_select?(column_name)
|
257
|
+
column_name.is_a?(::String) && /\bDISTINCT[\s(]/i.match?(column_name)
|
258
|
+
end
|
259
|
+
|
256
260
|
def aggregate_column(column_name)
|
257
261
|
return column_name if Arel::Expressions === column_name
|
258
262
|
|
259
|
-
|
260
|
-
|
261
|
-
else
|
262
|
-
Arel.sql(column_name == :all ? "*" : column_name.to_s)
|
263
|
+
arel_column(column_name.to_s) do |name|
|
264
|
+
Arel.sql(column_name == :all ? "*" : name)
|
263
265
|
end
|
264
266
|
end
|
265
267
|
|
@@ -304,25 +306,22 @@ module ActiveRecord
|
|
304
306
|
end
|
305
307
|
|
306
308
|
def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
|
307
|
-
|
309
|
+
group_fields = group_values
|
308
310
|
|
309
|
-
if
|
310
|
-
association =
|
311
|
-
associated =
|
312
|
-
group_fields = Array(
|
313
|
-
else
|
314
|
-
group_fields = group_attrs
|
311
|
+
if group_fields.size == 1 && group_fields.first.respond_to?(:to_sym)
|
312
|
+
association = klass._reflect_on_association(group_fields.first)
|
313
|
+
associated = association && association.belongs_to? # only count belongs_to associations
|
314
|
+
group_fields = Array(association.foreign_key) if associated
|
315
315
|
end
|
316
316
|
group_fields = arel_columns(group_fields)
|
317
317
|
|
318
|
-
group_aliases = group_fields.map { |field|
|
318
|
+
group_aliases = group_fields.map { |field|
|
319
|
+
field = connection.visitor.compile(field) if Arel.arel_node?(field)
|
320
|
+
column_alias_for(field.to_s.downcase)
|
321
|
+
}
|
319
322
|
group_columns = group_aliases.zip(group_fields)
|
320
323
|
|
321
|
-
|
322
|
-
aggregate_alias = "count_all"
|
323
|
-
else
|
324
|
-
aggregate_alias = column_alias_for([operation, column_name].join(" "))
|
325
|
-
end
|
324
|
+
aggregate_alias = column_alias_for("#{operation} #{column_name.to_s.downcase}")
|
326
325
|
|
327
326
|
select_values = [
|
328
327
|
operation_over_aggregate_column(
|
@@ -367,25 +366,21 @@ module ActiveRecord
|
|
367
366
|
end]
|
368
367
|
end
|
369
368
|
|
370
|
-
# Converts the given
|
369
|
+
# Converts the given field to the value that the database adapter returns as
|
371
370
|
# a usable column name:
|
372
371
|
#
|
373
372
|
# column_alias_for("users.id") # => "users_id"
|
374
373
|
# column_alias_for("sum(id)") # => "sum_id"
|
375
374
|
# column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
|
376
375
|
# column_alias_for("count(*)") # => "count_all"
|
377
|
-
def column_alias_for(
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
table_name.strip!
|
386
|
-
table_name.gsub!(/ +/, "_")
|
387
|
-
|
388
|
-
@klass.connection.table_alias_for(table_name)
|
376
|
+
def column_alias_for(field)
|
377
|
+
column_alias = +field
|
378
|
+
column_alias.gsub!(/\*/, "all")
|
379
|
+
column_alias.gsub!(/\W+/, " ")
|
380
|
+
column_alias.strip!
|
381
|
+
column_alias.gsub!(/ +/, "_")
|
382
|
+
|
383
|
+
connection.table_alias_for(column_alias)
|
389
384
|
end
|
390
385
|
|
391
386
|
def type_for(field, &block)
|
@@ -413,16 +408,17 @@ module ActiveRecord
|
|
413
408
|
|
414
409
|
def build_count_subquery(relation, column_name, distinct)
|
415
410
|
if column_name == :all
|
411
|
+
column_alias = Arel.star
|
416
412
|
relation.select_values = [ Arel.sql(FinderMethods::ONE_AS_ONE) ] unless distinct
|
417
413
|
else
|
418
414
|
column_alias = Arel.sql("count_column")
|
419
415
|
relation.select_values = [ aggregate_column(column_name).as(column_alias) ]
|
420
416
|
end
|
421
417
|
|
422
|
-
|
423
|
-
select_value = operation_over_aggregate_column(column_alias
|
418
|
+
subquery_alias = Arel.sql("subquery_for_count")
|
419
|
+
select_value = operation_over_aggregate_column(column_alias, "count", false)
|
424
420
|
|
425
|
-
|
421
|
+
relation.build_subquery(subquery_alias, select_value)
|
426
422
|
end
|
427
423
|
end
|
428
424
|
end
|