from datetime import datetime from typing import Optional, List, Tuple # Base Attribute class class Attribute: def __init__( self, attrib_name: str, # Attribute name and id. display_name: str, # Input label or table column header. html_input_type: str = "text", # HTML form input type. Determines MySQL data type. placeholder: str = "", # HTML form input placeholder. required: bool = False, # HTML form input "required" attribute and MySQL "Not Null" constraint unique: bool = False, # MySQL "unique" constraint primary: bool = False, # MySQL "primary key" constraint index: bool = False, # bool: MySQL index compareto: Optional[List[Tuple[str, str]]] = None, # Compare to another attribute of the item for validation title: str = None, # Description text, HTML "title" attribute ): if not attrib_name: raise ValueError("Attribute name cannot be empty.") if not display_name: raise ValueError(f"Display name cannot be empty for attribute '{attrib_name}'.") self.attrib_name = attrib_name self.display_name = display_name self.html_input_type = html_input_type self.placeholder = placeholder self.required = required self.unique = unique self.primary = primary self.index = index self.compareto = compareto self.title = title # Validate compareto if self.compareto is not None: validate_comparison(self) # Text Attribute class textAttribute(Attribute): def __init__( self, regex: Optional[str] = None, # Regex for value validation default_val: str = None, # Default value compareto: Optional[List[Tuple[str, str]]] = None, **kwargs # Additional arguments for the base class ): super().__init__(html_input_type="text", **kwargs) self.regex = regex self.default_val = default_val self.compareto = compareto # Integer Attribute class intAttribute(Attribute): def __init__( self, min_val: Optional[int] = None, # Min value max_val: Optional[int] = None, # Max value step_val: Optional[int] = None, # Increment step default_val: Optional[int] = None, # Default value auto_increment: bool = False, # bool: MySQL autoincrement compareto: Optional[List[Tuple[str, str]]] = None, **kwargs # Additional arguments for the base class ): super().__init__(html_input_type="number", **kwargs) self.min_val = min_val self.max_val = max_val self.step_val = step_val self.default_val = default_val self.auto_increment = auto_increment self.compareto = compareto # Validate min_val and max_val if self.min_val is not None and self.max_val is not None and self.min_val > self.max_val: raise ValueError(f"min_val ({self.min_val}) cannot be greater than max_val ({self.max_val}).") # Float Attribute class floatAttribute(Attribute): def __init__( self, min_val: Optional[float] = None, # Min value max_val: Optional[float] = None, # Max value step_val: Optional[float] = None, # Increment step default_val: Optional[float] = None, # Default value auto_increment: bool = False, # bool: MySQL autoincrement compareto: Optional[List[Tuple[str, str]]] = None, **kwargs # Additional arguments for the base class ): super().__init__(html_input_type="number", **kwargs) self.min_val = min_val self.max_val = max_val self.step_val = step_val self.default_val = default_val self.auto_increment = auto_increment self.compareto = compareto # Validate min_val and max_val if self.min_val is not None and self.max_val is not None and self.min_val > self.max_val: raise ValueError(f"min_val ({self.min_val}) cannot be greater than max_val ({self.max_val}).") # Date Attribute class dateAttribute(Attribute): def __init__( self, min_val: Optional[str] = None, # Min value (string in "YYYY-MM-DD" format) max_val: Optional[str] = None, # Max value (string in "YYYY-MM-DD" format) default_val: Optional[str] = None, # Default value (string in "YYYY-MM-DD" format) compareto: Optional[List[Tuple[str, str]]] = None, **kwargs # Additional arguments for the base class ): super().__init__(html_input_type="date", **kwargs) self.min_val = self._parse_date(min_val) if min_val else None self.max_val = self._parse_date(max_val) if max_val else None self.default_val = self._parse_date(default_val) if default_val else None self.compareto = compareto def _parse_date(self, date_str: str) -> datetime: """Parse a date string into a datetime object.""" try: return datetime.strptime(date_str, "%Y-%m-%d") except ValueError as e: raise ValueError(f"Invalid date format for '{date_str}'. Expected 'YYYY-MM-DD'.") from e # Select Attribute class selectAttribute(Attribute): def __init__( self, options: Optional[List[str]] = None, # List of options default_val: Optional[str] = None, # Default value **kwargs # Additional arguments for the base class ): super().__init__(html_input_type="select", **kwargs) self.options = options if options else [] self.default_val = default_val if default_val else (self.options[0] if self.options else None) # Validate default_val if self.default_val and self.default_val not in self.options: raise ValueError(f"Default value '{self.default_val}' is not in the options list.")