Feature/adding mset replacement functionality 20210615#445
Feature/adding mset replacement functionality 20210615#445
Conversation
lkuchenb
left a comment
There was a problem hiding this comment.
Thanks!
I don't think this would work yet, replaced_msets is joining MSetReplacementEvent with MetadataSet based on metadataset_id which is referring to the new metadataset rather than the old metadataset_s_.
The MetaDataSet class will need an attribute
MetaDataSet.replaced_by_event_id # foreign key
MetaDataSet.replaced_by_event # relationship
which refers to the replacement event if it was replaced. To be able to access also the replacement events in which a metadataset is in the "new" role there should also be a relationship attribute
MetaDataSet.replaces_event # relationship
based on MsetReplacementEvent.metadataset_id. Maybe that attribute should also be renamed to new_metadataset_id to make immediately clear which role the foreign entity linked here has.
datameta/models/db.py
Outdated
| user_id = Column(Integer, ForeignKey('users.id'), nullable=False) | ||
| datetime = Column(DateTime, nullable=False) | ||
| # former 'is_deprecated' label from MetaDataSet | ||
| reason = Column(String(140), nullable=False) |
There was a problem hiding this comment.
| reason = Column(String(140), nullable=False) | |
| label = Column(String(140), nullable=False) |
datameta/api/metadatasets.py
Outdated
| if replaces and not replaces_label: | ||
| return HTTPBadRequest() |
There was a problem hiding this comment.
Please return a proper validation error with a message. Also the inverse case should be checked and fail with a proper message (I mean the case label specified without any replacements to make)
datameta/api/metadatasets.py
Outdated
| if target_mset is None: | ||
| raise HTTPForbidden() |
There was a problem hiding this comment.
The invalid replacement IDs should be collected and returned as a validation error
lkuchenb
left a comment
There was a problem hiding this comment.
Thanks! Generally looking good, comments below.
datameta/api/metadatasets.py
Outdated
| if replaces and not replaces_label: | ||
| raise errors.get_validation_error(messages=['No reason (label) given for Metadataset replacement.']) # maybe label should be reason. | ||
| if not replaces and replaces_label: | ||
| raise errors.get_validation_error(messages=["No metadataset ids specified (replacement reason (label) is given."]) |
There was a problem hiding this comment.
| raise errors.get_validation_error(messages=["No metadataset ids specified (replacement reason (label) is given."]) | |
| raise errors.get_validation_error(messages=["No metadataset IDs specified (replacement reason (label) is given."]) |
| if awaiting_service is not None: | ||
| if awaiting_service not in readable_services_by_id: | ||
| raise errors.get_validation_error(messages=['Invalid service ID specified'], fields=['awaitingServices']) | ||
| raise errors.get_validation_error(messages=['Invalid service ID specified'], fields=['awaitingService']) |
datameta/api/metadatasets.py
Outdated
| for _, target_mset in msets: | ||
| target_mset.replaced_via_event_id = mset_repl_evt.id |
There was a problem hiding this comment.
This requires checking whether replaced_via_event_id was previously set. Only if it is None, a replacement is legal. Otherwise, a validation error should be returned.
datameta/api/metadatasets.py
Outdated
| raise errors.get_validation_error(messages=messages, entities=entities) | ||
|
|
||
| already_replaced = [ | ||
| (f"MetaDataSet was already replaced via event {target_mset.replaced_via_event_id}", mset_id) |
There was a problem hiding this comment.
This exposes an internal database ID. Also, I'd hide the event logic to the user and rather print the ID of the new mset (get_identifier).
datameta/api/metadatasets.py
Outdated
| if missing_msets: | ||
| messages, entities = zip(*missing_msets) | ||
| raise errors.get_validation_error(messages=list(messages), entities=list(entities)) | ||
| raise errors.get_validation_error(messages=list(messages), entities=list(entities)) # @lkuchenb: any idea why these list-casts are necessary to please mypy? they're not required in e.g validation.py:63 |
There was a problem hiding this comment.
zip() returns tuples, not lists
There was a problem hiding this comment.
that i know :P but why does it not complain in validation.py, line 63, which also uses zip-derived values for the arguments?
There was a problem hiding this comment.
No idea. But we should probably not be so strict about the argument type in errors.get_validation_error and relax it to Iterable
There was a problem hiding this comment.
| raise errors.get_validation_error(messages=list(messages), entities=list(entities)) # @lkuchenb: any idea why these list-casts are necessary to please mypy? they're not required in e.g validation.py:63 | |
| raise errors.get_validation_error(messages=list(messages), entities=list(entities)) |
|
The breaking test fixed via 0289f2a is probably due to something I don't understand regarding the fixtures. |
lkuchenb
left a comment
There was a problem hiding this comment.
Thanks a lot, also for already incorporating the visualization of the replacements in the "View" pane!
Here are my remarks:
datameta/api/metadatasets.py
Outdated
| if missing_msets: | ||
| messages, entities = zip(*missing_msets) | ||
| raise errors.get_validation_error(messages=list(messages), entities=list(entities)) | ||
| raise errors.get_validation_error(messages=list(messages), entities=list(entities)) # @lkuchenb: any idea why these list-casts are necessary to please mypy? they're not required in e.g validation.py:63 |
There was a problem hiding this comment.
| raise errors.get_validation_error(messages=list(messages), entities=list(entities)) # @lkuchenb: any idea why these list-casts are necessary to please mypy? they're not required in e.g validation.py:63 | |
| raise errors.get_validation_error(messages=list(messages), entities=list(entities)) |
| submission_datetime = mdata_set.submission.date.isoformat(), | ||
| submission_label = mdata_set.submission.label, | ||
| service_executions = service_executions, | ||
| replaced_by = get_identifier(mdata_set.replaced_via_event.new_metadataset) if mdata_set.replaced_via_event else None |
There was a problem hiding this comment.
This will fire two additional queries for every mdata_set, first when accessing the replaced_via_event attribute, then when accessing the new_metadataset attribute. Since we know we will be accessing those fields, we can instruct SQLAlchemy not to use lazy loading, but to join the corresponding relations already when we query the mdata_sets. Please add the corresponding joins in L177.
Co-authored-by: Leon Kuchenbecker <leon.kuchenbecker@uni-tuebingen.de>
|
I tried to merge it yesterday, only some minor conflicts arose. |
No description provided.