-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into standardize-returned-response
- Loading branch information
Showing
11 changed files
with
226 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import datetime | ||
|
||
from fastapi import APIRouter, Depends, Query, Request | ||
from sqlmodel import Session, or_ | ||
|
||
from ..database import get_session | ||
from ..logging import get_logger | ||
from ..models import Clip, ClipWithPagination | ||
from ..query_helpers import apply_filters, apply_sorting, handle_pagination | ||
from ..schemas import Pagination | ||
|
||
router = APIRouter() | ||
logger = get_logger() | ||
|
||
|
||
@router.get('/', response_model=ClipWithPagination) | ||
def get_clips( | ||
request: Request, | ||
project_id: list[str] | None = Query(None, description='Project ID'), | ||
tags: list[str] | None = Query(None, description='Tags'), | ||
article_type: list[str] | None = Query(None, description='Article type'), | ||
published_at_from: datetime.date | ||
| datetime.datetime | ||
| None = Query(None, description='Published at from'), | ||
published_at_to: datetime.date | ||
| datetime.datetime | ||
| None = Query(None, description='Published at to'), | ||
search: str | ||
| None = Query( | ||
None, | ||
description='Case insensitive search string. Currently searches on `project_id` and `title` fields only.', | ||
), | ||
current_page: int = Query(1, description='Page number', ge=1), | ||
per_page: int = Query(100, description='Items per page', le=200, ge=1), | ||
sort: list[str] = Query( | ||
default=['project_id'], | ||
description='List of sorting parameters in the format `field_name` or `+field_name` for ascending order or `-field_name` for descending order.', | ||
), | ||
session: Session = Depends(get_session), | ||
): | ||
""" | ||
Get clips associated with a project | ||
""" | ||
logger.info(f'Getting clips: {request.url}') | ||
|
||
filters = [ | ||
('article_type', article_type, 'ilike', Clip), | ||
('tags', tags, 'ANY', Clip), | ||
('published_at', published_at_from, '>=', Clip), | ||
('published_at', published_at_to, '<=', Clip), | ||
('project_id', project_id, 'ilike', Clip), | ||
] | ||
|
||
query = session.query(Clip) | ||
|
||
for attribute, values, operation, model in filters: | ||
query = apply_filters( | ||
query=query, model=model, attribute=attribute, values=values, operation=operation | ||
) | ||
|
||
# Handle 'search' filter separately due to its unique logic | ||
if search: | ||
search_pattern = f'%{search}%' | ||
query = query.filter( | ||
or_(Clip.project_id.ilike(search_pattern), Clip.title.ilike(search_pattern)) | ||
) | ||
|
||
if sort: | ||
query = apply_sorting(query=query, sort=sort, model=Clip, primary_key='id') | ||
|
||
total_entries, current_page, total_pages, next_page, results = handle_pagination( | ||
query=query, current_page=current_page, per_page=per_page, request=request | ||
) | ||
|
||
return ClipWithPagination( | ||
pagination=Pagination( | ||
total_entries=total_entries, | ||
current_page=current_page, | ||
total_pages=total_pages, | ||
next_page=next_page, | ||
), | ||
data=results, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
"""add clips to database | ||
Revision ID: f099826eeacd | ||
Revises: cd307c691d94 | ||
Create Date: 2023-10-21 19:19:30.263534 | ||
""" | ||
import sqlalchemy as sa | ||
import sqlmodel | ||
from alembic import op | ||
from sqlalchemy.dialects import postgresql | ||
|
||
# revision identifiers, used by Alembic. | ||
revision = 'f099826eeacd' | ||
down_revision = 'cd307c691d94' | ||
branch_labels = None | ||
depends_on = None | ||
|
||
|
||
def upgrade() -> None: | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.create_table( | ||
'clip', | ||
sa.Column('tags', postgresql.ARRAY(sa.String()), nullable=True), | ||
sa.Column('id', sa.Integer(), nullable=False), | ||
sa.Column('project_id', sqlmodel.sql.sqltypes.AutoString(), nullable=False), | ||
sa.Column('published_at', sa.DateTime(), nullable=False), | ||
sa.Column('title', sqlmodel.sql.sqltypes.AutoString(), nullable=True), | ||
sa.Column('url', sqlmodel.sql.sqltypes.AutoString(), nullable=True), | ||
sa.Column('notes', sqlmodel.sql.sqltypes.AutoString(), nullable=True), | ||
sa.Column('is_waybacked', sa.Boolean(), nullable=False), | ||
sa.Column('article_type', sqlmodel.sql.sqltypes.AutoString(), nullable=False), | ||
sa.PrimaryKeyConstraint('id'), | ||
) | ||
# ### end Alembic commands ### | ||
|
||
|
||
def downgrade() -> None: | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.drop_table('clip') | ||
# ### end Alembic commands ### |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import pytest | ||
|
||
|
||
def test_get_clips(test_app): | ||
response = test_app.get('/clips/') | ||
assert response.status_code == 200 | ||
assert isinstance(response.json()['data'], list) | ||
|
||
|
||
@pytest.mark.parametrize('article_type', ['foo']) | ||
@pytest.mark.parametrize('tags', ['foo']) | ||
def test_get_filtered_clips(test_app, article_type, tags): | ||
response = test_app.get(f'/clips/?article_type={article_type}&tags={tags}&search=carbon') | ||
assert response.status_code == 200 | ||
assert isinstance(response.json()['data'], list) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters