diff --git a/src/dug/api_models/__init__.py b/src/dug/api_models/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/dug/api_models/grapql.py b/src/dug/api_models/grapql.py new file mode 100644 index 00000000..01018f29 --- /dev/null +++ b/src/dug/api_models/grapql.py @@ -0,0 +1,33 @@ +import strawberry +from typing import List + +# This type represents the metadata object +@strawberry.type +class MetaData: + total_count: int + offset: int + size: int + + +# This is the top-level response for a query asking for studies +@strawberry.type +class StudyAPIResponse: + results: List[Study] + metadata: Optional[MetaData] + + +# This is the top-level response for a query asking for variables +@strawberry.type +class VariableAPIResponse: + results: List[Variable] + metadata: Optional[MetaData] + + +# This is the top-level response for a query asking for concepts +@strawberry.type +class ConceptAPIResponse: + results: List[Concept] + metadata: MetaData # This was not Optional in your Pydantic model + + # We use the 'JSON' scalar to handle a generic 'dict' type + concept_types: JSON \ No newline at end of file diff --git a/src/dug/api_models/request_models.py b/src/dug/api_models/request_models.py index a26420a5..1bb6f087 100644 --- a/src/dug/api_models/request_models.py +++ b/src/dug/api_models/request_models.py @@ -12,6 +12,12 @@ class SearchConceptQuery(BaseModel): size: int = 20 concept_types: list = None + +class SearchStudiesQuery(BaseModel): + query: str + offset: int = 0 + size: int = 1000 + class SearchVariablesQuery(BaseModel): query: str concept: str = "" @@ -44,9 +50,10 @@ class SearchProgramQuery(BaseModel): #index: str = "variables_index" size:int = 100 + class SearchQuery(BaseModel): - id: Optional[str] = None query: Optional[str] = None + parent_id: Optional[str] = None size: Optional[int] = 100 offset: Optional[int] = 0 diff --git a/src/dug/api_models/response_models.py b/src/dug/api_models/response_models.py index 5a3d1562..16a716a2 100644 --- a/src/dug/api_models/response_models.py +++ b/src/dug/api_models/response_models.py @@ -1,5 +1,5 @@ from dug.core.parsers._base import * -from pydantic import BaseModel +from pydantic import BaseModel, model_serializer from typing import Optional @@ -34,7 +34,10 @@ class ConceptsAPIResponse(BaseModel): class VariableResponse(ElasticDugElementResult, DugVariable): - pass + @model_serializer + def serialize(self): + response = self.get_response_dict() + return response class VariablesAPIResponse(DugAPIResponse): @@ -42,18 +45,25 @@ class VariablesAPIResponse(DugAPIResponse): class StudyResponse(ElasticDugElementResult, DugStudy): - pass + @model_serializer + def serialize(self): + response = self.get_response_dict() + response.pop('abstract') + return response class StudyAPIResponse(DugAPIResponse): results: List[StudyResponse] -class CdeResponse(ElasticDugElementResult, DugSection): - pass +class SectionResponse(ElasticDugElementResult, DugSection): + @model_serializer + def serialize(self): + response = self.get_response_dict() + return response -class CdeAPIResponse(DugAPIResponse): - results: List[CdeResponse] +class SectionAPIResponse(DugAPIResponse): + results: List[SectionResponse] diff --git a/src/dug/core/parsers/_base.py b/src/dug/core/parsers/_base.py index ee1d1346..0e5590a8 100644 --- a/src/dug/core/parsers/_base.py +++ b/src/dug/core/parsers/_base.py @@ -70,10 +70,16 @@ def get_searchable_dict(self): 'metadata': self.metadata, 'parents': self.parents, 'programs': self.program_name_list, - 'identifiers': list(self.concepts.keys()), + 'identifiers': list(self.concepts.keys()) if self.concepts else [], } return es_elem + def get_response_dict(self): + response = self.get_searchable_dict() + things_to_hide = ['search_terms', 'optional_terms',] + return {x: response[x] for x in response if x not in things_to_hide} + + def get_id(self) -> str: return f'{self.id}' diff --git a/src/dug/server.py b/src/dug/server.py index e34b9d6d..a4fe4b5e 100644 --- a/src/dug/server.py +++ b/src/dug/server.py @@ -372,7 +372,7 @@ async def get_variables(search_query: SearchVariablesQuery): @APP.post('/studies', tags=['v2.0'], response_model=StudyAPIResponse) -async def get_studies(query: SearchQuery): +async def get_studies(query: SearchStudiesQuery): """ Handles GET requests to retrieve a list of studies. @@ -403,7 +403,7 @@ async def get_studies(query: SearchQuery): """ - result, total_count = await search.search_study_new(study_id=query.id, study_name=query.query, + result, total_count = await search.search_study_new(study_name=query.query, offset=query.offset, size=query.size) studies = [] for study in result: @@ -421,12 +421,13 @@ async def get_studies(query: SearchQuery): } -@APP.post('/cdes', tags=['v2.0'], response_model=VariablesAPIResponse) +@APP.post('/cdes', tags=['v2.0'], response_model=SectionAPIResponse) async def get_cdes(search_query: SearchQuery): """ Searches for CDEs """ - elastic_results, total_count = await search.search_cde(**search_query.model_dump(exclude={"index"})) + #@TODO use parent ID if passed down + elastic_results, total_count = await search.search_cde(**search_query.model_dump(exclude={"parent_id"})) results = [] for result in elastic_results: item = result.get("_source")