Skip to content

Commit d54beff

Browse files
authored
fix(filter): return leaf unchanged for non-shiftable operator (#333)
1 parent 888ffd3 commit d54beff

File tree

2 files changed

+94
-12
lines changed
  • src/datasource_toolkit

2 files changed

+94
-12
lines changed

src/datasource_toolkit/forestadmin/datasource_toolkit/interfaces/query/filter/factory.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def __replace(leaf: ConditionTree) -> ConditionTree:
4545
leaf = cast(ConditionTreeLeaf, leaf)
4646
time_transform = time_transforms(1)
4747
if leaf.operator not in SHIFTED_OPERATORS:
48-
raise FilterFactoryException(f"'{leaf.operator}' is not shiftable ")
48+
return leaf
4949

5050
alternative: Alternative = time_transform[leaf.operator][0]
5151
leaf = alternative["replacer"](leaf, tz)

src/datasource_toolkit/tests/interfaces/query/filter/test_factory.py

Lines changed: 93 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,25 @@
1010
import pytest
1111
from forestadmin.agent_toolkit.utils.context import User
1212
from forestadmin.datasource_toolkit.collections import Collection
13-
from forestadmin.datasource_toolkit.interfaces.fields import FieldType, ManyToMany, Operator
14-
from forestadmin.datasource_toolkit.interfaces.query.condition_tree.nodes.branch import Aggregator, ConditionTreeBranch
15-
from forestadmin.datasource_toolkit.interfaces.query.condition_tree.nodes.leaf import ConditionTreeLeaf
16-
from forestadmin.datasource_toolkit.interfaces.query.filter.factory import FilterFactory, FilterFactoryException
17-
from forestadmin.datasource_toolkit.interfaces.query.filter.paginated import PaginatedFilter
13+
from forestadmin.datasource_toolkit.interfaces.fields import (
14+
FieldType,
15+
ManyToMany,
16+
Operator,
17+
)
18+
from forestadmin.datasource_toolkit.interfaces.query.condition_tree.nodes.branch import (
19+
Aggregator,
20+
ConditionTreeBranch,
21+
)
22+
from forestadmin.datasource_toolkit.interfaces.query.condition_tree.nodes.leaf import (
23+
ConditionTreeLeaf,
24+
)
25+
from forestadmin.datasource_toolkit.interfaces.query.filter.factory import (
26+
FilterFactory,
27+
FilterFactoryException,
28+
)
29+
from forestadmin.datasource_toolkit.interfaces.query.filter.paginated import (
30+
PaginatedFilter,
31+
)
1832
from forestadmin.datasource_toolkit.interfaces.query.filter.unpaginated import Filter
1933
from forestadmin.datasource_toolkit.interfaces.query.projections import Projection
2034

@@ -38,15 +52,75 @@ def test_shift_period_filter(mock_time_transform: mock.MagicMock):
3852
mock_replacer = mock.MagicMock(return_value="fake_replacer")
3953
mock_time_transform.return_value = {Operator.PREVIOUS_YEAR: [{"replacer": mock_replacer}]}
4054
with mock.patch(
41-
"forestadmin.datasource_toolkit.interfaces.query.filter.factory.SHIFTED_OPERATORS", {Operator.PREVIOUS_YEAR}
55+
"forestadmin.datasource_toolkit.interfaces.query.filter.factory.SHIFTED_OPERATORS",
56+
{Operator.PREVIOUS_YEAR},
4257
):
4358
assert shift_period_filter_replacer(leaf) == "fake_replacer"
4459
mock_time_transform.assert_called_once_with(1)
4560
mock_replacer.assert_called_once_with(leaf, "UTC")
4661

47-
with mock.patch("forestadmin.datasource_toolkit.interfaces.query.filter.factory.SHIFTED_OPERATORS", {}):
48-
with pytest.raises(FilterFactoryException):
49-
shift_period_filter_replacer(leaf)
62+
with mock.patch(
63+
"forestadmin.datasource_toolkit.interfaces.query.filter.factory.SHIFTED_OPERATORS",
64+
{},
65+
):
66+
assert shift_period_filter_replacer(leaf) == leaf
67+
68+
69+
@mock.patch("forestadmin.datasource_toolkit.interfaces.query.filter.factory.time_transforms")
70+
def test_shift_period_filter_with_complex_condition_tree(
71+
mock_time_transform: mock.MagicMock,
72+
):
73+
tz = zoneinfo.ZoneInfo("UTC")
74+
shift_period_filter_replacer = FilterFactory._shift_period_filter(tz)
75+
76+
leaf_previous_year = ConditionTreeLeaf(field="date_field", operator=Operator.PREVIOUS_YEAR)
77+
leaf_equal = ConditionTreeLeaf(field="name", operator=Operator.EQUAL, value="test")
78+
leaf_greater_than = ConditionTreeLeaf(field="age", operator=Operator.GREATER_THAN, value=18)
79+
leaf_previous_month = ConditionTreeLeaf(field="created_at", operator=Operator.PREVIOUS_MONTH)
80+
81+
mock_replacer_year = mock.MagicMock(
82+
return_value=ConditionTreeLeaf(field="date_field", operator=Operator.EQUAL, value="replaced_year")
83+
)
84+
mock_replacer_month = mock.MagicMock(
85+
return_value=ConditionTreeLeaf(field="created_at", operator=Operator.EQUAL, value="replaced_month")
86+
)
87+
88+
mock_time_transform.return_value = {
89+
Operator.PREVIOUS_YEAR: [{"replacer": mock_replacer_year}],
90+
Operator.PREVIOUS_MONTH: [{"replacer": mock_replacer_month}],
91+
}
92+
93+
with mock.patch(
94+
"forestadmin.datasource_toolkit.interfaces.query.filter.factory.SHIFTED_OPERATORS",
95+
{Operator.PREVIOUS_YEAR, Operator.PREVIOUS_MONTH},
96+
):
97+
complex_tree = ConditionTreeBranch(
98+
aggregator=Aggregator.AND,
99+
conditions=[
100+
leaf_previous_year,
101+
leaf_equal,
102+
leaf_greater_than,
103+
leaf_previous_month,
104+
],
105+
)
106+
107+
result = complex_tree.replace(shift_period_filter_replacer)
108+
109+
mock_replacer_year.assert_called_once_with(leaf_previous_year, tz)
110+
mock_replacer_month.assert_called_once_with(leaf_previous_month, tz)
111+
112+
assert isinstance(result, ConditionTreeBranch)
113+
assert result.aggregator == Aggregator.AND
114+
assert len(result.conditions) == 4
115+
116+
assert result.conditions[0] == ConditionTreeLeaf(
117+
field="date_field", operator=Operator.EQUAL, value="replaced_year"
118+
)
119+
assert result.conditions[1] == leaf_equal # EQUAL should remain unchanged
120+
assert result.conditions[2] == leaf_greater_than # GREATER_THAN should remain unchanged
121+
assert result.conditions[3] == ConditionTreeLeaf(
122+
field="created_at", operator=Operator.EQUAL, value="replaced_month"
123+
)
50124

51125

52126
@mock.patch("forestadmin.datasource_toolkit.interfaces.query.filter.factory.FilterFactory._shift_period_filter")
@@ -106,7 +180,11 @@ async def test_make_through_filter():
106180

107181
mock_collection = mock.MagicMock()
108182
mock_collection.list = mock.AsyncMock(return_value=[{"id": 1}])
109-
with mock.patch.object(collection.datasource, "get_collection", return_value=mock_collection):
183+
with mock.patch.object(
184+
collection.datasource,
185+
"get_collection",
186+
return_value=mock_collection,
187+
):
110188
res = await FilterFactory.make_through_filter(
111189
mocked_caller,
112190
collection,
@@ -182,7 +260,11 @@ async def test_make_through_filter():
182260
Aggregator.AND,
183261
conditions=[
184262
ConditionTreeLeaf("child_id", Operator.EQUAL, "fake_value"),
185-
ConditionTreeLeaf("parent_id", Operator.IN, ["fake_record_1", "fake_record_2"]),
263+
ConditionTreeLeaf(
264+
"parent_id",
265+
Operator.IN,
266+
["fake_record_1", "fake_record_2"],
267+
),
186268
],
187269
)
188270
}

0 commit comments

Comments
 (0)