Skip to content

Remove unused parent and child relationships from API/store #1126

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

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
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
2 changes: 1 addition & 1 deletion pydatalab/schemas/sample.json
Original file line number Diff line number Diff line change
Expand Up @@ -614,4 +614,4 @@
]
}
}
}
}
72 changes: 7 additions & 65 deletions pydatalab/src/pydatalab/routes/v0_1/items.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
from pydatalab.models import ITEM_MODELS
from pydatalab.models.items import Item
from pydatalab.models.people import Person
from pydatalab.models.relationships import RelationshipType
from pydatalab.models.utils import generate_unique_refcode
from pydatalab.mongo import ITEMS_FTS_FIELDS, flask_mongo
from pydatalab.permissions import PUBLIC_USER_ID, active_users_or_get_only, get_default_permissions
Expand Down Expand Up @@ -884,11 +883,7 @@ def get_item_data(
except IndexError:
doc = None

if not doc or (
not current_user.is_authenticated
and not CONFIG.TESTING
and doc["type"] != "starting_materials"
):
if not doc:
return (
jsonify(
{
Expand All @@ -903,68 +898,17 @@ def get_item_data(
try:
ItemModel = ITEM_MODELS[doc["type"]]
except KeyError:
if "type" in doc:
raise KeyError(f"Item {item_id=} has invalid type: {doc['type']}")
else:
raise KeyError(f"Item {item_id=} has no type field in document.")
raise KeyError(f"{item_id=} has invalid type: {doc.get('type')}")

# Load database document into item model to run all validation and
# setting of any missing default values
doc = ItemModel(**doc)

# If the request asked to load blocks, loop through `display_order` and
# run the block lifecycle routines, eventually returning JSON
if load_blocks:
doc.blocks_obj = reserialize_blocks(doc.display_order, doc.blocks_obj)

# find any documents with relationships that mention this document
relationships_query_results = flask_mongo.db.items.find(
filter={
"$or": [
{"relationships.item_id": doc.item_id},
{"relationships.refcode": doc.refcode},
{"relationships.immutable_id": doc.immutable_id},
]
},
projection={
"item_id": 1,
"refcode": 1,
"relationships": {
"$elemMatch": {
"$or": [
{"item_id": doc.item_id},
{"refcode": doc.refcode},
],
},
},
},
)

# loop over and collect all 'outer' relationships presented by other items
incoming_relationships: dict[RelationshipType, set[str]] = {}
for d in relationships_query_results:
for k in d["relationships"]:
if k["relation"] not in incoming_relationships:
incoming_relationships[k["relation"]] = set()
incoming_relationships[k["relation"]].add(
d["item_id"] or d["refcode"] or d["immutable_id"]
)

# loop over and aggregate all 'inner' relationships presented by this item
inlined_relationships: dict[RelationshipType, set[str]] = {}
if doc.relationships is not None:
inlined_relationships = {
relation: {
d.item_id or d.refcode or d.immutable_id
for d in doc.relationships
if d.relation == relation
}
for relation in RelationshipType
}

# reunite parents and children from both directions of the relationships field
parents = incoming_relationships.get(RelationshipType.CHILD, set()).union(
inlined_relationships.get(RelationshipType.PARENT, set())
)
children = incoming_relationships.get(RelationshipType.PARENT, set()).union(
inlined_relationships.get(RelationshipType.CHILD, set())
)

# Must be exported to JSON first to apply the custom pydantic JSON encoders
return_dict = json.loads(doc.json(exclude_unset=True))

Expand All @@ -982,8 +926,6 @@ def get_item_data(
"item_id": item_id,
"item_data": return_dict,
"files_data": files_data,
"child_items": sorted(children),
"parent_items": sorted(parents),
}
)

Expand Down
24 changes: 3 additions & 21 deletions pydatalab/tests/server/test_samples.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,12 +258,6 @@ def test_new_sample_with_relationships(client, complicated_sample):
f"/get-item-data/{complicated_sample.item_id}",
)

assert response.json["parent_items"] == [
"starting_material_1",
"starting_material_2",
"starting_material_3",
]
assert response.json["child_items"] == []
assert [d["item_id"] for d in response.json["item_data"]["relationships"]] == [
"starting_material_1",
"starting_material_2",
Expand Down Expand Up @@ -309,12 +303,6 @@ def test_new_sample_with_relationships(client, complicated_sample):
)

assert len(response.json["item_data"]["synthesis_constituents"]) == 2
assert response.json["parent_items"] == [
"starting_material_1",
"starting_material_2",
# i.e., "starting_material_3", has been removed
]
assert response.json["child_items"] == []
assert [d.get("item_id") for d in response.json["item_data"]["relationships"]] == [
"starting_material_1",
"starting_material_2",
Expand Down Expand Up @@ -370,12 +358,12 @@ def test_saved_sample_has_new_relationships(client, default_sample_dict, complic
response = client.get(
f"/get-item-data/{default_sample_dict['item_id']}",
)
assert complicated_sample.item_id in response.json["parent_items"]

response = client.get(
f"/get-item-data/{complicated_sample.item_id}",
)
assert sample_dict["item_id"] in response.json["child_items"]
assert sample_dict["item_id"] in {
d["item"]["item_id"] for d in response.json["item_data"]["synthesis_constituents"]
}


@pytest.mark.dependency(depends=["test_saved_sample_has_new_relationships"])
Expand Down Expand Up @@ -406,12 +394,6 @@ def test_copy_from_sample(client, complicated_sample):
f"/get-item-data/{copy_doc['item_id']}",
)

assert response.json["parent_items"] == [
"starting_material_1",
"starting_material_2",
"starting_material_3",
]


@pytest.mark.dependency(depends=["test_copy_from_sample"])
def test_create_multiple_samples(client, complicated_sample):
Expand Down
117 changes: 0 additions & 117 deletions webapp/src/components/RelationshipVisualization.vue

This file was deleted.

4 changes: 0 additions & 4 deletions webapp/src/server_fetch_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -445,8 +445,6 @@ export async function getItemData(item_id) {
store.commit("createItemData", {
item_id: item_id,
item_data: response_json.item_data,
child_items: response_json.child_items,
parent_items: response_json.parent_items,
});

return "success";
Expand All @@ -461,8 +459,6 @@ export async function getItemByRefcode(refcode) {
refcode: refcode,
item_id: response_json.item_data.item_id,
item_data: response_json.item_data,
child_items: response_json.child_items,
parent_items: response_json.parent_items,
});
return "success";
})
Expand Down
7 changes: 1 addition & 6 deletions webapp/src/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,8 @@ export default createStore({
state: {
all_item_data: {}, // keys: item_ids, vals: objects containing all data
all_block_data: {},
all_item_children: {},
all_item_parents: {},
all_collection_data: {},
all_collection_children: {},
all_collection_parents: {},
refcode_to_id: {},
sample_list: null,
equipment_list: null,
Expand Down Expand Up @@ -165,10 +162,8 @@ export default createStore({
},
createItemData(state, payload) {
// payload should have the following fields:
// refcode, item_id, item_data, child_items, parent_items
// refcode, item_id, item_data
state.all_item_data[payload.item_id] = payload.item_data;
state.all_item_children[payload.item_id] = payload.child_items;
state.all_item_parents[payload.item_id] = payload.parent_items;
state.saved_status_items[payload.item_id] = true;
state.refcode_to_id[payload.refcode] = payload.item_id;
},
Expand Down
Loading