activerecord-shard_for 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +28 -0
  5. data/.travis.yml +4 -0
  6. data/Appraisals +26 -0
  7. data/CODE_OF_CONDUCT.md +49 -0
  8. data/Gemfile +5 -0
  9. data/Guardfile +21 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +296 -0
  12. data/Rakefile +10 -0
  13. data/activerecord-shard_for.gemspec +40 -0
  14. data/bin/console +15 -0
  15. data/bin/setup +8 -0
  16. data/gemfiles/.bundle/config +1 -0
  17. data/gemfiles/ar_4.1.0.gemfile +7 -0
  18. data/gemfiles/ar_4.1.0.gemfile.lock +186 -0
  19. data/gemfiles/ar_4.1.7.gemfile +7 -0
  20. data/gemfiles/ar_4.1.7.gemfile.lock +186 -0
  21. data/gemfiles/ar_4.1.8.gemfile +7 -0
  22. data/gemfiles/ar_4.1.8.gemfile.lock +186 -0
  23. data/gemfiles/ar_4.2.gemfile +7 -0
  24. data/gemfiles/ar_4.2.gemfile.lock +186 -0
  25. data/gemfiles/ar_5.0.gemfile +7 -0
  26. data/gemfiles/ar_5.0.gemfile.lock +182 -0
  27. data/gemfiles/rails_edge.gemfile +8 -0
  28. data/gemfiles/rails_edge.gemfile.lock +193 -0
  29. data/lib/activerecord/shard_for.rb +32 -0
  30. data/lib/activerecord/shard_for/all_shards_in_parallel.rb +43 -0
  31. data/lib/activerecord/shard_for/cluster_config.rb +32 -0
  32. data/lib/activerecord/shard_for/config.rb +45 -0
  33. data/lib/activerecord/shard_for/connection_router.rb +33 -0
  34. data/lib/activerecord/shard_for/database_tasks.rb +185 -0
  35. data/lib/activerecord/shard_for/errors.rb +14 -0
  36. data/lib/activerecord/shard_for/hash_modulo_router.rb +18 -0
  37. data/lib/activerecord/shard_for/model.rb +134 -0
  38. data/lib/activerecord/shard_for/railtie.rb +10 -0
  39. data/lib/activerecord/shard_for/replication_mapping.rb +37 -0
  40. data/lib/activerecord/shard_for/shard_repogitory.rb +69 -0
  41. data/lib/activerecord/shard_for/version.rb +5 -0
  42. data/lib/activerecord/tasks/activerecord_shard_for.rake +42 -0
  43. metadata +323 -0
@@ -0,0 +1,14 @@
1
+ module ActiveRecord
2
+ module ShardFor
3
+ class Error < ::StandardError
4
+ end
5
+
6
+ # Raised when try to put new record without distkey attribute.
7
+ class MissingDistkeyAttribute < Error
8
+ end
9
+
10
+ # Inherit from AR::RecordNotFound to enable to handle as AR's one.
11
+ class RecordNotFound < ActiveRecord::RecordNotFound
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,18 @@
1
+ require 'zlib'
2
+
3
+ module ActiveRecord
4
+ module ShardFor
5
+ class HashModuloRouter < ConnectionRouter
6
+ # @param [String] key sharding key
7
+ def route(key)
8
+ hash(key) % connection_count
9
+ end
10
+
11
+ private
12
+
13
+ def hash(v)
14
+ Zlib.crc32(v.to_s)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,134 @@
1
+ require 'active_support/concern'
2
+
3
+ module ActiveRecord
4
+ module ShardFor
5
+ module Model
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ class_attribute :cluster_router, instance_writer: false
10
+ class_attribute :shard_repository, instance_writer: false
11
+ class_attribute :replication_mapping, instance_writer: false
12
+ class_attribute :distkey, instance_writer: false
13
+ end
14
+
15
+ module ClassMethods
16
+ # The cluster config must be defined before `use_cluster`
17
+ # @param [Symbol] name A cluster name which is set by ActiveRecord::ShardFor.configure
18
+ def use_cluster(name, router_name)
19
+ cluster_config = ActiveRecord::ShardFor.config.fetch_cluster_config(name)
20
+ cluster_router_class = ActiveRecord::ShardFor.config.fetch_cluster_router(router_name)
21
+ self.cluster_router = cluster_router_class.new(cluster_config)
22
+ self.shard_repository = ActiveRecord::ShardFor::ShardRepogitory.new(cluster_config, self)
23
+ self.abstract_class = true
24
+ end
25
+
26
+ # Returns a generated model class of included model class which has proper
27
+ # connection config for the shard for given key.
28
+ # @param [String] key A value of distkey
29
+ # @return [Class] A generated model class for given distkey value
30
+ def shard_for(key)
31
+ connection_name = cluster_router.fetch_connection_name(key)
32
+ shard_repository.fetch(connection_name)
33
+ end
34
+
35
+ # Create new record with given attributes in proper shard for given key.
36
+ # When distkey value is empty, raises ActiveRecord::ShardFor::MissingDistkeyAttribute
37
+ # error.
38
+ # @param [Hash] attributes
39
+ # @return [ActiveRecord::Base] A shard model instance
40
+ # @raise [ActiveRecord::ShardFor::MissingDistkeyAttribute]
41
+ def put!(attributes)
42
+ raise '`distkey` is not defined. Use `def_distkey`.' unless distkey
43
+ key = attributes[distkey]
44
+ raise ActiveRecord::ShardFor::MissingDistkeyAttribute unless key || attributes[distkey.to_s]
45
+
46
+ @before_put_callback.call(attributes) if @before_put_callback
47
+
48
+ shard_for(key).create!(attributes)
49
+ end
50
+
51
+ # Register hook to assign auto-generated distkey or something.
52
+ # Sometimes you want to generates distkey value before validation. Since
53
+ # activerecord-shard_for generates sub class of your models, AR's callback is not
54
+ # useless for this usecase, so activerecord-shard_for offers its own callback method.
55
+ # @example
56
+ # class User
57
+ # include ActiveRecord::ShardFor::Model
58
+ # use_cluster :user
59
+ # def_distkey :name
60
+ # before_put do |attributes|
61
+ # attributes[:name] = generate_name unless attributes[:name]
62
+ # end
63
+ # end
64
+ def before_put(&block)
65
+ @before_put_callback = block
66
+ end
67
+
68
+ # Returns nil when not found. Except that, is same as `.get!`.
69
+ # @param [String] key
70
+ # @return [ActiveRecord::Base, nil] A shard model instance
71
+ def get(key)
72
+ shard_for(key).find_by(distkey => key)
73
+ end
74
+
75
+ # `.get!` raises ActiveRecord::ShardFor::RecordNotFound which is child class of
76
+ # `ActiveRecord::RecordNotFound` so you can rescue that exception as same
77
+ # as AR's RecordNotFound.
78
+ # @param [String] key
79
+ # @return [ActiveRecord::Base] A shard model instance
80
+ # @raise [ActiveRecord::ShardFor::RecordNotFound]
81
+ def get!(key)
82
+ model = get(key)
83
+ return model if model
84
+
85
+ raise ActiveRecord::ShardFor::RecordNotFound
86
+ end
87
+
88
+ # Distkey is a column. activerecord-shard_for gave to cluster_router that value
89
+ # and cluster_router determine which shard to store.
90
+ # @param [Symbol] column
91
+ def def_distkey(column)
92
+ self.distkey = column.to_sym
93
+ end
94
+
95
+ # Returns all generated shard model class. Useful to query to all shards.
96
+ # @return [Array<Class>] An array of shard models
97
+ # @example
98
+ # User.all_shards.flat_map {|m| m.find_by(name: 'alice') }.compact
99
+ def all_shards
100
+ shard_repository.all
101
+ end
102
+
103
+ # @return [ActiveRecord::ShardFor::AllShardsInParallel]
104
+ # @example
105
+ # User.all_shards_in_parallel.map {|m| m.where.find_by(name: 'Alice') }.compact
106
+ def all_shards_in_parallel
107
+ AllShardsInParallel.new(all_shards)
108
+ end
109
+ alias_method :parallel, :all_shards_in_parallel
110
+
111
+ # @param [Hash{Symbol => Symbol}] mapping A pairs of role name and
112
+ # AR model class name.
113
+ def replicates_with(mapping)
114
+ self.replication_mapping = ActiveRecord::ShardFor::ReplicationMapping.new(mapping)
115
+ end
116
+
117
+ # See example definitions in `spec/models.rb`.
118
+ # @param [Symbol] A role name of target cluster.
119
+ # @return [Class, Object] if block given then yielded result else
120
+ # target shard model.
121
+ # @example
122
+ # UserReadonly.all_shards.each do |m|
123
+ # target_ids = m.where(age: 1).pluck(:id)
124
+ # m.switch(:master) do |master|
125
+ # master.where(id: target_ids).delete_all
126
+ # end
127
+ # end
128
+ def switch(role_name, &block)
129
+ replication_mapping.switch(self, role_name, &block)
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,10 @@
1
+ module ActiveRecord
2
+ module ShardFor
3
+ # Railtie of activerecord-shard_for
4
+ class Railtie < ::Rails::Railtie
5
+ rake_tasks do
6
+ load File.expand_path('../../tasks/activerecord_shard_for.rake', __FILE__)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,37 @@
1
+ module ActiveRecord
2
+ module ShardFor
3
+ class ReplicationMapping
4
+ def initialize(mapping)
5
+ @mapping = mapping
6
+ @lock = Mutex.new
7
+ end
8
+
9
+ # @param [Class] A shard model having connection to specific shard
10
+ # @param [Symbol] A role name of target cluster.
11
+ # @return [Class, Object] if block given then yielded result else
12
+ # target shard model.
13
+ def switch(from, role_name)
14
+ @lock.synchronize { constantize! unless constantized? }
15
+
16
+ model = @mapping.fetch(role_name)
17
+ target_shard_model = model.shard_repository.fetch_by_key(from.assigned_key)
18
+
19
+ if block_given?
20
+ target_shard_model.connection_pool.with_connection { yield target_shard_model }
21
+ else
22
+ target_shard_model
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def constantize!
29
+ @mapping = Hash[@mapping.map { |k, name| [k, name.to_s.constantize] }]
30
+ end
31
+
32
+ def constantized?
33
+ @mapping.values.first.is_a? Class
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,69 @@
1
+ module ActiveRecord
2
+ module ShardFor
3
+ class ShardRepogitory
4
+ attr_reader :base_class
5
+
6
+ # @param [ClusterConfig] cluster_config
7
+ # @param [Class] base_class A AR Model
8
+ def initialize(cluster_config, base_class)
9
+ @base_class = base_class
10
+
11
+ shards = cluster_config.connection_registry.map do |key, connection_name|
12
+ [connection_name, generate_model_for_shard(connection_name, key)]
13
+ end
14
+
15
+ @shards = Hash[shards]
16
+ end
17
+
18
+ # @param [Symbol] connection_name
19
+ # @return [Class] A model class for this shard
20
+ def fetch(connection_name)
21
+ @shards.fetch(connection_name)
22
+ end
23
+
24
+ # @param [Object] key sharding key object for connection
25
+ # @return [Class, nil] A AR model class.
26
+ def fetch_by_key(key)
27
+ @shards.find { |_, model| model.assigned_key == key }[1]
28
+ end
29
+
30
+ # @return [Array<Class>]
31
+ def all
32
+ @shards.values
33
+ end
34
+
35
+ private
36
+
37
+ # @param [Symbol] connection_name
38
+ # @param [Range] slot_range
39
+ # @return [Class] A sub class of given AR model.
40
+ # A sub class has connection setting for specific shard.
41
+ def generate_model_for_shard(connection_name, key)
42
+ class_name = generate_class_name(connection_name)
43
+
44
+ model = Class.new(base_class) do
45
+ self.table_name = base_class.table_name
46
+ class << self
47
+ attr_reader :assigned_key
48
+ end
49
+ @assigned_key = key
50
+
51
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
52
+ def self.name
53
+ "#{base_class.name}::#{class_name}"
54
+ end
55
+ RUBY
56
+ end
57
+
58
+ model.class_eval { establish_connection(connection_name) }
59
+ model
60
+ end
61
+
62
+ # @param [Symbol] connection_name
63
+ # @return [String]
64
+ def generate_class_name(connection_name)
65
+ "ShardFor#{connection_name.to_s.tr('-', '_').classify}"
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,5 @@
1
+ module ActiveRecord
2
+ module ShardFor
3
+ VERSION = '0.1.0'.freeze
4
+ end
5
+ end
@@ -0,0 +1,42 @@
1
+ namespace :activerecord do
2
+ namespace :shard_for do
3
+ desc 'Show all defined clusters and their detail'
4
+ task info: %i(environment) do
5
+ ActiveRecord::ShardFor::DatabaseTasks.info
6
+ end
7
+
8
+ desc 'Setup all databases in all clusters'
9
+ task setup: %i(create_all load_schema_all) do
10
+ end
11
+
12
+ desc 'Create all databases in all clusters'
13
+ task :create_all => :environment do
14
+ ActiveRecord::ShardFor::DatabaseTasks.invoke_task_for_all_clusters('create')
15
+ end
16
+
17
+ desc 'Drop all databases in all clusters'
18
+ task :drop_all => :environment do
19
+ ActiveRecord::ShardFor::DatabaseTasks.invoke_task_for_all_clusters('drop')
20
+ end
21
+
22
+ desc 'Load schema to all databases in all clusters'
23
+ task :load_schema_all => :environment do
24
+ ActiveRecord::ShardFor::DatabaseTasks.invoke_task_for_all_clusters('load_schema')
25
+ end
26
+
27
+ desc 'Create all databases in specific cluster'
28
+ task :create, %i(cluster_name) => %i(environment) do |_, args|
29
+ ActiveRecord::ShardFor::DatabaseTasks.create_all_databases(args)
30
+ end
31
+
32
+ desc 'Drop all databases in specific cluster'
33
+ task :drop, %i(cluster_name) => %i(environment) do |_, args|
34
+ ActiveRecord::ShardFor::DatabaseTasks.drop_all_databases(args)
35
+ end
36
+
37
+ desc 'Load schema to all databases in specific cluster'
38
+ task :load_schema, %i(cluster_name) => %i(environment) do |_, args|
39
+ ActiveRecord::ShardFor::DatabaseTasks.load_schema_all_databases(args)
40
+ end
41
+ end
42
+ end
metadata ADDED
@@ -0,0 +1,323 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: activerecord-shard_for
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - yuemori
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-07-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
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: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 4.1.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 4.1.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: expeditor
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 0.1.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 0.1.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.11'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.11'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: pry-doc
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: pry-stack_explorer
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: pry-inline
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: pry-rescue
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: rubocop
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: guard-rubocop
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: guard-rspec
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
209
+ - !ruby/object:Gem::Dependency
210
+ name: appraisal
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - ">="
214
+ - !ruby/object:Gem::Version
215
+ version: '0'
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
223
+ - !ruby/object:Gem::Dependency
224
+ name: sqlite3
225
+ requirement: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - ">="
228
+ - !ruby/object:Gem::Version
229
+ version: '0'
230
+ type: :development
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - ">="
235
+ - !ruby/object:Gem::Version
236
+ version: '0'
237
+ - !ruby/object:Gem::Dependency
238
+ name: rspec-parameterized
239
+ requirement: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - ">="
242
+ - !ruby/object:Gem::Version
243
+ version: '0'
244
+ type: :development
245
+ prerelease: false
246
+ version_requirements: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - ">="
249
+ - !ruby/object:Gem::Version
250
+ version: '0'
251
+ description: Database sharding library for ActiveRecord
252
+ email:
253
+ - yuemori@aiming-inc.com
254
+ executables: []
255
+ extensions: []
256
+ extra_rdoc_files: []
257
+ files:
258
+ - ".gitignore"
259
+ - ".rspec"
260
+ - ".rubocop.yml"
261
+ - ".travis.yml"
262
+ - Appraisals
263
+ - CODE_OF_CONDUCT.md
264
+ - Gemfile
265
+ - Guardfile
266
+ - LICENSE.txt
267
+ - README.md
268
+ - Rakefile
269
+ - activerecord-shard_for.gemspec
270
+ - bin/console
271
+ - bin/setup
272
+ - gemfiles/.bundle/config
273
+ - gemfiles/ar_4.1.0.gemfile
274
+ - gemfiles/ar_4.1.0.gemfile.lock
275
+ - gemfiles/ar_4.1.7.gemfile
276
+ - gemfiles/ar_4.1.7.gemfile.lock
277
+ - gemfiles/ar_4.1.8.gemfile
278
+ - gemfiles/ar_4.1.8.gemfile.lock
279
+ - gemfiles/ar_4.2.gemfile
280
+ - gemfiles/ar_4.2.gemfile.lock
281
+ - gemfiles/ar_5.0.gemfile
282
+ - gemfiles/ar_5.0.gemfile.lock
283
+ - gemfiles/rails_edge.gemfile
284
+ - gemfiles/rails_edge.gemfile.lock
285
+ - lib/activerecord/shard_for.rb
286
+ - lib/activerecord/shard_for/all_shards_in_parallel.rb
287
+ - lib/activerecord/shard_for/cluster_config.rb
288
+ - lib/activerecord/shard_for/config.rb
289
+ - lib/activerecord/shard_for/connection_router.rb
290
+ - lib/activerecord/shard_for/database_tasks.rb
291
+ - lib/activerecord/shard_for/errors.rb
292
+ - lib/activerecord/shard_for/hash_modulo_router.rb
293
+ - lib/activerecord/shard_for/model.rb
294
+ - lib/activerecord/shard_for/railtie.rb
295
+ - lib/activerecord/shard_for/replication_mapping.rb
296
+ - lib/activerecord/shard_for/shard_repogitory.rb
297
+ - lib/activerecord/shard_for/version.rb
298
+ - lib/activerecord/tasks/activerecord_shard_for.rake
299
+ homepage: https://github.com/yuemori/activerecord-shard_for
300
+ licenses:
301
+ - MIT
302
+ metadata: {}
303
+ post_install_message:
304
+ rdoc_options: []
305
+ require_paths:
306
+ - lib
307
+ required_ruby_version: !ruby/object:Gem::Requirement
308
+ requirements:
309
+ - - ">="
310
+ - !ruby/object:Gem::Version
311
+ version: '0'
312
+ required_rubygems_version: !ruby/object:Gem::Requirement
313
+ requirements:
314
+ - - ">="
315
+ - !ruby/object:Gem::Version
316
+ version: '0'
317
+ requirements: []
318
+ rubyforge_project:
319
+ rubygems_version: 2.5.1
320
+ signing_key:
321
+ specification_version: 4
322
+ summary: Database sharding library for ActiveRecord
323
+ test_files: []