# Path: django_sharding_library/routing_read_strategies.py
# class PrimaryOnlyRoutingStrategy(BaseRoutingStrategy):
#     """
#     A strategy which will always read from the primary, unless overridden,
#     regardless of replicas defined.
#     """
#     def pick_read_db(self, primary_db_name):
#         return primary_db_name
# 
# Path: django_sharding_library/sharding_functions.py
# class RoundRobinBucketingStrategy(BaseShardedModelBucketingStrategy):
#     """
#     A shard selection strategy that assigns shards in a round-robin way.
#     This is non-deterministic and this strategy assumes the shard is saved to
#     the model.
#     """
#     def __init__(self, shard_group, databases):
#         super(RoundRobinBucketingStrategy, self).__init__(shard_group)
#         shards = self.get_shards(databases)
#         # To help balance out the fact that this would start the round-robin
#         # bucketing at initialization time, we start at a random index.
#         max_index = max(0, len(shards) - 1)
#         starting_index = randint(0, max_index)
#         shards = shards[starting_index:] + shards[:starting_index]
#         self._shards_cycle = cycle(shards)
# 
#     def pick_shard(self, model_sharded_by):
#         return next(self._shards_cycle)
# 
# Path: django_sharding_library/signals.py
# def save_shard_handler(sender, instance, **kwargs):
#     """
#     Saves the shard to the model in the field `shard`.
#     e.g. usage:
#     @receiver(models.signals.pre_save, sender=User)
#     def shard_handler(sender, instance, **kwargs):
#         save_shard_handler(sender, instance, **kwargs)
#     """
#     app_config_app_label = getattr(settings, 'DJANGO_SHARDING_SETTINGS', {}).get('APP_CONFIG_APP', 'django_sharding')
#     bucketer = apps.get_app_config(app_config_app_label).get_bucketer(sender.django_sharding__shard_group)
#     shard_fields = list(filter(lambda field: getattr(field, 'django_sharding__stores_shard', False), sender._meta.fields))
# 
#     if not any(shard_fields):
#         shard_field_name = getattr(sender, 'django_sharding__shard_field', None)
#         shard_fields = list(filter(lambda field: field.name == shard_field_name, sender._meta.fields))
# 
#     if not any(shard_fields):
#         return
# 
#     if len(shard_fields) > 1:
#         raise Exception('The model {} has multuple fields for shard storage: {}'.format(sender, shard_fields))
#     shard_field = shard_fields[0]
# 
#     if not getattr(instance, shard_field.name, None):
#         setattr(instance, shard_field.name, bucketer.pick_shard(instance))


from django.apps import AppConfig, apps
from django.conf import settings
from django.db import models
from django.dispatch import receiver
from django_sharding_library.routing_read_strategies import PrimaryOnlyRoutingStrategy
from django_sharding_library.sharding_functions import RoundRobinBucketingStrategy
from django_sharding_library.signals import save_shard_handler



class ShardingConfig(AppConfig):
    name = 'django_sharding'

    def ready(self):
        shard_settings = getattr(settings, 'DJANGO_SHARDING_SETTINGS', {})
        shard_groups = [settings.DATABASES[db_settings]['SHARD_GROUP'] for db_settings in settings.DATABASES]
        shard_groups = set(filter(lambda group: group is not None, shard_groups))
        self.bucketers = {}
        self.routing_strategies = {}
        for shard_group in shard_groups:
            group_settings = shard_settings.get(shard_group, {})
            self.bucketers[shard_group] = group_settings.get(
                'BUCKETING_STRATEGY',

# Path: django_sharding_library/routing_read_strategies.py
# class PrimaryOnlyRoutingStrategy(BaseRoutingStrategy):
#     """
#     A strategy which will always read from the primary, unless overridden,
#     regardless of replicas defined.
#     """
#     def pick_read_db(self, primary_db_name):
#         return primary_db_name
# 
# Path: django_sharding_library/sharding_functions.py
# class RoundRobinBucketingStrategy(BaseShardedModelBucketingStrategy):
#     """
#     A shard selection strategy that assigns shards in a round-robin way.
#     This is non-deterministic and this strategy assumes the shard is saved to
#     the model.
#     """
#     def __init__(self, shard_group, databases):
#         super(RoundRobinBucketingStrategy, self).__init__(shard_group)
#         shards = self.get_shards(databases)
#         # To help balance out the fact that this would start the round-robin
#         # bucketing at initialization time, we start at a random index.
#         max_index = max(0, len(shards) - 1)
#         starting_index = randint(0, max_index)
#         shards = shards[starting_index:] + shards[:starting_index]
#         self._shards_cycle = cycle(shards)
# 
#     def pick_shard(self, model_sharded_by):
#         return next(self._shards_cycle)
# 
# Path: django_sharding_library/signals.py
# def save_shard_handler(sender, instance, **kwargs):
#     """
#     Saves the shard to the model in the field `shard`.
#     e.g. usage:
#     @receiver(models.signals.pre_save, sender=User)
#     def shard_handler(sender, instance, **kwargs):
#         save_shard_handler(sender, instance, **kwargs)
#     """
#     app_config_app_label = getattr(settings, 'DJANGO_SHARDING_SETTINGS', {}).get('APP_CONFIG_APP', 'django_sharding')
#     bucketer = apps.get_app_config(app_config_app_label).get_bucketer(sender.django_sharding__shard_group)
#     shard_fields = list(filter(lambda field: getattr(field, 'django_sharding__stores_shard', False), sender._meta.fields))
# 
#     if not any(shard_fields):
#         shard_field_name = getattr(sender, 'django_sharding__shard_field', None)
#         shard_fields = list(filter(lambda field: field.name == shard_field_name, sender._meta.fields))
# 
#     if not any(shard_fields):
#         return
# 
#     if len(shard_fields) > 1:
#         raise Exception('The model {} has multuple fields for shard storage: {}'.format(sender, shard_fields))
#     shard_field = shard_fields[0]
# 
#     if not getattr(instance, shard_field.name, None):
#         setattr(instance, shard_field.name, bucketer.pick_shard(instance))


# Path: django_sharding/apps.py
from django.apps import AppConfig, apps
from django.conf import settings
from django.db import models
from django.dispatch import receiver
from django_sharding_library.routing_read_strategies import PrimaryOnlyRoutingStrategy
from django_sharding_library.sharding_functions import RoundRobinBucketingStrategy
from django_sharding_library.signals import save_shard_handler




class ShardingConfig(AppConfig):
    name = 'django_sharding'

    def ready(self):
        shard_settings = getattr(settings, 'DJANGO_SHARDING_SETTINGS', {})
        shard_groups = [settings.DATABASES[db_settings]['SHARD_GROUP'] for db_settings in settings.DATABASES]
        shard_groups = set(filter(lambda group: group is not None, shard_groups))
        self.bucketers = {}
        self.routing_strategies = {}
        for shard_group in shard_groups:
            group_settings = shard_settings.get(shard_group, {})
            self.bucketers[shard_group] = group_settings.get(
                'BUCKETING_STRATEGY',

                RoundRobinBucketingStrategy(shard_group=shard_group, databases=settings.DATABASES)