# Path: psqlextra/partitioning/range_strategy.py
# class PostgresRangePartitioningStrategy(PostgresPartitioningStrategy):
#     """Base class for implementing a partitioning strategy for a range
#     partitioned table."""
# 
# Path: psqlextra/partitioning/time_partition.py
# class PostgresTimePartition(PostgresRangePartition):
#     """Time-based range table partition.
# 
#     :see:PostgresTimePartitioningStrategy for more info.
#     """
# 
#     _unit_name_format = {
#         PostgresTimePartitionUnit.YEARS: "%Y",
#         PostgresTimePartitionUnit.MONTHS: "%Y_%b",
#         PostgresTimePartitionUnit.WEEKS: "%Y_week_%W",
#         PostgresTimePartitionUnit.DAYS: "%Y_%b_%d",
#     }
# 
#     def __init__(
#         self, size: PostgresTimePartitionSize, start_datetime: datetime
#     ) -> None:
#         end_datetime = start_datetime + size.as_delta()
# 
#         super().__init__(
#             from_values=start_datetime.strftime("%Y-%m-%d"),
#             to_values=end_datetime.strftime("%Y-%m-%d"),
#         )
# 
#         self.size = size
#         self.start_datetime = start_datetime
#         self.end_datetime = end_datetime
# 
#     def name(self) -> str:
#         name_format = self._unit_name_format.get(self.size.unit)
#         if not name_format:
#             raise PostgresPartitioningError("Unknown size/unit")
# 
#         return self.start_datetime.strftime(name_format).lower()
# 
#     def deconstruct(self) -> dict:
#         return {
#             **super().deconstruct(),
#             "size_unit": self.size.unit.value,
#             "size_value": self.size.value,
#         }
# 
# 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 datetime import datetime, timezone
from typing import Generator, Optional
from dateutil.relativedelta import relativedelta
from .range_strategy import PostgresRangePartitioningStrategy
from .time_partition import PostgresTimePartition
from .time_partition_size import PostgresTimePartitionSize




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,

# Path: psqlextra/partitioning/range_strategy.py
# class PostgresRangePartitioningStrategy(PostgresPartitioningStrategy):
#     """Base class for implementing a partitioning strategy for a range
#     partitioned table."""
# 
# Path: psqlextra/partitioning/time_partition.py
# class PostgresTimePartition(PostgresRangePartition):
#     """Time-based range table partition.
# 
#     :see:PostgresTimePartitioningStrategy for more info.
#     """
# 
#     _unit_name_format = {
#         PostgresTimePartitionUnit.YEARS: "%Y",
#         PostgresTimePartitionUnit.MONTHS: "%Y_%b",
#         PostgresTimePartitionUnit.WEEKS: "%Y_week_%W",
#         PostgresTimePartitionUnit.DAYS: "%Y_%b_%d",
#     }
# 
#     def __init__(
#         self, size: PostgresTimePartitionSize, start_datetime: datetime
#     ) -> None:
#         end_datetime = start_datetime + size.as_delta()
# 
#         super().__init__(
#             from_values=start_datetime.strftime("%Y-%m-%d"),
#             to_values=end_datetime.strftime("%Y-%m-%d"),
#         )
# 
#         self.size = size
#         self.start_datetime = start_datetime
#         self.end_datetime = end_datetime
# 
#     def name(self) -> str:
#         name_format = self._unit_name_format.get(self.size.unit)
#         if not name_format:
#             raise PostgresPartitioningError("Unknown size/unit")
# 
#         return self.start_datetime.strftime(name_format).lower()
# 
#     def deconstruct(self) -> dict:
#         return {
#             **super().deconstruct(),
#             "size_unit": self.size.unit.value,
#             "size_value": self.size.value,
#         }
# 
# 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/current_time_strategy.py
from datetime import datetime, timezone
from typing import Generator, Optional
from dateutil.relativedelta import relativedelta
from .range_strategy import PostgresRangePartitioningStrategy
from .time_partition import PostgresTimePartition
from .time_partition_size import PostgresTimePartitionSize





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,