|
1 | | -from typing import List, Optional, Tuple, Dict, Any |
| 1 | +from typing import List, Optional, Tuple, Dict, Any, Union |
| 2 | +import re |
2 | 3 |
|
3 | 4 | from sqlalchemy import text |
4 | 5 | from sqlalchemy.orm import Session |
@@ -28,6 +29,36 @@ def _get_check_pg_partman_ext_statement() -> Tuple[str, Dict[str, Any]]: |
28 | 29 | """Get statement and params for checking/creating pg_partman extension.""" |
29 | 30 | return "create extension if not exists pg_partman cascade;", {} |
30 | 31 |
|
| 32 | + @staticmethod |
| 33 | + def _validate_partition_interval(interval: Union[int, str]) -> str: |
| 34 | + """Validate partition interval format. |
| 35 | +
|
| 36 | + Args: |
| 37 | + interval: Either an integer for numeric partitioning or a string for time-based partitioning |
| 38 | + (e.g., '1 day', '1 hour', '7 days') |
| 39 | +
|
| 40 | + Returns: |
| 41 | + The validated interval as a string |
| 42 | +
|
| 43 | + Raises: |
| 44 | + ValueError: If the interval format is invalid |
| 45 | + """ |
| 46 | + if isinstance(interval, int): |
| 47 | + if interval <= 0: |
| 48 | + raise ValueError("Numeric partition interval must be positive") |
| 49 | + return str(interval) |
| 50 | + |
| 51 | + # Validate time-based interval format |
| 52 | + # Valid PostgreSQL interval formats: '1 day', '7 days', '1 hour', '1 month', etc. |
| 53 | + time_pattern = r"^\d+\s+(microsecond|millisecond|second|minute|hour|day|week|month|year)s?$" |
| 54 | + if not re.match(time_pattern, interval.strip(), re.IGNORECASE): |
| 55 | + raise ValueError( |
| 56 | + f"Invalid time-based partition interval: '{interval}'. " |
| 57 | + "Expected format: '<number> <unit>' where unit is one of: " |
| 58 | + "microsecond, millisecond, second, minute, hour, day, week, month, year" |
| 59 | + ) |
| 60 | + return interval.strip() |
| 61 | + |
31 | 62 | @staticmethod |
32 | 63 | def _get_create_queue_statement( |
33 | 64 | queue_name: str, unlogged: bool |
@@ -349,6 +380,14 @@ async def create_partitioned_queue_async( |
349 | 380 | session: Async SQLAlchemy session. |
350 | 381 | commit: Whether to commit the transaction. |
351 | 382 | """ |
| 383 | + # Validate partition intervals |
| 384 | + partition_interval = PGMQOperation._validate_partition_interval( |
| 385 | + partition_interval |
| 386 | + ) |
| 387 | + retention_interval = PGMQOperation._validate_partition_interval( |
| 388 | + retention_interval |
| 389 | + ) |
| 390 | + |
352 | 391 | stmt, params = PGMQOperation._get_create_partitioned_queue_statement( |
353 | 392 | queue_name, partition_interval, retention_interval |
354 | 393 | ) |
|
0 commit comments