Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/adding mset replacement functionality 20210615 #445

Open
wants to merge 65 commits into
base: develop
Choose a base branch
from

Conversation

cschu
Copy link
Contributor

@cschu cschu commented Jun 15, 2021

No description provided.

Copy link
Member

@lkuchenb lkuchenb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
reason = Column(String(140), nullable=False)
label = Column(String(140), nullable=False)

datameta/api/metadatasets.py Outdated Show resolved Hide resolved
Comment on lines 156 to 157
if replaces and not replaces_label:
return HTTPBadRequest()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Comment on lines 189 to 190
if target_mset is None:
raise HTTPForbidden()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The invalid replacement IDs should be collected and returned as a validation error

Copy link
Member

@lkuchenb lkuchenb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Generally looking good, comments below.

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."])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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."])

@@ -279,7 +311,7 @@ def get_metadatasets(request: Request) -> List[MetaDataSetResponse]:
query = query.filter(Submission.date < submitted_before.astimezone(timezone.utc))
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'])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment on lines 199 to 200
for _, target_mset in msets:
target_mset.replaced_via_event_id = mset_repl_evt.id
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

if missing_msets:
messages, entities = zip(*missing_msets)
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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

@@ -220,7 +220,7 @@ def replace_metadatasets(request: Request) -> SubmissionResponse:

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

zip() returns tuples, not lists

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that i know :P but why does it not complain in validation.py, line 63, which also uses zip-derived values for the arguments?

Copy link
Member

@lkuchenb lkuchenb Jul 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea. But we should probably not be so strict about the argument type in errors.get_validation_error and relax it to Iterable

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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))

@cschu
Copy link
Contributor Author

cschu commented Jul 7, 2021

The breaking test fixed via 0289f2a is probably due to something I don't understand regarding the fixtures.

Copy link
Member

@lkuchenb lkuchenb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot, also for already incorporating the visualization of the replacements in the "View" pane!

Here are my remarks:

datameta/api/openapi.yaml Outdated Show resolved Hide resolved
datameta/api/users.py Outdated Show resolved Hide resolved
datameta/models/db.py Outdated Show resolved Hide resolved
@@ -220,7 +220,7 @@ def replace_metadatasets(request: Request) -> SubmissionResponse:

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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))

tests/integration/test_bulkdelete.py Outdated Show resolved Hide resolved
datameta/api/metadatasets.py Outdated Show resolved Hide resolved
datameta/api/openapi.yaml Outdated Show resolved Hide resolved
@@ -224,6 +224,7 @@ def post(request: Request):
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
Copy link
Member

@lkuchenb lkuchenb Aug 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

datameta/static/js/view.js Outdated Show resolved Hide resolved
datameta/static/js/view.js Outdated Show resolved Hide resolved
@ckaipf
Copy link
Contributor

ckaipf commented Feb 3, 2023

I tried to merge it yesterday, only some minor conflicts arose.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants