Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 69 additions & 1 deletion pydatalab/src/pydatalab/routes/v0_1/items.py
Original file line number Diff line number Diff line change
Expand Up @@ -808,9 +808,30 @@ def update_item_permissions(refcode: str):

@ITEMS.route("/delete-sample/", methods=["POST"])
def delete_sample():
request_json = request.get_json() # noqa: F821 pylint: disable=undefined-variable
request_json = request.get_json()
item_id = request_json["item_id"]

item_to_delete = flask_mongo.db.items.find_one(
{"item_id": item_id, **get_default_permissions(user_only=True, deleting=True)},
projection={"refcode": 1, "_id": 1, "name": 1, "chemform": 1},
)

if not item_to_delete:
return (
jsonify(
{
"status": "error",
"message": f"Authorization required to attempt to delete sample with {item_id=} from the database.",
}
),
401,
)

refcode = item_to_delete.get("refcode")
immutable_id = item_to_delete["_id"]
item_name = item_to_delete.get("name") or item_id
item_chemform = item_to_delete.get("chemform")

result = flask_mongo.db.items.delete_one(
{"item_id": item_id, **get_default_permissions(user_only=True, deleting=True)}
)
Expand All @@ -825,6 +846,53 @@ def delete_sample():
),
401,
)

flask_mongo.db.items.update_many(
{"relationships.item_id": item_id}, {"$pull": {"relationships": {"item_id": item_id}}}
)

if refcode:
flask_mongo.db.items.update_many(
{"relationships.refcode": refcode}, {"$pull": {"relationships": {"refcode": refcode}}}
)

flask_mongo.db.items.update_many(
{"relationships.immutable_id": immutable_id},
{"$pull": {"relationships": {"immutable_id": immutable_id}}},
)

inline_item = {"name": item_name}
if item_chemform:
inline_item["chemform"] = item_chemform

items_with_constituent = flask_mongo.db.items.find(
{
"$or": [
{"synthesis_constituents.item.item_id": item_id},
{"synthesis_constituents.item.refcode": refcode},
{"synthesis_constituents.item.immutable_id": immutable_id},
]
}
)

for item in items_with_constituent:
updated_constituents = []
for constituent in item.get("synthesis_constituents", []):
constituent_item = constituent.get("item", {})

if (
constituent_item.get("item_id") == item_id
or constituent_item.get("refcode") == refcode
or constituent_item.get("immutable_id") == immutable_id
):
constituent["item"] = inline_item.copy()

updated_constituents.append(constituent)

flask_mongo.db.items.update_one(
{"_id": item["_id"]}, {"$set": {"synthesis_constituents": updated_constituents}}
)

return (
jsonify(
{
Expand Down
58 changes: 58 additions & 0 deletions pydatalab/tests/server/test_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,61 @@ def test_simple_graph(admin_client):
graph = admin_client.get("/item-graph/parent").json
assert len(graph["nodes"]) == 6
assert len(graph["edges"]) == 5


def test_delete_item_cleans_relationships_and_constituents(admin_client):
"""Test that deleting an item removes relationships and transforms synthesis_constituents to inline."""

parent = Sample(item_id="parent_to_delete", name="Test Parent", chemform="NaCl")
response = admin_client.post(
"/new-sample/",
json={"new_sample_data": json.loads(parent.json())},
)
assert response.status_code == 201

child = Sample(
item_id="child_with_constituent",
synthesis_constituents=[
Constituent(item={"type": "samples", "item_id": "parent_to_delete"}, quantity=5.0)
],
)
response = admin_client.post(
"/new-sample/",
json={"new_sample_data": json.loads(child.json())},
)
assert response.status_code == 201

response = admin_client.get("/get-item-data/child_with_constituent")
assert response.status_code == 200
assert "parent_to_delete" in response.json["parent_items"]
relationships = response.json["item_data"]["relationships"]
assert any(r.get("item_id") == "parent_to_delete" for r in relationships)

constituents = response.json["item_data"]["synthesis_constituents"]
assert len(constituents) == 1
assert constituents[0]["item"]["item_id"] == "parent_to_delete"
assert constituents[0]["item"]["type"] == "samples"

response = admin_client.post("/delete-sample/", json={"item_id": "parent_to_delete"})
assert response.status_code == 200

response = admin_client.get("/get-item-data/child_with_constituent")
assert response.status_code == 200
assert "parent_to_delete" not in response.json["parent_items"]
relationships = response.json["item_data"]["relationships"]
assert not any(r.get("item_id") == "parent_to_delete" for r in relationships)

constituents = response.json["item_data"]["synthesis_constituents"]
assert len(constituents) == 1
constituent_item = constituents[0]["item"]
assert constituent_item["name"] == "Test Parent"
assert constituent_item["chemform"] == "NaCl"
assert "item_id" not in constituent_item
assert "refcode" not in constituent_item
assert "type" not in constituent_item
assert "immutable_id" not in constituent_item

graph = admin_client.get("/item-graph/child_with_constituent").json
assert graph["status"] == "success"
assert len(graph["nodes"]) == 1
assert graph["nodes"][0]["data"]["id"] == "child_with_constituent"