activerecord-shard_for 0.1.0

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.
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: []