Skip to content

Commit d0ea236

Browse files
committed
docs: added docstrings to classes and methods
1 parent 7321483 commit d0ea236

File tree

11 files changed

+310
-54
lines changed

11 files changed

+310
-54
lines changed

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@ install: ## Install development dependencies
3939
cp .env.example .env
4040
@echo "Development dependencies has been setup."
4141

42-
migrate: ## Run the database migration
42+
migration: ## Create the database migration script
43+
$(ALEMBIC) revision --autogenerate
44+
45+
migrate: ## Apply the database migration
4346
$(ALEMBIC) upgrade head
4447

4548
check: ## Run all checks using tox and pre-commit
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""added index to blog model fields
2+
3+
Revision ID: e74c9e9b4d84
4+
Revises: 79befb39e85d
5+
Create Date: 2024-07-25 17:47:05.878080
6+
7+
"""
8+
9+
from typing import Sequence, Union
10+
11+
from alembic import op
12+
13+
14+
# revision identifiers, used by Alembic.
15+
revision: str = "e74c9e9b4d84"
16+
down_revision: Union[str, None] = "79befb39e85d"
17+
branch_labels: Union[str, Sequence[str], None] = None
18+
depends_on: Union[str, Sequence[str], None] = None
19+
20+
21+
def upgrade() -> None:
22+
# ### commands auto generated by Alembic - please adjust! ###
23+
op.drop_constraint("blogs_title_key", "blogs", type_="unique")
24+
op.create_index(op.f("ix_blogs_created_at"), "blogs", ["created_at"], unique=False)
25+
op.create_index(op.f("ix_blogs_is_deleted"), "blogs", ["is_deleted"], unique=False)
26+
op.create_index(op.f("ix_blogs_title"), "blogs", ["title"], unique=True)
27+
# ### end Alembic commands ###
28+
29+
30+
def downgrade() -> None:
31+
# ### commands auto generated by Alembic - please adjust! ###
32+
op.drop_index(op.f("ix_blogs_title"), table_name="blogs")
33+
op.drop_index(op.f("ix_blogs_is_deleted"), table_name="blogs")
34+
op.drop_index(op.f("ix_blogs_created_at"), table_name="blogs")
35+
op.create_unique_constraint("blogs_title_key", "blogs", ["title"])
36+
# ### end Alembic commands ###

api/v1/models/blog.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,37 +16,48 @@ class Blog(Base):
1616
primary_key=True,
1717
index=True,
1818
autoincrement=True,
19+
doc="Unique identifier for the blog post.",
1920
)
2021
title = Column(
2122
String(255),
2223
nullable=False,
2324
unique=True,
25+
index=True,
26+
doc="Title of the blog post. Must be unique.",
2427
)
2528
excerpt = Column(
2629
String(300),
2730
nullable=False,
31+
doc="Summary of the blog post.",
2832
)
2933
content = Column(
3034
Text,
3135
nullable=False,
36+
doc="Full content of the blog post.",
3237
)
3338
image_url = Column(
3439
String(255),
3540
nullable=False,
41+
doc="URL of the image associated with the blog post.",
3642
)
3743
is_deleted = Column(
3844
Boolean,
3945
default=False,
4046
nullable=False,
47+
index=True,
48+
doc="Flag to indicate if the blog post is deleted.",
4149
)
4250
created_at = Column(
4351
DateTime(timezone=True),
4452
server_default=func.now(),
4553
nullable=False,
54+
index=True,
55+
doc="Timestamp when the blog post was created.",
4656
)
4757
updated_at = Column(
4858
DateTime(timezone=True),
4959
server_default=func.now(),
5060
onupdate=func.now(),
5161
nullable=False,
62+
doc="Timestamp when the blog post was last updated.",
5263
)

api/v1/routes/blog.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,20 @@ async def create_blog(
2828
blog: BlogCreate,
2929
db: Session = Depends(get_db),
3030
) -> BlogResponse:
31+
"""
32+
Create a new blog post.
33+
34+
Args:
35+
blog (BlogCreate): The blog post data to create.
36+
db (Session): The database session dependency.
37+
38+
Returns:
39+
BlogResponse: The created blog post response.
40+
41+
Raises:
42+
HTTPException: If a blog post with the same title already
43+
exists or a database error occurs.
44+
"""
3145
try:
3246
return BlogService.create_blog(db, blog)
3347
except ValueError as e:
@@ -60,6 +74,20 @@ async def list_blog(
6074
page_size: int = Query(10, ge=1, le=100),
6175
db: Session = Depends(get_db),
6276
) -> BlogListResponse:
77+
"""
78+
Retrieve a list of blog posts with pagination.
79+
80+
Args:
81+
page (int): The page number for pagination.
82+
page_size (int): The number of items per page.
83+
db (Session): The database session dependency.
84+
85+
Returns:
86+
BlogListResponse: The list of blog posts with pagination info.
87+
88+
Raises:
89+
HTTPException: If a database error occurs.
90+
"""
6391
try:
6492
return BlogService.list_blog(db, page, page_size)
6593
except SQLAlchemyError as e:
@@ -85,6 +113,19 @@ async def read_blog(
85113
id: int,
86114
db: Session = Depends(get_db),
87115
) -> BlogResponse:
116+
"""
117+
Retrieve a blog post by ID.
118+
119+
Args:
120+
id (int): The ID of the blog post to retrieve.
121+
db (Session): The database session dependency.
122+
123+
Returns:
124+
BlogResponse: The blog post response.
125+
126+
Raises:
127+
HTTPException: If the blog post is not found or a database error occurs.
128+
"""
88129
try:
89130
return BlogService.read_blog(db, id)
90131
except ValueError as e:
@@ -117,6 +158,21 @@ async def update_blog(
117158
blog_update: BlogUpdate,
118159
db: Session = Depends(get_db),
119160
) -> BlogResponse:
161+
"""
162+
Update an existing blog post by ID.
163+
164+
Args:
165+
id (int): The ID of the blog post to update.
166+
blog_update (BlogUpdate): The updated blog post data.
167+
db (Session): The database session dependency.
168+
169+
Returns:
170+
BlogResponse: The updated blog post response.
171+
172+
Raises:
173+
HTTPException: If the blog post is not found, a conflict occurs,
174+
or a database error occurs.
175+
"""
120176
try:
121177
return BlogService.update_blog(db, id, blog_update)
122178
except RequestValidationError as e:
@@ -155,6 +211,16 @@ async def delete_blog(
155211
id: int,
156212
db: Session = Depends(get_db),
157213
) -> None:
214+
"""
215+
Delete a blog post by ID (soft delete).
216+
217+
Args:
218+
id (int): The ID of the blog post to delete.
219+
db (Session): The database session dependency.
220+
221+
Raises:
222+
HTTPException: If the blog post is not found or a database error occurs.
223+
"""
158224
try:
159225
BlogService.delete_blog(db, id)
160226
except ValueError as e:

api/v1/schemas/blog.py

Lines changed: 71 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,27 @@ class BlogBase(BaseModel):
1313
...,
1414
min_length=10,
1515
max_length=255,
16-
description="Title of the blog post",
16+
description="Title of the blog post. Must be between 10 and 255 characters.",
1717
)
1818
excerpt: str = Field(
1919
...,
2020
min_length=20,
2121
max_length=300,
22-
description="Short excerpt of the blog post",
22+
description="Short excerpt of the blog post. Must be between 20 and 300 characters.",
2323
)
2424
content: str = Field(
2525
...,
26-
description="Content of the blog post",
26+
description="Full content of the blog post.",
2727
)
2828
image_url: str = Field(
2929
...,
3030
max_length=255,
31-
description="URL of the blog post image",
31+
description="URL of the blog post image.",
32+
)
33+
is_deleted: Optional[bool] = Field(
34+
False,
35+
description="Flag to indicate if the blog post is deleted. Defaults to False.",
3236
)
33-
is_deleted: Optional[bool] = False
3437

3538

3639
class BlogCreate(BlogBase):
@@ -46,41 +49,87 @@ class BlogUpdate(BaseModel):
4649
None,
4750
min_length=10,
4851
max_length=255,
49-
description="Title of the blog post",
52+
description="Title of the blog post. Must be between 10 and 255 characters.",
5053
)
5154
excerpt: Optional[str] = Field(
5255
None,
5356
min_length=20,
5457
max_length=300,
55-
description="Short excerpt of the blog post",
58+
description="Short excerpt of the blog post. Must be between 20 and 300 characters.",
59+
)
60+
content: Optional[str] = Field(
61+
None,
62+
description="Full content of the blog post.",
63+
)
64+
image_url: Optional[str] = Field(
65+
None,
66+
max_length=255,
67+
description="URL of the blog post image.",
68+
)
69+
is_deleted: Optional[bool] = Field(
70+
False,
71+
description="Flag to indicate if the blog post is deleted. Defaults to False.",
5672
)
57-
content: Optional[str]
58-
image_url: Optional[str]
59-
is_deleted: Optional[bool] = False
6073

6174

6275
class BlogResponse(BlogBase):
6376
"""Schema for returning blog post data."""
6477

65-
id: int
66-
created_at: datetime
67-
updated_at: datetime
78+
id: int = Field(
79+
...,
80+
description="Unique identifier for the blog post.",
81+
)
82+
created_at: datetime = Field(
83+
...,
84+
description="Timestamp when the blog post was created.",
85+
)
86+
updated_at: datetime = Field(
87+
...,
88+
description="Timestamp when the blog post was last updated.",
89+
)
6890

6991

7092
class BlogListItemResponse(BaseModel):
7193
"""Schema for representing a blog post item in the list response."""
7294

73-
id: int
74-
title: str
75-
excerpt: str
76-
image_url: str
77-
created_at: datetime
95+
id: int = Field(
96+
...,
97+
description="Unique identifier for the blog post.",
98+
)
99+
title: str = Field(
100+
...,
101+
description="Title of the blog post.",
102+
)
103+
excerpt: str = Field(
104+
...,
105+
description="Short excerpt of the blog post.",
106+
)
107+
image_url: str = Field(
108+
...,
109+
description="URL of the blog post image.",
110+
)
111+
created_at: datetime = Field(
112+
...,
113+
description="Timestamp when the blog post was created.",
114+
)
78115

79116

80117
class BlogListResponse(BaseModel):
81118
"""Schema for representing a blog post listing in the API response."""
82119

83-
count: int
84-
next: Optional[str]
85-
previous: Optional[str]
86-
results: List[BlogListItemResponse]
120+
count: int = Field(
121+
...,
122+
description="Total number of blog posts.",
123+
)
124+
next: Optional[str] = Field(
125+
None,
126+
description="URL to the next page of results, if available.",
127+
)
128+
previous: Optional[str] = Field(
129+
None,
130+
description="URL to the previous page of results, if available.",
131+
)
132+
results: List[BlogListItemResponse] = Field(
133+
...,
134+
description="List of blog post items.",
135+
)

0 commit comments

Comments
 (0)