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.
@@ -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
@@ -1,3 +1,3 @@
1
1
  module ActiveShard
2
- VERSION = '0.2.2'
2
+ VERSION = '0.2.3'
3
3
  end
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.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