Skip to content

Commit 970ccc8

Browse files
author
Robert Segal
committed
Added render() as queryable mixin
1 parent baca528 commit 970ccc8

File tree

6 files changed

+81
-0
lines changed

6 files changed

+81
-0
lines changed

mpt_api_client/http/mixins/queryable_mixin.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def order_by(self, *fields: str) -> Self:
2323
rql=self.query_state.filter, # type: ignore[attr-defined]
2424
order_by=list(fields),
2525
select=self.query_state.select, # type: ignore[attr-defined]
26+
with_render=self.query_state.with_render, # type: ignore[attr-defined]
2627
)
2728
)
2829

@@ -39,6 +40,7 @@ def filter(self, rql: RQLQuery) -> Self:
3940
rql=combined_filter,
4041
order_by=self.query_state.order_by, # type: ignore[attr-defined]
4142
select=self.query_state.select, # type: ignore[attr-defined]
43+
with_render=self.query_state.with_render, # type: ignore[attr-defined]
4244
)
4345
)
4446

@@ -60,6 +62,22 @@ def select(self, *fields: str) -> Self:
6062
rql=self.query_state.filter, # type: ignore[attr-defined]
6163
order_by=self.query_state.order_by, # type: ignore[attr-defined]
6264
select=list(fields),
65+
with_render=self.query_state.with_render, # type: ignore[attr-defined]
66+
),
67+
)
68+
69+
def with_render(self) -> Self:
70+
"""Set render state.
71+
72+
Returns:
73+
New copy of the collection with render() added to the query.
74+
"""
75+
return self._create_new_instance(
76+
QueryState(
77+
rql=self.query_state.filter, # type: ignore[attr-defined]
78+
order_by=self.query_state.order_by, # type: ignore[attr-defined]
79+
select=self.query_state.select, # type: ignore[attr-defined]
80+
with_render=True,
6381
),
6482
)
6583

mpt_api_client/http/query_state.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,21 @@ def __init__(
1717
rql: RQLQuery | None = None,
1818
order_by: list[str] | None = None,
1919
select: list[str] | None = None,
20+
*,
21+
with_render: bool = False,
2022
) -> None:
2123
"""Initialize the query state with optional filter, ordering, and selection criteria.
2224
2325
Args:
2426
rql: RQL query for filtering data.
2527
order_by: List of fields to order by (prefix with '-' for descending).
2628
select: List of fields to select in the response.
29+
with_render: Whether to include the render() parameter in the query string.
2730
"""
2831
self._filter = rql
2932
self._order_by = order_by
3033
self._select = select
34+
self._with_render = with_render
3135

3236
@property
3337
def filter(self) -> RQLQuery | None:
@@ -44,6 +48,11 @@ def select(self) -> list[str] | None:
4448
"""Get the current select fields."""
4549
return self._select
4650

51+
@property
52+
def with_render(self) -> bool:
53+
"""Get the current render state."""
54+
return self._with_render
55+
4756
def build(self, query_params: dict[str, Any] | None = None) -> str:
4857
"""Build a query string from the current state and additional parameters.
4958
@@ -66,7 +75,11 @@ def build(self, query_params: dict[str, Any] | None = None) -> str:
6675
if self._filter:
6776
query_parts.append(str(self._filter))
6877

78+
if self._with_render:
79+
query_parts.append("render()")
80+
6981
if query_parts:
7082
query = "&".join(query_parts)
7183
return f"{query}"
84+
7285
return ""

tests/e2e/audit/records/test_async_records.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,14 @@ async def test_get_record_not_found(async_mpt_vendor: AsyncMPTClient) -> None:
4242

4343
with pytest.raises(MPTAPIError):
4444
await service.get("REC-000-000-000")
45+
46+
47+
async def test_get_records_with_render(async_mpt_vendor: AsyncMPTClient, product_id: str) -> None:
48+
template_chars = ["{{", "}}"]
49+
service = async_mpt_vendor.audit.records.filter(RQLQuery(object__id=product_id)).with_render()
50+
records = [record async for record in service.iterate()]
51+
52+
result = records[0]
53+
54+
assert result.object.id == product_id
55+
assert not any(char in result.details for char in template_chars)

tests/e2e/audit/records/test_sync_records.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,14 @@ def test_get_record_not_found(mpt_vendor: MPTClient) -> None:
4343

4444
with pytest.raises(MPTAPIError):
4545
service.get("REC-000-000-000")
46+
47+
48+
def test_get_records_with_render(mpt_vendor: MPTClient, product_id) -> None:
49+
template_chars = ["{{", "}}"]
50+
service = mpt_vendor.audit.records.filter(RQLQuery(object__id=product_id)).with_render()
51+
records = list(service.iterate())
52+
53+
result = records[0]
54+
55+
assert result.object.id == product_id
56+
assert not any(char in result.details for char in template_chars)

tests/unit/http/mixins/test_queryable_mixin.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,12 @@ def test_queryable_mixin_method_chaining(
7878
assert result.query_state.filter == filter_status_active
7979
assert result.query_state.order_by == ["created", "-name"]
8080
assert result.query_state.select == ["id", "name"]
81+
82+
83+
def test_queryable_mixin_with_render(dummy_service: DummyService) -> None:
84+
result = dummy_service.with_render()
85+
86+
assert result != dummy_service
87+
assert not dummy_service.query_state.with_render
88+
assert result.query_state.with_render
89+
assert result.select("id").query_state.with_render

tests/unit/http/test_query_state.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def test_build_url(filter_status_active):
2323
rql=filter_status_active,
2424
select=["-audit", "product.agreements", "-product.agreements.product"],
2525
order_by=["-created", "name"],
26+
with_render=False,
2627
)
2728

2829
result = query_state.build()
@@ -34,6 +35,24 @@ def test_build_url(filter_status_active):
3435
)
3536

3637

38+
def test_build_url_with_render(filter_status_active):
39+
query_state = QueryState(
40+
rql=filter_status_active,
41+
select=["-audit", "product.agreements", "-product.agreements.product"],
42+
order_by=["-created", "name"],
43+
with_render=True,
44+
)
45+
46+
result = query_state.build()
47+
48+
assert result == (
49+
"order=-created,name"
50+
"&select=-audit,product.agreements,-product.agreements.product"
51+
"&eq(status,'active')"
52+
"&render()"
53+
)
54+
55+
3756
def test_empty_build(query_state):
3857
result = query_state.build()
3958

0 commit comments

Comments
 (0)