-
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.
PDCT-310 Added get, search, and count for family events (#23)
- Loading branch information
1 parent
7ae4b2f
commit cd8d332
Showing
26 changed files
with
911 additions
and
31 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
"""Endpoints for managing Family Event entities.""" | ||
import logging | ||
|
||
from fastapi import APIRouter, HTTPException, status | ||
|
||
import app.service.event as event_service | ||
from app.errors import RepositoryError, ValidationError | ||
from app.model.event import EventReadDTO | ||
|
||
event_router = r = APIRouter() | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
|
||
@r.get( | ||
"/events", | ||
response_model=list[EventReadDTO], | ||
) | ||
async def get_all_events() -> list[EventReadDTO]: | ||
""" | ||
Returns all family events. | ||
:return EventDTO: returns a EventDTO if the event is found. | ||
""" | ||
found_events = event_service.all() | ||
|
||
if not found_events: | ||
raise HTTPException( | ||
status_code=status.HTTP_404_NOT_FOUND, | ||
detail="No family events found", | ||
) | ||
|
||
return found_events | ||
|
||
|
||
@r.get( | ||
"/events/", | ||
response_model=list[EventReadDTO], | ||
) | ||
async def search_event(q: str = "") -> list[EventReadDTO]: | ||
""" | ||
Searches for family events matching the "q" URL parameter. | ||
:param str q: The string to match, defaults to "" | ||
:raises HTTPException: If nothing found a 404 is returned. | ||
:return list[EventDTO]: A list of matching events. | ||
""" | ||
try: | ||
events_found = event_service.search(q) | ||
except RepositoryError as e: | ||
raise HTTPException( | ||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail=e.message | ||
) | ||
|
||
if not events_found: | ||
raise HTTPException( | ||
status_code=status.HTTP_404_NOT_FOUND, | ||
detail=f"Events not found for term: {q}", | ||
) | ||
|
||
return events_found | ||
|
||
|
||
@r.get( | ||
"/events/{import_id}", | ||
response_model=EventReadDTO, | ||
) | ||
async def get_event(import_id: str) -> EventReadDTO: | ||
""" | ||
Returns a specific family event given an import id. | ||
:param str import_id: Specified import_id. | ||
:raises HTTPException: If the event is not found a 404 is returned. | ||
:return EventDTO: returns a EventDTO if the event is found. | ||
""" | ||
try: | ||
event = event_service.get(import_id) | ||
except ValidationError as e: | ||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=e.message) | ||
except RepositoryError as e: | ||
raise HTTPException( | ||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail=e.message | ||
) | ||
|
||
if event is None: | ||
raise HTTPException( | ||
status_code=status.HTTP_404_NOT_FOUND, | ||
detail=f"Event not found: {import_id}", | ||
) | ||
|
||
return event |
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,20 @@ | ||
from datetime import datetime | ||
from pydantic import BaseModel | ||
from typing import Optional | ||
|
||
from app.clients.db.models.law_policy.family import ( | ||
EventStatus, | ||
) | ||
|
||
|
||
class EventReadDTO(BaseModel): | ||
"""JSON Representation of a Event for reading.""" | ||
|
||
# From FamilyEvent | ||
import_id: str | ||
event_title: str | ||
date: datetime | ||
event_type_value: str | ||
family_import_id: str | ||
family_document_import_id: Optional[str] = None | ||
event_status: EventStatus |
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,135 @@ | ||
"""Operations on the repository for the Family entity.""" | ||
|
||
import logging | ||
from datetime import datetime | ||
from typing import Optional, Tuple, cast | ||
|
||
from sqlalchemy import or_ | ||
from sqlalchemy.orm import Query, Session | ||
from sqlalchemy.exc import NoResultFound | ||
from sqlalchemy_utils import escape_like | ||
|
||
from app.clients.db.models.law_policy import ( | ||
EventStatus, | ||
FamilyEvent, | ||
Family, | ||
FamilyDocument, | ||
) | ||
from app.model.event import EventReadDTO | ||
|
||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
FamilyEventTuple = Tuple[FamilyEvent, Family, FamilyDocument] | ||
|
||
|
||
def _get_query(db: Session) -> Query: | ||
# NOTE: SqlAlchemy will make a complete hash of the query generation | ||
# if columns are used in the query() call. Therefore, entire | ||
# objects are returned. | ||
return ( | ||
db.query(FamilyEvent, Family, FamilyDocument) | ||
.filter(FamilyEvent.family_import_id == Family.import_id) | ||
.join( | ||
FamilyDocument, | ||
FamilyDocument.family_import_id == FamilyEvent.family_document_import_id, | ||
isouter=True, | ||
) | ||
) | ||
|
||
|
||
def _event_to_dto(db: Session, family_event_meta: FamilyEventTuple) -> EventReadDTO: | ||
family_event = family_event_meta[0] | ||
|
||
family_document_import_id = ( | ||
None | ||
if family_event.family_document_import_id is None | ||
else cast(str, family_event.family_document_import_id) | ||
) | ||
|
||
return EventReadDTO( | ||
import_id=cast(str, family_event.import_id), | ||
event_title=cast(str, family_event.title), | ||
date=cast(datetime, family_event.date), | ||
family_import_id=cast(str, family_event.family_import_id), | ||
family_document_import_id=family_document_import_id, | ||
event_type_value=cast(str, family_event.event_type_name), | ||
event_status=cast(EventStatus, family_event.status), | ||
) | ||
|
||
|
||
def all(db: Session) -> list[EventReadDTO]: | ||
""" | ||
Returns all family events. | ||
:param db Session: The database connection. | ||
:return Optional[EventReadDTO]: All family events in the database. | ||
""" | ||
family_event_metas = _get_query(db).all() | ||
|
||
if not family_event_metas: | ||
return [] | ||
|
||
result = [_event_to_dto(db, event_meta) for event_meta in family_event_metas] | ||
return result | ||
|
||
|
||
def get(db: Session, import_id: str) -> Optional[EventReadDTO]: | ||
""" | ||
Gets a single family event from the repository. | ||
:param db Session: The database connection. | ||
:param str import_id: The import_id of the event. | ||
:return Optional[EventReadDTO]: A single family event or nothing. | ||
""" | ||
try: | ||
family_event_meta = ( | ||
_get_query(db).filter(FamilyEvent.import_id == import_id).one() | ||
) | ||
except NoResultFound as e: | ||
_LOGGER.error(e) | ||
return | ||
|
||
return _event_to_dto(db, family_event_meta) | ||
|
||
|
||
def search(db: Session, search_term: str) -> Optional[list[EventReadDTO]]: | ||
""" | ||
Get family events matching a search term on the event title or type. | ||
:param db Session: The database connection. | ||
:param str search_term: Any search term to filter on the event title | ||
or event type name. | ||
:return Optional[list[EventReadDTO]]: A list of matching family | ||
events or none. | ||
""" | ||
term = f"%{escape_like(search_term)}%" | ||
search = or_(FamilyEvent.title.ilike(term), FamilyEvent.event_type_name.ilike(term)) | ||
|
||
try: | ||
found = _get_query(db).filter(search).all() | ||
except NoResultFound as e: | ||
_LOGGER.error(e) | ||
return | ||
|
||
if not found: | ||
return [] | ||
|
||
return [_event_to_dto(db, f) for f in found] | ||
|
||
|
||
def count(db: Session) -> Optional[int]: | ||
""" | ||
Counts the number of family events in the repository. | ||
:param db Session: The database connection. | ||
:return Optional[int]: The number of family events in the repository | ||
or nothing. | ||
""" | ||
try: | ||
n_events = _get_query(db).count() | ||
except NoResultFound as e: | ||
_LOGGER.error(e) | ||
return | ||
|
||
return n_events |
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
Oops, something went wrong.