From 4e64502eebcd88bc67b34e05a749c2a3239d52ea Mon Sep 17 00:00:00 2001 From: Pierre Merlet Date: Thu, 9 Oct 2025 17:00:23 +0200 Subject: [PATCH 1/3] fix(get_records_ids): exclude filters when getting the ids if all_records is false --- .../resources/collections/filter.py | 9 ++- .../tests/resources/actions/test_resources.py | 75 +++++++++++++++++++ 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/src/agent_toolkit/forestadmin/agent_toolkit/resources/collections/filter.py b/src/agent_toolkit/forestadmin/agent_toolkit/resources/collections/filter.py index e01c460bb..8377372c5 100644 --- a/src/agent_toolkit/forestadmin/agent_toolkit/resources/collections/filter.py +++ b/src/agent_toolkit/forestadmin/agent_toolkit/resources/collections/filter.py @@ -76,9 +76,12 @@ def _all_records_subset_query(request: Request) -> Dict[str, Any]: def _subset_or_query(request: Request, key: str) -> Optional[str]: res = None if request.body: - sub_res = _all_records_subset_query(request).get(key) - if sub_res: - res = str(sub_res) + # Only use all_records_subset_query when all_records is true + attributes = request.body.get("data", {}).get("attributes", {}) + if attributes.get("all_records", False): + sub_res = _all_records_subset_query(request).get(key) + if sub_res: + res = str(sub_res) if not res and request.query: res = request.query.get(key) if res: diff --git a/src/agent_toolkit/tests/resources/actions/test_resources.py b/src/agent_toolkit/tests/resources/actions/test_resources.py index b07c61b69..10d1f3b15 100644 --- a/src/agent_toolkit/tests/resources/actions/test_resources.py +++ b/src/agent_toolkit/tests/resources/actions/test_resources.py @@ -1034,3 +1034,78 @@ def test_execute_should_get_all_form_fields_included_hidden(self): response.body, '{"success": "hidden_value"}', ) + + def test_execute_should_ignore_all_records_subset_query_filters_when_all_records_is_false(self): + """Test that when all_records is false, filters from all_records_subset_query are ignored.""" + collected_filter = None + + async def execute_with_filter_capture(ctx, rb): + nonlocal collected_filter + collected_filter = ctx.filter + return rb.success("done") + + self.decorated_collection_book.add_action( + "test_bulk_action", + { + "scope": ActionsScope.BULK, + "execute": execute_with_filter_capture, + }, + ) + + body_params = { + "data": { + "attributes": { + "values": {}, + "ids": ["1", "2"], + "collection_name": "Book", + "parent_collection_name": None, + "parent_collection_id": None, + "parent_association_name": None, + "all_records": False, + "all_records_subset_query": { + "fields[Book]": "id,name,cost", + "page[number]": 1, + "page[size]": 15, + "sort": "-id", + "timezone": "Europe/Paris", + # This filter should be IGNORED when all_records is false + "filters": '{"field":"id","operator":"greater_than","value":"100"}', + }, + "all_records_ids_excluded": [], + "smart_action_id": "Book-test_bulk_action", + "signed_approval_request": None, + }, + "type": "custom-action-requests", + } + } + + request = ActionRequest( + method=RequestMethod.POST, + action_name="test_bulk_action", + collection=self.decorated_collection_book, + body=body_params, + query={ + "timezone": "Europe/Paris", + "collection_name": "Book", + "action_name": 0, + "slug": "test_bulk_action", + }, + headers={}, + user=self.mocked_caller, + client_ip="127.0.0.1", + ) + + response = self.loop.run_until_complete(self.action_resource.execute(request)) + self.assertEqual(response.status, 200) + + # The filter should NOT contain the "greater_than" condition from all_records_subset_query + # It should only contain the ID match condition for ids [1, 2] + self.assertIsNotNone(collected_filter) + if collected_filter.condition_tree: + filter_str = str(collected_filter.condition_tree) + # Should not contain the greater_than filter from all_records_subset_query + self.assertNotIn("greater_than", filter_str.lower()) + self.assertNotIn(">", filter_str) + # Should contain the selected IDs (1 and 2) + self.assertIn("1", filter_str) + self.assertIn("2", filter_str) From f677eab74e6cb6b707447887f991227feeb08dc0 Mon Sep 17 00:00:00 2001 From: Pierre Merlet Date: Thu, 9 Oct 2025 17:21:04 +0200 Subject: [PATCH 2/3] trigger CI From 9da47672794b0b84adbb2c43d41c09d79a0a45d9 Mon Sep 17 00:00:00 2001 From: Pierre Merlet Date: Thu, 9 Oct 2025 17:51:28 +0200 Subject: [PATCH 3/3] fix: handle AttributeError when request.body.data is a list --- .../agent_toolkit/resources/collections/filter.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/agent_toolkit/forestadmin/agent_toolkit/resources/collections/filter.py b/src/agent_toolkit/forestadmin/agent_toolkit/resources/collections/filter.py index 8377372c5..426ead3b6 100644 --- a/src/agent_toolkit/forestadmin/agent_toolkit/resources/collections/filter.py +++ b/src/agent_toolkit/forestadmin/agent_toolkit/resources/collections/filter.py @@ -77,11 +77,15 @@ def _subset_or_query(request: Request, key: str) -> Optional[str]: res = None if request.body: # Only use all_records_subset_query when all_records is true - attributes = request.body.get("data", {}).get("attributes", {}) - if attributes.get("all_records", False): - sub_res = _all_records_subset_query(request).get(key) - if sub_res: - res = str(sub_res) + try: + attributes = request.body.get("data", {}).get("attributes", {}) + if attributes.get("all_records", False): + sub_res = _all_records_subset_query(request).get(key) + if sub_res: + res = str(sub_res) + except AttributeError: + # data may be a list + pass if not res and request.query: res = request.query.get(key) if res: