# Path: psqlextra/models/partitioned.py
# class PostgresPartitionedModel(
#     PostgresModel, metaclass=PostgresPartitionedModelMeta
# ):
#     """Base class for taking advantage of PostgreSQL's 11.x native support for
#     table partitioning."""
# 
#     class Meta:
#         abstract = True
#         base_manager_name = "objects"
# 
# Path: psqlextra/partitioning/config.py
# class PostgresPartitioningConfig:
#     """Configuration for partitioning a specific model according to the
#     specified strategy."""
# 
#     def __init__(
#         self,
#         model: PostgresPartitionedModel,
#         strategy: PostgresPartitioningStrategy,
#     ) -> None:
#         self.model = model
#         self.strategy = strategy
# 
# Path: psqlextra/partitioning/constants.py
# AUTO_PARTITIONED_COMMENT = "psqlextra_auto_partitioned"
# 
# Path: psqlextra/partitioning/error.py
# class PostgresPartitioningError(RuntimeError):
#     """Raised when the partitioning configuration is broken or automatically
#     creating/deleting partitions fails."""
# 
# Path: psqlextra/partitioning/partition.py
# class PostgresPartition:
#     """Base class for a PostgreSQL table partition."""
# 
#     @abstractmethod
#     def name(self) -> str:
#         """Generates/computes the name for this partition."""
# 
#     @abstractmethod
#     def create(
#         self,
#         model: PostgresPartitionedModel,
#         schema_editor: PostgresSchemaEditor,
#         comment: Optional[str] = None,
#     ) -> None:
#         """Creates this partition in the database."""
# 
#     @abstractmethod
#     def delete(
#         self,
#         model: PostgresPartitionedModel,
#         schema_editor: PostgresSchemaEditor,
#     ) -> None:
#         """Deletes this partition from the database."""
# 
#     def deconstruct(self) -> dict:
#         """Deconstructs this partition into a dict of attributes/fields."""
# 
#         return {"name": self.name()}
# 
# Path: psqlextra/partitioning/plan.py
# class PostgresModelPartitioningPlan:
#     """Describes the partitions that are going to be created/deleted for a
#     particular partitioning config.
# 
#     A "partitioning config" applies to one model.
#     """
# 
#     config: PostgresPartitioningConfig
#     creations: List[PostgresPartition] = field(default_factory=list)
#     deletions: List[PostgresPartition] = field(default_factory=list)
# 
#     def apply(self, using: Optional[str]) -> None:
#         """Applies this partitioning plan by creating and deleting the planned
#         partitions.
# 
#         Applying the plan runs in a transaction.
# 
#         Arguments:
#             using:
#                 Name of the database connection to use.
#         """
# 
#         connection = connections[using or "default"]
# 
#         with transaction.atomic():
#             with connection.schema_editor() as schema_editor:
#                 for partition in self.creations:
#                     partition.create(
#                         self.config.model,
#                         schema_editor,
#                         comment=AUTO_PARTITIONED_COMMENT,
#                     )
# 
#                 for partition in self.deletions:
#                     partition.delete(self.config.model, schema_editor)
# 
#     def print(self) -> None:
#         """Prints this model plan to the terminal in a readable format."""
# 
#         print(f"{self.config.model.__name__}:")
# 
#         for partition in self.deletions:
#             print("  - %s" % partition.name())
#             for key, value in partition.deconstruct().items():
#                 print(f"     {key}: {value}")
# 
#         for partition in self.creations:
#             print("  + %s" % partition.name())
#             for key, value in partition.deconstruct().items():
#                 print(f"     {key}: {value}")
# 
# class PostgresPartitioningPlan:
#     """Describes the partitions that are going to be created/deleted."""
# 
#     model_plans: List[PostgresModelPartitioningPlan]
# 
#     @property
#     def creations(self) -> List[PostgresPartition]:
#         """Gets a complete flat list of the partitions that are going to be
#         created."""
# 
#         creations = []
#         for model_plan in self.model_plans:
#             creations.extend(model_plan.creations)
#         return creations
# 
#     @property
#     def deletions(self) -> List[PostgresPartition]:
#         """Gets a complete flat list of the partitions that are going to be
#         deleted."""
# 
#         deletions = []
#         for model_plan in self.model_plans:
#             deletions.extend(model_plan.deletions)
#         return deletions
# 
#     def apply(self, using: Optional[str] = None) -> None:
#         """Applies this plan by creating/deleting all planned partitions."""
# 
#         for model_plan in self.model_plans:
#             model_plan.apply(using=using)
# 
#     def print(self) -> None:
#         """Prints this plan to the terminal in a readable format."""
# 
#         for model_plan in self.model_plans:
#             model_plan.print()
#             print("")
# 
#         create_count = len(self.creations)
#         delete_count = len(self.deletions)
# 
#         print(f"{delete_count} partitions will be deleted")
#         print(f"{create_count} partitions will be created")


from typing import List, Optional, Tuple
from django.db import connections
from psqlextra.models import PostgresPartitionedModel
from .config import PostgresPartitioningConfig
from .constants import AUTO_PARTITIONED_COMMENT
from .error import PostgresPartitioningError
from .partition import PostgresPartition
from .plan import PostgresModelPartitioningPlan, PostgresPartitioningPlan
            skip_create:
                If set to True, no partitions will be marked
                for creation, regardless of the configuration.

            skip_delete:
                If set to True, no partitions will be marked
                for deletion, regardless of the configuration.

            using:
                Name of the database connection to use.

        Returns:
            A plan describing what partitions would be created
            and deleted if the plan is applied.
        """

        model_plans = []

        for config in self.configs:
            model_plan = self._plan_for_config(
                config,
                skip_create=skip_create,
                skip_delete=skip_delete,
                using=using,
            )
            if not model_plan:
                continue

            model_plans.append(model_plan)


# Path: psqlextra/models/partitioned.py
# class PostgresPartitionedModel(
#     PostgresModel, metaclass=PostgresPartitionedModelMeta
# ):
#     """Base class for taking advantage of PostgreSQL's 11.x native support for
#     table partitioning."""
# 
#     class Meta:
#         abstract = True
#         base_manager_name = "objects"
# 
# Path: psqlextra/partitioning/config.py
# class PostgresPartitioningConfig:
#     """Configuration for partitioning a specific model according to the
#     specified strategy."""
# 
#     def __init__(
#         self,
#         model: PostgresPartitionedModel,
#         strategy: PostgresPartitioningStrategy,
#     ) -> None:
#         self.model = model
#         self.strategy = strategy
# 
# Path: psqlextra/partitioning/constants.py
# AUTO_PARTITIONED_COMMENT = "psqlextra_auto_partitioned"
# 
# Path: psqlextra/partitioning/error.py
# class PostgresPartitioningError(RuntimeError):
#     """Raised when the partitioning configuration is broken or automatically
#     creating/deleting partitions fails."""
# 
# Path: psqlextra/partitioning/partition.py
# class PostgresPartition:
#     """Base class for a PostgreSQL table partition."""
# 
#     @abstractmethod
#     def name(self) -> str:
#         """Generates/computes the name for this partition."""
# 
#     @abstractmethod
#     def create(
#         self,
#         model: PostgresPartitionedModel,
#         schema_editor: PostgresSchemaEditor,
#         comment: Optional[str] = None,
#     ) -> None:
#         """Creates this partition in the database."""
# 
#     @abstractmethod
#     def delete(
#         self,
#         model: PostgresPartitionedModel,
#         schema_editor: PostgresSchemaEditor,
#     ) -> None:
#         """Deletes this partition from the database."""
# 
#     def deconstruct(self) -> dict:
#         """Deconstructs this partition into a dict of attributes/fields."""
# 
#         return {"name": self.name()}
# 
# Path: psqlextra/partitioning/plan.py
# class PostgresModelPartitioningPlan:
#     """Describes the partitions that are going to be created/deleted for a
#     particular partitioning config.
# 
#     A "partitioning config" applies to one model.
#     """
# 
#     config: PostgresPartitioningConfig
#     creations: List[PostgresPartition] = field(default_factory=list)
#     deletions: List[PostgresPartition] = field(default_factory=list)
# 
#     def apply(self, using: Optional[str]) -> None:
#         """Applies this partitioning plan by creating and deleting the planned
#         partitions.
# 
#         Applying the plan runs in a transaction.
# 
#         Arguments:
#             using:
#                 Name of the database connection to use.
#         """
# 
#         connection = connections[using or "default"]
# 
#         with transaction.atomic():
#             with connection.schema_editor() as schema_editor:
#                 for partition in self.creations:
#                     partition.create(
#                         self.config.model,
#                         schema_editor,
#                         comment=AUTO_PARTITIONED_COMMENT,
#                     )
# 
#                 for partition in self.deletions:
#                     partition.delete(self.config.model, schema_editor)
# 
#     def print(self) -> None:
#         """Prints this model plan to the terminal in a readable format."""
# 
#         print(f"{self.config.model.__name__}:")
# 
#         for partition in self.deletions:
#             print("  - %s" % partition.name())
#             for key, value in partition.deconstruct().items():
#                 print(f"     {key}: {value}")
# 
#         for partition in self.creations:
#             print("  + %s" % partition.name())
#             for key, value in partition.deconstruct().items():
#                 print(f"     {key}: {value}")
# 
# class PostgresPartitioningPlan:
#     """Describes the partitions that are going to be created/deleted."""
# 
#     model_plans: List[PostgresModelPartitioningPlan]
# 
#     @property
#     def creations(self) -> List[PostgresPartition]:
#         """Gets a complete flat list of the partitions that are going to be
#         created."""
# 
#         creations = []
#         for model_plan in self.model_plans:
#             creations.extend(model_plan.creations)
#         return creations
# 
#     @property
#     def deletions(self) -> List[PostgresPartition]:
#         """Gets a complete flat list of the partitions that are going to be
#         deleted."""
# 
#         deletions = []
#         for model_plan in self.model_plans:
#             deletions.extend(model_plan.deletions)
#         return deletions
# 
#     def apply(self, using: Optional[str] = None) -> None:
#         """Applies this plan by creating/deleting all planned partitions."""
# 
#         for model_plan in self.model_plans:
#             model_plan.apply(using=using)
# 
#     def print(self) -> None:
#         """Prints this plan to the terminal in a readable format."""
# 
#         for model_plan in self.model_plans:
#             model_plan.print()
#             print("")
# 
#         create_count = len(self.creations)
#         delete_count = len(self.deletions)
# 
#         print(f"{delete_count} partitions will be deleted")
#         print(f"{create_count} partitions will be created")


# Path: psqlextra/partitioning/manager.py
from typing import List, Optional, Tuple
from django.db import connections
from psqlextra.models import PostgresPartitionedModel
from .config import PostgresPartitioningConfig
from .constants import AUTO_PARTITIONED_COMMENT
from .error import PostgresPartitioningError
from .partition import PostgresPartition
from .plan import PostgresModelPartitioningPlan, PostgresPartitioningPlan

            skip_create:
                If set to True, no partitions will be marked
                for creation, regardless of the configuration.

            skip_delete:
                If set to True, no partitions will be marked
                for deletion, regardless of the configuration.

            using:
                Name of the database connection to use.

        Returns:
            A plan describing what partitions would be created
            and deleted if the plan is applied.
        """

        model_plans = []

        for config in self.configs:
            model_plan = self._plan_for_config(
                config,
                skip_create=skip_create,
                skip_delete=skip_delete,
                using=using,
            )
            if not model_plan:
                continue

            model_plans.append(model_plan)


        return PostgresPartitioningPlan(model_plans)