Skip to content

Commit 57430f4

Browse files
committed
docstring for CRUDBase
1 parent c1c83dc commit 57430f4

File tree

1 file changed

+162
-8
lines changed

1 file changed

+162
-8
lines changed

src/app/crud/crud_base.py

Lines changed: 162 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from sqlalchemy.ext.asyncio import AsyncSession
77
from sqlalchemy.engine.row import Row
88

9-
from .helper import _extract_matching_columns_from_schema, _extract_matching_columns_from_kwargs, _extract_matching_columns_from_column_names
9+
from .helper import _extract_matching_columns_from_schema, _extract_matching_columns_from_kwargs
1010

1111
ModelType = TypeVar("ModelType")
1212
CreateSchemaType = TypeVar("CreateSchemaType", bound=BaseModel)
@@ -15,27 +15,102 @@
1515
DeleteSchemaType = TypeVar("DeleteSchemaType", bound=BaseModel)
1616

1717
class CRUDBase(Generic[ModelType, CreateSchemaType, UpdateSchemaType, UpdateSchemaInternalType, DeleteSchemaType]):
18+
"""
19+
Base class for CRUD operations on a model.
20+
21+
Parameters
22+
----------
23+
model : Type[ModelType]
24+
The SQLAlchemy model type.
25+
"""
1826
def __init__(self, model: Type[ModelType]) -> None:
1927
self._model = model
2028

2129
async def create(
22-
self, db: AsyncSession, object: CreateSchemaType
30+
self,
31+
db: AsyncSession,
32+
object: CreateSchemaType
2333
) -> ModelType:
34+
"""
35+
Create a new record in the database.
36+
37+
Parameters
38+
----------
39+
db : AsyncSession
40+
The SQLAlchemy async session.
41+
object : CreateSchemaType
42+
The Pydantic schema containing the data to be saved.
43+
44+
Returns
45+
-------
46+
ModelType
47+
The created database object.
48+
"""
2449
object_dict = object.model_dump()
2550
db_object = self._model(**object_dict)
2651
db.add(db_object)
2752
await db.commit()
2853
return db_object
2954

30-
async def get(self, db: AsyncSession, schema_to_select: Type[BaseModel] | None = None, **kwargs) -> ModelType | None:
55+
async def get(
56+
self,
57+
db: AsyncSession,
58+
schema_to_select: Type[BaseModel] | None = None,
59+
**kwargs
60+
) -> ModelType | None:
61+
"""
62+
Fetch a single record based on filters.
63+
64+
Parameters
65+
----------
66+
db : AsyncSession
67+
The SQLAlchemy async session.
68+
schema_to_select : Type[BaseModel] | None, optional
69+
Pydantic schema for selecting specific columns. Default is None to select all columns.
70+
kwargs : dict
71+
Filters to apply to the query.
72+
73+
Returns
74+
-------
75+
ModelType | None
76+
The fetched database row or None if not found.
77+
"""
3178
to_select = _extract_matching_columns_from_schema(model=self._model, schema=schema_to_select)
3279
stmt = select(*to_select) \
3380
.filter_by(**kwargs)
3481

3582
result = await db.execute(stmt)
3683
return result.first()
3784

38-
async def get_multi(self, db: AsyncSession, offset: int = 0, limit: int = 100, schema_to_select: Type[BaseModel] | None = None, **kwargs) -> List[ModelType]:
85+
async def get_multi(
86+
self,
87+
db: AsyncSession,
88+
offset: int = 0,
89+
limit: int = 100,
90+
schema_to_select: Type[BaseModel] | None = None,
91+
**kwargs
92+
) -> List[ModelType]:
93+
"""
94+
Fetch multiple records based on filters.
95+
96+
Parameters
97+
----------
98+
db : AsyncSession
99+
The SQLAlchemy async session.
100+
offset : int, optional
101+
Number of rows to skip before fetching. Default is 0.
102+
limit : int, optional
103+
Maximum number of rows to fetch. Default is 100.
104+
schema_to_select : Type[BaseModel] | None, optional
105+
Pydantic schema for selecting specific columns. Default is None to select all columns.
106+
kwargs : dict
107+
Filters to apply to the query.
108+
109+
Returns
110+
-------
111+
List[ModelType]
112+
List of fetched database rows.
113+
"""
39114
to_select = _extract_matching_columns_from_schema(model=self._model, schema=schema_to_select)
40115
stmt = select(*to_select) \
41116
.filter_by(**kwargs) \
@@ -45,7 +120,26 @@ async def get_multi(self, db: AsyncSession, offset: int = 0, limit: int = 100, s
45120
result = await db.execute(stmt)
46121
return result.all()
47122

48-
async def exists(self, db: AsyncSession, **kwargs) -> bool:
123+
async def exists(
124+
self,
125+
db: AsyncSession,
126+
**kwargs
127+
) -> bool:
128+
"""
129+
Check if a record exists based on filters.
130+
131+
Parameters
132+
----------
133+
db : AsyncSession
134+
The SQLAlchemy async session.
135+
kwargs : dict
136+
Filters to apply to the query.
137+
138+
Returns
139+
-------
140+
bool
141+
True if a record exists, False otherwise.
142+
"""
49143
to_select = _extract_matching_columns_from_kwargs(model=self._model, kwargs=kwargs)
50144
stmt = select(*to_select) \
51145
.filter_by(**kwargs) \
@@ -54,7 +148,28 @@ async def exists(self, db: AsyncSession, **kwargs) -> bool:
54148

55149
return result.first() is not None
56150

57-
async def update(self, db: AsyncSession, object: Union[UpdateSchemaType, Dict[str, Any]], **kwargs) -> ModelType | None:
151+
async def update(
152+
self,
153+
db: AsyncSession,
154+
object: Union[UpdateSchemaType, Dict[str, Any]],
155+
**kwargs
156+
) -> None:
157+
"""
158+
Update an existing record in the database.
159+
160+
Parameters
161+
----------
162+
db : AsyncSession
163+
The SQLAlchemy async session.
164+
object : Union[UpdateSchemaType, Dict[str, Any]]
165+
The Pydantic schema or dictionary containing the data to be updated.
166+
kwargs : dict
167+
Filters for the update.
168+
169+
Returns
170+
-------
171+
None
172+
"""
58173
if isinstance(object, dict):
59174
update_data = object
60175
else:
@@ -68,12 +183,51 @@ async def update(self, db: AsyncSession, object: Union[UpdateSchemaType, Dict[st
68183
await db.execute(stmt)
69184
await db.commit()
70185

71-
async def db_delete(self, db: AsyncSession, **kwargs):
186+
async def db_delete(
187+
self,
188+
db: AsyncSession,
189+
**kwargs
190+
) -> None:
191+
"""
192+
Delete a record in the database.
193+
194+
Parameters
195+
----------
196+
db : AsyncSession
197+
The SQLAlchemy async session.
198+
kwargs : dict
199+
Filters for the delete.
200+
201+
Returns
202+
-------
203+
None
204+
"""
72205
stmt = delete(self._model).filter_by(**kwargs)
73206
await db.execute(stmt)
74207
await db.commit()
75208

76-
async def delete(self, db: AsyncSession, db_row: Row | None = None, **kwargs) -> ModelType | None:
209+
async def delete(
210+
self,
211+
db: AsyncSession,
212+
db_row: Row | None = None,
213+
**kwargs
214+
) -> None:
215+
"""
216+
Soft delete a record if it has "is_deleted" attribute, otherwise perform a hard delete.
217+
218+
Parameters
219+
----------
220+
db : AsyncSession
221+
The SQLAlchemy async session.
222+
db_row : Row | None, optional
223+
Existing database row to delete. If None, it will be fetched based on `kwargs`. Default is None.
224+
kwargs : dict
225+
Filters for fetching the database row if not provided.
226+
227+
Returns
228+
-------
229+
None
230+
"""
77231
db_row = db_row or await self.get(db=db, **kwargs)
78232
if db_row:
79233
if "is_deleted" in db_row:

0 commit comments

Comments
 (0)