Skip to content

Commit

Permalink
General refactoring and cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
brasten committed Aug 16, 2011
1 parent 10a5a54 commit 76bb4a3
Show file tree
Hide file tree
Showing 17 changed files with 462 additions and 91 deletions.
4 changes: 3 additions & 1 deletion .gitignore
@@ -1,4 +1,6 @@
.rvmrc .rvmrc
.rspec .rspec
.idea .idea
pkg pkg
.bundle
coverage
2 changes: 2 additions & 0 deletions Gemfile
Expand Up @@ -2,5 +2,7 @@ source :rubygems


group :development do group :development do
gem "rspec", ">= 2.6" gem "rspec", ">= 2.6"
gem "simplecov", "0.4.2"
gem "activerecord", "~> 3.0.0" gem "activerecord", "~> 3.0.0"
gem "sqlite3-ruby"
end end
8 changes: 8 additions & 0 deletions Gemfile.lock
Expand Up @@ -23,6 +23,12 @@ GEM
rspec-expectations (2.6.0) rspec-expectations (2.6.0)
diff-lcs (~> 1.1.2) diff-lcs (~> 1.1.2)
rspec-mocks (2.6.0) rspec-mocks (2.6.0)
simplecov (0.4.2)
simplecov-html (~> 0.4.4)
simplecov-html (0.4.5)
sqlite3 (1.3.4)
sqlite3-ruby (1.3.3)
sqlite3 (>= 1.3.3)
tzinfo (0.3.29) tzinfo (0.3.29)


PLATFORMS PLATFORMS
Expand All @@ -31,3 +37,5 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
activerecord (~> 3.0.0) activerecord (~> 3.0.0)
rspec (>= 2.6) rspec (>= 2.6)
simplecov (= 0.4.2)
sqlite3-ruby
43 changes: 34 additions & 9 deletions lib/active_shard/active_record/connection_handler.rb
@@ -1,3 +1,4 @@
require 'active_record'
require 'active_record/connection_adapters/abstract/connection_pool' require 'active_record/connection_adapters/abstract/connection_pool'


module ActiveShard module ActiveShard
Expand All @@ -15,7 +16,7 @@ class ConnectionHandler < ::ActiveRecord::ConnectionAdapters::ConnectionHandler
# #
# @param [Array<ShardDefinition>] shard_definitions # @param [Array<ShardDefinition>] shard_definitions
# @param [Hash] options # @param [Hash] options
# @option options [ShardLookupHandler] :shard_lookup # @option options [ShardLookupHandler, #lookup_active_shard] :shard_lookup
# #
def initialize( shard_definitions, options={} ) def initialize( shard_definitions, options={} )
@shard_lookup = options[ :shard_lookup ] @shard_lookup = options[ :shard_lookup ]
Expand All @@ -28,26 +29,26 @@ def initialize( shard_definitions, options={} )


def initialize_shard_definitions( definitions ) def initialize_shard_definitions( definitions )
definitions.each do |definition| definitions.each do |definition|
schema_pools[ definition.schema.to_sym ] ||= SchemaConnectionPool.new( schema_pools[ definition.schema.to_sym ] ||= new_schema_pool( definition )
::ActiveRecord::Base::ConnectionSpecification.new( definition.connection_spec, definition.adapter_method )
)




connection_pools[ connection_pool_id( definition.schema, definition.name ) ] = connection_pools[ connection_pool_id( definition.schema, definition.name ) ] = new_connection_pool( definition )
::ActiveRecord::ConnectionAdapters::ConnectionPool.new(
::ActiveRecord::Base::ConnectionSpecification.new( definition.connection_spec, definition.adapter_method )
)
end end
end end


# I want to put this in here, but it seems to cause problems that I haven't yet tracked down. [BLS]
#
#def establish_connection( *args ) #def establish_connection( *args )
# raise NoMethodError, "Sharded models do not support establish_connection" # raise NoMethodError, "Sharded models do not support establish_connection"
#end #end


# Retrieve connection pool for class # Retrieve connection pool for class
# #
# @param [#schema_name] klass An object which responds to #schema_name
# @return [ConnectionPool,SchemaConnectionPool] connection pool
#
def retrieve_connection_pool( klass ) def retrieve_connection_pool( klass )
schema_name = klass.schema_name schema_name = ( sn = klass.schema_name ).nil? ? nil : sn.to_sym


active_shard_name = shard_lookup.lookup_active_shard( schema_name ) active_shard_name = shard_lookup.lookup_active_shard( schema_name )


Expand All @@ -60,6 +61,30 @@ def retrieve_connection_pool( klass )


attr_reader :schema_pools attr_reader :schema_pools


def new_schema_pool( definition )
schema_pool_class.new(
connection_specification_class.new( definition.connection_spec, definition.adapter_method )
)
end

def new_connection_pool( definition )
connection_pool_class.new(
connection_specification_class.new( definition.connection_spec, definition.adapter_method )
)
end

def connection_pool_class
::ActiveRecord::ConnectionAdapters::ConnectionPool
end

def schema_pool_class
SchemaConnectionPool
end

def connection_specification_class
::ActiveRecord::Base::ConnectionSpecification
end

def connection_pool_id( schema_name, shard_name ) def connection_pool_id( schema_name, shard_name )
"#{schema_name.to_s}+#{shard_name.to_s}".to_sym "#{schema_name.to_s}+#{shard_name.to_s}".to_sym
end end
Expand Down
30 changes: 30 additions & 0 deletions lib/active_shard/active_record/pool_factory.rb
@@ -0,0 +1,30 @@
module ActiveShard
module ActiveRecord
class PoolFactory

attr_accessor :connection_pool_class
attr_accessor :schema_pool_class

# Initializes a new PoolFactory
#
# @param [Hash] options
# @option options [Class] connection_pool_class
# @option options [Class] schema_pool_class
#
def initialize( options={} )
@connection_pool_class = options[:connection_pool_class]
@schema_pool_class = options[:schema_pool_class]
end


def create_connection_pool( definition )

end

def create_schema_pool( definition )

end

end
end
end
10 changes: 5 additions & 5 deletions lib/active_shard/active_record/schema_connection_adapter.rb
Expand Up @@ -4,19 +4,19 @@ module ActiveShard
module ActiveRecord module ActiveRecord
class SchemaConnectionAdapter class SchemaConnectionAdapter


delegate :columns, :verify, :verify!, :run_callbacks, :quote_table_name, :quote_value, :quote, :to => :adapter delegate :columns, :verify, :verify!, :run_callbacks, :quote_table_name, :quote_value, :quote, :to => :target


def initialize( adapter ) def initialize( target )
@adapter = adapter @target = target
end end


def method_missing( sym, *args, &block ) def method_missing( sym, *args, &block )
raise ::ActiveShard::NoActiveShardError raise ::ActiveShard::NoActiveShardError
end end


private private
def adapter def target
@adapter @target
end end
end end
end end
Expand Down
3 changes: 2 additions & 1 deletion lib/active_shard/exceptions.rb
Expand Up @@ -6,11 +6,12 @@ module ActiveShard
# than nesting. # than nesting.
# #


# Base exception for all ActiveShard errors
#
class ActiveShardError < StandardError; end class ActiveShardError < StandardError; end


class DefinitionError < ActiveShardError; end class DefinitionError < ActiveShardError; end
class NameNotUniqueError < DefinitionError; end class NameNotUniqueError < DefinitionError; end

class NoActiveShardError < ActiveShardError; end class NoActiveShardError < ActiveShardError; end


end end
3 changes: 3 additions & 0 deletions lib/active_shard/scope.rb
Expand Up @@ -52,6 +52,9 @@ def push( active_shards )


# Remove the last scope from the stack # Remove the last scope from the stack
# #
# FIXME: Symbols (for AnySchema) may not roll back properly if multiple
# the same symbol is on the stack several times
#
def pop( pop_until=nil ) def pop( pop_until=nil )
if pop_until.nil? if pop_until.nil?
scope_crumbs.pop scope_crumbs.pop
Expand Down
2 changes: 1 addition & 1 deletion lib/active_shard/scope_manager.rb
Expand Up @@ -17,7 +17,7 @@ class ScopeManager
# scope instances # scope instances
# #
def initialize( options={} ) def initialize( options={} )
@scope_class = options[:scope_class] if options[:scope_class] self.scope_class = options[:scope_class] if options[:scope_class]
end end


# @see ActiveShard::Scope#push # @see ActiveShard::Scope#push
Expand Down
26 changes: 24 additions & 2 deletions lib/active_shard/shard_definition.rb
Expand Up @@ -15,9 +15,31 @@ class << self
# @return [Hash] hash of environments and lists of Definitions # @return [Hash] hash of environments and lists of Definitions
# #
def from_yaml_file( file_name ) def from_yaml_file( file_name )
definitions = {} from_yaml( File.open( file_name ).read() )
end

# Returns a hash with environments as the hash keys and
# a list of ShardDefinitions as the hash values
#
# @param [String] yaml YAML string to parse
#
# @return [Hash] hash of environments and lists of Definitions
#
def from_yaml( yaml )
hash = YAML.load( ERB.new( yaml ).result )


hash = YAML.load( ERB.new( File.open( file_name ).read() ).result ) from_hash( hash )
end

# Returns a hash with environments as the hash keys and
# a list of ShardDefinitions as the hash values
#
# @param [Hash] hash raw hash in YAML-format
#
# @return [Hash] hash of environments and lists of Definitions
#
def from_hash( hash )
definitions = {}


hash.each_pair do |environment, schemas| hash.each_pair do |environment, schemas|
schemas.each_pair do |schema, shards| schemas.each_pair do |schema, shards|
Expand Down
16 changes: 7 additions & 9 deletions lib/active_shard/shard_lookup_handler.rb
@@ -1,28 +1,26 @@
module ActiveShard module ActiveShard


# Handles current and schema shard resolution using the current # Handles current shard resolution using the provided scope
# scope and #
class ShardLookupHandler class ShardLookupHandler


# Initializes a shard lookup handler # Initializes a shard lookup handler
# #
# @param [Hash] options # @param [Hash] options
# @option options [Scope,ScopeManager] :scope # @option options [Scope,ScopeManager] :scope
# @option options [Config] :config
# scope instances
# #
def initialize( options={} ) def initialize( options={} )
@scope = options[:scope] @scope = options[:scope]
@config = options[:config]
end end


# Returns the active shard for the provided schema, or nil if none.
#
# @param [Symbol] schema_name
# @return [Symbol, nil] shard name if any
#
def lookup_active_shard( schema_name ) def lookup_active_shard( schema_name )
@scope.active_shard_for_schema( schema_name ) @scope.active_shard_for_schema( schema_name )
end end


def lookup_schema_shard( schema_name )
@config.schema_shard_name_by_schema( schema_name )
end

end end
end end
89 changes: 89 additions & 0 deletions spec/active_shard/active_record/connection_handler_spec.rb
@@ -0,0 +1,89 @@
require 'spec_helper'
require 'active_shard/active_record/connection_handler'

module ActiveShard::ActiveRecord

describe ConnectionHandler do
let :shard_definitions do
yaml = <<-EOY
test:
schema_one:
shard_one:
adapter: sqlite3
database: spec/output/shard_one.db
shard_two:
adapter: sqlite3
database: spec/output/shard_two.db
schema_two:
shard_three:
adapter: sqlite3
database: spec/output/shard_three.db
shard_four:
adapter: sqlite3
database: spec/output/shard_four.db
shard_five:
adapter: sqlite3
database: spec/output/shard_five.db
schema_three:
shard_six:
adapter: sqlite3
database: spec/output/shard_six.db
shard_seven:
adapter: sqlite3
database: spec/output/shard_seven.db
EOY
ActiveShard::ShardDefinition.from_yaml( yaml )[:test]
end

describe "#retrieve_connection_pool" do
context "with schema/shards" do
let :lookup_handler do
handler = mock(:handler)
handler.stub!(:lookup_active_shard).and_return(nil)
handler
end

let :handler do
ConnectionHandler.new( shard_definitions, :shard_lookup => lookup_handler )
end

context "with active shards :schema_one => :shard_two, :schema_two => :shard_four" do
let :lookup_handler do
handler = mock(:handler)
handler.stub!(:lookup_active_shard).with(:schema_one).and_return(:shard_two)
handler.stub!(:lookup_active_shard).with(:schema_two).and_return(:shard_four)
handler.stub!(:lookup_active_shard).with(:schema_three).and_return(nil)
handler
end

it "should return connection_pool for shard_two when klass.schema_name == :schema_one" do
pool = handler.retrieve_connection_pool( mock(:klass, :schema_name => :schema_one) )
pool.spec.config[:adapter].should == 'sqlite3'
pool.spec.config[:database].should == 'spec/output/shard_two.db'
pool.should be_instance_of( ::ActiveRecord::ConnectionAdapters::ConnectionPool )
end

it "should return connection_pool for shard_four when klass.schema_name == :schema_two" do
pool = handler.retrieve_connection_pool( mock(:klass, :schema_name => :schema_two) )
pool.spec.config[:adapter].should == 'sqlite3'
pool.spec.config[:database].should == 'spec/output/shard_four.db'
pool.should be_instance_of( ::ActiveRecord::ConnectionAdapters::ConnectionPool )
end

it "should return schema_connection_pool for shard_six when klass.schema_name == :schema_three" do
pool = handler.retrieve_connection_pool( mock(:klass, :schema_name => :schema_three) )
pool.spec.config[:adapter].should == 'sqlite3'
pool.spec.config[:database].should == 'spec/output/shard_six.db'
pool.should be_instance_of( ::ActiveShard::ActiveRecord::SchemaConnectionPool )
end
end


end

end


end

end
12 changes: 12 additions & 0 deletions spec/active_shard/active_record/schema_connection_pool_spec.rb
@@ -0,0 +1,12 @@
require 'spec_helper'
require 'active_shard/active_record/schema_connection_pool'

module ActiveShard::ActiveRecord

describe SchemaConnectionPool do



end

end

0 comments on commit 76bb4a3

Please sign in to comment.