Skip to content
Snippets Groups Projects
Commit b83fd406 authored by Eva Bardou's avatar Eva Bardou :frog: Committed by Yoann Schneider
Browse files

Add an helper for the `CreateElementChildren` endpoint

parent f490c8d2
No related branches found
Tags 0.4.0b1
1 merge request!573Add an helper for the `CreateElementChildren` endpoint
Pipeline #185555 passed
......@@ -24,7 +24,12 @@ def pluralize(singular: str, count: int) -> str:
if count == 1:
return singular
some_exceptions = {"entity": "entities", "metadata": "metadata", "class": "classes"}
some_exceptions = {
"child": "children",
"class": "classes",
"entity": "entities",
"metadata": "metadata",
}
if singular in some_exceptions:
return some_exceptions[singular]
......
......@@ -3,6 +3,7 @@ ElementsWorker methods for elements and element types.
"""
from collections.abc import Iterable
from operator import attrgetter
from typing import NamedTuple
from uuid import UUID
from warnings import warn
......@@ -346,6 +347,52 @@ class ElementMixin:
child=child.id,
)
@unsupported_cache
@batch_publication
def create_element_children(
self,
parent: Element,
children: list[Element],
batch_size: int = DEFAULT_BATCH_SIZE,
) -> list[str]:
"""
Link multiple elements to a single parent through the API.
:param parent: Parent element.
:param children: A list of child elements.
:param batch_size: The size of each batch, which will be used to split the publication to avoid API errors.
:returns: A list containing the string UUID of each child linked to the parent.
"""
assert parent and isinstance(
parent, Element
), "parent shouldn't be null and should be of type Element"
assert children and isinstance(
children, list
), "children shouldn't be null and should be of type list"
for index, child in enumerate(children):
assert isinstance(
child, Element
), f"Child at index {index} in children: Should be of type Element"
if self.is_read_only:
logger.warning("Cannot link elements as this worker is in read-only mode")
return
return [
child_id
for batch in make_batches(children, "child", batch_size)
for child_id in self.api_client.request(
"CreateElementChildren",
id=parent.id,
body={
"children": list(map(attrgetter("id"), batch)),
},
)["children"]
]
def partial_update_element(
self, element: Element | CachedElement, **kwargs
) -> dict:
......
......@@ -1500,6 +1500,139 @@ def test_create_element_parent(responses, mock_elements_worker):
}
@pytest.mark.parametrize(
("arg_name", "data", "error_message"),
[
(
"parent",
None,
"parent shouldn't be null and should be of type Element",
),
(
"parent",
"not element type",
"parent shouldn't be null and should be of type Element",
),
(
"children",
None,
"children shouldn't be null and should be of type list",
),
(
"children",
"not a list",
"children shouldn't be null and should be of type list",
),
(
"children",
[
Element({"id": "11111111-1111-1111-1111-111111111111"}),
"not element type",
],
"Child at index 1 in children: Should be of type Element",
),
],
)
def test_create_element_children_wrong_params(
arg_name, data, error_message, mock_elements_worker
):
with pytest.raises(AssertionError, match=error_message):
mock_elements_worker.create_element_children(
**{
"parent": Element({"id": "12341234-1234-1234-1234-123412341234"}),
"children": [
Element({"id": "11111111-1111-1111-1111-111111111111"}),
Element({"id": "22222222-2222-2222-2222-222222222222"}),
],
# Overwrite with wrong data
arg_name: data,
},
)
def test_create_element_children_api_error(responses, mock_elements_worker):
parent = Element({"id": "12341234-1234-1234-1234-123412341234"})
responses.add(
responses.POST,
f"http://testserver/api/v1/element/parent/{parent.id}/",
status=418,
)
with pytest.raises(ErrorResponse):
mock_elements_worker.create_element_children(
parent=parent,
children=[
Element({"id": "11111111-1111-1111-1111-111111111111"}),
Element({"id": "22222222-2222-2222-2222-222222222222"}),
],
)
assert len(responses.calls) == len(BASE_API_CALLS) + 1
assert [
(call.request.method, call.request.url) for call in responses.calls
] == BASE_API_CALLS + [
(
"POST",
f"http://testserver/api/v1/element/parent/{parent.id}/",
)
]
@pytest.mark.parametrize("batch_size", [DEFAULT_BATCH_SIZE, 1])
def test_create_element_children(batch_size, responses, mock_elements_worker):
parent = Element({"id": "12341234-1234-1234-1234-123412341234"})
first_child = Element({"id": "11111111-1111-1111-1111-111111111111"})
second_child = Element({"id": "22222222-2222-2222-2222-222222222222"})
responses.add(
responses.POST,
f"http://testserver/api/v1/element/parent/{parent.id}/",
status=200,
json={"children": []},
)
mock_elements_worker.create_element_children(
parent=parent,
children=[first_child, second_child],
batch_size=batch_size,
)
bulk_api_calls = [
(
"POST",
f"http://testserver/api/v1/element/parent/{parent.id}/",
)
]
if batch_size != DEFAULT_BATCH_SIZE:
bulk_api_calls.append(
(
"POST",
f"http://testserver/api/v1/element/parent/{parent.id}/",
)
)
assert len(responses.calls) == len(BASE_API_CALLS) + len(bulk_api_calls)
assert [
(call.request.method, call.request.url) for call in responses.calls
] == BASE_API_CALLS + bulk_api_calls
bodies = []
first_call_idx = None
if batch_size > 1:
first_call_idx = -1
bodies.append({"children": [first_child.id, second_child.id]})
else:
first_call_idx = -2
bodies.append({"children": [first_child.id]})
bodies.append({"children": [second_child.id]})
assert [
json.loads(bulk_call.request.body)
for bulk_call in responses.calls[first_call_idx:]
] == bodies
@pytest.mark.parametrize(
("payload", "error"),
[
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment