49 lines
1.7 KiB
Python
49 lines
1.7 KiB
Python
from __future__ import annotations
|
|
|
|
import uuid
|
|
from dataclasses import dataclass, field
|
|
from typing import Any
|
|
|
|
from shared.base_entity import BaseEntity
|
|
from shared.types import ChartType
|
|
|
|
from src.domain.entities.field_binding import FieldBinding
|
|
from src.domain.entities.style_config import StyleConfig
|
|
|
|
|
|
@dataclass
|
|
class ChartInstance(BaseEntity):
|
|
"""Aggregate root representing a configured chart."""
|
|
|
|
dataset_id: uuid.UUID = field(default_factory=uuid.uuid4)
|
|
chart_type: ChartType = ChartType.BAR
|
|
bindings: list[FieldBinding] = field(default_factory=list)
|
|
style: StyleConfig = field(default_factory=dict)
|
|
filters: list[dict[str, Any]] = field(default_factory=list)
|
|
sort_config: dict[str, Any] | None = None
|
|
top_n: int | None = None
|
|
|
|
# ------------------------------------------------------------------
|
|
# Domain behaviour
|
|
# ------------------------------------------------------------------
|
|
|
|
def update_bindings(self, bindings: list[FieldBinding]) -> None:
|
|
"""Replace current bindings after validation."""
|
|
errors = self.validate_bindings(bindings)
|
|
if errors:
|
|
raise ValueError("; ".join(errors))
|
|
self.bindings = bindings
|
|
self.touch()
|
|
|
|
def update_style(self, style: StyleConfig) -> None:
|
|
"""Merge new style properties into current style."""
|
|
self.style.update(style)
|
|
self.touch()
|
|
|
|
def validate_bindings(self, bindings: list[FieldBinding] | None = None) -> list[str]:
|
|
"""Return a list of validation error messages (empty means valid)."""
|
|
from src.domain.services.binding_validation import validate_bindings as _validate
|
|
|
|
target = bindings if bindings is not None else self.bindings
|
|
return _validate(self.chart_type, target)
|