activerecord 3.0.0 → 4.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 +7 -0
- data/CHANGELOG.md +2102 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +35 -44
- data/examples/performance.rb +110 -100
- data/lib/active_record/aggregations.rb +59 -75
- data/lib/active_record/associations/alias_tracker.rb +76 -0
- data/lib/active_record/associations/association.rb +248 -0
- data/lib/active_record/associations/association_scope.rb +135 -0
- data/lib/active_record/associations/belongs_to_association.rb +60 -59
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +16 -59
- data/lib/active_record/associations/builder/association.rb +108 -0
- data/lib/active_record/associations/builder/belongs_to.rb +98 -0
- data/lib/active_record/associations/builder/collection_association.rb +89 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +39 -0
- data/lib/active_record/associations/builder/has_many.rb +15 -0
- data/lib/active_record/associations/builder/has_one.rb +25 -0
- data/lib/active_record/associations/builder/singular_association.rb +32 -0
- data/lib/active_record/associations/collection_association.rb +608 -0
- data/lib/active_record/associations/collection_proxy.rb +986 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +40 -112
- data/lib/active_record/associations/has_many_association.rb +83 -76
- data/lib/active_record/associations/has_many_through_association.rb +147 -66
- data/lib/active_record/associations/has_one_association.rb +67 -108
- data/lib/active_record/associations/has_one_through_association.rb +21 -25
- data/lib/active_record/associations/join_dependency/join_association.rb +174 -0
- data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
- data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
- data/lib/active_record/associations/join_dependency.rb +235 -0
- data/lib/active_record/associations/join_helper.rb +45 -0
- data/lib/active_record/associations/preloader/association.rb +121 -0
- data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
- data/lib/active_record/associations/preloader/collection_association.rb +24 -0
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +60 -0
- data/lib/active_record/associations/preloader/has_many.rb +17 -0
- data/lib/active_record/associations/preloader/has_many_through.rb +19 -0
- data/lib/active_record/associations/preloader/has_one.rb +23 -0
- data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
- data/lib/active_record/associations/preloader/singular_association.rb +21 -0
- data/lib/active_record/associations/preloader/through_association.rb +63 -0
- data/lib/active_record/associations/preloader.rb +178 -0
- data/lib/active_record/associations/singular_association.rb +64 -0
- data/lib/active_record/associations/through_association.rb +87 -0
- data/lib/active_record/associations.rb +512 -1224
- data/lib/active_record/attribute_assignment.rb +201 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +49 -12
- data/lib/active_record/attribute_methods/dirty.rb +51 -28
- data/lib/active_record/attribute_methods/primary_key.rb +94 -22
- data/lib/active_record/attribute_methods/query.rb +5 -4
- data/lib/active_record/attribute_methods/read.rb +63 -72
- data/lib/active_record/attribute_methods/serialization.rb +162 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -41
- data/lib/active_record/attribute_methods/write.rb +39 -13
- data/lib/active_record/attribute_methods.rb +362 -29
- data/lib/active_record/autosave_association.rb +132 -75
- data/lib/active_record/base.rb +83 -1627
- data/lib/active_record/callbacks.rb +69 -47
- data/lib/active_record/coders/yaml_column.rb +38 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +411 -138
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +21 -11
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +234 -173
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +36 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +82 -25
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +176 -414
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +70 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +562 -232
- data/lib/active_record/connection_adapters/abstract/transaction.rb +203 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +281 -53
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +782 -0
- data/lib/active_record/connection_adapters/column.rb +318 -0
- data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +273 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +365 -450
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +97 -0
- data/lib/active_record/connection_adapters/postgresql/cast.rb +152 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +242 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +366 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +171 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +489 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +672 -752
- data/lib/active_record/connection_adapters/schema_cache.rb +129 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +588 -17
- data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
- data/lib/active_record/connection_handling.rb +98 -0
- data/lib/active_record/core.rb +463 -0
- data/lib/active_record/counter_cache.rb +108 -101
- data/lib/active_record/dynamic_matchers.rb +131 -0
- data/lib/active_record/errors.rb +54 -13
- data/lib/active_record/explain.rb +38 -0
- data/lib/active_record/explain_registry.rb +30 -0
- data/lib/active_record/explain_subscriber.rb +29 -0
- data/lib/active_record/fixture_set/file.rb +55 -0
- data/lib/active_record/fixtures.rb +703 -785
- data/lib/active_record/inheritance.rb +200 -0
- data/lib/active_record/integration.rb +60 -0
- data/lib/active_record/locale/en.yml +8 -1
- data/lib/active_record/locking/optimistic.rb +69 -60
- data/lib/active_record/locking/pessimistic.rb +34 -12
- data/lib/active_record/log_subscriber.rb +40 -6
- data/lib/active_record/migration/command_recorder.rb +164 -0
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/migration.rb +614 -216
- data/lib/active_record/model_schema.rb +345 -0
- data/lib/active_record/nested_attributes.rb +248 -119
- data/lib/active_record/null_relation.rb +65 -0
- data/lib/active_record/persistence.rb +275 -57
- data/lib/active_record/query_cache.rb +29 -9
- data/lib/active_record/querying.rb +62 -0
- data/lib/active_record/railtie.rb +135 -21
- data/lib/active_record/railties/console_sandbox.rb +5 -0
- data/lib/active_record/railties/controller_runtime.rb +17 -5
- data/lib/active_record/railties/databases.rake +249 -359
- data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
- data/lib/active_record/readonly_attributes.rb +30 -0
- data/lib/active_record/reflection.rb +283 -103
- data/lib/active_record/relation/batches.rb +38 -34
- data/lib/active_record/relation/calculations.rb +252 -139
- data/lib/active_record/relation/delegation.rb +125 -0
- data/lib/active_record/relation/finder_methods.rb +182 -188
- data/lib/active_record/relation/merger.rb +161 -0
- data/lib/active_record/relation/predicate_builder.rb +86 -21
- data/lib/active_record/relation/query_methods.rb +917 -134
- data/lib/active_record/relation/spawn_methods.rb +53 -92
- data/lib/active_record/relation.rb +405 -143
- data/lib/active_record/result.rb +67 -0
- data/lib/active_record/runtime_registry.rb +17 -0
- data/lib/active_record/sanitization.rb +168 -0
- data/lib/active_record/schema.rb +20 -14
- data/lib/active_record/schema_dumper.rb +55 -46
- data/lib/active_record/schema_migration.rb +39 -0
- data/lib/active_record/scoping/default.rb +146 -0
- data/lib/active_record/scoping/named.rb +175 -0
- data/lib/active_record/scoping.rb +82 -0
- data/lib/active_record/serialization.rb +8 -46
- data/lib/active_record/serializers/xml_serializer.rb +21 -68
- data/lib/active_record/statement_cache.rb +26 -0
- data/lib/active_record/store.rb +156 -0
- data/lib/active_record/tasks/database_tasks.rb +203 -0
- data/lib/active_record/tasks/firebird_database_tasks.rb +56 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +143 -0
- data/lib/active_record/tasks/oracle_database_tasks.rb +45 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +51 -0
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +48 -0
- data/lib/active_record/test_case.rb +57 -28
- data/lib/active_record/timestamp.rb +49 -18
- data/lib/active_record/transactions.rb +106 -63
- data/lib/active_record/translation.rb +22 -0
- data/lib/active_record/validations/associated.rb +25 -24
- data/lib/active_record/validations/presence.rb +65 -0
- data/lib/active_record/validations/uniqueness.rb +123 -83
- data/lib/active_record/validations.rb +29 -29
- data/lib/active_record/version.rb +7 -5
- data/lib/active_record.rb +83 -34
- data/lib/rails/generators/active_record/migration/migration_generator.rb +46 -9
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +19 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +30 -8
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -5
- data/lib/rails/generators/active_record/model/templates/model.rb +7 -2
- data/lib/rails/generators/active_record/model/templates/module.rb +3 -1
- data/lib/rails/generators/active_record.rb +4 -8
- metadata +163 -121
- data/CHANGELOG +0 -6023
- data/examples/associations.png +0 -0
- data/lib/active_record/association_preload.rb +0 -403
- data/lib/active_record/associations/association_collection.rb +0 -562
- data/lib/active_record/associations/association_proxy.rb +0 -295
- data/lib/active_record/associations/through_association_scope.rb +0 -154
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -113
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -401
- data/lib/active_record/dynamic_finder_match.rb +0 -53
- data/lib/active_record/dynamic_scope_match.rb +0 -32
- data/lib/active_record/named_scope.rb +0 -138
- data/lib/active_record/observer.rb +0 -140
- data/lib/active_record/session_store.rb +0 -340
- data/lib/rails/generators/active_record/model/templates/migration.rb +0 -16
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -2
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -24
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -16
@@ -0,0 +1,203 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Tasks # :nodoc:
|
3
|
+
class DatabaseAlreadyExists < StandardError; end # :nodoc:
|
4
|
+
class DatabaseNotSupported < StandardError; end # :nodoc:
|
5
|
+
|
6
|
+
# <tt>ActiveRecord::Tasks::DatabaseTasks</tt> is a utility class, which encapsulates
|
7
|
+
# logic behind common tasks used to manage database and migrations.
|
8
|
+
#
|
9
|
+
# The tasks defined here are used in rake tasks provided by Active Record.
|
10
|
+
#
|
11
|
+
# In order to use DatabaseTasks, a few config values need to be set. All the needed
|
12
|
+
# config values are set by Rails already, so it's necessary to do it only if you
|
13
|
+
# want to change the defaults or when you want to use Active Record outside of Rails
|
14
|
+
# (in such case after configuring the database tasks, you can also use the rake tasks
|
15
|
+
# defined in Active Record).
|
16
|
+
#
|
17
|
+
#
|
18
|
+
# The possible config values are:
|
19
|
+
#
|
20
|
+
# * +env+: current environment (like Rails.env).
|
21
|
+
# * +database_configuration+: configuration of your databases (as in +config/database.yml+).
|
22
|
+
# * +db_dir+: your +db+ directory.
|
23
|
+
# * +fixtures_path+: a path to fixtures directory.
|
24
|
+
# * +migrations_paths+: a list of paths to directories with migrations.
|
25
|
+
# * +seed_loader+: an object which will load seeds, it needs to respond to the +load_seed+ method.
|
26
|
+
#
|
27
|
+
# Example usage of +DatabaseTasks+ outside Rails could look as such:
|
28
|
+
#
|
29
|
+
# include ActiveRecord::Tasks
|
30
|
+
# DatabaseTasks.database_configuration = YAML.load(File.read('my_database_config.yml'))
|
31
|
+
# DatabaseTasks.db_dir = 'db'
|
32
|
+
# # other settings...
|
33
|
+
#
|
34
|
+
# DatabaseTasks.create_current('production')
|
35
|
+
module DatabaseTasks
|
36
|
+
extend self
|
37
|
+
|
38
|
+
attr_writer :current_config
|
39
|
+
attr_accessor :database_configuration, :migrations_paths, :seed_loader, :db_dir,
|
40
|
+
:fixtures_path, :env
|
41
|
+
|
42
|
+
LOCAL_HOSTS = ['127.0.0.1', 'localhost']
|
43
|
+
|
44
|
+
def register_task(pattern, task)
|
45
|
+
@tasks ||= {}
|
46
|
+
@tasks[pattern] = task
|
47
|
+
end
|
48
|
+
|
49
|
+
register_task(/mysql/, ActiveRecord::Tasks::MySQLDatabaseTasks)
|
50
|
+
register_task(/postgresql/, ActiveRecord::Tasks::PostgreSQLDatabaseTasks)
|
51
|
+
register_task(/sqlite/, ActiveRecord::Tasks::SQLiteDatabaseTasks)
|
52
|
+
|
53
|
+
register_task(/firebird/, ActiveRecord::Tasks::FirebirdDatabaseTasks)
|
54
|
+
register_task(/sqlserver/, ActiveRecord::Tasks::SqlserverDatabaseTasks)
|
55
|
+
register_task(/(oci|oracle)/, ActiveRecord::Tasks::OracleDatabaseTasks)
|
56
|
+
|
57
|
+
def current_config(options = {})
|
58
|
+
options.reverse_merge! :env => env
|
59
|
+
if options.has_key?(:config)
|
60
|
+
@current_config = options[:config]
|
61
|
+
else
|
62
|
+
@current_config ||= if ENV['DATABASE_URL']
|
63
|
+
database_url_config
|
64
|
+
else
|
65
|
+
ActiveRecord::Base.configurations[options[:env]]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def create(*arguments)
|
71
|
+
configuration = arguments.first
|
72
|
+
class_for_adapter(configuration['adapter']).new(*arguments).create
|
73
|
+
rescue DatabaseAlreadyExists
|
74
|
+
$stderr.puts "#{configuration['database']} already exists"
|
75
|
+
rescue Exception => error
|
76
|
+
$stderr.puts error, *(error.backtrace)
|
77
|
+
$stderr.puts "Couldn't create database for #{configuration.inspect}"
|
78
|
+
end
|
79
|
+
|
80
|
+
def create_all
|
81
|
+
each_local_configuration { |configuration| create configuration }
|
82
|
+
end
|
83
|
+
|
84
|
+
def create_current(environment = env)
|
85
|
+
each_current_configuration(environment) { |configuration|
|
86
|
+
create configuration
|
87
|
+
}
|
88
|
+
ActiveRecord::Base.establish_connection environment
|
89
|
+
end
|
90
|
+
|
91
|
+
def create_database_url
|
92
|
+
create database_url_config
|
93
|
+
end
|
94
|
+
|
95
|
+
def drop(*arguments)
|
96
|
+
configuration = arguments.first
|
97
|
+
class_for_adapter(configuration['adapter']).new(*arguments).drop
|
98
|
+
rescue Exception => error
|
99
|
+
$stderr.puts error, *(error.backtrace)
|
100
|
+
$stderr.puts "Couldn't drop #{configuration['database']}"
|
101
|
+
end
|
102
|
+
|
103
|
+
def drop_all
|
104
|
+
each_local_configuration { |configuration| drop configuration }
|
105
|
+
end
|
106
|
+
|
107
|
+
def drop_current(environment = env)
|
108
|
+
each_current_configuration(environment) { |configuration|
|
109
|
+
drop configuration
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
def drop_database_url
|
114
|
+
drop database_url_config
|
115
|
+
end
|
116
|
+
|
117
|
+
def charset_current(environment = env)
|
118
|
+
charset ActiveRecord::Base.configurations[environment]
|
119
|
+
end
|
120
|
+
|
121
|
+
def charset(*arguments)
|
122
|
+
configuration = arguments.first
|
123
|
+
class_for_adapter(configuration['adapter']).new(*arguments).charset
|
124
|
+
end
|
125
|
+
|
126
|
+
def collation_current(environment = env)
|
127
|
+
collation ActiveRecord::Base.configurations[environment]
|
128
|
+
end
|
129
|
+
|
130
|
+
def collation(*arguments)
|
131
|
+
configuration = arguments.first
|
132
|
+
class_for_adapter(configuration['adapter']).new(*arguments).collation
|
133
|
+
end
|
134
|
+
|
135
|
+
def purge(configuration)
|
136
|
+
class_for_adapter(configuration['adapter']).new(configuration).purge
|
137
|
+
end
|
138
|
+
|
139
|
+
def structure_dump(*arguments)
|
140
|
+
configuration = arguments.first
|
141
|
+
filename = arguments.delete_at 1
|
142
|
+
class_for_adapter(configuration['adapter']).new(*arguments).structure_dump(filename)
|
143
|
+
end
|
144
|
+
|
145
|
+
def structure_load(*arguments)
|
146
|
+
configuration = arguments.first
|
147
|
+
filename = arguments.delete_at 1
|
148
|
+
class_for_adapter(configuration['adapter']).new(*arguments).structure_load(filename)
|
149
|
+
end
|
150
|
+
|
151
|
+
def load_seed
|
152
|
+
if seed_loader
|
153
|
+
seed_loader.load_seed
|
154
|
+
else
|
155
|
+
raise "You tried to load seed data, but no seed loader is specified. Please specify seed " +
|
156
|
+
"loader with ActiveRecord::Tasks::DatabaseTasks.seed_loader = your_seed_loader\n" +
|
157
|
+
"Seed loader should respond to load_seed method"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
private
|
162
|
+
|
163
|
+
def database_url_config
|
164
|
+
@database_url_config ||=
|
165
|
+
ConnectionAdapters::ConnectionSpecification::Resolver.new(ENV["DATABASE_URL"], {}).spec.config.stringify_keys
|
166
|
+
end
|
167
|
+
|
168
|
+
def class_for_adapter(adapter)
|
169
|
+
key = @tasks.keys.detect { |pattern| adapter[pattern] }
|
170
|
+
unless key
|
171
|
+
raise DatabaseNotSupported, "Rake tasks not supported by '#{adapter}' adapter"
|
172
|
+
end
|
173
|
+
@tasks[key]
|
174
|
+
end
|
175
|
+
|
176
|
+
def each_current_configuration(environment)
|
177
|
+
environments = [environment]
|
178
|
+
environments << 'test' if environment == 'development'
|
179
|
+
|
180
|
+
configurations = ActiveRecord::Base.configurations.values_at(*environments)
|
181
|
+
configurations.compact.each do |configuration|
|
182
|
+
yield configuration unless configuration['database'].blank?
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def each_local_configuration
|
187
|
+
ActiveRecord::Base.configurations.each_value do |configuration|
|
188
|
+
next unless configuration['database']
|
189
|
+
|
190
|
+
if local_database?(configuration)
|
191
|
+
yield configuration
|
192
|
+
else
|
193
|
+
$stderr.puts "This task only modifies local databases. #{configuration['database']} is on a remote host."
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def local_database?(configuration)
|
199
|
+
configuration['host'].blank? || LOCAL_HOSTS.include?(configuration['host'])
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Tasks # :nodoc:
|
3
|
+
class FirebirdDatabaseTasks # :nodoc:
|
4
|
+
delegate :connection, :establish_connection, to: ActiveRecord::Base
|
5
|
+
|
6
|
+
def initialize(configuration)
|
7
|
+
ActiveSupport::Deprecation.warn "This database tasks were deprecated, because this tasks should be served by the 3rd party adapter."
|
8
|
+
@configuration = configuration
|
9
|
+
end
|
10
|
+
|
11
|
+
def create
|
12
|
+
$stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
|
13
|
+
end
|
14
|
+
|
15
|
+
def drop
|
16
|
+
$stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
|
17
|
+
end
|
18
|
+
|
19
|
+
def purge
|
20
|
+
establish_connection(:test)
|
21
|
+
connection.recreate_database!
|
22
|
+
end
|
23
|
+
|
24
|
+
def charset
|
25
|
+
$stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
|
26
|
+
end
|
27
|
+
|
28
|
+
def structure_dump(filename)
|
29
|
+
set_firebird_env(configuration)
|
30
|
+
db_string = firebird_db_string(configuration)
|
31
|
+
Kernel.system "isql -a #{db_string} > #{filename}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def structure_load(filename)
|
35
|
+
set_firebird_env(configuration)
|
36
|
+
db_string = firebird_db_string(configuration)
|
37
|
+
Kernel.system "isql -i #{filename} #{db_string}"
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def set_firebird_env(config)
|
43
|
+
ENV['ISC_USER'] = config['username'].to_s if config['username']
|
44
|
+
ENV['ISC_PASSWORD'] = config['password'].to_s if config['password']
|
45
|
+
end
|
46
|
+
|
47
|
+
def firebird_db_string(config)
|
48
|
+
FireRuby::Database.db_string_for(config.symbolize_keys)
|
49
|
+
end
|
50
|
+
|
51
|
+
def configuration
|
52
|
+
@configuration
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Tasks # :nodoc:
|
3
|
+
class MySQLDatabaseTasks # :nodoc:
|
4
|
+
DEFAULT_CHARSET = ENV['CHARSET'] || 'utf8'
|
5
|
+
DEFAULT_COLLATION = ENV['COLLATION'] || 'utf8_unicode_ci'
|
6
|
+
ACCESS_DENIED_ERROR = 1045
|
7
|
+
|
8
|
+
delegate :connection, :establish_connection, to: ActiveRecord::Base
|
9
|
+
|
10
|
+
def initialize(configuration)
|
11
|
+
@configuration = configuration
|
12
|
+
end
|
13
|
+
|
14
|
+
def create
|
15
|
+
establish_connection configuration_without_database
|
16
|
+
connection.create_database configuration['database'], creation_options
|
17
|
+
establish_connection configuration
|
18
|
+
rescue ActiveRecord::StatementInvalid => error
|
19
|
+
if /database exists/ === error.message
|
20
|
+
raise DatabaseAlreadyExists
|
21
|
+
else
|
22
|
+
raise
|
23
|
+
end
|
24
|
+
rescue error_class => error
|
25
|
+
if error.respond_to?(:errno) && error.errno == ACCESS_DENIED_ERROR
|
26
|
+
$stdout.print error.error
|
27
|
+
establish_connection root_configuration_without_database
|
28
|
+
connection.create_database configuration['database'], creation_options
|
29
|
+
if configuration['username'] != 'root'
|
30
|
+
connection.execute grant_statement.gsub(/\s+/, ' ').strip
|
31
|
+
end
|
32
|
+
establish_connection configuration
|
33
|
+
else
|
34
|
+
$stderr.puts "Couldn't create database for #{configuration.inspect}, #{creation_options.inspect}"
|
35
|
+
$stderr.puts "(If you set the charset manually, make sure you have a matching collation)" if configuration['encoding']
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def drop
|
40
|
+
establish_connection configuration
|
41
|
+
connection.drop_database configuration['database']
|
42
|
+
end
|
43
|
+
|
44
|
+
def purge
|
45
|
+
establish_connection :test
|
46
|
+
connection.recreate_database configuration['database'], creation_options
|
47
|
+
end
|
48
|
+
|
49
|
+
def charset
|
50
|
+
connection.charset
|
51
|
+
end
|
52
|
+
|
53
|
+
def collation
|
54
|
+
connection.collation
|
55
|
+
end
|
56
|
+
|
57
|
+
def structure_dump(filename)
|
58
|
+
args = prepare_command_options('mysqldump')
|
59
|
+
args.concat(["--result-file", "#{filename}"])
|
60
|
+
args.concat(["--no-data"])
|
61
|
+
args.concat(["#{configuration['database']}"])
|
62
|
+
unless Kernel.system(*args)
|
63
|
+
$stderr.puts "Could not dump the database structure. "\
|
64
|
+
"Make sure `mysqldump` is in your PATH and check the command output for warnings."
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def structure_load(filename)
|
69
|
+
args = prepare_command_options('mysql')
|
70
|
+
args.concat(['--execute', %{SET FOREIGN_KEY_CHECKS = 0; SOURCE #{filename}; SET FOREIGN_KEY_CHECKS = 1}])
|
71
|
+
args.concat(["--database", "#{configuration['database']}"])
|
72
|
+
Kernel.system(*args)
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def configuration
|
78
|
+
@configuration
|
79
|
+
end
|
80
|
+
|
81
|
+
def configuration_without_database
|
82
|
+
configuration.merge('database' => nil)
|
83
|
+
end
|
84
|
+
|
85
|
+
def creation_options
|
86
|
+
Hash.new.tap do |options|
|
87
|
+
options[:charset] = configuration['encoding'] if configuration.include? 'encoding'
|
88
|
+
options[:collation] = configuration['collation'] if configuration.include? 'collation'
|
89
|
+
|
90
|
+
# Set default charset only when collation isn't set.
|
91
|
+
options[:charset] ||= DEFAULT_CHARSET unless options[:collation]
|
92
|
+
|
93
|
+
# Set default collation only when charset is also default.
|
94
|
+
options[:collation] ||= DEFAULT_COLLATION if options[:charset] == DEFAULT_CHARSET
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def error_class
|
99
|
+
if configuration['adapter'] =~ /jdbc/
|
100
|
+
require 'active_record/railties/jdbcmysql_error'
|
101
|
+
ArJdbcMySQL::Error
|
102
|
+
elsif defined?(Mysql2)
|
103
|
+
Mysql2::Error
|
104
|
+
elsif defined?(Mysql)
|
105
|
+
Mysql::Error
|
106
|
+
else
|
107
|
+
StandardError
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def grant_statement
|
112
|
+
<<-SQL
|
113
|
+
GRANT ALL PRIVILEGES ON #{configuration['database']}.*
|
114
|
+
TO '#{configuration['username']}'@'localhost'
|
115
|
+
IDENTIFIED BY '#{configuration['password']}' WITH GRANT OPTION;
|
116
|
+
SQL
|
117
|
+
end
|
118
|
+
|
119
|
+
def root_configuration_without_database
|
120
|
+
configuration_without_database.merge(
|
121
|
+
'username' => 'root',
|
122
|
+
'password' => root_password
|
123
|
+
)
|
124
|
+
end
|
125
|
+
|
126
|
+
def root_password
|
127
|
+
$stdout.print "Please provide the root password for your mysql installation\n>"
|
128
|
+
$stdin.gets.strip
|
129
|
+
end
|
130
|
+
|
131
|
+
def prepare_command_options(command)
|
132
|
+
args = [command]
|
133
|
+
args.concat(['--user', configuration['username']]) if configuration['username']
|
134
|
+
args << "--password=#{configuration['password']}" if configuration['password']
|
135
|
+
args.concat(['--default-character-set', configuration['encoding']]) if configuration['encoding']
|
136
|
+
configuration.slice('host', 'port', 'socket').each do |k, v|
|
137
|
+
args.concat([ "--#{k}", v ]) if v
|
138
|
+
end
|
139
|
+
args
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Tasks # :nodoc:
|
3
|
+
class OracleDatabaseTasks # :nodoc:
|
4
|
+
delegate :connection, :establish_connection, to: ActiveRecord::Base
|
5
|
+
|
6
|
+
def initialize(configuration)
|
7
|
+
ActiveSupport::Deprecation.warn "This database tasks were deprecated, because this tasks should be served by the 3rd party adapter."
|
8
|
+
@configuration = configuration
|
9
|
+
end
|
10
|
+
|
11
|
+
def create
|
12
|
+
$stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
|
13
|
+
end
|
14
|
+
|
15
|
+
def drop
|
16
|
+
$stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
|
17
|
+
end
|
18
|
+
|
19
|
+
def purge
|
20
|
+
establish_connection(:test)
|
21
|
+
connection.structure_drop.split(";\n\n").each { |ddl| connection.execute(ddl) }
|
22
|
+
end
|
23
|
+
|
24
|
+
def charset
|
25
|
+
$stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
|
26
|
+
end
|
27
|
+
|
28
|
+
def structure_dump(filename)
|
29
|
+
establish_connection(configuration)
|
30
|
+
File.open(filename, "w:utf-8") { |f| f << connection.structure_dump }
|
31
|
+
end
|
32
|
+
|
33
|
+
def structure_load(filename)
|
34
|
+
establish_connection(configuration)
|
35
|
+
IO.read(filename).split(";\n\n").each { |ddl| connection.execute(ddl) }
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def configuration
|
41
|
+
@configuration
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Tasks # :nodoc:
|
5
|
+
class PostgreSQLDatabaseTasks # :nodoc:
|
6
|
+
DEFAULT_ENCODING = ENV['CHARSET'] || 'utf8'
|
7
|
+
|
8
|
+
delegate :connection, :establish_connection, :clear_active_connections!,
|
9
|
+
to: ActiveRecord::Base
|
10
|
+
|
11
|
+
def initialize(configuration)
|
12
|
+
@configuration = configuration
|
13
|
+
end
|
14
|
+
|
15
|
+
def create(master_established = false)
|
16
|
+
establish_master_connection unless master_established
|
17
|
+
connection.create_database configuration['database'],
|
18
|
+
configuration.merge('encoding' => encoding)
|
19
|
+
establish_connection configuration
|
20
|
+
rescue ActiveRecord::StatementInvalid => error
|
21
|
+
if /database .* already exists/ === error.message
|
22
|
+
raise DatabaseAlreadyExists
|
23
|
+
else
|
24
|
+
raise
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def drop
|
29
|
+
establish_master_connection
|
30
|
+
connection.drop_database configuration['database']
|
31
|
+
end
|
32
|
+
|
33
|
+
def charset
|
34
|
+
connection.encoding
|
35
|
+
end
|
36
|
+
|
37
|
+
def collation
|
38
|
+
connection.collation
|
39
|
+
end
|
40
|
+
|
41
|
+
def purge
|
42
|
+
clear_active_connections!
|
43
|
+
drop
|
44
|
+
create true
|
45
|
+
end
|
46
|
+
|
47
|
+
def structure_dump(filename)
|
48
|
+
set_psql_env
|
49
|
+
search_path = configuration['schema_search_path']
|
50
|
+
unless search_path.blank?
|
51
|
+
search_path = search_path.split(",").map{|search_path_part| "--schema=#{Shellwords.escape(search_path_part.strip)}" }.join(" ")
|
52
|
+
end
|
53
|
+
|
54
|
+
command = "pg_dump -i -s -x -O -f #{Shellwords.escape(filename)} #{search_path} #{Shellwords.escape(configuration['database'])}"
|
55
|
+
raise 'Error dumping database' unless Kernel.system(command)
|
56
|
+
|
57
|
+
File.open(filename, "a") { |f| f << "SET search_path TO #{ActiveRecord::Base.connection.schema_search_path};\n\n" }
|
58
|
+
end
|
59
|
+
|
60
|
+
def structure_load(filename)
|
61
|
+
set_psql_env
|
62
|
+
Kernel.system("psql -q -f #{filename} #{configuration['database']}")
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def configuration
|
68
|
+
@configuration
|
69
|
+
end
|
70
|
+
|
71
|
+
def encoding
|
72
|
+
configuration['encoding'] || DEFAULT_ENCODING
|
73
|
+
end
|
74
|
+
|
75
|
+
def establish_master_connection
|
76
|
+
establish_connection configuration.merge(
|
77
|
+
'database' => 'postgres',
|
78
|
+
'schema_search_path' => 'public'
|
79
|
+
)
|
80
|
+
end
|
81
|
+
|
82
|
+
def set_psql_env
|
83
|
+
ENV['PGHOST'] = configuration['host'] if configuration['host']
|
84
|
+
ENV['PGPORT'] = configuration['port'].to_s if configuration['port']
|
85
|
+
ENV['PGPASSWORD'] = configuration['password'].to_s if configuration['password']
|
86
|
+
ENV['PGUSER'] = configuration['username'].to_s if configuration['username']
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Tasks # :nodoc:
|
3
|
+
class SQLiteDatabaseTasks # :nodoc:
|
4
|
+
delegate :connection, :establish_connection, to: ActiveRecord::Base
|
5
|
+
|
6
|
+
def initialize(configuration, root = Rails.root)
|
7
|
+
@configuration, @root = configuration, root
|
8
|
+
end
|
9
|
+
|
10
|
+
def create
|
11
|
+
raise DatabaseAlreadyExists if File.exist?(configuration['database'])
|
12
|
+
|
13
|
+
establish_connection configuration
|
14
|
+
connection
|
15
|
+
end
|
16
|
+
|
17
|
+
def drop
|
18
|
+
require 'pathname'
|
19
|
+
path = Pathname.new configuration['database']
|
20
|
+
file = path.absolute? ? path.to_s : File.join(root, path)
|
21
|
+
|
22
|
+
FileUtils.rm(file) if File.exist?(file)
|
23
|
+
end
|
24
|
+
alias :purge :drop
|
25
|
+
|
26
|
+
def charset
|
27
|
+
connection.encoding
|
28
|
+
end
|
29
|
+
|
30
|
+
def structure_dump(filename)
|
31
|
+
dbfile = configuration['database']
|
32
|
+
`sqlite3 #{dbfile} .schema > #{filename}`
|
33
|
+
end
|
34
|
+
|
35
|
+
def structure_load(filename)
|
36
|
+
dbfile = configuration['database']
|
37
|
+
`sqlite3 #{dbfile} < "#{filename}"`
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def configuration
|
43
|
+
@configuration
|
44
|
+
end
|
45
|
+
|
46
|
+
def root
|
47
|
+
@root
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Tasks # :nodoc:
|
5
|
+
class SqlserverDatabaseTasks # :nodoc:
|
6
|
+
delegate :connection, :establish_connection, to: ActiveRecord::Base
|
7
|
+
|
8
|
+
def initialize(configuration)
|
9
|
+
ActiveSupport::Deprecation.warn "This database tasks were deprecated, because this tasks should be served by the 3rd party adapter."
|
10
|
+
@configuration = configuration
|
11
|
+
end
|
12
|
+
|
13
|
+
def create
|
14
|
+
$stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
|
15
|
+
end
|
16
|
+
|
17
|
+
def drop
|
18
|
+
$stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
|
19
|
+
end
|
20
|
+
|
21
|
+
def purge
|
22
|
+
test = configuration.deep_dup
|
23
|
+
test_database = test['database']
|
24
|
+
test['database'] = 'master'
|
25
|
+
establish_connection(test)
|
26
|
+
connection.recreate_database!(test_database)
|
27
|
+
end
|
28
|
+
|
29
|
+
def charset
|
30
|
+
$stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
|
31
|
+
end
|
32
|
+
|
33
|
+
def structure_dump(filename)
|
34
|
+
Kernel.system("smoscript -s #{configuration['host']} -d #{configuration['database']} -u #{configuration['username']} -p #{configuration['password']} -f #{filename} -A -U")
|
35
|
+
end
|
36
|
+
|
37
|
+
def structure_load(filename)
|
38
|
+
Kernel.system("sqlcmd -S #{configuration['host']} -d #{configuration['database']} -U #{configuration['username']} -P #{configuration['password']} -i #{filename}")
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def configuration
|
44
|
+
@configuration
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|