Skip to content

Commit

Permalink
Merge pull request #99 from OCHA-DAP/feature/HDX-9831-hum-needs
Browse files Browse the repository at this point in the history
Feature/hdx 9831 hum needs
  • Loading branch information
danmihaila authored May 22, 2024
2 parents 26a1972 + 31bf223 commit db27e83
Show file tree
Hide file tree
Showing 12 changed files with 260 additions and 251 deletions.
3 changes: 2 additions & 1 deletion hdx_hapi/config/doc_snippets.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
DOC_ADMIN2_CODE = 'Filter the response by the 2nd subnational administrative divisions. The admin2 codes refer to the p-codes in the <a href="https://data.humdata.org/dashboards/cod?">Common Operational Datasets</a>.'
DOC_ADMIN2_NAME = 'Filter the response by the 1st subnational administrative divisions. The admin2 names refer to the <a href="https://data.humdata.org/dashboards/cod?">Common Operational Datasets</a>.'
DOC_AGE_RANGE_SUMMARY = 'Get the list of age ranges used for disaggregating population data'
DOC_AGE_RANGE_CODE = 'Filter the response by the age range. These are expressed as [start year]-[end year]. The end year is assumed to be inclusive, though that is not always explicit in the source data.'
DOC_AGE_RANGE = 'Filter the response by the age range. These are expressed as [start year]-[end year]. The end year is assumed to be inclusive, though that is not always explicit in the source data.'
DOC_GENDER_SUMMARY = 'Get the list of gender codes used for disaggregating population data'
DOC_GENDER_CODE = 'Filter the response by the gender code.'
DOC_GENDER = 'Filter the response by the gender.'
DOC_GENDER_DESCRIPTION = 'Filter the response by the gender description.'
DOC_HDX_DATASET_ID = 'Filter the response by the dataset ID, which is a unique and fixed identifier of a Dataset on HDX. A URL in the pattern of `https://data.humdata.org/dataset/[dataset id]` will load the dataset page on HDX.'
DOC_HDX_DATASET_NAME = 'Filter the response by the URL-safe name of the dataset as displayed on HDX. This name is unique but can change. A URL in the pattern of `https://data.humdata.org/dataset/[dataset name]` will load the dataset page on HDX.'
Expand Down
103 changes: 48 additions & 55 deletions hdx_hapi/db/dao/humanitarian_needs_view_dao.py
Original file line number Diff line number Diff line change
@@ -1,77 +1,68 @@
import datetime
from typing import Optional

from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select

from hdx_hapi.db.models.views.all_views import HumanitarianNeedsView
from hdx_hapi.db.dao.util.util import apply_location_admin_filter, apply_pagination, case_insensitive_filter
from hdx_hapi.endpoints.util.util import PaginationParams
from hdx_hapi.db.dao.util.util import (
apply_location_admin_filter,
apply_pagination,
apply_reference_period_filter,
)
from hdx_hapi.endpoints.util.util import PaginationParams, ReferencePeriodParameters
from hapi_schema.utils.enums import DisabledMarker, Gender, PopulationGroup, PopulationStatus


async def humanitarian_needs_view_list(
pagination_parameters: PaginationParams,
ref_period_parameters: ReferencePeriodParameters,
db: AsyncSession,
gender_code: str = None,
age_range_code: str = None,
disabled_marker: bool = None,
sector_code: str = None,
sector_name: str = None,
population_group_code: str = None,
population_status_code: str = None,
population: int = None,
dataset_hdx_provider_stub: str = None,
resource_update_date_min: datetime = None,
resource_update_date_max: datetime = None,
hapi_updated_date_min: datetime = None,
hapi_updated_date_max: datetime = None,
hapi_replaced_date_min: datetime = None,
hapi_replaced_date_max: datetime = None,
location_code: str = None,
location_name: str = None,
admin1_code: str = None,
admin1_name: str = None,
admin1_is_unspecified: bool = None,
location_ref: int = None,
admin2_code: str = None,
admin2_name: str = None,
admin2_is_unspecified: bool = None,
admin1_ref: int = None,
admin2_ref: int = None,
admin2_ref: Optional[int] = None,
gender: Optional[Gender] = None,
age_range: Optional[str] = None,
min_age: Optional[int] = None,
max_age: Optional[int] = None,
disabled_marker: Optional[DisabledMarker] = None,
sector_code: Optional[str] = None,
population_group: Optional[PopulationGroup] = None,
population_status: Optional[PopulationStatus] = None,
population: Optional[int] = None,
sector_name: Optional[str] = None,
location_code: Optional[str] = None,
location_name: Optional[str] = None,
location_ref: Optional[int] = None,
admin1_code: Optional[str] = None,
admin2_code: Optional[str] = None,
admin2_name: Optional[str] = None,
admin1_ref: Optional[int] = None,
admin1_name: Optional[str] = None,
admin1_is_unspecified: Optional[bool] = None,
admin2_is_unspecified: Optional[bool] = None,
):
query = select(HumanitarianNeedsView)

if gender_code:
query = case_insensitive_filter(query, HumanitarianNeedsView.gender_code, gender_code)
if age_range_code:
query = query.where(HumanitarianNeedsView.age_range_code == age_range_code)
if gender:
query = query.where(HumanitarianNeedsView.gender == gender)
if age_range:
query = query.where(HumanitarianNeedsView.age_range == age_range)
# if min_age:
# query = query.where(HumanitarianNeedsView.min_age == min_age)
# if max_age:
# query = query.where(HumanitarianNeedsView.max_age == max_age)
if disabled_marker:
query = query.where(HumanitarianNeedsView.disabled_marker == disabled_marker)
if sector_code:
query = query.where(HumanitarianNeedsView.sector_code.icontains(sector_code))
if sector_name:
query = query.where(HumanitarianNeedsView.sector_name.icontains(sector_name))
if population_group_code:
query = query.where(HumanitarianNeedsView.population_group_code.icontains(population_group_code))
if population_status_code:
query = query.where(HumanitarianNeedsView.population_status_code.icontains(population_status_code))
if population_group:
query = query.where(HumanitarianNeedsView.population_group == population_group)
if population_status:
query = query.where(HumanitarianNeedsView.population_status == population_status)

if population:
query = query.where(HumanitarianNeedsView.population == population)
if dataset_hdx_provider_stub:
query = case_insensitive_filter(
query, HumanitarianNeedsView.dataset_hdx_provider_stub, dataset_hdx_provider_stub
)
if resource_update_date_min:
query = query.where(HumanitarianNeedsView.resource_update_date >= resource_update_date_min)
if resource_update_date_max:
query = query.where(HumanitarianNeedsView.resource_update_date < resource_update_date_max)
if hapi_updated_date_min:
query = query.where(HumanitarianNeedsView.hapi_updated_date >= hapi_updated_date_min)
if hapi_updated_date_max:
query = query.where(HumanitarianNeedsView.hapi_updated_date < hapi_updated_date_max)
if hapi_replaced_date_min:
query = query.where(HumanitarianNeedsView.hapi_replaced_date >= hapi_replaced_date_min)
if hapi_replaced_date_max:
query = query.where(HumanitarianNeedsView.hapi_replaced_date < hapi_replaced_date_max)

if sector_name:
query = query.where(HumanitarianNeedsView.sector_name.icontains(sector_name))

query = apply_location_admin_filter(
query,
Expand All @@ -89,6 +80,8 @@ async def humanitarian_needs_view_list(
admin2_is_unspecified,
)

query = apply_reference_period_filter(query, ref_period_parameters, HumanitarianNeedsView)

query = apply_pagination(query, pagination_parameters)

result = await db.execute(query)
Expand Down
4 changes: 2 additions & 2 deletions hdx_hapi/endpoints/get_demographic.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from sqlalchemy.ext.asyncio import AsyncSession
from hdx_hapi.config.doc_snippets import (
DOC_AGE_RANGE_CODE,
DOC_AGE_RANGE,
DOC_AGE_RANGE_SUMMARY,
DOC_GENDER_CODE,
DOC_GENDER_DESCRIPTION,
Expand Down Expand Up @@ -38,7 +38,7 @@ async def get_age_ranges(
common_parameters: Annotated[CommonEndpointParams, Depends(common_endpoint_parameters)],
db: AsyncSession = Depends(get_db),
code: Annotated[
str, Query(max_length=32, openapi_examples={'20-24': {'value': '20-24'}}, description=f'{DOC_AGE_RANGE_CODE}')
str, Query(max_length=32, openapi_examples={'20-24': {'value': '20-24'}}, description=f'{DOC_AGE_RANGE}')
] = None,
output_format: OutputFormat = OutputFormat.JSON,
):
Expand Down
124 changes: 59 additions & 65 deletions hdx_hapi/endpoints/get_humanitarian_needs.py
Original file line number Diff line number Diff line change
@@ -1,129 +1,123 @@
from datetime import date
from typing import Annotated
from typing import Annotated, Optional
from fastapi import Depends, Query, APIRouter
from pydantic import NaiveDatetime


from sqlalchemy.ext.asyncio import AsyncSession

from hdx_hapi.config.doc_snippets import (
DOC_GENDER_CODE,
DOC_AGE_RANGE_CODE,
DOC_GENDER,
DOC_AGE_RANGE,
DOC_SECTOR_CODE,
DOC_SECTOR_NAME,
DOC_HDX_PROVIDER_STUB,
DOC_ADMIN1_CODE,
DOC_ADMIN2_NAME,
DOC_ADMIN2_CODE,
DOC_LOCATION_CODE,
DOC_LOCATION_NAME,
DOC_SEE_ADMIN1,
DOC_SEE_LOC,
DOC_UPDATE_DATE_MAX,
DOC_UPDATE_DATE_MIN,
DOC_SEE_ADMIN2,
DOC_HAPI_UPDATED_DATE_MIN,
DOC_HAPI_UPDATED_DATE_MAX,
DOC_HAPI_REPLACED_DATE_MIN,
DOC_HAPI_REPLACED_DATE_MAX,
)

from hdx_hapi.endpoints.models.base import HapiGenericResponse
from hdx_hapi.endpoints.models.humanitarian_needs import HumanitarianNeedsResponse
from hdx_hapi.endpoints.util.util import AdminLevel, CommonEndpointParams, OutputFormat, common_endpoint_parameters
from hdx_hapi.services.csv_transform_logic import transform_result_to_csv_stream_if_requested
from hdx_hapi.services.humanitarian_needs_logic import get_humanitarian_needs_srv
from hdx_hapi.services.sql_alchemy_session import get_db
from hapi_schema.utils.enums import DisabledMarker, Gender, PopulationGroup, PopulationStatus
from hdx_hapi.endpoints.util.util import (
CommonEndpointParams,
OutputFormat,
ReferencePeriodParameters,
common_endpoint_parameters,
reference_period_parameters,
AdminLevel,
)

router = APIRouter(
tags=['Humanitarian Needs'],
tags=['Affected people'],
)


@router.get(
'/api/themes/humanitarian_needs',
'/api/affected-people/humanitarian-needs',
response_model=HapiGenericResponse[HumanitarianNeedsResponse],
summary='Get humanitarian needs data',
include_in_schema=False,
)
@router.get(
'/api/v1/themes/humanitarian_needs',
'/api/v1/affected-people/humanitarian-needs',
response_model=HapiGenericResponse[HumanitarianNeedsResponse],
summary='Get humanitarian needs data',
)
async def get_humanitarian_needs(
ref_period_parameters: Annotated[ReferencePeriodParameters, Depends(reference_period_parameters)],
common_parameters: Annotated[CommonEndpointParams, Depends(common_endpoint_parameters)],
db: AsyncSession = Depends(get_db),
gender_code: Annotated[str, Query(max_length=1, description=f'{DOC_GENDER_CODE}')] = None,
age_range_code: Annotated[str, Query(max_length=32, description=f'{DOC_AGE_RANGE_CODE}')] = None,
disabled_marker: Annotated[bool, Query(description='Disabled marker')] = None,
sector_code: Annotated[str, Query(max_length=32, description=f'{DOC_SECTOR_CODE}')] = None,
sector_name: Annotated[str, Query(max_length=512, description=f'{DOC_SECTOR_NAME}')] = None,
population_group_code: Annotated[str, Query(max_length=32, description='Population group code')] = None,
population_status_code: Annotated[str, Query(max_length=32, description='Population status code')] = None,
population: Annotated[int, Query(description='Population')] = None,
dataset_hdx_provider_stub: Annotated[str, Query(max_length=128, description=f'{DOC_HDX_PROVIDER_STUB}')] = None,
resource_update_date_min: Annotated[
NaiveDatetime | date,
Query(description=f'{DOC_UPDATE_DATE_MIN}', openapi_examples={'2020-01-01': {'value': '2020-01-01'}}),
admin2_ref: Annotated[Optional[int], Query(description='Admin2 reference')] = None,
gender: Annotated[Optional[Gender], Query(max_length=1, description=f'{DOC_GENDER}')] = None,
age_range: Annotated[Optional[str], Query(max_length=32, description=f'{DOC_AGE_RANGE}')] = None,
min_age: Annotated[Optional[int], Query(description='Min age')] = None,
max_age: Annotated[Optional[int], Query(description='Max age')] = None,
disabled_marker: Annotated[Optional[DisabledMarker], Query(description='Disabled marker')] = None,
sector_code: Annotated[Optional[str], Query(max_length=32, description=f'{DOC_SECTOR_CODE}')] = None,
population_group: Annotated[Optional[PopulationGroup], Query(max_length=32, description='Population group')] = None,
population_status: Annotated[
Optional[PopulationStatus], Query(max_length=32, description='Population status')
] = None,
resource_update_date_max: Annotated[
NaiveDatetime | date,
Query(description=f'{DOC_UPDATE_DATE_MAX}', openapi_examples={'2024-12-31': {'value': '2024-12-31'}}),
population: Annotated[Optional[int], Query(description='Population')] = None,
# reference_period_start: Annotated[
# NaiveDatetime | date,
# Query(description='Reference period start', openapi_examples={'2020-01-01': {'value': '2020-01-01'}}),
# ] = None,
# reference_period_end: Annotated[
# NaiveDatetime | date,
# Query(description='Reference period end', openapi_examples={'2024-12-31': {'value': '2024-12-31'}}),
# ] = None,
sector_name: Annotated[Optional[str], Query(max_length=512, description=f'{DOC_SECTOR_NAME}')] = None,
location_code: Annotated[
Optional[str], Query(max_length=128, description=f'{DOC_LOCATION_CODE} {DOC_SEE_LOC}')
] = None,
hapi_updated_date_min: Annotated[
NaiveDatetime | date,
Query(description=f'{DOC_HAPI_UPDATED_DATE_MIN}'),
location_name: Annotated[
Optional[str], Query(max_length=512, description=f'{DOC_LOCATION_NAME} {DOC_SEE_LOC}')
] = None,
hapi_updated_date_max: Annotated[
NaiveDatetime | date,
Query(description=f'{DOC_HAPI_UPDATED_DATE_MAX}'),
location_ref: Annotated[Optional[int], Query(description='Location reference')] = None,
admin1_code: Annotated[
Optional[str], Query(max_length=128, description=f'{DOC_ADMIN1_CODE} {DOC_SEE_ADMIN1}')
] = None,
hapi_replaced_date_min: Annotated[
NaiveDatetime | date,
Query(description=f'{DOC_HAPI_REPLACED_DATE_MIN}'),
admin2_code: Annotated[
Optional[str], Query(max_length=128, description=f'{DOC_ADMIN2_CODE} {DOC_SEE_ADMIN2}')
] = None,
hapi_replaced_date_max: Annotated[
NaiveDatetime | date,
Query(description=f'{DOC_HAPI_REPLACED_DATE_MAX}'),
admin2_name: Annotated[
Optional[str], Query(max_length=512, description=f'{DOC_ADMIN2_NAME} {DOC_SEE_ADMIN2}')
] = None,
location_code: Annotated[str, Query(max_length=128, description=f'{DOC_LOCATION_CODE} {DOC_SEE_LOC}')] = None,
location_name: Annotated[str, Query(max_length=512, description=f'{DOC_LOCATION_NAME} {DOC_SEE_LOC}')] = None,
admin1_code: Annotated[str, Query(max_length=128, description=f'{DOC_ADMIN1_CODE} {DOC_SEE_ADMIN1}')] = None,
location_ref: Annotated[int, Query(description='Location reference')] = None,
# admin1_name: Annotated[str, Query(max_length=512, description=f'{DOC_ADMIN1_NAME} {DOC_SEE_ADMIN1}')] = None,
admin2_code: Annotated[str, Query(max_length=128, description=f'{DOC_ADMIN2_CODE} {DOC_SEE_ADMIN2}')] = None,
admin2_name: Annotated[str, Query(max_length=512, description=f'{DOC_ADMIN2_NAME} {DOC_SEE_ADMIN2}')] = None,
admin1_ref: Annotated[int, Query(description='Admin1 reference')] = None,
admin_level: Annotated[AdminLevel, Query(description='Filter the response by admin level')] = None,
admin1_ref: Annotated[Optional[int], Query(description='Admin1 reference')] = None,
admin_level: Annotated[Optional[AdminLevel], Query(description='Filter the response by admin level')] = None,
output_format: OutputFormat = OutputFormat.JSON,
):
"""
Return the list of humanitarian needs data
"""
result = await get_humanitarian_needs_srv(
pagination_parameters=common_parameters,
ref_period_parameters=ref_period_parameters,
db=db,
gender_code=gender_code,
age_range_code=age_range_code,
admin2_ref=admin2_ref,
gender=gender,
age_range=age_range,
min_age=min_age,
max_age=max_age,
disabled_marker=disabled_marker,
sector_code=sector_code,
sector_name=sector_name,
population_group_code=population_group_code,
population_status_code=population_status_code,
population_group=population_group,
population_status=population_status,
population=population,
dataset_hdx_provider_stub=dataset_hdx_provider_stub,
resource_update_date_min=resource_update_date_min,
resource_update_date_max=resource_update_date_max,
hapi_updated_date_min=hapi_updated_date_min,
hapi_updated_date_max=hapi_updated_date_max,
hapi_replaced_date_min=hapi_replaced_date_min,
hapi_replaced_date_max=hapi_replaced_date_max,
sector_name=sector_name,
location_code=location_code,
location_name=location_name,
admin1_code=admin1_code,
# admin1_name=admin1_name,
location_ref=location_ref,
admin1_code=admin1_code,
admin2_code=admin2_code,
admin2_name=admin2_name,
admin1_ref=admin1_ref,
Expand Down
31 changes: 13 additions & 18 deletions hdx_hapi/endpoints/models/humanitarian_needs.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,23 @@
from datetime import datetime
from pydantic import ConfigDict, Field, NaiveDatetime
from typing import Optional

from hdx_hapi.endpoints.models.base import HapiBaseModel, HapiModelWithAdmins
from hapi_schema.utils.enums import Gender, PopulationGroup, PopulationStatus, DisabledMarker


class HumanitarianNeedsResponse(HapiBaseModel, HapiModelWithAdmins):
gender_code: Optional[str] = Field(max_length=1)
age_range_code: Optional[str] = Field(max_length=32)
disabled_marker: Optional[bool] = None
sector_code: Optional[str] = Field(max_length=32)
sector_name: Optional[str] = Field(max_length=512)
population_status_code: Optional[str] = Field(max_length=32)
population_group_code: Optional[str] = Field(max_length=32)
population: int = None

reference_period_start: Optional[NaiveDatetime]
reference_period_end: Optional[NaiveDatetime]

dataset_hdx_stub: str = Field(max_length=128)
dataset_hdx_provider_stub: str = Field(max_length=128)
resource_hdx_id: str = Field(max_length=36)

hapi_updated_date: datetime
hapi_replaced_date: Optional[datetime]
gender: Gender
age_range: str = Field(max_length=32)
min_age: Optional[int] = Field(ge=0)
max_age: Optional[int] = Field(ge=0)
disabled_marker: DisabledMarker
sector_code: str = Field(max_length=32)
population_group: PopulationGroup
population_status: PopulationStatus
population: int = Field(ge=0)
reference_period_start: NaiveDatetime
reference_period_end: Optional[NaiveDatetime]
sector_name: Optional[str] = Field(max_length=512)

model_config = ConfigDict(from_attributes=True)
Loading

0 comments on commit db27e83

Please sign in to comment.