2025-02-18 19:17:04 +00:00
|
|
|
from datetime import datetime
|
2025-02-19 10:38:10 +00:00
|
|
|
from typing import Optional, List, Tuple
|
2025-02-18 10:40:27 +00:00
|
|
|
|
2025-02-18 19:17:04 +00:00
|
|
|
# Base Attribute class
|
2025-02-18 10:40:27 +00:00
|
|
|
class Attribute:
|
2025-02-19 10:38:10 +00:00
|
|
|
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
|
2025-02-18 19:17:04 +00:00
|
|
|
):
|
2025-02-19 10:38:10 +00:00
|
|
|
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
|
2025-02-18 10:40:27 +00:00
|
|
|
self.display_name = display_name
|
|
|
|
self.html_input_type = html_input_type
|
2025-02-19 10:38:10 +00:00
|
|
|
self.placeholder = placeholder
|
2025-02-18 10:40:27 +00:00
|
|
|
self.required = required
|
|
|
|
self.unique = unique
|
|
|
|
self.primary = primary
|
|
|
|
self.index = index
|
|
|
|
self.compareto = compareto
|
2025-02-18 19:17:04 +00:00
|
|
|
self.title = title
|
|
|
|
|
2025-02-19 10:38:10 +00:00
|
|
|
# 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
|
2025-02-18 19:17:04 +00:00
|
|
|
compareto: Optional[List[Tuple[str, str]]] = None,
|
2025-02-19 10:38:10 +00:00
|
|
|
**kwargs # Additional arguments for the base class
|
2025-02-18 19:17:04 +00:00
|
|
|
):
|
2025-02-19 10:38:10 +00:00
|
|
|
super().__init__(html_input_type="text", **kwargs)
|
2025-02-18 19:17:04 +00:00
|
|
|
self.regex = regex
|
|
|
|
self.default_val = default_val
|
2025-02-19 10:38:10 +00:00
|
|
|
self.compareto = compareto
|
2025-02-18 19:17:04 +00:00
|
|
|
|
2025-02-19 10:38:10 +00:00
|
|
|
# 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
|
2025-02-18 19:17:04 +00:00
|
|
|
compareto: Optional[List[Tuple[str, str]]] = None,
|
2025-02-19 10:38:10 +00:00
|
|
|
**kwargs # Additional arguments for the base class
|
2025-02-18 19:17:04 +00:00
|
|
|
):
|
2025-02-19 10:38:10 +00:00
|
|
|
super().__init__(html_input_type="number", **kwargs)
|
2025-02-18 19:17:04 +00:00
|
|
|
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
|
2025-02-19 10:38:10 +00:00
|
|
|
self.compareto = compareto
|
2025-02-18 19:17:04 +00:00
|
|
|
|
2025-02-19 10:38:10 +00:00
|
|
|
# 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
|
2025-02-18 19:17:04 +00:00
|
|
|
compareto: Optional[List[Tuple[str, str]]] = None,
|
2025-02-19 10:38:10 +00:00
|
|
|
**kwargs # Additional arguments for the base class
|
2025-02-18 19:17:04 +00:00
|
|
|
):
|
2025-02-19 10:38:10 +00:00
|
|
|
super().__init__(html_input_type="number", **kwargs)
|
2025-02-18 19:17:04 +00:00
|
|
|
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
|
2025-02-19 10:38:10 +00:00
|
|
|
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}).")
|
2025-02-18 19:17:04 +00:00
|
|
|
|
2025-02-19 10:38:10 +00:00
|
|
|
# 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)
|
2025-02-18 19:17:04 +00:00
|
|
|
compareto: Optional[List[Tuple[str, str]]] = None,
|
2025-02-19 10:38:10 +00:00
|
|
|
**kwargs # Additional arguments for the base class
|
2025-02-18 19:17:04 +00:00
|
|
|
):
|
2025-02-19 10:38:10 +00:00
|
|
|
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
|
2025-02-18 19:17:04 +00:00
|
|
|
):
|
2025-02-19 10:38:10 +00:00
|
|
|
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)
|
2025-02-18 19:17:04 +00:00
|
|
|
|
2025-02-19 10:38:10 +00:00
|
|
|
# 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.")
|