ar-octopus 0.8.0 → 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.mkdn +9 -2
- data/ar-octopus.gemspec +1 -1
- data/lib/octopus/association.rb +35 -0
- data/lib/octopus/association_collection.rb +33 -47
- data/lib/octopus/migration.rb +5 -4
- data/lib/octopus/model.rb +34 -13
- data/lib/octopus/proxy.rb +20 -10
- data/lib/octopus/rails3/abstract_adapter.rb +0 -11
- data/lib/octopus/rails3/persistence.rb +8 -16
- data/lib/octopus/rails3/singular_association.rb +5 -5
- data/lib/octopus/version.rb +1 -1
- data/spec/config/shards.yml +5 -1
- data/spec/migrations/15_create_user_on_shards_of_default_group_with_versions.rb +9 -0
- data/spec/octopus/association_spec.rb +52 -5
- data/spec/octopus/migration_spec.rb +14 -0
- data/spec/octopus/proxy_spec.rb +33 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MTRmYWZkMTg0YzU4MTM4YmNjYTM3MDE3MDVjZjQ1MjdiYmE2NDkwMg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ODhhZTJjNDQzZDVhMWZhYzc1NzRjYWNjOTdlYTQ5MTNlYzk5YWJkMA==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
Y2JiNmI0MjEzYWRjYTFhYjMwN2IyYWQwMTQyMDI1M2UyYTdiNzU3NGY4ZDlm
|
10
|
+
MGYwNDQ2NGViMjhjOGRjMTZiNjdjN2VhODZiOGQ3ZWQ2Njg5OTFjZWE1ZDQ5
|
11
|
+
ZThjNjUxOTNhYzYyNTMwMjk3MjkwYmYzNmU3YjA0Y2MzMjMyZmE=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MjU1YzZlNzczNGM2OGQ2YzMxYmZhMWE4M2QzYTQ5ZjM1NjEwYTQ4MDJiMDY5
|
14
|
+
YzM0Mjg4OTc4MmI4ZGYxMTlhNDJmYWMxMzA3MjU5ZDdmNjIwNmNmNmNlMmY3
|
15
|
+
OWZjY2RkNTViY2MzOTdjMjU5NTg2NjFkNDcyZmRiMWU5NDA2MWM=
|
data/README.mkdn
CHANGED
@@ -27,7 +27,7 @@ When using replication, all writes queries will be sent to master, and read quer
|
|
27
27
|
|
28
28
|
Add this line to Gemfile:
|
29
29
|
|
30
|
-
gem 'ar-octopus'
|
30
|
+
gem 'ar-octopus'
|
31
31
|
|
32
32
|
Currently, Octopus doesn't support Rails 2. If you need support for rails 2, please use the version 0.5.0.
|
33
33
|
|
@@ -107,6 +107,13 @@ You also could send a migration to a group of shards. This migration will be se
|
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
110
|
+
You can specify a `default_migration_group` for migrations, so that modifications to each individual migration file are not needed:
|
111
|
+
|
112
|
+
octopus:
|
113
|
+
default_migration_group: europe_databases
|
114
|
+
|
115
|
+
There is no need for a corresponding `default_migration_shard` - simply define that database to be your master. You might want this setting if all of your databases have identical schemas, but are not replicated.
|
116
|
+
|
110
117
|
### Rails Controllers
|
111
118
|
|
112
119
|
If you want to send a specified action, or all actions from a controller, to a specific shard, use this syntax:
|
@@ -157,7 +164,7 @@ If you are having issues running the octopus spec suite, verify your database us
|
|
157
164
|
|
158
165
|
## Thanks
|
159
166
|
|
160
|
-
This project is sponsored by the <a href="http://www.rubysoc.org">Ruby Summer of Code</a>,
|
167
|
+
This project is sponsored by the <a href="http://www.rubysoc.org">Ruby Summer of Code</a>, Rapid River Software,
|
161
168
|
and my mentors <a href="http://github.com/mperham">Mike Perham</a> and <a href="http://github.com/amitagarwal">Amit Agarwal</a>.
|
162
169
|
|
163
170
|
## Copyright
|
data/ar-octopus.gemspec
CHANGED
@@ -29,7 +29,7 @@ Gem::Specification.new do |s|
|
|
29
29
|
s.add_development_dependency 'mysql2', '> 0.3'
|
30
30
|
s.add_development_dependency 'pg', '>= 0.11.0'
|
31
31
|
s.add_development_dependency 'sqlite3', '>= 1.3.4'
|
32
|
-
s.add_development_dependency 'pry'
|
32
|
+
s.add_development_dependency 'pry-debugger'
|
33
33
|
s.add_development_dependency 'appraisal', '>= 0.3.8'
|
34
34
|
|
35
35
|
s.license = 'MIT'
|
data/lib/octopus/association.rb
CHANGED
@@ -3,6 +3,39 @@ module Octopus::Association
|
|
3
3
|
base.send(:include, InstanceMethods)
|
4
4
|
end
|
5
5
|
|
6
|
+
module QueryOnCurrentShard
|
7
|
+
|
8
|
+
METHODS= %w[
|
9
|
+
all
|
10
|
+
average
|
11
|
+
count
|
12
|
+
empty?
|
13
|
+
exists?
|
14
|
+
find
|
15
|
+
find_by_sql
|
16
|
+
first
|
17
|
+
last
|
18
|
+
maximum
|
19
|
+
minimum
|
20
|
+
pluck
|
21
|
+
scoping
|
22
|
+
size
|
23
|
+
sum
|
24
|
+
to_a
|
25
|
+
]
|
26
|
+
|
27
|
+
METHODS.each do |m|
|
28
|
+
define_method m.to_sym do |*args,&block|
|
29
|
+
if self.respond_to?(:proxy_association) and self.proxy_association
|
30
|
+
self.proxy_association.owner.run_on_shard { super(*args, &block) }
|
31
|
+
else
|
32
|
+
super(*args, &block)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
6
39
|
module InstanceMethods
|
7
40
|
def set_connection_on_association(record)
|
8
41
|
return unless ::Octopus.enabled?
|
@@ -64,6 +97,8 @@ module Octopus::Association
|
|
64
97
|
else
|
65
98
|
options[:before_remove] = :set_connection_on_association
|
66
99
|
end
|
100
|
+
|
101
|
+
options[:extend] = [ Octopus::Association::QueryOnCurrentShard, options[:extend] ].flatten.compact
|
67
102
|
end
|
68
103
|
end
|
69
104
|
|
@@ -1,63 +1,49 @@
|
|
1
1
|
module Octopus::AssociationCollection
|
2
2
|
|
3
|
+
METHODS = %w[
|
4
|
+
reader
|
5
|
+
writer
|
6
|
+
ids_reader
|
7
|
+
ids_writer
|
8
|
+
create
|
9
|
+
create!
|
10
|
+
build
|
11
|
+
any?
|
12
|
+
count
|
13
|
+
empty?
|
14
|
+
first
|
15
|
+
include?
|
16
|
+
last
|
17
|
+
length
|
18
|
+
load_target
|
19
|
+
many?
|
20
|
+
size
|
21
|
+
select
|
22
|
+
uniq
|
23
|
+
]
|
24
|
+
|
3
25
|
def self.included(base)
|
4
26
|
base.instance_eval do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
alias_method_chain :ids_writer, :octopus
|
9
|
-
alias_method_chain :create, :octopus
|
10
|
-
alias_method_chain :create!, :octopus
|
11
|
-
alias_method_chain :build, :octopus
|
27
|
+
METHODS.each do |m|
|
28
|
+
alias_method_chain m.to_sym, :octopus
|
29
|
+
end
|
12
30
|
end
|
13
31
|
end
|
14
32
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
def writer_with_octopus(*args)
|
26
|
-
owner.reload_connection
|
27
|
-
writer_without_octopus(*args)
|
28
|
-
end
|
29
|
-
|
30
|
-
def ids_reader_with_octopus(*args)
|
31
|
-
owner.reload_connection
|
32
|
-
ids_reader_without_octopus(*args)
|
33
|
-
end
|
34
|
-
|
35
|
-
def ids_writer_with_octopus(*args)
|
36
|
-
owner.reload_connection
|
37
|
-
ids_writer_without_octopus(*args)
|
38
|
-
end
|
39
|
-
|
40
|
-
def create_with_octopus(*args, &block)
|
41
|
-
owner.reload_connection
|
42
|
-
create_without_octopus(*args, &block)
|
43
|
-
end
|
44
|
-
|
45
|
-
def create_with_octopus!(*args, &block)
|
46
|
-
owner.reload_connection
|
47
|
-
create_without_octopus!(*args, &block)
|
33
|
+
METHODS.each do |m|
|
34
|
+
m =~ /([^!?]+)([!?])?/
|
35
|
+
method, punctuation = [ $1, $2 ]
|
36
|
+
with = :"#{method}_with_octopus#{punctuation}"
|
37
|
+
without = :"#{method}_without_octopus#{punctuation}"
|
38
|
+
define_method with do |*args, &block|
|
39
|
+
@owner.run_on_shard { send(without, *args, &block) }
|
40
|
+
end
|
48
41
|
end
|
49
42
|
|
50
43
|
def should_wrap_the_connection?
|
51
44
|
@owner.respond_to?(:current_shard) && @owner.current_shard != nil
|
52
45
|
end
|
53
46
|
|
54
|
-
def count(*args)
|
55
|
-
if should_wrap_the_connection?
|
56
|
-
Octopus.using(@owner.current_shard) { super }
|
57
|
-
else
|
58
|
-
super
|
59
|
-
end
|
60
|
-
end
|
61
47
|
end
|
62
48
|
|
63
49
|
ActiveRecord::Associations::CollectionAssociation.send(:include, Octopus::AssociationCollection)
|
data/lib/octopus/migration.rb
CHANGED
@@ -16,10 +16,10 @@ module Octopus::Migration
|
|
16
16
|
include InstanceOrClassMethods
|
17
17
|
|
18
18
|
def self.included(base)
|
19
|
-
base.
|
19
|
+
base.extend(ClassMethods)
|
20
20
|
|
21
21
|
base.alias_method_chain :announce, :octopus
|
22
|
-
base.class_attribute :current_shard, :current_group, :instance_reader => false, :instance_writer => false
|
22
|
+
base.class_attribute :current_shard, :current_group, :current_group_specified, :instance_reader => false, :instance_writer => false
|
23
23
|
end
|
24
24
|
|
25
25
|
module ClassMethods
|
@@ -34,13 +34,14 @@ module Octopus::Migration
|
|
34
34
|
return self unless connection.is_a?(Octopus::Proxy)
|
35
35
|
|
36
36
|
self.current_group = groups
|
37
|
+
self.current_group_specified = true
|
37
38
|
self
|
38
39
|
end
|
39
40
|
|
40
41
|
def shards
|
41
42
|
shards = Set.new
|
42
43
|
|
43
|
-
if groups = current_group
|
44
|
+
if groups = (current_group_specified ? current_group : Octopus.config[:default_migration_group])
|
44
45
|
Array.wrap(groups).each do |group|
|
45
46
|
group_shards = connection.shards_for_group(group)
|
46
47
|
shards.merge(group_shards) if group_shards
|
@@ -56,7 +57,7 @@ end
|
|
56
57
|
|
57
58
|
module Octopus::Migrator
|
58
59
|
def self.included(base)
|
59
|
-
base.
|
60
|
+
base.extend(ClassMethods)
|
60
61
|
|
61
62
|
base.class_eval do
|
62
63
|
class << self
|
data/lib/octopus/model.rb
CHANGED
@@ -31,7 +31,7 @@ module Octopus::Model
|
|
31
31
|
|
32
32
|
def hijack_initializer()
|
33
33
|
attr_accessor :current_shard
|
34
|
-
|
34
|
+
around_save :run_on_shard
|
35
35
|
|
36
36
|
def set_current_shard
|
37
37
|
return unless Octopus.enabled?
|
@@ -72,9 +72,36 @@ module Octopus::Model
|
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
|
+
def self.clear_active_connections_with_octopus!
|
76
|
+
if should_use_normal_connection?
|
77
|
+
clear_active_connections_without_octopus!
|
78
|
+
else
|
79
|
+
connection_proxy.clear_active_connections!
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.clear_all_connections_with_octopus!
|
84
|
+
if should_use_normal_connection?
|
85
|
+
clear_all_connections_without_octopus!
|
86
|
+
else
|
87
|
+
connection_proxy.clear_all_connections!
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.connected_with_octopus?
|
92
|
+
if should_use_normal_connection?
|
93
|
+
connected_without_octopus?
|
94
|
+
else
|
95
|
+
connection_proxy.connected?
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
75
99
|
class << self
|
76
100
|
alias_method_chain :connection, :octopus
|
77
101
|
alias_method_chain :connection_pool, :octopus
|
102
|
+
alias_method_chain :clear_all_connections!, :octopus
|
103
|
+
alias_method_chain :clear_active_connections!, :octopus
|
104
|
+
alias_method_chain :connected?, :octopus
|
78
105
|
end
|
79
106
|
end
|
80
107
|
end
|
@@ -93,18 +120,12 @@ module Octopus::Model
|
|
93
120
|
self.respond_to?(:current_shard) && !self.current_shard.nil?
|
94
121
|
end
|
95
122
|
|
96
|
-
def
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
result
|
103
|
-
end
|
104
|
-
|
105
|
-
def reload_connection()
|
106
|
-
return unless should_set_current_shard?
|
107
|
-
self.class.connection_proxy.current_shard = self.current_shard
|
123
|
+
def run_on_shard(&block)
|
124
|
+
if self.current_shard
|
125
|
+
self.class.connection_proxy.run_queries_on_shard(self.current_shard, &block)
|
126
|
+
else
|
127
|
+
yield
|
128
|
+
end
|
108
129
|
end
|
109
130
|
|
110
131
|
def equality_with_octopus(comparison_object)
|
data/lib/octopus/proxy.rb
CHANGED
@@ -12,7 +12,6 @@ class Octopus::Proxy
|
|
12
12
|
@shards = HashWithIndifferentAccess.new
|
13
13
|
@groups = {}
|
14
14
|
@adapters = Set.new
|
15
|
-
@shards[:master] = ActiveRecord::Base.connection_pool_without_octopus()
|
16
15
|
@config = ActiveRecord::Base.connection_pool_without_octopus.connection.instance_variable_get(:@config)
|
17
16
|
|
18
17
|
if !config.nil?
|
@@ -23,7 +22,7 @@ class Octopus::Proxy
|
|
23
22
|
shards_config ||= []
|
24
23
|
|
25
24
|
shards_config.each do |key, value|
|
26
|
-
if value.is_a?(String)
|
25
|
+
if value.is_a?(String)
|
27
26
|
value = resolve_string_connection(value).merge(:octopus_shard => key)
|
28
27
|
initialize_adapter(value['adapter'])
|
29
28
|
@shards[key.to_sym] = connection_pool_for(value, "#{value['adapter']}_connection")
|
@@ -45,6 +44,8 @@ class Octopus::Proxy
|
|
45
44
|
end
|
46
45
|
end
|
47
46
|
end
|
47
|
+
|
48
|
+
@shards[:master] ||= ActiveRecord::Base.connection_pool_without_octopus()
|
48
49
|
end
|
49
50
|
|
50
51
|
def initialize_replication(config)
|
@@ -137,7 +138,7 @@ class Octopus::Proxy
|
|
137
138
|
# Rails 3.1 sets automatic_reconnect to false when it removes
|
138
139
|
# connection pool. Octopus can potentially retain a reference to a closed
|
139
140
|
# connection pool. Previously, that would work since the pool would just
|
140
|
-
# reconnect, but in Rails 3.1 the flag prevents this.
|
141
|
+
# reconnect, but in Rails 3.1 the flag prevents this.
|
141
142
|
def safe_connection(connection_pool)
|
142
143
|
connection_pool.automatic_reconnect ||= true
|
143
144
|
connection_pool.connection()
|
@@ -219,19 +220,28 @@ class Octopus::Proxy
|
|
219
220
|
end
|
220
221
|
|
221
222
|
def enable_query_cache!
|
222
|
-
|
223
|
-
|
224
|
-
c.clear_query_cache_without_octopus
|
225
|
-
c.enable_query_cache!
|
226
|
-
end
|
223
|
+
clear_query_cache
|
224
|
+
@shards.each { |k, v| safe_connection(v).enable_query_cache! }
|
227
225
|
end
|
228
226
|
|
229
227
|
def disable_query_cache!
|
230
228
|
@shards.each { |k, v| safe_connection(v).disable_query_cache! }
|
231
229
|
end
|
232
230
|
|
233
|
-
def
|
234
|
-
@shards.each { |k, v| safe_connection(v).
|
231
|
+
def clear_query_cache
|
232
|
+
@shards.each { |k, v| safe_connection(v).clear_query_cache }
|
233
|
+
end
|
234
|
+
|
235
|
+
def clear_active_connections!
|
236
|
+
@shards.each { |k, v| v.release_connection }
|
237
|
+
end
|
238
|
+
|
239
|
+
def clear_all_connections!
|
240
|
+
@shards.each { |k, v| v.disconnect! }
|
241
|
+
end
|
242
|
+
|
243
|
+
def connected?
|
244
|
+
@shards.any? { |k, v| v.connected? }
|
235
245
|
end
|
236
246
|
|
237
247
|
protected
|
@@ -26,7 +26,6 @@ module Octopus
|
|
26
26
|
|
27
27
|
def self.included(base)
|
28
28
|
base.alias_method_chain :initialize, :octopus_shard
|
29
|
-
base.alias_method_chain :clear_query_cache, :octopus
|
30
29
|
end
|
31
30
|
|
32
31
|
def octopus_shard
|
@@ -38,16 +37,6 @@ module Octopus
|
|
38
37
|
@instrumenter = InstrumenterDecorator.new(self, @instrumenter)
|
39
38
|
end
|
40
39
|
|
41
|
-
# Intercept calls to clear_query_cache and make sure that all
|
42
|
-
# query caches on all shards are invalidated, just to be safe.
|
43
|
-
def clear_query_cache_with_octopus
|
44
|
-
if Octopus.enabled?
|
45
|
-
ActiveRecord::Base.connection_proxy.clear_all_query_caches!
|
46
|
-
else
|
47
|
-
clear_query_cache_without_octopus
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
40
|
end
|
52
41
|
end
|
53
42
|
end
|
@@ -2,43 +2,35 @@ module Octopus
|
|
2
2
|
module Rails3
|
3
3
|
module Persistence
|
4
4
|
def update_attribute(*args)
|
5
|
-
|
6
|
-
super
|
5
|
+
run_on_shard { super }
|
7
6
|
end
|
8
7
|
|
9
8
|
def update_attributes(*args)
|
10
|
-
|
11
|
-
super
|
9
|
+
run_on_shard { super }
|
12
10
|
end
|
13
11
|
|
14
12
|
def update_attributes!(*args)
|
15
|
-
|
16
|
-
super
|
13
|
+
run_on_shard { super }
|
17
14
|
end
|
18
15
|
|
19
16
|
def reload(*args)
|
20
|
-
|
21
|
-
super
|
17
|
+
run_on_shard { super }
|
22
18
|
end
|
23
19
|
|
24
20
|
def delete
|
25
|
-
|
26
|
-
super
|
21
|
+
run_on_shard { super }
|
27
22
|
end
|
28
23
|
|
29
24
|
def destroy
|
30
|
-
|
31
|
-
super
|
25
|
+
run_on_shard { super }
|
32
26
|
end
|
33
27
|
|
34
28
|
def touch(name=nil)
|
35
|
-
|
36
|
-
super
|
29
|
+
run_on_shard { super }
|
37
30
|
end
|
38
31
|
|
39
32
|
def update_column(*args)
|
40
|
-
|
41
|
-
super
|
33
|
+
run_on_shard { super }
|
42
34
|
end
|
43
35
|
end
|
44
36
|
end
|
@@ -10,23 +10,23 @@ module Octopus::SingularAssociation
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def reader_with_octopus(*args)
|
13
|
-
owner.
|
13
|
+
owner.run_on_shard { reader_without_octopus(*args) }
|
14
14
|
end
|
15
15
|
|
16
16
|
def writer_with_octopus(*args)
|
17
|
-
owner.
|
17
|
+
owner.run_on_shard { writer_without_octopus(*args) }
|
18
18
|
end
|
19
19
|
|
20
20
|
def create_with_octopus(*args)
|
21
|
-
owner.
|
21
|
+
owner.run_on_shard { create_without_octopus(*args) }
|
22
22
|
end
|
23
23
|
|
24
24
|
def create_with_octopus!(*args)
|
25
|
-
owner.
|
25
|
+
owner.run_on_shard { create_without_octopus!(*args) }
|
26
26
|
end
|
27
27
|
|
28
28
|
def build_with_octopus(*args)
|
29
|
-
owner.
|
29
|
+
owner.run_on_shard { build_without_octopus(*args) }
|
30
30
|
end
|
31
31
|
|
32
32
|
end
|
data/lib/octopus/version.rb
CHANGED
data/spec/config/shards.yml
CHANGED
@@ -3,7 +3,7 @@ mysql: &mysql
|
|
3
3
|
username: <%= ENV['MYSQL_USER'] || 'root' %>
|
4
4
|
host: localhost
|
5
5
|
|
6
|
-
octopus:
|
6
|
+
octopus: &octopus
|
7
7
|
shards:
|
8
8
|
alone_shard:
|
9
9
|
database: octopus_shard_5
|
@@ -45,6 +45,10 @@ octopus:
|
|
45
45
|
|
46
46
|
protocol_shard: postgres://<%= ENV['POSTGRES_USER'] || 'postgres' %>@localhost:5432/octopus_shard_2
|
47
47
|
|
48
|
+
octopus_with_default_migration_group:
|
49
|
+
<<: *octopus
|
50
|
+
default_migration_group: country_shards
|
51
|
+
|
48
52
|
production_raise_error:
|
49
53
|
shards:
|
50
54
|
history_shards:
|
@@ -53,7 +53,7 @@ describe Octopus::Association, :shards => [:brazil, :master, :canada] do
|
|
53
53
|
c.save()
|
54
54
|
k.save()
|
55
55
|
|
56
|
-
Computer.includes(:keyboard).find(c.id).should == c
|
56
|
+
Computer.using(:brazil).includes(:keyboard).find(c.id).should == c
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
@@ -71,11 +71,17 @@ describe Octopus::Association, :shards => [:brazil, :master, :canada] do
|
|
71
71
|
it "should find all models in the specified shard" do
|
72
72
|
@brazil_role.permission_ids().should == [@permission_brazil.id]
|
73
73
|
@brazil_role.permissions().should == [@permission_brazil]
|
74
|
+
|
75
|
+
@brazil_role.permissions.first.should eq(@permission_brazil)
|
76
|
+
@brazil_role.permissions.last.should eq(@permission_brazil)
|
74
77
|
end
|
75
78
|
|
76
79
|
it "should finds the client that the item belongs" do
|
77
80
|
@permission_brazil.role_ids.should == [@brazil_role.id]
|
78
81
|
@permission_brazil.roles.should == [@brazil_role]
|
82
|
+
|
83
|
+
@permission_brazil.roles.first.should eq(@brazil_role)
|
84
|
+
@permission_brazil.roles.last.should eq(@brazil_role)
|
79
85
|
end
|
80
86
|
|
81
87
|
it "should update the attribute for the item" do
|
@@ -226,8 +232,11 @@ describe Octopus::Association, :shards => [:brazil, :master, :canada] do
|
|
226
232
|
end
|
227
233
|
|
228
234
|
it "should find all models in the specified shard" do
|
229
|
-
@programmer.project_ids().should
|
230
|
-
@programmer.projects().should
|
235
|
+
@programmer.project_ids().should eq([@project.id])
|
236
|
+
@programmer.projects().should eq([@project])
|
237
|
+
|
238
|
+
@programmer.projects.first.should eq(@project)
|
239
|
+
@programmer.projects.last.should eq(@project)
|
231
240
|
end
|
232
241
|
|
233
242
|
|
@@ -379,8 +388,11 @@ describe Octopus::Association, :shards => [:brazil, :master, :canada] do
|
|
379
388
|
end
|
380
389
|
|
381
390
|
it "should find all models in the specified shard" do
|
382
|
-
@brazil_client.item_ids.should
|
383
|
-
@brazil_client.items().should
|
391
|
+
@brazil_client.item_ids.should eq([@item_brazil.id])
|
392
|
+
@brazil_client.items().should eq([@item_brazil])
|
393
|
+
|
394
|
+
@brazil_client.items.last.should eq(@item_brazil)
|
395
|
+
@brazil_client.items.first.should eq(@item_brazil)
|
384
396
|
end
|
385
397
|
|
386
398
|
it "should finds the client that the item belongs" do
|
@@ -412,6 +424,25 @@ describe Octopus::Association, :shards => [:brazil, :master, :canada] do
|
|
412
424
|
c.items().should == [item2]
|
413
425
|
end
|
414
426
|
|
427
|
+
context "when calling methods on a collection generated by an association" do
|
428
|
+
let(:collection) { @brazil_client.items }
|
429
|
+
before :each do
|
430
|
+
@brazil_client.items.create(:name => 'Brazil Item #2')
|
431
|
+
end
|
432
|
+
|
433
|
+
it "can call collection indexes directly without resetting the collection's current_shard" do
|
434
|
+
last_item = collection[1]
|
435
|
+
collection.length.should == 2
|
436
|
+
collection.should eq([ collection[0], last_item ])
|
437
|
+
end
|
438
|
+
|
439
|
+
it "can call methods on the collection without resetting the collection's current_shard" do
|
440
|
+
last_item = collection[collection.size-1]
|
441
|
+
collection.length.should == 2
|
442
|
+
collection.should eq([ collection[0], last_item ])
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
415
446
|
describe "it should works when using" do
|
416
447
|
before(:each) do
|
417
448
|
@item_brazil_2 = Item.using(:brazil).create!(:name => "Brazil Item 2")
|
@@ -434,6 +465,14 @@ describe Octopus::Association, :shards => [:brazil, :master, :canada] do
|
|
434
465
|
@brazil_client.items.to_set.should == [@item_brazil, @item_brazil_2].to_set
|
435
466
|
end
|
436
467
|
|
468
|
+
it "all" do
|
469
|
+
item = @brazil_client.items.build(:name => "Builded Item")
|
470
|
+
item.save()
|
471
|
+
i = @brazil_client.items
|
472
|
+
i.to_set.should == [@item_brazil, item].to_set
|
473
|
+
i.reload.all.to_set.should == [@item_brazil, item].to_set
|
474
|
+
end
|
475
|
+
|
437
476
|
it "build" do
|
438
477
|
item = @brazil_client.items.build(:name => "Builded Item")
|
439
478
|
item.save()
|
@@ -570,6 +609,14 @@ describe Octopus::Association, :shards => [:brazil, :master, :canada] do
|
|
570
609
|
@brazil_client.comments.to_set.should == [@comment_brazil, @comment_brazil_2].to_set
|
571
610
|
end
|
572
611
|
|
612
|
+
it "all" do
|
613
|
+
comment = @brazil_client.comments.build(:name => "Builded Comment")
|
614
|
+
comment.save()
|
615
|
+
c = @brazil_client.comments
|
616
|
+
c.to_set.should == [@comment_brazil, comment].to_set
|
617
|
+
c.reload.all.to_set.should == [@comment_brazil, comment].to_set
|
618
|
+
end
|
619
|
+
|
573
620
|
it "build" do
|
574
621
|
comment = @brazil_client.comments.build(:name => "Builded Comment")
|
575
622
|
comment.save()
|
@@ -98,4 +98,18 @@ describe Octopus::Migration do
|
|
98
98
|
Octopus.using(:russia) { ActiveRecord::Migrator.get_all_versions }.should include(14)
|
99
99
|
end
|
100
100
|
end
|
101
|
+
|
102
|
+
describe "when using a default_migration_group" do
|
103
|
+
it "should run migrations on all shards in the default_migration_group" do
|
104
|
+
OctopusHelper.using_environment :octopus_with_default_migration_group do
|
105
|
+
OctopusHelper.migrating_to_version 15 do
|
106
|
+
Octopus.using(:master) { ActiveRecord::Migrator.get_all_versions }.should_not include(15)
|
107
|
+
Octopus.using(:canada) { ActiveRecord::Migrator.get_all_versions }.should include(15)
|
108
|
+
Octopus.using(:brazil) { ActiveRecord::Migrator.get_all_versions }.should include(15)
|
109
|
+
Octopus.using(:russia) { ActiveRecord::Migrator.get_all_versions }.should include(15)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
101
115
|
end
|
data/spec/octopus/proxy_spec.rb
CHANGED
@@ -263,4 +263,37 @@ describe Octopus::Proxy do
|
|
263
263
|
end
|
264
264
|
end
|
265
265
|
end
|
266
|
+
|
267
|
+
describe "connection reuse" do
|
268
|
+
before :each do
|
269
|
+
@item_brazil_conn = Item.using(:brazil).new(:name => 'Brazil Item').connection.select_connection
|
270
|
+
@item_canada_conn = Item.using(:canada).new(:name => 'Canada Item').connection.select_connection
|
271
|
+
end
|
272
|
+
|
273
|
+
it "reuses connections" do
|
274
|
+
Item.using(:brazil).new(:name => 'Another Brazil Item').connection.select_connection.should eq(@item_brazil_conn)
|
275
|
+
Item.using(:canada).new(:name => 'Another Canada Item').connection.select_connection.should eq(@item_canada_conn)
|
276
|
+
end
|
277
|
+
|
278
|
+
it "reuses connections after clear_active_connections! is called" do
|
279
|
+
Item.using(:brazil).new(:name => 'Another Brazil Item').connection.select_connection.should eq(@item_brazil_conn)
|
280
|
+
Item.using(:canada).new(:name => 'Another Canada Item').connection.select_connection.should eq(@item_canada_conn)
|
281
|
+
end
|
282
|
+
|
283
|
+
it "creates new connections after clear_all_connections! is called" do
|
284
|
+
Item.clear_all_connections!
|
285
|
+
Item.using(:brazil).new(:name => 'Another Brazil Item').connection.select_connection.should_not eq(@item_brazil_conn)
|
286
|
+
Item.using(:canada).new(:name => 'Another Canada Item').connection.select_connection.should_not eq(@item_canada_conn)
|
287
|
+
end
|
288
|
+
|
289
|
+
it "is consistent with connected?" do
|
290
|
+
Item.connected?.should be_true
|
291
|
+
ActiveRecord::Base.connected?.should be_true
|
292
|
+
|
293
|
+
Item.clear_all_connections!
|
294
|
+
|
295
|
+
Item.connected?.should be_false
|
296
|
+
ActiveRecord::Base.connected?.should be_false
|
297
|
+
end
|
298
|
+
end
|
266
299
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ar-octopus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thiago Pradi
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2014-01-28 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|
@@ -111,7 +111,7 @@ dependencies:
|
|
111
111
|
- !ruby/object:Gem::Version
|
112
112
|
version: 1.3.4
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
|
-
name: pry
|
114
|
+
name: pry-debugger
|
115
115
|
requirement: !ruby/object:Gem::Requirement
|
116
116
|
requirements:
|
117
117
|
- - ! '>='
|
@@ -260,6 +260,7 @@ files:
|
|
260
260
|
- spec/migrations/12_create_users_using_block.rb
|
261
261
|
- spec/migrations/13_create_users_using_block_and_using.rb
|
262
262
|
- spec/migrations/14_create_users_on_shards_of_a_group_with_versions.rb
|
263
|
+
- spec/migrations/15_create_user_on_shards_of_default_group_with_versions.rb
|
263
264
|
- spec/migrations/1_create_users_on_master.rb
|
264
265
|
- spec/migrations/2_create_users_on_canada.rb
|
265
266
|
- spec/migrations/3_create_users_on_both_shards.rb
|
@@ -324,6 +325,7 @@ test_files:
|
|
324
325
|
- spec/migrations/12_create_users_using_block.rb
|
325
326
|
- spec/migrations/13_create_users_using_block_and_using.rb
|
326
327
|
- spec/migrations/14_create_users_on_shards_of_a_group_with_versions.rb
|
328
|
+
- spec/migrations/15_create_user_on_shards_of_default_group_with_versions.rb
|
327
329
|
- spec/migrations/1_create_users_on_master.rb
|
328
330
|
- spec/migrations/2_create_users_on_canada.rb
|
329
331
|
- spec/migrations/3_create_users_on_both_shards.rb
|