Skip to content

Commit a7bf304

Browse files
committed
Add example model referencing list of objects
1 parent 86dfaa7 commit a7bf304

File tree

2 files changed

+27
-11
lines changed

2 files changed

+27
-11
lines changed

api/api/public.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,12 @@ async def get_descendents(
4949
uuid: shared_data_models.UUID, db: Repository = Depends()
5050
) -> List[source_type]:
5151
return await db.get_docs(
52-
doc_filter={source_attribute: uuid}, doc_type=source_type
52+
# !!!!
53+
# source_attribute has list values sometimes (for models that reference a list of other objects)
54+
# mongo queries just so happen have the semantics we want
55+
# a.i. list_attribute: some_val means "any value in list_attribute is equal to some_val"
56+
doc_filter={source_attribute: uuid},
57+
doc_type=source_type,
5358
)
5459

5560
return get_descendents
@@ -60,14 +65,18 @@ async def get_descendents(
6065
if len(uuid_field_type.metadata):
6166
parent_type = uuid_field_type.metadata[0] # convention
6267

63-
router.add_api_route(
64-
f"/{to_snake(parent_type.__name__)}/{{uuid}}/{to_snake(model.__name__)}",
65-
response_model=List[model],
66-
operation_id=f"get{model.__name__}In{parent_type.__name__}",
67-
summary=f"Get {model.__name__} In {parent_type.__name__}",
68-
methods=["GET"],
69-
endpoint=make_reverse_link_handler(uuid_field_name, model),
70-
)
68+
# List validators (e.g. MinLength) are also set in the type.metadata list
69+
# -> only generate backlinks for types that have metadata that is also one of the exposed types
70+
# ? Maybe find a better way to wrap "foreign key"-type relationships, like a custom generic similar to List so we can also drop the [0] convention?
71+
if parent_type in models_public:
72+
router.add_api_route(
73+
f"/{to_snake(parent_type.__name__)}/{{uuid}}/{to_snake(model.__name__)}",
74+
response_model=List[model],
75+
operation_id=f"get{model.__name__}In{parent_type.__name__}",
76+
summary=f"Get {model.__name__} In {parent_type.__name__}",
77+
methods=["GET"],
78+
endpoint=make_reverse_link_handler(uuid_field_name, model),
79+
)
7180

7281

7382
def make_router() -> APIRouter:

bia-shared-datamodels/src/bia_shared_datamodels/bia_data_model.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,14 @@ def fields_by_type(cls, field_type: Any) -> Dict[str, FieldInfo]:
7878
fields_filtered = {}
7979

8080
for field_name, field_info in cls.model_fields.items():
81-
if field_info.annotation is field_type:
81+
# conditions split for clarity
82+
field_type_exact = field_info.annotation is field_type
83+
field_type_container_list = (
84+
hasattr(field_info.annotation, "__origin__")
85+
and field_info.annotation.__origin__ is list
86+
and field_info.annotation.__args__[0] is field_type
87+
)
88+
if field_type_exact or field_type_container_list:
8289
fields_filtered[field_name] = field_info
8390

8491
return fields_filtered
@@ -131,7 +138,7 @@ class ExperimentalImagingDataset(
131138

132139
class Specimen(semantic_models.Specimen, DocumentMixin):
133140
imaging_preparation_protocol_uuid: List[UUID] = Field(min_length=1)
134-
sample_of_uuid: List[UUID] = Field(min_length=1)
141+
sample_of_uuid: Annotated[List[UUID], BioSample] = Field(min_length=1)
135142
growth_protocol_uuid: List[UUID] = Field()
136143

137144
model_config = ConfigDict(model_version_latest=1)

0 commit comments

Comments
 (0)