active_shard 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/active_shard/rails/database.rake +329 -0
- data/lib/active_shard/version.rb +1 -1
- metadata +2 -1
@@ -0,0 +1,329 @@
|
|
1
|
+
namespace :shards do
|
2
|
+
|
3
|
+
desc 'Create the database from config/database.yml for the current Rails.env (use db:create:all to create all dbs in the config)'
|
4
|
+
task :create => :environment do
|
5
|
+
|
6
|
+
# Make the test database at the same time as the development one, if it exists
|
7
|
+
if Rails.env.development?
|
8
|
+
ActiveShard.config.shard_definitions( :test ).each do |definition|
|
9
|
+
create_database(definition)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
ActiveShard.config.shard_definitions( Rails.env.to_sym ).each do |definition|
|
13
|
+
create_database( definition )
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def create_database( definition )
|
18
|
+
begin
|
19
|
+
if definition.connection_adapter =~ /sqlite/
|
20
|
+
active_shard_does_not_implement!( definition.connection_adapter )
|
21
|
+
else
|
22
|
+
pool = ActiveShard::ActiveRecord::ConnectionProxyPool.new( definition )
|
23
|
+
pool.connection
|
24
|
+
end
|
25
|
+
rescue
|
26
|
+
case definition.connection_adapter
|
27
|
+
when /mysql/
|
28
|
+
@charset = ENV['CHARSET'] || 'utf8'
|
29
|
+
@collation = ENV['COLLATION'] || 'utf8_unicode_ci'
|
30
|
+
creation_options = {:charset => (definition.connection_spec['charset'] || @charset), :collation => (definition.connection_spec['collation'] || @collation)}
|
31
|
+
error_class = definition.connection_adapter =~ /mysql2/ ? Mysql2::Error : Mysql::Error
|
32
|
+
access_denied_error = 1045
|
33
|
+
begin
|
34
|
+
sd = ActiveShard::ShardDefinition.new(
|
35
|
+
definition.name, { :schema => definition.schema }.merge( definition.connection_spec ).merge( :database => nil )
|
36
|
+
)
|
37
|
+
|
38
|
+
pool = ActiveShard::ActiveRecord::ConnectionProxyPool.new( sd )
|
39
|
+
|
40
|
+
pool.connection.create_database( definition.connection_database, creation_options )
|
41
|
+
|
42
|
+
ActiveShard::ActiveRecord::ConnectionProxyPool.new( definition ).connection
|
43
|
+
rescue error_class => sqlerr
|
44
|
+
$stderr.puts sqlerr.error
|
45
|
+
$stderr.puts "Couldn't create database for #{definition.inspect}"
|
46
|
+
end
|
47
|
+
when 'postgresql'
|
48
|
+
active_shard_does_not_implement!( 'postgresql' )
|
49
|
+
end
|
50
|
+
else
|
51
|
+
$stderr.puts "#{definition.connection_database} already exists"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
desc "Migrate the database (options: VERSION=x, VERBOSE=false)."
|
56
|
+
task :migrate, [:shard_name] => :environment do |t, args|
|
57
|
+
schemas = {}
|
58
|
+
|
59
|
+
active_shard_definitions( args ).each do |shard_definition|
|
60
|
+
with_shard( shard_definition.name ) do |shard_name, schema|
|
61
|
+
schemas[schema] = shard_name
|
62
|
+
|
63
|
+
ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
|
64
|
+
ActiveRecord::Migrator.migrate("db/migrate/#{schema}/", ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
schemas.each_pair { |schema, shard| dump_schema( shard ) }
|
69
|
+
end
|
70
|
+
|
71
|
+
namespace :migrate do
|
72
|
+
# desc 'Rollbacks the database one migration and re migrate up (options: STEP=x, VERSION=x).'
|
73
|
+
task :redo, [:shard_name] => :environment do |t, args|
|
74
|
+
if ENV["VERSION"]
|
75
|
+
Rake::Task["shards:migrate:down"].invoke( *args.values )
|
76
|
+
Rake::Task["shards:migrate:up"].invoke( *args.values )
|
77
|
+
else
|
78
|
+
Rake::Task["shards:rollback"].invoke( *args.values )
|
79
|
+
Rake::Task["shards:migrate"].invoke( *args.values )
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# desc 'Runs the "up" for a given migration VERSION.'
|
84
|
+
task :up, [:shard_name] => :environment do |t, args|
|
85
|
+
version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
|
86
|
+
raise "VERSION is required" unless version
|
87
|
+
|
88
|
+
with_shard( args ) do |shard_name, schema|
|
89
|
+
ActiveRecord::Migrator.run(:up, "db/migrate/#{schema}", version)
|
90
|
+
|
91
|
+
dump_schema( shard_name )
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# desc 'Runs the "down" for a given migration VERSION.'
|
96
|
+
task :down, [:shard_name] => :environment do |t, args|
|
97
|
+
version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
|
98
|
+
raise "VERSION is required" unless version
|
99
|
+
|
100
|
+
with_shard( args ) do |shard_name, schema|
|
101
|
+
ActiveRecord::Migrator.run(:down, "db/migrate/#{schema}", version)
|
102
|
+
|
103
|
+
dump_schema( shard_name )
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
desc 'Rolls the schema back to the previous version (specify steps w/ STEP=n).'
|
109
|
+
task :rollback, [:shard_name] => :environment do |t, args|
|
110
|
+
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
|
111
|
+
|
112
|
+
with_shard( args ) do |shard_name, schema|
|
113
|
+
ActiveRecord::Migrator.rollback("db/migrate/#{schema}", step)
|
114
|
+
|
115
|
+
dump_schema( shard_name )
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# desc 'Pushes the schema to the next version (specify steps w/ STEP=n).'
|
120
|
+
task :forward, [:shard_name] => :environment do |t, args|
|
121
|
+
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
|
122
|
+
|
123
|
+
with_shard( args ) do |shard_name, schema|
|
124
|
+
ActiveRecord::Migrator.forward("db/migrate/#{schema}", step)
|
125
|
+
|
126
|
+
dump_schema( shard_name )
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
desc "Retrieves the current schema version number"
|
131
|
+
task :version, [:shard_name] => :environment do |t, args|
|
132
|
+
with_shard( args ) do |shard_name, schema|
|
133
|
+
puts "Current version: #{ActiveRecord::Migrator.current_version}"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
namespace :schema do
|
138
|
+
|
139
|
+
desc "Create a db/<schema>_schema.rb file that can be portably used against any DB supported by AR"
|
140
|
+
task :dump, [:shard_name] => :environment do |t, args|
|
141
|
+
require 'active_record/schema_dumper'
|
142
|
+
|
143
|
+
defs = active_shard_definitions( args )
|
144
|
+
|
145
|
+
defs.schemas.each do |schema|
|
146
|
+
shard_definition = defs.by_schema( schema ).first
|
147
|
+
|
148
|
+
with_shard( shard_definition.name ) do
|
149
|
+
File.open( "#{Rails.root}/db/#{schema}_schema.rb", "w" ) do |file|
|
150
|
+
ActiveRecord::SchemaDumper.dump( ActiveRecord::Base.connection, file )
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
Rake::Task["shards:schema:dump"].reenable
|
156
|
+
end
|
157
|
+
|
158
|
+
desc "Load a <schema>_schema.rb file into the database"
|
159
|
+
task :load, [:shard_name] => :environment do |t, args|
|
160
|
+
defs = active_shard_definitions( args )
|
161
|
+
|
162
|
+
defs.each do |shard_definition|
|
163
|
+
with_shard( shard_definition.name ) do
|
164
|
+
ActiveRecord::Schema.class_eval <<-EOM
|
165
|
+
def self.migrations_path
|
166
|
+
"db/migrate/#{shard_definition.schema}"
|
167
|
+
end
|
168
|
+
EOM
|
169
|
+
|
170
|
+
file = "#{Rails.root}/db/#{shard_definition.schema}_schema.rb"
|
171
|
+
if File.exists?( file )
|
172
|
+
load( file )
|
173
|
+
else
|
174
|
+
abort %{#{file} doesn't exist yet. Run "rake shards:migrate[#{shard_definition.name}]" to create it then try again. 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}
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
namespace :structure do
|
182
|
+
desc "Dump the database structure to an SQL file"
|
183
|
+
task :dump, [:shard_name] => :environment do |t, args|
|
184
|
+
ActiveShard.with_environment( :development ) do
|
185
|
+
defs = active_shard_definitions( args )
|
186
|
+
|
187
|
+
defs.schemas.each do |schema|
|
188
|
+
shard_definition = defs.by_schema( schema ).first
|
189
|
+
|
190
|
+
with_shard( shard_definition.name ) do
|
191
|
+
|
192
|
+
structure_file_path = "#{Rails.root}/db/#{schema}_structure.sql"
|
193
|
+
|
194
|
+
abcs = ActiveShard.shard( shard_definition.name ).connection_adapter
|
195
|
+
case abcs
|
196
|
+
when /mysql/, "oci", "oracle"
|
197
|
+
# We are already connected via with_shard, so just use.
|
198
|
+
#
|
199
|
+
File.open( structure_file_path, "w+" ) { |f| f << ActiveRecord::Base.connection.structure_dump }
|
200
|
+
when "postgresql", "sqlite", "sqlite3", "sqlserver", "firebird"
|
201
|
+
active_shard_does_not_implement!(abcs)
|
202
|
+
else
|
203
|
+
raise "Task not supported by '#{abcs}'"
|
204
|
+
end
|
205
|
+
|
206
|
+
if ActiveRecord::Base.connection.supports_migrations?
|
207
|
+
File.open( structure_file_path, "a" ) { |f| f << ActiveRecord::Base.connection.dump_schema_information }
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
namespace :test do
|
216
|
+
# desc "Recreate the test database from the current schema.rb"
|
217
|
+
task :load => 'shards:test:purge' do
|
218
|
+
ActiveShard.with_environment( :test ) do
|
219
|
+
ActiveRecord::Schema.verbose = false
|
220
|
+
|
221
|
+
puts "Building test shards ..."
|
222
|
+
ActiveShard.shard_definitions.each do |shard_definition|
|
223
|
+
puts " --> #{shard_definition.name} (#{shard_definition.schema})"
|
224
|
+
Rake::Task["shards:schema:load"].invoke( shard_definition.name )
|
225
|
+
Rake::Task["shards:schema:load"].reenable
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
# desc "Recreate the test database from the current environment's database schema"
|
231
|
+
task :clone => %w(shards:schema:dump shards:test:load)
|
232
|
+
|
233
|
+
# desc "Recreate the test databases from the development structure"
|
234
|
+
task :clone_structure, [:shard_name] => [ "shards:structure:dump", "shards:test:purge" ] do |t, args|
|
235
|
+
ActiveShard.with_environment( :test ) do
|
236
|
+
defs = active_shard_definitions( args )
|
237
|
+
|
238
|
+
defs.each do |shard_definition|
|
239
|
+
adapter = shard_definition.connection_adapter
|
240
|
+
|
241
|
+
case adapter
|
242
|
+
when /mysql/
|
243
|
+
with_shard( shard_definition.name ) do
|
244
|
+
ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0')
|
245
|
+
IO.readlines("#{Rails.root}/db/#{shard_definition.schema}_structure.sql").join.split("\n\n").each do |table|
|
246
|
+
ActiveRecord::Base.connection.execute(table)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
when "postgresql", "sqlite", "sqlite3", "sqlserver", "oci", "oracle", "firebird"
|
250
|
+
active_shard_does_not_implement!( adapter )
|
251
|
+
else
|
252
|
+
raise "Task not supported by '#{adapter}'"
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
# desc "Empty the test database"
|
259
|
+
task :purge => :environment do
|
260
|
+
ActiveShard.with_environment( :test ) do
|
261
|
+
ActiveShard.shard_definitions.each do |shard_definition|
|
262
|
+
with_shard( shard_definition.name ) do |shard_name, schema|
|
263
|
+
adapter = ActiveShard.shard( shard_name ).connection_adapter
|
264
|
+
|
265
|
+
case adapter
|
266
|
+
when /mysql/
|
267
|
+
ActiveRecord::Base.connection.recreate_database(
|
268
|
+
shard_definition.connection_database,
|
269
|
+
shard_definition.connection_spec
|
270
|
+
)
|
271
|
+
when "postgresql", "sqlite", "sqlite3", "sqlserver", "oci", "oracle", "firebird"
|
272
|
+
active_shard_does_not_implement!( adapter )
|
273
|
+
else
|
274
|
+
raise "Task not supported by '#{abcs["test"]["adapter"]}'"
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
# desc 'Check for pending migrations and load the test schema'
|
282
|
+
task :prepare => :environment do
|
283
|
+
clone_schema
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
def dump_schema( *args )
|
289
|
+
Rake::Task[{ :sql => "shards:structure:dump", :ruby => "shards:schema:dump" }[ActiveRecord::Base.schema_format]].invoke(*args)
|
290
|
+
end
|
291
|
+
|
292
|
+
def clone_schema( *args )
|
293
|
+
Rake::Task[{ :sql => "shards:test:clone_structure", :ruby => "shards:test:load" }[ActiveRecord::Base.schema_format]].invoke(*args)
|
294
|
+
end
|
295
|
+
|
296
|
+
def active_shard_does_not_implement!( adapter )
|
297
|
+
raise "Unimplemented by ActiveShard at the moment. If someone using #{adapter} wants to fix this, that would be awesome!"
|
298
|
+
end
|
299
|
+
|
300
|
+
def active_shard_definitions( options={} )
|
301
|
+
shard_name = options[ :shard_name ]
|
302
|
+
|
303
|
+
if shard_name.blank?
|
304
|
+
ActiveShard.shard_definitions
|
305
|
+
else
|
306
|
+
ActiveShard::ShardCollection.new([ ActiveShard.shard( shard_name ) ])
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
def with_shard( args )
|
311
|
+
shard_name =
|
312
|
+
case args
|
313
|
+
when Symbol, String
|
314
|
+
args.to_sym
|
315
|
+
else
|
316
|
+
args[ :shard_name ].nil? ? nil : args[ :shard_name ].to_sym
|
317
|
+
end
|
318
|
+
|
319
|
+
raise "No shard specified. Please run with shard name, rake task[shard_name]" unless shard_name
|
320
|
+
|
321
|
+
schema = ActiveShard.shard( shard_name ).schema.to_sym
|
322
|
+
|
323
|
+
ActiveRecord::Base.send( :include, ActiveShard::ActiveRecord::ShardSupport )
|
324
|
+
ActiveRecord::Base.schema_name( schema )
|
325
|
+
|
326
|
+
ActiveShard.with( shard_name ) do
|
327
|
+
yield( shard_name, schema )
|
328
|
+
end
|
329
|
+
end
|
data/lib/active_shard/version.rb
CHANGED
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: active_shard
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.2.
|
5
|
+
version: 0.2.3
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Brasten Sager
|
@@ -45,6 +45,7 @@ files:
|
|
45
45
|
- lib/active_shard/active_record.rb
|
46
46
|
- lib/active_shard/config.rb
|
47
47
|
- lib/active_shard/exceptions.rb
|
48
|
+
- lib/active_shard/rails/database.rake
|
48
49
|
- lib/active_shard/railtie.rb
|
49
50
|
- lib/active_shard/scope.rb
|
50
51
|
- lib/active_shard/scope_manager.rb
|