sengiri 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: []