-
Nony Dutton authored
Currently, there is no (simple) way to ask a model if it connects to a single database or to multiple shards. Furthermore, without looping through a model's connections, I don't believe there's an easy way to return a list of shards a model can connect to. This commit adds a `@shard_keys` ivar that's set whenever `.connects_to` is called. It sets the ivar to the result of `shards.keys`. `shards` in `.connects_to` defaults to an empty hash and therefore when calling `connects_to database: {...}` `@shard_keys` will be set to an empty array. `@shard_keys` is set _before_ the following lines: ``` if shards.empty? shards[:default] = database end ``` This conditional sets the one and only shard (`:default`) to the value of `database` that we pass to `.connects_to`. This allows for calling `connected_to(shard: :default)` on models configured to only connect to a database e.g.: ```ruby class UnshardedBase < ActiveRecord::Base self.abstract_class = true connects_to database: { writing: :primary } end class UnshardedModel < UnshardedBase end UnshardedBase.connected_to(shard: :default) { UnshardedBase.connection_pool.db_config.name } => primary ``` This is ultimately still an _unsharded_ model which is why `@shard_keys` gets set before the conditional. With the new `@shard_keys` ivar we need a way for descendants of the abstract AR model to return that same value. For that we leverage the existing `.connection_class_for_self` method. That method returns the ancestor of the model where `.connects_to` was called, or returns self if it's the connection class: ```ruby class UnshardedBase < ActiveRecord::Base self.abstract_class = true connects_to database: { writing: :primary } end class UnshardedModel < UnshardedBase end ActiveRecord::Base.connection_class_for_self => ActiveRecord::Base UnshardedBase.connection_class_for_self => UnshardedBase(abstract) UnshardedModel.connection_class_for_self => UnshardedBase(abstract) ``` The new `.shard_keys` method is a getter which returns the value of `@shard_keys` from the connection class or it returns an empty array. The empty array is necessary in cases where `connects_to` was never called. Finally, I've added an `.connected_to_all_shards` method which takes all of the arguments for `.connected_to` except for `shard`. Instead, it loops through every shard key and then delegates everything else to `.connected_to`. I've used `.map` instead of `.each` so that we can collect the results of each block.
Nony Dutton authoredCurrently, there is no (simple) way to ask a model if it connects to a single database or to multiple shards. Furthermore, without looping through a model's connections, I don't believe there's an easy way to return a list of shards a model can connect to. This commit adds a `@shard_keys` ivar that's set whenever `.connects_to` is called. It sets the ivar to the result of `shards.keys`. `shards` in `.connects_to` defaults to an empty hash and therefore when calling `connects_to database: {...}` `@shard_keys` will be set to an empty array. `@shard_keys` is set _before_ the following lines: ``` if shards.empty? shards[:default] = database end ``` This conditional sets the one and only shard (`:default`) to the value of `database` that we pass to `.connects_to`. This allows for calling `connected_to(shard: :default)` on models configured to only connect to a database e.g.: ```ruby class UnshardedBase < ActiveRecord::Base self.abstract_class = true connects_to database: { writing: :primary } end class UnshardedModel < UnshardedBase end UnshardedBase.connected_to(shard: :default) { UnshardedBase.connection_pool.db_config.name } => primary ``` This is ultimately still an _unsharded_ model which is why `@shard_keys` gets set before the conditional. With the new `@shard_keys` ivar we need a way for descendants of the abstract AR model to return that same value. For that we leverage the existing `.connection_class_for_self` method. That method returns the ancestor of the model where `.connects_to` was called, or returns self if it's the connection class: ```ruby class UnshardedBase < ActiveRecord::Base self.abstract_class = true connects_to database: { writing: :primary } end class UnshardedModel < UnshardedBase end ActiveRecord::Base.connection_class_for_self => ActiveRecord::Base UnshardedBase.connection_class_for_self => UnshardedBase(abstract) UnshardedModel.connection_class_for_self => UnshardedBase(abstract) ``` The new `.shard_keys` method is a getter which returns the value of `@shard_keys` from the connection class or it returns an empty array. The empty array is necessary in cases where `connects_to` was never called. Finally, I've added an `.connected_to_all_shards` method which takes all of the arguments for `.connected_to` except for `shard`. Instead, it loops through every shard key and then delegates everything else to `.connected_to`. I've used `.map` instead of `.each` so that we can collect the results of each block.
Loading