Coverage for src / lexigram / contracts / data / repository.py: 0%
16 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-15 18:57 +0800
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-15 18:57 +0800
1"""RepositoryProtocol protocols.
3Generic repository patterns for data access abstraction.
4"""
6from __future__ import annotations
8from typing import TYPE_CHECKING, Any, Generic, Protocol, TypeVar, runtime_checkable
10if TYPE_CHECKING:
11 from lexigram.contracts.domain.specification import SpecificationProtocol
13T = TypeVar("T")
16@runtime_checkable
17class ReadOnlyRepositoryProtocol(Protocol, Generic[T]):
18 """Protocol for read-only repository operations.
20 Use this for query-only access patterns (CQRS query side).
22 Example:
23 ```python
24 class UserQueryRepository:
25 async def get(self, id: str) -> User | None:
26 return await self.db.query("users").where(id=id).first()
28 async def list(self, skip: int = 0, limit: int = 100) -> list[User]:
29 return await self.db.query("users").offset(skip).limit(limit).all()
30 ```
31 """
33 async def get(self, item_id: str) -> T | None:
34 """Get entity by ID.
36 Args:
37 item_id: Entity identifier.
39 Returns:
40 Entity if found, None otherwise.
41 """
42 ...
44 async def list(
45 self,
46 skip: int = 0,
47 limit: int = 100,
48 **filters: Any,
49 ) -> list[T]:
50 """List entities with pagination.
52 Args:
53 skip: Number of records to skip.
54 limit: Maximum records to return.
55 **filters: Optional filter criteria.
57 Returns:
58 List of entities.
59 """
60 ...
62 async def find_by_spec(self, spec: SpecificationProtocol[T]) -> list[T]: # type: ignore[valid-type]
63 """Find entities matching a complex specification.
65 Args:
66 spec: The DDD specification to evaluate.
68 Returns:
69 List of matching entities.
70 """
71 ...
73 async def count(self, **filters: Any) -> int:
74 """Count entities matching filters.
76 Args:
77 **filters: Optional filter criteria.
79 Returns:
80 Total count of matching entities.
81 """
82 ...
85@runtime_checkable
86class RepositoryProtocol(ReadOnlyRepositoryProtocol[T], Protocol, Generic[T]):
87 """Protocol for full repository operations.
89 Extends ReadOnlyRepositoryProtocol with write operations.
91 Example:
92 ```python
93 class UserRepository:
94 async def save(self, entity: User) -> User:
95 if entity.id:
96 await self.db.update("users", entity.dict()).where(id=entity.id)
97 else:
98 entity.id = await self.db.insert("users", entity.dict())
99 return entity
101 async def delete(self, id: str) -> bool:
102 result = await self.db.delete("users").where(id=id)
103 return result.affected_rows > 0
104 ```
105 """
107 async def save(self, entity: T) -> T:
108 """Save (create or update) an entity.
110 Args:
111 entity: Entity to save.
113 Returns:
114 Saved entity with any generated fields populated.
115 """
116 ...
118 async def delete(self, item_id: str) -> bool:
119 """Delete entity by ID.
121 Args:
122 item_id: Entity identifier.
124 Returns:
125 True if deleted, False if not found.
126 """
127 ...
129 async def save_many(self, entities: list[T]) -> list[T]:
130 """Save (create or update) multiple entities in a single operation.
132 Implementations SHOULD execute this as a batch for efficiency.
134 Args:
135 entities: Entities to save.
137 Returns:
138 Saved entities with any generated fields populated.
139 """
140 ...
142 async def delete_many(self, item_ids: list[str]) -> int:
143 """Delete multiple entities by ID.
145 Implementations SHOULD execute this as a batch for efficiency.
147 Args:
148 item_ids: Entity identifiers to delete.
150 Returns:
151 Number of entities actually deleted.
152 """
153 ...
156__all__ = [
157 "ReadOnlyRepositoryProtocol",
158 "RepositoryProtocol",
159 "T",
160]