# 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/current_time_strategy.py
# class PostgresCurrentTimePartitioningStrategy(
#     PostgresRangePartitioningStrategy
# ):
#     """Implments a time based partitioning strategy where each partition
#     contains values for a specific time period.
# 
#     All buckets will be equal in size and start at the start of the
#     unit. With monthly partitioning, partitions start on the 1st and
#     with weekly partitioning, partitions start on monday.
#     """
# 
#     def __init__(
#         self,
#         size: PostgresTimePartitionSize,
#         count: int,
#         max_age: Optional[relativedelta] = None,
#     ) -> None:
#         """Initializes a new instance of :see:PostgresTimePartitioningStrategy.
# 
#         Arguments:
#             size:
#                 The size of each partition.
# 
#             count:
#                 The amount of partitions to create ahead
#                 from the current date/time.
# 
#             max_age:
#                 Maximum age of a partition. Partitions
#                 older than this are deleted during
#                 auto cleanup.
#         """
# 
#         self.size = size
#         self.count = count
#         self.max_age = max_age
# 
#     def to_create(self) -> Generator[PostgresTimePartition, None, None]:
#         current_datetime = self.size.start(self.get_start_datetime())
# 
#         for _ in range(self.count):
#             yield PostgresTimePartition(
#                 start_datetime=current_datetime, size=self.size
#             )
# 
#             current_datetime += self.size.as_delta()
# 
#     def to_delete(self) -> Generator[PostgresTimePartition, None, None]:
#         if not self.max_age:
#             return
# 
#         current_datetime = self.size.start(
#             self.get_start_datetime() - self.max_age
#         )
# 
#         while True:
#             yield PostgresTimePartition(
#                 start_datetime=current_datetime, size=self.size
#             )
# 
#             current_datetime -= self.size.as_delta()
# 
#     def get_start_datetime(self) -> datetime:
#         return datetime.now(timezone.utc)
# 
# Path: psqlextra/partitioning/time_partition_size.py
# class PostgresTimePartitionSize:
#     """Size of a time-based range partition table."""
# 
#     unit: PostgresTimePartitionUnit
#     value: int
# 
#     def __init__(
#         self,
#         years: Optional[int] = None,
#         months: Optional[int] = None,
#         weeks: Optional[int] = None,
#         days: Optional[int] = None,
#     ) -> None:
#         sizes = [years, months, weeks, days]
# 
#         if not any(sizes):
#             raise PostgresPartitioningError("Partition cannot be 0 in size.")
# 
#         if len([size for size in sizes if size and size > 0]) > 1:
#             raise PostgresPartitioningError(
#                 "Partition can only have on size unit."
#             )
# 
#         if years:
#             self.unit = PostgresTimePartitionUnit.YEARS
#             self.value = years
#         elif months:
#             self.unit = PostgresTimePartitionUnit.MONTHS
#             self.value = months
#         elif weeks:
#             self.unit = PostgresTimePartitionUnit.WEEKS
#             self.value = weeks
#         elif days:
#             self.unit = PostgresTimePartitionUnit.DAYS
#             self.value = days
#         else:
#             raise PostgresPartitioningError(
#                 "Unsupported time partitioning unit"
#             )
# 
#     def as_delta(self) -> relativedelta:
#         if self.unit == PostgresTimePartitionUnit.YEARS:
#             return relativedelta(years=self.value)
# 
#         if self.unit == PostgresTimePartitionUnit.MONTHS:
#             return relativedelta(months=self.value)
# 
#         if self.unit == PostgresTimePartitionUnit.WEEKS:
#             return relativedelta(weeks=self.value)
# 
#         if self.unit == PostgresTimePartitionUnit.DAYS:
#             return relativedelta(days=self.value)
# 
#         raise PostgresPartitioningError(
#             "Unsupported time partitioning unit: %s" % self.unit
#         )
# 
#     def start(self, dt: datetime) -> datetime:
#         if self.unit == PostgresTimePartitionUnit.YEARS:
#             return self._ensure_datetime(dt.replace(month=1, day=1))
# 
#         if self.unit == PostgresTimePartitionUnit.MONTHS:
#             return self._ensure_datetime(dt.replace(day=1))
# 
#         if self.unit == PostgresTimePartitionUnit.WEEKS:
#             return self._ensure_datetime(dt - relativedelta(days=dt.weekday()))
# 
#         return self._ensure_datetime(dt)
# 
#     @staticmethod
#     def _ensure_datetime(dt: Union[date, datetime]) -> datetime:
#         return datetime(year=dt.year, month=dt.month, day=dt.day)
# 
#     def __repr__(self) -> str:
#         return "PostgresTimePartitionSize<%s, %s>" % (self.unit, self.value)


from typing import Optional
from dateutil.relativedelta import relativedelta
from psqlextra.models import PostgresPartitionedModel
from .config import PostgresPartitioningConfig
from .current_time_strategy import PostgresCurrentTimePartitioningStrategy
from .time_partition_size import PostgresTimePartitionSize





def partition_by_current_time(
    model: PostgresPartitionedModel,
    count: int,
    years: Optional[int] = None,
    months: Optional[int] = None,

# 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/current_time_strategy.py
# class PostgresCurrentTimePartitioningStrategy(
#     PostgresRangePartitioningStrategy
# ):
#     """Implments a time based partitioning strategy where each partition
#     contains values for a specific time period.
# 
#     All buckets will be equal in size and start at the start of the
#     unit. With monthly partitioning, partitions start on the 1st and
#     with weekly partitioning, partitions start on monday.
#     """
# 
#     def __init__(
#         self,
#         size: PostgresTimePartitionSize,
#         count: int,
#         max_age: Optional[relativedelta] = None,
#     ) -> None:
#         """Initializes a new instance of :see:PostgresTimePartitioningStrategy.
# 
#         Arguments:
#             size:
#                 The size of each partition.
# 
#             count:
#                 The amount of partitions to create ahead
#                 from the current date/time.
# 
#             max_age:
#                 Maximum age of a partition. Partitions
#                 older than this are deleted during
#                 auto cleanup.
#         """
# 
#         self.size = size
#         self.count = count
#         self.max_age = max_age
# 
#     def to_create(self) -> Generator[PostgresTimePartition, None, None]:
#         current_datetime = self.size.start(self.get_start_datetime())
# 
#         for _ in range(self.count):
#             yield PostgresTimePartition(
#                 start_datetime=current_datetime, size=self.size
#             )
# 
#             current_datetime += self.size.as_delta()
# 
#     def to_delete(self) -> Generator[PostgresTimePartition, None, None]:
#         if not self.max_age:
#             return
# 
#         current_datetime = self.size.start(
#             self.get_start_datetime() - self.max_age
#         )
# 
#         while True:
#             yield PostgresTimePartition(
#                 start_datetime=current_datetime, size=self.size
#             )
# 
#             current_datetime -= self.size.as_delta()
# 
#     def get_start_datetime(self) -> datetime:
#         return datetime.now(timezone.utc)
# 
# Path: psqlextra/partitioning/time_partition_size.py
# class PostgresTimePartitionSize:
#     """Size of a time-based range partition table."""
# 
#     unit: PostgresTimePartitionUnit
#     value: int
# 
#     def __init__(
#         self,
#         years: Optional[int] = None,
#         months: Optional[int] = None,
#         weeks: Optional[int] = None,
#         days: Optional[int] = None,
#     ) -> None:
#         sizes = [years, months, weeks, days]
# 
#         if not any(sizes):
#             raise PostgresPartitioningError("Partition cannot be 0 in size.")
# 
#         if len([size for size in sizes if size and size > 0]) > 1:
#             raise PostgresPartitioningError(
#                 "Partition can only have on size unit."
#             )
# 
#         if years:
#             self.unit = PostgresTimePartitionUnit.YEARS
#             self.value = years
#         elif months:
#             self.unit = PostgresTimePartitionUnit.MONTHS
#             self.value = months
#         elif weeks:
#             self.unit = PostgresTimePartitionUnit.WEEKS
#             self.value = weeks
#         elif days:
#             self.unit = PostgresTimePartitionUnit.DAYS
#             self.value = days
#         else:
#             raise PostgresPartitioningError(
#                 "Unsupported time partitioning unit"
#             )
# 
#     def as_delta(self) -> relativedelta:
#         if self.unit == PostgresTimePartitionUnit.YEARS:
#             return relativedelta(years=self.value)
# 
#         if self.unit == PostgresTimePartitionUnit.MONTHS:
#             return relativedelta(months=self.value)
# 
#         if self.unit == PostgresTimePartitionUnit.WEEKS:
#             return relativedelta(weeks=self.value)
# 
#         if self.unit == PostgresTimePartitionUnit.DAYS:
#             return relativedelta(days=self.value)
# 
#         raise PostgresPartitioningError(
#             "Unsupported time partitioning unit: %s" % self.unit
#         )
# 
#     def start(self, dt: datetime) -> datetime:
#         if self.unit == PostgresTimePartitionUnit.YEARS:
#             return self._ensure_datetime(dt.replace(month=1, day=1))
# 
#         if self.unit == PostgresTimePartitionUnit.MONTHS:
#             return self._ensure_datetime(dt.replace(day=1))
# 
#         if self.unit == PostgresTimePartitionUnit.WEEKS:
#             return self._ensure_datetime(dt - relativedelta(days=dt.weekday()))
# 
#         return self._ensure_datetime(dt)
# 
#     @staticmethod
#     def _ensure_datetime(dt: Union[date, datetime]) -> datetime:
#         return datetime(year=dt.year, month=dt.month, day=dt.day)
# 
#     def __repr__(self) -> str:
#         return "PostgresTimePartitionSize<%s, %s>" % (self.unit, self.value)


# Path: psqlextra/partitioning/shorthands.py
from typing import Optional
from dateutil.relativedelta import relativedelta
from psqlextra.models import PostgresPartitionedModel
from .config import PostgresPartitioningConfig
from .current_time_strategy import PostgresCurrentTimePartitioningStrategy
from .time_partition_size import PostgresTimePartitionSize






def partition_by_current_time(
    model: PostgresPartitionedModel,
    count: int,
    years: Optional[int] = None,
    months: Optional[int] = None,

    weeks: Optional[int] = None,