# Path: boardinghouse/signals.py

# 
# Path: boardinghouse/exceptions.py
# class TemplateSchemaActivation(Forbidden):
#     """
#     An exception that will be raised when a user attempts to activate
#     the settings.TEMPLATE_SCHEMA schema.
#     """
#     def __init__(self, *args, **kwargs):
#         super(TemplateSchemaActivation, self).__init__(
#             'Activating template schema forbidden.', *args, **kwargs
#         )
# 
# class Forbidden(Exception):
#     """
#     An exception that will be raised when an attempt to activate a non-valid
#     schema is made.
#     """
# 
# Path: boardinghouse/schema.py
# def _schema_exists(schema_name, cursor=None):
#     if cursor:
#         cursor.execute('''SELECT schema_name
#                             FROM information_schema.schemata
#                            WHERE schema_name = %s''',
#                        [schema_name])
#         return bool(cursor.fetchone())
# 
#     cursor = connection.cursor()
#     try:
#         return _schema_exists(schema_name, cursor)
#     finally:
#         cursor.close()
# 
# def _schema_table_exists():
#     return _table_exists(get_schema_model()._meta.db_table)
# 
# def activate_template_schema():
#     """
#     Activate the template schema.
# 
#     You probably don't want to do this. Sometimes you do (like for instance
#     to apply migrations).
#     """
#     from .signals import schema_pre_activate, schema_post_activate
# 
#     _thread_locals.schema = None
#     schema_name = settings.TEMPLATE_SCHEMA
#     schema_pre_activate.send(sender=None, schema_name=schema_name)
#     _set_search_path(schema_name)
#     if _get_search_path() != schema_name:
#         raise SchemaNotFound('Template schema was not activated. It seems "{0}" is active.'.format(_get_search_path()))
#     schema_post_activate.send(sender=None, schema_name=schema_name)
# 
# def get_active_schema_name():
#     """
#     Get the currently active schema.
# 
#     This requires a database query to ask it what the current `search_path` is.
#     """
#     active_schema = getattr(_thread_locals, 'schema', None)
# 
#     if not active_schema:
#         reported_schema = _get_search_path()[0]
# 
#         if _get_schema(reported_schema):
#             active_schema = reported_schema
#         else:
#             active_schema = None
# 
#         _thread_locals.schema = active_schema
# 
#     return active_schema
# 
# def get_schema_model():
#     """
#     Return the class that is currently set as the schema model.
#     """
#     try:
#         return apps.get_model(settings.BOARDINGHOUSE_SCHEMA_MODEL)
#     except AttributeError:
#         raise ImproperlyConfigured("BOARDINGHOUSE_SCHEMA_MODEL is not set: is 'boardinghouse' in your INSTALLED_APPS?")
#     except ValueError:
#         raise ImproperlyConfigured("BOARDINGHOUSE_SCHEMA_MODEL must be of the form 'app_label.model_name'")
#     except LookupError:
#         raise ImproperlyConfigured(
#             "BOARDINGHOUSE_SCHEMA_MODEL refers to model '{0!s}' that has not been installed".format(
#                 settings.BOARDINGHOUSE_SCHEMA_MODEL))
# 
# def is_shared_model(model):
#     """
#     Is the model (or instance of a model) one that should be in the
#     public/shared schema?
#     """
#     if model._is_shared_model:
#         return True
# 
#     app_model = '{m.app_label}.{m.model_name}'.format(m=model._meta).lower()
# 
#     # These should be case insensitive!
#     if app_model in REQUIRED_SHARED_MODELS:
#         return True
# 
#     if app_model in [x.lower() for x in settings.SHARED_MODELS]:
#         return True
# 
#     # Sometimes, we want a join table to be private.
#     if app_model in [x.lower() for x in settings.PRIVATE_MODELS]:
#         return False
# 
#     # if all fields are auto or fk, then we are a join model,
#     # and if all related objects are shared, then we must
#     # also be shared, unless we were explicitly marked as private
#     # above.
#     if _is_join_model(model):
#         return all(
#             is_shared_model(field.remote_field.model)
#             for field in model._meta.fields
#             if field.remote_field
#         )
# 
#     return False


import logging
from django.conf import settings
from django.core.cache import cache
from django.db import connection, models
from django.dispatch import receiver
from boardinghouse import signals
from boardinghouse.exceptions import TemplateSchemaActivation, Forbidden
from boardinghouse.schema import (
    _schema_exists, _schema_table_exists, activate_template_schema,
    get_active_schema_name, get_schema_model, is_shared_model,
)
    from django import db
@receiver(signals.schemata_deleted, weak=False)
def drop_schemata(sender, schemata, connection=None, **kwargs):
    cursor = (connection or db.connection).cursor()
    # Is there a way to do this without opening up an SQL injection hole?
    # I guess we have to rely on the fact that schema.schema is always a valid name...?
    sql = ';'.join(['DROP SCHEMA IF EXISTS {0} CASCADE'.format(schema) for schema in schemata])
    if sql:
        cursor.execute(sql)
        for schema in schemata:
            LOGGER.info('Schema dropped: %s', schema)


@receiver(models.signals.post_init, sender=None)
def inject_schema_attribute(sender, instance, **kwargs):
    """
    A signal listener that injects the current schema on the object
    just after it is instantiated.

    You may use this in conjunction with :class:`MultiSchemaMixin`, it will
    respect any value that has already been set on the instance.
    """
    if is_shared_model(sender):
        return
    if not getattr(instance, '_schema', None):
        instance._schema = get_active_schema_name()


@receiver(signals.schema_aware_operation)
def execute_on_all_schemata(sender, db_table, function, **kwargs):
    if _schema_table_exists():

# Path: boardinghouse/signals.py

# 
# Path: boardinghouse/exceptions.py
# class TemplateSchemaActivation(Forbidden):
#     """
#     An exception that will be raised when a user attempts to activate
#     the settings.TEMPLATE_SCHEMA schema.
#     """
#     def __init__(self, *args, **kwargs):
#         super(TemplateSchemaActivation, self).__init__(
#             'Activating template schema forbidden.', *args, **kwargs
#         )
# 
# class Forbidden(Exception):
#     """
#     An exception that will be raised when an attempt to activate a non-valid
#     schema is made.
#     """
# 
# Path: boardinghouse/schema.py
# def _schema_exists(schema_name, cursor=None):
#     if cursor:
#         cursor.execute('''SELECT schema_name
#                             FROM information_schema.schemata
#                            WHERE schema_name = %s''',
#                        [schema_name])
#         return bool(cursor.fetchone())
# 
#     cursor = connection.cursor()
#     try:
#         return _schema_exists(schema_name, cursor)
#     finally:
#         cursor.close()
# 
# def _schema_table_exists():
#     return _table_exists(get_schema_model()._meta.db_table)
# 
# def activate_template_schema():
#     """
#     Activate the template schema.
# 
#     You probably don't want to do this. Sometimes you do (like for instance
#     to apply migrations).
#     """
#     from .signals import schema_pre_activate, schema_post_activate
# 
#     _thread_locals.schema = None
#     schema_name = settings.TEMPLATE_SCHEMA
#     schema_pre_activate.send(sender=None, schema_name=schema_name)
#     _set_search_path(schema_name)
#     if _get_search_path() != schema_name:
#         raise SchemaNotFound('Template schema was not activated. It seems "{0}" is active.'.format(_get_search_path()))
#     schema_post_activate.send(sender=None, schema_name=schema_name)
# 
# def get_active_schema_name():
#     """
#     Get the currently active schema.
# 
#     This requires a database query to ask it what the current `search_path` is.
#     """
#     active_schema = getattr(_thread_locals, 'schema', None)
# 
#     if not active_schema:
#         reported_schema = _get_search_path()[0]
# 
#         if _get_schema(reported_schema):
#             active_schema = reported_schema
#         else:
#             active_schema = None
# 
#         _thread_locals.schema = active_schema
# 
#     return active_schema
# 
# def get_schema_model():
#     """
#     Return the class that is currently set as the schema model.
#     """
#     try:
#         return apps.get_model(settings.BOARDINGHOUSE_SCHEMA_MODEL)
#     except AttributeError:
#         raise ImproperlyConfigured("BOARDINGHOUSE_SCHEMA_MODEL is not set: is 'boardinghouse' in your INSTALLED_APPS?")
#     except ValueError:
#         raise ImproperlyConfigured("BOARDINGHOUSE_SCHEMA_MODEL must be of the form 'app_label.model_name'")
#     except LookupError:
#         raise ImproperlyConfigured(
#             "BOARDINGHOUSE_SCHEMA_MODEL refers to model '{0!s}' that has not been installed".format(
#                 settings.BOARDINGHOUSE_SCHEMA_MODEL))
# 
# def is_shared_model(model):
#     """
#     Is the model (or instance of a model) one that should be in the
#     public/shared schema?
#     """
#     if model._is_shared_model:
#         return True
# 
#     app_model = '{m.app_label}.{m.model_name}'.format(m=model._meta).lower()
# 
#     # These should be case insensitive!
#     if app_model in REQUIRED_SHARED_MODELS:
#         return True
# 
#     if app_model in [x.lower() for x in settings.SHARED_MODELS]:
#         return True
# 
#     # Sometimes, we want a join table to be private.
#     if app_model in [x.lower() for x in settings.PRIVATE_MODELS]:
#         return False
# 
#     # if all fields are auto or fk, then we are a join model,
#     # and if all related objects are shared, then we must
#     # also be shared, unless we were explicitly marked as private
#     # above.
#     if _is_join_model(model):
#         return all(
#             is_shared_model(field.remote_field.model)
#             for field in model._meta.fields
#             if field.remote_field
#         )
# 
#     return False


# Path: boardinghouse/receivers.py
import logging
from django.conf import settings
from django.core.cache import cache
from django.db import connection, models
from django.dispatch import receiver
from boardinghouse import signals
from boardinghouse.exceptions import TemplateSchemaActivation, Forbidden
from boardinghouse.schema import (
    _schema_exists, _schema_table_exists, activate_template_schema,
    get_active_schema_name, get_schema_model, is_shared_model,
)
    from django import db

@receiver(signals.schemata_deleted, weak=False)
def drop_schemata(sender, schemata, connection=None, **kwargs):
    cursor = (connection or db.connection).cursor()
    # Is there a way to do this without opening up an SQL injection hole?
    # I guess we have to rely on the fact that schema.schema is always a valid name...?
    sql = ';'.join(['DROP SCHEMA IF EXISTS {0} CASCADE'.format(schema) for schema in schemata])
    if sql:
        cursor.execute(sql)
        for schema in schemata:
            LOGGER.info('Schema dropped: %s', schema)


@receiver(models.signals.post_init, sender=None)
def inject_schema_attribute(sender, instance, **kwargs):
    """
    A signal listener that injects the current schema on the object
    just after it is instantiated.

    You may use this in conjunction with :class:`MultiSchemaMixin`, it will
    respect any value that has already been set on the instance.
    """
    if is_shared_model(sender):
        return
    if not getattr(instance, '_schema', None):
        instance._schema = get_active_schema_name()


@receiver(signals.schema_aware_operation)
def execute_on_all_schemata(sender, db_table, function, **kwargs):
    if _schema_table_exists():

        for each in get_schema_model().objects.all():