sengiri 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e96f58180e38a69f58dabf28faa0722d4eca41b3
4
+ data.tar.gz: 97123fb3ce73b761c46ac5127e06f619f3ab6e3a
5
+ SHA512:
6
+ metadata.gz: c5992be99772ef05bd1a3ed049bbe72ed7a3ed1767f7b9d91562043be7c7f5ad6e484301cb03e37b717f775532fc6657a83187c9c0536011aa641920de550bf1
7
+ data.tar.gz: 8a3449b6f80cecb874ea5ac8e7914313eac1f6184377af0af8c66a858dccd793eb51f3c11c7446a864003cb45d2a86190a4a03daeab77b9224ea244f425a56fe
@@ -0,0 +1,20 @@
1
+ Copyright 2014 mewlist
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,42 @@
1
+ # Sengiri
2
+
3
+ Flexible sharding access for Ruby on Rails with ActiveRecord
4
+
5
+ ## Sharding model generator
6
+
7
+ rails g sengiri:model mygroup user name:string
8
+
9
+ ## database.yml
10
+
11
+ mysql: &mysql
12
+ adapter: mysql2
13
+ encoding: utf8
14
+ reconnect: false
15
+ pool: 1
16
+ username: root
17
+ password:
18
+ host: localhost
19
+
20
+ mygroup_1:
21
+ <<: *mysql
22
+ database: mygroup_1
23
+ host: hosta
24
+ mygroup_2:
25
+ <<: *mysql
26
+ database: mygroup_2
27
+ host: hostb
28
+ mygroup_3:
29
+ <<: *mysql
30
+ database: mygroup_3
31
+ host: hostc
32
+ .
33
+ .
34
+ .
35
+
36
+ ## Sharding migration
37
+
38
+ rake sengiri:mygroup:db:create
39
+ rake sengiri:mygroup:db:migrate
40
+
41
+
42
+ This project rocks and uses MIT-LICENSE.
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'sengiri'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+ Bundler::GemHelper.install_tasks
21
+
@@ -0,0 +1,18 @@
1
+ module Sengiri
2
+ require "sengiri/model/base"
3
+ require "sengiri/railtie" if defined? Rails
4
+ end
5
+
6
+
7
+ module ActiveRecord
8
+ class Relation
9
+ def broadcast
10
+ records = []
11
+ klass.shard_names.each do |shard_name|
12
+ records += shard(shard_name).find_by_sql(arel.to_sql)
13
+ end
14
+ @records = records
15
+ @records
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ require 'rails/generators/active_record'
2
+ require 'rails/generators/active_record/migration/migration_generator'
3
+
4
+ module Sengiri
5
+ module Generators
6
+ class MigrationGenerator < ActiveRecord::Generators::MigrationGenerator
7
+ remove_argument :name, :attributes
8
+ argument :group, type: :string, :banner => "SHARDING_GROUP"
9
+ argument :name, type: :string
10
+ argument :attributes, :type => :array, :default => [], :banner => "field[:type][:index] field[:type][:index]"
11
+
12
+ source_root File.expand_path("../templates", __FILE__)
13
+
14
+ def create_migration_file
15
+ set_local_assigns!
16
+ validate_file_name!
17
+ binding.pry
18
+ migration_template @migration_template, "db/sengiri/#{self.group}/#{file_name}.rb"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,36 @@
1
+ require 'rails/generators/active_record'
2
+ require 'rails/generators/active_record/model/model_generator'
3
+
4
+ module Sengiri
5
+ module Generators
6
+ class ModelGenerator < ActiveRecord::Generators::ModelGenerator
7
+ remove_argument :name, :attributes
8
+ argument :group, type: :string, :banner => "SHARDING_GROUP"
9
+ argument :name, type: :string
10
+ argument :attributes, :type => :array, :default => [], :banner => "field[:type][:index] field[:type][:index]"
11
+
12
+ source_root File.expand_path("../templates", __FILE__)
13
+
14
+ def create_migration_file
15
+ return unless options[:migration] && options[:parent].nil?
16
+ attributes.each { |a| a.attr_options.delete(:index) if a.reference? && !a.has_index? } if options[:indexes] == false
17
+ migration_template "create_table_migration.rb", "db/sengiri/#{self.group}/create_#{table_name}.rb"
18
+ end
19
+
20
+ def create_model_file
21
+ template 'model.rb', File.join('app/models', class_path, "#{file_name}.rb")
22
+ end
23
+
24
+ def create_module_file
25
+ return if regular_class_path.empty?
26
+ template 'module.rb', File.join('app/models', "#{class_path.join('/')}.rb") if behavior == :invoke
27
+ end
28
+ protected
29
+
30
+ # Used by the migration template to determine the parent name of the model
31
+ def parent_class_name
32
+ options[:parent] || "Sengiri::Model::Base"
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,9 @@
1
+ module Sengiri
2
+ module Generators
3
+ class GroupGenerator < Rails::Generators::NamedBase
4
+ def create_directories
5
+ empty_directory "db/sengiri/#{file_name}"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ class <%= migration_class_name %> < ActiveRecord::Migration
2
+ def change
3
+ create_table :<%= table_name %> do |t|
4
+ <% attributes.each do |attribute| -%>
5
+ <% if attribute.password_digest? -%>
6
+ t.string :password_digest<%= attribute.inject_options %>
7
+ <% else -%>
8
+ t.<%= attribute.type %> :<%= attribute.name %><%= attribute.inject_options %>
9
+ <% end -%>
10
+ <% end -%>
11
+ <% if options[:timestamps] %>
12
+ t.timestamps
13
+ <% end -%>
14
+ end
15
+ <% attributes_with_index.each do |attribute| -%>
16
+ add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>
17
+ <% end -%>
18
+ end
19
+ end
@@ -0,0 +1,39 @@
1
+ class <%= migration_class_name %> < ActiveRecord::Migration
2
+ <%- if migration_action == 'add' -%>
3
+ def change
4
+ <% attributes.each do |attribute| -%>
5
+ <%- if attribute.reference? -%>
6
+ add_reference :<%= table_name %>, :<%= attribute.name %><%= attribute.inject_options %>
7
+ <%- else -%>
8
+ add_column :<%= table_name %>, :<%= attribute.name %>, :<%= attribute.type %><%= attribute.inject_options %>
9
+ <%- if attribute.has_index? -%>
10
+ add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>
11
+ <%- end -%>
12
+ <%- end -%>
13
+ <%- end -%>
14
+ end
15
+ <%- elsif migration_action == 'join' -%>
16
+ def change
17
+ create_join_table :<%= join_tables.first %>, :<%= join_tables.second %> do |t|
18
+ <%- attributes.each do |attribute| -%>
19
+ <%= '# ' unless attribute.has_index? -%>t.index <%= attribute.index_name %><%= attribute.inject_index_options %>
20
+ <%- end -%>
21
+ end
22
+ end
23
+ <%- else -%>
24
+ def change
25
+ <% attributes.each do |attribute| -%>
26
+ <%- if migration_action -%>
27
+ <%- if attribute.reference? -%>
28
+ remove_reference :<%= table_name %>, :<%= attribute.name %><%= attribute.inject_options %>
29
+ <%- else -%>
30
+ <%- if attribute.has_index? -%>
31
+ remove_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>
32
+ <%- end -%>
33
+ remove_column :<%= table_name %>, :<%= attribute.name %>, :<%= attribute.type %><%= attribute.inject_options %>
34
+ <%- end -%>
35
+ <%- end -%>
36
+ <%- end -%>
37
+ end
38
+ <%- end -%>
39
+ end
@@ -0,0 +1,11 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %> < <%= parent_class_name.classify %>
3
+ sharding_group :<%= group %>
4
+ <% attributes.select(&:reference?).each do |attribute| -%>
5
+ belongs_to :<%= attribute.name %><%= ', polymorphic: true' if attribute.polymorphic? %>
6
+ <% end -%>
7
+ <% if attributes.any?(&:password_digest?) -%>
8
+ has_secure_password
9
+ <% end -%>
10
+ end
11
+ <% end -%>
@@ -0,0 +1,7 @@
1
+ <% module_namespacing do -%>
2
+ module <%= class_path.map(&:camelize).join('::') %>
3
+ def self.table_name_prefix
4
+ '<%= namespaced? ? namespaced_class_path.join('_') : class_path.join('_') %>_'
5
+ end
6
+ end
7
+ <% end -%>
@@ -0,0 +1,107 @@
1
+ module Sengiri
2
+ module Model
3
+ class Base < ActiveRecord::Base
4
+ self.abstract_class = true
5
+ attr_reader :current_shard
6
+
7
+ def initialize(attributes = nil, options = {})
8
+ @shard_name = self.class.shard_name
9
+ super
10
+ end
11
+
12
+ def sharding_group_name
13
+ self.class.instance_variable_get :@sharding_group_name
14
+ end
15
+
16
+ def shard_name
17
+ self.class.instance_variable_get :@shard_name
18
+ end
19
+
20
+ class << self
21
+ def shard_name ; @shard_name end
22
+ def sharding_group_name; @sharding_group_name end
23
+
24
+ def shard_classes
25
+ return @shard_class_hash.values if @shard_class_hash
26
+ []
27
+ end
28
+
29
+ def sharding_group(name, confs=nil)
30
+ @dbconfs = confs if confs
31
+ @sharding_group_name = name
32
+ @shard_class_hash = {}
33
+ first = true
34
+ shard_names.each do |s|
35
+ klass = Class.new(self)
36
+ Object.const_set self.name + s, klass
37
+ klass.instance_variable_set :@shard_name, s
38
+ klass.instance_variable_set :@dbconfs, dbconfs
39
+ klass.instance_variable_set :@sharding_group_name, name
40
+ #
41
+ # first shard shares connection with base class
42
+ #
43
+ if first
44
+ establish_shard_connection s
45
+ else
46
+ klass.establish_shard_connection s
47
+ end
48
+ first = false
49
+ if defined? Ardisconnector::Middleware
50
+ Ardisconnector::Middleware.models << klass
51
+ end
52
+ @shard_class_hash[s] = klass
53
+ end
54
+ end
55
+
56
+ def dbconfs
57
+ if defined? Rails
58
+ @dbconfs ||= Rails.application.config.database_configuration.select {|name| /^#{@sharding_group_name}/ =~ name }
59
+
60
+ end
61
+ @dbconfs
62
+ end
63
+
64
+ def shard_names
65
+ @shard_names ||= dbconfs.map do |k,v|
66
+ k.gsub("#{@sharding_group_name}_shards_", '')
67
+ end
68
+ @shard_names
69
+ end
70
+
71
+ def shard(name)
72
+ if block_given?
73
+ yield @shard_class_hash[name.to_s]
74
+ end
75
+ @shard_class_hash[name.to_s]
76
+ end
77
+
78
+ def shards(&block)
79
+ transaction do
80
+ shard_names.each do |shard_name|
81
+ block.call shard(shard_name)
82
+ end
83
+ end
84
+ end
85
+
86
+ def transaction(klasses=shard_classes, &block)
87
+ if shard_name
88
+ super &block
89
+ else
90
+ if klasses.length > 0
91
+ klass = klasses.pop
92
+ klass.transaction do
93
+ transaction klasses, &block
94
+ end
95
+ else
96
+ yield
97
+ end
98
+ end
99
+ end
100
+
101
+ def establish_shard_connection(name)
102
+ establish_connection dbconfs["#{@sharding_group_name}_shards_#{name}"]
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,32 @@
1
+ module Sengiri
2
+ class Railtie < Rails::Railtie
3
+ rake_tasks do
4
+ dbdir = Rails.application.config.paths["db"].first
5
+ dirs = Dir.glob(dbdir + '/sengiri/*').select do |f|
6
+ FileTest::directory? f
7
+ end
8
+ sharding_names = dirs.map{|dir| dir.split('/').last }
9
+ sharding_names.each do |name|
10
+ ENV['SHARD'] = name
11
+ load "sengiri/railties/sharding.rake"
12
+ end
13
+
14
+ namespace :sengiri do
15
+ task :load_task do
16
+ Rake.application.in_namespace(:sengiri) do
17
+ # load activerecord databasees task in namespace
18
+ spec = Gem::Specification.find_by_name("activerecord")
19
+ rakefile = spec.gem_dir + "/lib/active_record/railties/databases.rake"
20
+ Rake.load_rakefile rakefile
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ generators do
27
+ require "sengiri/generators/sharding_generator"
28
+ require "sengiri/generators/migration_generator"
29
+ require "sengiri/generators/model_generator"
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,101 @@
1
+ require 'active_record'
2
+ require 'pry'
3
+
4
+ shard = ENV['SHARD']
5
+
6
+ namespace :sengiri do
7
+ db_ns = namespace :db do
8
+ task :load_config do
9
+ end
10
+ end
11
+
12
+ namespace shard do
13
+
14
+ namespace :db do
15
+
16
+ dbconfs = Rails.application.config.database_configuration.select {|name| /^#{shard}/ =~ name }
17
+ switch_db_config = lambda do
18
+ puts "now on '#{shard}' sharding"
19
+
20
+ shard_group_dir = "db/sengiri/#{shard}"
21
+ ActiveRecord::Base.configurations = dbconfs
22
+ Rails.application.config.paths.add shard_group_dir
23
+
24
+ ActiveRecord::Tasks::DatabaseTasks.seed_loader = Rails.application
25
+ ActiveRecord::Tasks::DatabaseTasks.env = Rails.env
26
+ ActiveRecord::Tasks::DatabaseTasks.db_dir = Rails.application.config.paths["db"].first
27
+ ActiveRecord::Tasks::DatabaseTasks.database_configuration = dbconfs
28
+ ActiveRecord::Tasks::DatabaseTasks.migrations_paths = Rails.application.paths[shard_group_dir].to_a
29
+ ActiveRecord::Tasks::DatabaseTasks.fixtures_path = File.join Rails.root, 'test', 'fixtures'
30
+ end
31
+
32
+ execute_on_shards = lambda do |task|
33
+ dbconfs.each do |k,dbconf|
34
+ ActiveRecord::Base.establish_connection dbconf
35
+ db_ns[task].execute
36
+ end
37
+ end
38
+
39
+ execute_with_dbtask_env = lambda do |task|
40
+ dbconfs.each do |k,dbconf|
41
+ ActiveRecord::Tasks::DatabaseTasks.env = k
42
+ db_ns[task].execute
43
+ end
44
+ end
45
+
46
+ task :load_config => ['sengiri:load_task'] do
47
+ switch_db_config.call
48
+ db_ns['load_config'].invoke
49
+ end
50
+
51
+ desc "create on '#{shard}' databases"
52
+ task :create => [:environment, :load_config] do
53
+ execute_with_dbtask_env.call :create
54
+ end
55
+
56
+ desc "drop on '#{shard}' databases"
57
+ task :drop => [:environment, :load_config] do
58
+ execute_with_dbtask_env.call :drop
59
+ end
60
+
61
+ desc "migrate on '#{shard}' databases"
62
+ task :migrate => [:environment, :load_config] do
63
+ execute_on_shards.call :migrate
64
+ end
65
+
66
+ desc "rollback on '#{shard}' databases"
67
+ task :rollback => [:environment, :load_config] do
68
+ execute_on_shards.call :rollback
69
+ end
70
+
71
+ namespace :migrate do
72
+ task :redo => [:environment, :load_config] do
73
+ execute_on_shards.call 'migrate:redo'
74
+ end
75
+
76
+ # desc 'Resets your database using your migrations for the current environment'
77
+ task :reset => [:environment, :load_config] do
78
+ Rake::Task["sengiri:#{shard}:db:drop"] .execute
79
+ Rake::Task["sengiri:#{shard}:db:create"] .execute
80
+ Rake::Task["sengiri:#{shard}:db:migrate"].execute
81
+ end
82
+
83
+ # desc 'Runs the "up" for a given migration VERSION.'
84
+ task :up => [:environment, :load_config] do
85
+ execute_on_shards.call 'migrate:up'
86
+ end
87
+
88
+ # desc 'Runs the "down" for a given migration VERSION.'
89
+ task :down => [:environment, :load_config] do
90
+ execute_on_shards.call 'migrate:down'
91
+ end
92
+
93
+ desc 'Display status of migrations'
94
+ task :status => [:environment, :load_config] do
95
+ execute_on_shards.call 'migrate:status'
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+
@@ -0,0 +1,3 @@
1
+ module Sengiri
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :tofu do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sengiri
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - mewlist
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 4.1.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 4.1.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: sqlite3
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Database sharding for Ruby on Rails. Supports sharding migration, access
56
+ and transaction
57
+ email:
58
+ - mewlist@mewlist.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - db/sengiri_shards_1.sqlite3
64
+ - db/sengiri_shards_2.sqlite3
65
+ - lib/sengiri/generators/migration_generator.rb
66
+ - lib/sengiri/generators/model_generator.rb
67
+ - lib/sengiri/generators/sharding_generator.rb
68
+ - lib/sengiri/generators/templates/create_table_migration.rb
69
+ - lib/sengiri/generators/templates/migration.rb
70
+ - lib/sengiri/generators/templates/model.rb
71
+ - lib/sengiri/generators/templates/module.rb
72
+ - lib/sengiri/model/base.rb
73
+ - lib/sengiri/railtie.rb
74
+ - lib/sengiri/railties/sharding.rake
75
+ - lib/sengiri/version.rb
76
+ - lib/sengiri.rb
77
+ - lib/tasks/sengiri.rake
78
+ - MIT-LICENSE
79
+ - Rakefile
80
+ - README.md
81
+ homepage: https://github.com/mewlist
82
+ licenses: []
83
+ metadata: {}
84
+ post_install_message:
85
+ rdoc_options: []
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ requirements: []
99
+ rubyforge_project:
100
+ rubygems_version: 2.0.3
101
+ signing_key:
102
+ specification_version: 4
103
+ summary: Database sharding for Ruby on Rails
104
+ test_files: []