From 5f2eaeaf5985c0eb6cc819a88d092e7d477384e2 Mon Sep 17 00:00:00 2001 From: pgm Date: Wed, 8 Jan 2025 16:11:15 -0500 Subject: [PATCH] feat(breadbox): Added support for associations to breadbox client and other associations small fixes (#164) --- breadbox-client/breadbox_facade/client.py | 39 ++++++++++++++++------ breadbox/breadbox/api/temp/associations.py | 11 +++++- breadbox/breadbox/crud/dataset.py | 17 ++++++++++ breadbox/breadbox/schemas/associations.py | 3 ++ 4 files changed, 59 insertions(+), 11 deletions(-) diff --git a/breadbox-client/breadbox_facade/client.py b/breadbox-client/breadbox_facade/client.py index d7e93acb..787f94e7 100644 --- a/breadbox-client/breadbox_facade/client.py +++ b/breadbox-client/breadbox_facade/client.py @@ -31,28 +31,28 @@ from breadbox_client.api.groups import remove_group_access as remove_group_access_client from breadbox_client.api.groups import get_groups as get_groups_client from breadbox_client.api.types import add_dimension_type as add_dimension_type_client -from breadbox_client.api.types import add_feature_type as add_feature_type_client -from breadbox_client.api.types import add_sample_type as add_sample_type_client from breadbox_client.api.types import get_dimension_type as get_dimension_type_client from breadbox_client.api.types import get_dimension_types as get_dimension_types_client from breadbox_client.api.types import get_feature_types as get_feature_types_client from breadbox_client.api.types import get_sample_types as get_sample_types_client from breadbox_client.api.types import remove_dimension_type as remove_dimension_type_client from breadbox_client.api.types import update_dimension_type as update_dimension_type_client -from breadbox_client.api.types import update_feature_type_metadata as update_feature_type_metadata_client -from breadbox_client.api.types import update_sample_type_metadata as update_sample_type_metadata_client +from breadbox_client.api.temp import get_associations as get_associations_client +from breadbox_client.api.temp import add_associations as add_associations_client +from breadbox_client.api.temp import get_associations_for_slice as get_associations_for_slice_client +# + from breadbox_client.models import ( AccessType, AddDatasetResponse, AddDimensionType, + Associations, + AssociationTable, + AssociationsIn, + AssociationsInAxis, AddDimensionTypeAxis, - AnnotationTypeMap, BodyAddDataType, - BodyAddFeatureType, - BodyAddSampleType, BodyGetDatasetData, - BodyUpdateFeatureTypeMetadata, - BodyUpdateSampleTypeMetadata, BodyUploadFile, ColumnMetadata, ComputeParams, @@ -66,12 +66,13 @@ GroupEntry, GroupEntryIn, GroupOut, - IdMapping, MatrixDatasetParams, MatrixDatasetParamsDatasetMetadataType0, MatrixDatasetParamsFormat, MatrixDatasetResponse, SampleTypeOut, + SliceQuery, + SliceQueryIdentifierType, TableDatasetParams, TableDatasetParamsColumnsMetadata, TableDatasetParamsDatasetMetadataType0, @@ -472,6 +473,24 @@ def remove_group_access(self, group_entry_id: str) -> str: breadbox_response = remove_group_access_client.sync_detailed(client=self.client, group_entry_id=group_entry_id) return self._parse_client_response(breadbox_response) + # ASSOCIATIONS + def get_associations(self) -> List[AssociationTable]: + breadbox_response = get_associations_client.sync_detailed(client=self.client) + return self._parse_client_response(breadbox_response) + + def add_associations(self, dataset_1_id:str, dataset_2_id: str, axis :str, associations_table_filename : str) -> AssociationTable: + with open(associations_table_filename, "rb") as fd: + uploaded_file = self.upload_file(fd) + + associations_in = AssociationsIn(axis = AssociationsInAxis(axis), dataset_1_id=dataset_1_id, dataset_2_id=dataset_2_id, file_ids=uploaded_file.file_ids, md5=uploaded_file.md5) + breadbox_response = add_associations_client.sync_detailed(client=self.client, body=associations_in) + + return self._parse_client_response(breadbox_response) + + def get_associations_for_slice(self, dataset_id: str, identifier: str, identifier_type: str) -> Associations: + breadbox_response = get_associations_for_slice_client.sync_detailed(client=self.client, body=SliceQuery(dataset_id=dataset_id, identifier=identifier, + identifier_type=SliceQueryIdentifierType(identifier_type))) + return self._parse_client_response(breadbox_response) # API diff --git a/breadbox/breadbox/api/temp/associations.py b/breadbox/breadbox/api/temp/associations.py index 45a4a829..9b2e4a46 100644 --- a/breadbox/breadbox/api/temp/associations.py +++ b/breadbox/breadbox/api/temp/associations.py @@ -16,6 +16,7 @@ from breadbox.crud import associations as associations_crud import uuid from breadbox.db.util import transaction +from typing import cast, Literal from .router import router @@ -46,7 +47,12 @@ def query_associations_for_slice( def get_associations(db: Annotated[SessionWithUser, Depends(get_db_with_user)]): return [ AssociationTable( - id=a.id, dataset_1_id=a.dataset_1_id, dataset_2_id=a.dataset_2_id + id=a.id, + dataset_1_id=a.dataset_1_id, + dataset_2_id=a.dataset_2_id, + dataset_1_name=a.dataset_1.name, + dataset_2_name=a.dataset_2.name, + axis=a.axis, ) for a in associations_crud.get_association_tables(db, None) ] @@ -117,4 +123,7 @@ def add_associations( id=assoc_table.id, dataset_1_id=assoc_table.dataset_1_id, dataset_2_id=assoc_table.dataset_2_id, + dataset_1_name=assoc_table.dataset_1.name, + dataset_2_name=assoc_table.dataset_2.name, + axis=cast(Literal["sample", "feature"], assoc_table.axis), ) diff --git a/breadbox/breadbox/crud/dataset.py b/breadbox/breadbox/crud/dataset.py index 65f8f8fe..6d346884 100644 --- a/breadbox/breadbox/crud/dataset.py +++ b/breadbox/breadbox/crud/dataset.py @@ -18,6 +18,7 @@ ColumnMetadata, UpdateDatasetParams, ) + from ..schemas.custom_http_exception import ( DatasetAccessError, ResourceNotFoundError, @@ -39,6 +40,7 @@ PropertyToIndex, ValueType, DimensionType, + PrecomputedAssociation, ) from breadbox.crud.group import ( get_group, @@ -1202,9 +1204,24 @@ def update_dataset( def delete_dataset( db: SessionWithUser, user: str, dataset: Dataset, filestore_location: str ): + from .associations import delete_association_table + if not user_has_access_to_group(dataset.group, user, write_access=True): return False + log.info("delete any referenced precomputed associations") + for associations in ( + db.query(PrecomputedAssociation) + .filter( + or_( + PrecomputedAssociation.dataset_1_id == dataset.id, + PrecomputedAssociation.dataset_2_id == dataset.id, + ) + ) + .all() + ): + delete_association_table(db, associations.id, filestore_location) + log.info("delete Dimension") db.query(Dimension).filter(Dimension.dataset_id == dataset.id).delete() log.info("delete_dataset %s delete dataset itself", dataset.id) diff --git a/breadbox/breadbox/schemas/associations.py b/breadbox/breadbox/schemas/associations.py index fd78c5a1..8d66e89e 100644 --- a/breadbox/breadbox/schemas/associations.py +++ b/breadbox/breadbox/schemas/associations.py @@ -36,5 +36,8 @@ class AssociationsIn(BaseModel): class AssociationTable(BaseModel): id: str + dataset_1_name: str + dataset_2_name: str + axis: Literal["sample", "feature"] dataset_1_id: str dataset_2_id: str