Coverage for src / lexigram / admin / relations / manager.py: 62%
29 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-13 22:14 +0800
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-13 22:14 +0800
1"""Relation manager for lexigram-admin.
3Provides base class for managing entity relationships in admin views.
4"""
6from __future__ import annotations
8from abc import ABC, abstractmethod
9from typing import TYPE_CHECKING, Any, ClassVar
11if TYPE_CHECKING:
12 from lexigram.ui.columns.types import Column
13from lexigram.di.decorators import inject
16@inject
17class AbstractRelationManager(ABC):
18 """Base class for managing entity relationships.
20 Subclasses define how to display and query related entities
21 for a parent resource.
23 Example:
24 class UserPetsRelationManager(AbstractRelationManager):
25 relationship_name = "pets"
27 @classmethod
28 def table(cls, table_config=None):
29 return [
30 TextColumn("name").sortable(),
31 BadgeColumn("species"),
32 ]
34 async def get_query(self):
35 return await pet_service.list(user_id=self.parent_id)
36 """
38 relationship_name: ClassVar[str] = ""
40 def __init__(self, parent_id: Any = None, parent: Any = None):
41 """Initialize relation manager.
43 Args:
44 parent_id: ID of the parent entity
45 parent: The parent entity object (optional)
46 """
47 self.parent_id = parent_id
48 self.parent = parent
50 @classmethod
51 @abstractmethod
52 def table(cls, table_config: Any = None) -> list[Column]:
53 """Define columns for displaying related entities.
55 Args:
56 table_config: Optional table configuration
58 Returns:
59 List of Column instances
60 """
61 ...
63 @abstractmethod
64 async def get_query(self) -> list[Any]:
65 """Get related entities for the parent.
67 Returns:
68 List of related entities
69 """
70 ...
72 async def count(self) -> int:
73 """Count related entities.
75 Returns:
76 Number of related entities
77 """
78 items = await self.get_query()
79 return len(items) if items else 0
81 async def get_items(
82 self,
83 *,
84 page: int = 1,
85 per_page: int = 20,
86 **filters: Any,
87 ) -> list[Any]:
88 """Get paginated related entities.
90 Args:
91 page: Page number (1-indexed)
92 per_page: Items per page
93 **filters: Additional filters
95 Returns:
96 List of related entities for the page
97 """
98 items = await self.get_query()
99 if not items:
100 return []
102 start = (page - 1) * per_page
103 end = start + per_page
104 return items[start:end]
106 @classmethod
107 def get_relationship_name(cls) -> str:
108 """Get the name of this relationship."""
109 return cls.relationship_name or cls.__name__.lower().replace(
110 "relationmanager",
111 "",
112 )
115__all__ = ["AbstractRelationManager"]