From 7fd5853020f405f39f65f706d9ac17b82f3d1b02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Pardou?= <jeremie@baserow.io> Date: Mon, 17 Feb 2025 09:19:23 +0000 Subject: [PATCH] Final fix for service responses --- .../builder/api/workflow_actions/views.py | 4 +- .../data_providers/data_provider_types.py | 7 ++-- .../contrib/builder/data_sources/handler.py | 2 +- .../contrib/builder/data_sources/service.py | 2 +- .../builder/workflow_actions/handler.py | 13 ++++--- .../builder/workflow_actions/service.py | 6 ++- .../contrib/dashboard/data_sources/handler.py | 2 +- .../local_baserow/service_types.py | 32 ++++++++-------- .../src/baserow/core/formula/registries.py | 3 +- backend/src/baserow/core/services/handler.py | 4 +- .../src/baserow/core/services/registries.py | 7 ++-- backend/src/baserow/core/services/types.py | 8 +++- .../test_data_provider_types.py | 10 ++--- .../test_delete_row_service_type.py | 4 +- .../test_get_row_service_type.py | 16 ++++---- .../test_list_rows_service_type.py | 38 ++++++++++++------- .../test_upsert_row_service_type.py | 6 +-- .../local_baserow/service_types.py | 6 +-- ...est_grouped_aggregate_rows_service_type.py | 30 +++++++-------- 19 files changed, 111 insertions(+), 89 deletions(-) diff --git a/backend/src/baserow/contrib/builder/api/workflow_actions/views.py b/backend/src/baserow/contrib/builder/api/workflow_actions/views.py index b57288113..8d7ee3264 100644 --- a/backend/src/baserow/contrib/builder/api/workflow_actions/views.py +++ b/backend/src/baserow/contrib/builder/api/workflow_actions/views.py @@ -404,6 +404,4 @@ class DispatchBuilderWorkflowActionView(APIView): request.user, workflow_action, dispatch_context # type: ignore ) - if not isinstance(response, Response): - response = Response(response) - return response + return Response(response.data, status=response.status) diff --git a/backend/src/baserow/contrib/builder/data_providers/data_provider_types.py b/backend/src/baserow/contrib/builder/data_providers/data_provider_types.py index 2b00dcc1c..23689d00a 100644 --- a/backend/src/baserow/contrib/builder/data_providers/data_provider_types.py +++ b/backend/src/baserow/contrib/builder/data_providers/data_provider_types.py @@ -5,8 +5,6 @@ from django.conf import settings from django.core.cache import cache from django.utils.translation import gettext as _ -from rest_framework.response import Response - from baserow.contrib.builder.data_providers.exceptions import ( DataProviderChunkInvalidException, FormDataProviderChunkInvalidException, @@ -31,6 +29,7 @@ from baserow.contrib.builder.workflow_actions.handler import ( from baserow.core.formula.exceptions import FormulaRecursion, InvalidBaserowFormula from baserow.core.formula.registries import DataProviderType from baserow.core.services.dispatch_context import DispatchContext +from baserow.core.services.types import DispatchResult from baserow.core.user_sources.constants import DEFAULT_USER_ROLE_PREFIX from baserow.core.user_sources.user_source_user import UserSourceUser from baserow.core.utils import get_value_at_path @@ -449,7 +448,7 @@ class PreviousActionProviderType(DataProviderType): self, dispatch_context: DispatchContext, workflow_action: WorkflowAction, - result: Any, + dispatch_result: DispatchResult, ) -> None: """ If the current_dispatch_id exists in the request data, create a unique @@ -470,7 +469,7 @@ class PreviousActionProviderType(DataProviderType): ) cache.set( cache_key, - {} if isinstance(result, Response) else result, + dispatch_result.data, timeout=settings.BUILDER_DISPATCH_ACTION_CACHE_TTL_SECONDS, ) diff --git a/backend/src/baserow/contrib/builder/data_sources/handler.py b/backend/src/baserow/contrib/builder/data_sources/handler.py index 83957995a..1f8154ad1 100644 --- a/backend/src/baserow/contrib/builder/data_sources/handler.py +++ b/backend/src/baserow/contrib/builder/data_sources/handler.py @@ -448,7 +448,7 @@ class DataSourceHandler: # it later dispatch_context.cache["data_source_contents"][ data_source.id - ] = service_dispatch + ] = service_dispatch.data return dispatch_context.cache["data_source_contents"][data_source.id] diff --git a/backend/src/baserow/contrib/builder/data_sources/service.py b/backend/src/baserow/contrib/builder/data_sources/service.py index fb476393b..366390e25 100644 --- a/backend/src/baserow/contrib/builder/data_sources/service.py +++ b/backend/src/baserow/contrib/builder/data_sources/service.py @@ -384,7 +384,7 @@ class DataSourceService: Dispatch the service related to the data_source if the user has the permission. :param user: The current user. - :param data_sources: The data source to be dispatched. + :param data_source: The data source to be dispatched. :param dispatch_context: The context used for the dispatch. :return: return the dispatch result. """ diff --git a/backend/src/baserow/contrib/builder/workflow_actions/handler.py b/backend/src/baserow/contrib/builder/workflow_actions/handler.py index 952e3f612..635642f4d 100644 --- a/backend/src/baserow/contrib/builder/workflow_actions/handler.py +++ b/backend/src/baserow/contrib/builder/workflow_actions/handler.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Optional +from typing import TYPE_CHECKING, Dict, Iterable, List, Optional from zipfile import ZipFile from django.core.files.storage import Storage @@ -25,6 +25,7 @@ from baserow.contrib.builder.workflow_actions.registries import ( ) from baserow.core.exceptions import IdDoesNotExist from baserow.core.services.handler import ServiceHandler +from baserow.core.services.types import DispatchResult from baserow.core.workflow_actions.handler import WorkflowActionHandler from baserow.core.workflow_actions.models import WorkflowAction from baserow.core.workflow_actions.registries import WorkflowActionType @@ -174,7 +175,7 @@ class BuilderWorkflowActionHandler(WorkflowActionHandler): self, workflow_action: BuilderWorkflowServiceAction, dispatch_context: BuilderDispatchContext, - ) -> Any: + ) -> DispatchResult: """ Dispatch the service related to the workflow_action. @@ -185,11 +186,13 @@ class BuilderWorkflowActionHandler(WorkflowActionHandler): :return: The result of dispatching the workflow action. """ - result = ServiceHandler().dispatch_service( + dispatch_result = ServiceHandler().dispatch_service( workflow_action.service.specific, dispatch_context ) for data_provider in builder_data_provider_type_registry.get_all(): - data_provider.post_dispatch(dispatch_context, workflow_action, result) + data_provider.post_dispatch( + dispatch_context, workflow_action, dispatch_result + ) - return result + return dispatch_result diff --git a/backend/src/baserow/contrib/builder/workflow_actions/service.py b/backend/src/baserow/contrib/builder/workflow_actions/service.py index 9ba890535..dc02ca5f8 100644 --- a/backend/src/baserow/contrib/builder/workflow_actions/service.py +++ b/backend/src/baserow/contrib/builder/workflow_actions/service.py @@ -40,6 +40,7 @@ from baserow.contrib.builder.workflow_actions.workflow_action_types import ( BuilderWorkflowActionType, ) from baserow.core.handler import CoreHandler +from baserow.core.services.types import DispatchResult if TYPE_CHECKING: from baserow.contrib.builder.models import Builder @@ -341,4 +342,7 @@ class BuilderWorkflowActionService: "external", {} ).get(workflow_action.service.id, []) - return self.remove_unused_field_names(result, field_names) + return DispatchResult( + data=self.remove_unused_field_names(result.data, field_names), + status=result.status, + ) diff --git a/backend/src/baserow/contrib/dashboard/data_sources/handler.py b/backend/src/baserow/contrib/dashboard/data_sources/handler.py index 4735fd831..02f20f1a5 100644 --- a/backend/src/baserow/contrib/dashboard/data_sources/handler.py +++ b/backend/src/baserow/contrib/dashboard/data_sources/handler.py @@ -307,7 +307,7 @@ class DashboardDataSourceHandler: data_source.service.specific, dispatch_context ) - return service_dispatch + return service_dispatch.data def export_data_source( self, diff --git a/backend/src/baserow/contrib/integrations/local_baserow/service_types.py b/backend/src/baserow/contrib/integrations/local_baserow/service_types.py index 8cb979518..55efbd031 100644 --- a/backend/src/baserow/contrib/integrations/local_baserow/service_types.py +++ b/backend/src/baserow/contrib/integrations/local_baserow/service_types.py @@ -17,7 +17,6 @@ from django.db.models import QuerySet from rest_framework import serializers from rest_framework.exceptions import ValidationError as DRFValidationError -from rest_framework.response import Response from baserow.contrib.builder.data_providers.exceptions import ( DataProviderChunkInvalidException, @@ -103,6 +102,7 @@ from baserow.core.services.registries import ( ServiceType, ) from baserow.core.services.types import ( + DispatchResult, ServiceDict, ServiceFilterDictSubClass, ServiceSortDictSubClass, @@ -1099,7 +1099,7 @@ class LocalBaserowListRowsUserServiceType( "public_allowed_properties": only_field_names, } - def dispatch_transform(self, dispatch_data: Dict[str, Any]) -> Any: + def dispatch_transform(self, dispatch_data: Dict[str, Any]) -> DispatchResult: """ Given the rows found in `dispatch_data`, serializes them. @@ -1120,10 +1120,12 @@ class LocalBaserowListRowsUserServiceType( field_ids=field_ids, ) - return { - "results": serializer(dispatch_data["results"], many=True).data, - "has_next_page": dispatch_data["has_next_page"], - } + return DispatchResult( + data={ + "results": serializer(dispatch_data["results"], many=True).data, + "has_next_page": dispatch_data["has_next_page"], + } + ) def get_record_names( self, @@ -1508,7 +1510,7 @@ class LocalBaserowAggregateRowsUserServiceType( def dispatch_transform( self, data: Dict[str, Any], - ) -> Dict[str, Any]: + ) -> DispatchResult: """ Responsible for transforming the data returned by the `dispatch_data` method into a format that can be used by the frontend. @@ -1517,7 +1519,7 @@ class LocalBaserowAggregateRowsUserServiceType( :return: A dictionary containing the aggregation result. """ - return data["data"] + return DispatchResult(data=data["data"]) def extract_properties(self, path: List[str], **kwargs) -> List[str]: """ @@ -1714,7 +1716,7 @@ class LocalBaserowGetRowUserServiceType( **kwargs, ) - def dispatch_transform(self, dispatch_data: Dict[str, Any]) -> Any: + def dispatch_transform(self, dispatch_data: Dict[str, Any]) -> DispatchResult: """ Responsible for serializing the `dispatch_data` row. @@ -1737,7 +1739,7 @@ class LocalBaserowGetRowUserServiceType( serialized_row = serializer(dispatch_data["data"]).data - return serialized_row + return DispatchResult(data=serialized_row) def resolve_service_formulas( self, @@ -2069,7 +2071,7 @@ class LocalBaserowUpsertRowServiceType( def enhance_queryset(self, queryset): return super().enhance_queryset(queryset).prefetch_related("field_mappings") - def dispatch_transform(self, dispatch_data: Dict[str, Any]) -> Any: + def dispatch_transform(self, dispatch_data: Dict[str, Any]) -> DispatchResult: """ Responsible for serializing the `dispatch_data` row. @@ -2091,7 +2093,7 @@ class LocalBaserowUpsertRowServiceType( ) serialized_row = serializer(dispatch_data["data"]).data - return serialized_row + return DispatchResult(data=serialized_row) def resolve_service_formulas( self, @@ -2331,17 +2333,17 @@ class LocalBaserowDeleteRowServiceType( resolved_values = super().resolve_service_formulas(service, dispatch_context) return self.resolve_row_id(resolved_values, service, dispatch_context) - def dispatch_transform(self, dispatch_data: Dict[str, Any]) -> Response: + def dispatch_transform(self, dispatch_data: Dict[str, Any]) -> DispatchResult: """ The delete row action's `dispatch_data` will contain an empty `data` dictionary. When we get to this method and wish to transform the data, we can simply return a 204 response. :param dispatch_data: The `dispatch_data` result. - :return: A 204 response. + :return: A dispatch result with no data, and a 204 status code. """ - return Response(status=204) + return DispatchResult(status=204) def dispatch_data( self, diff --git a/backend/src/baserow/core/formula/registries.py b/backend/src/baserow/core/formula/registries.py index a42471fbe..40ff72db6 100644 --- a/backend/src/baserow/core/formula/registries.py +++ b/backend/src/baserow/core/formula/registries.py @@ -15,6 +15,7 @@ from baserow.core.formula.types import ( ) from baserow.core.registry import Instance, Registry from baserow.core.services.dispatch_context import DispatchContext +from baserow.core.services.types import DispatchResult from baserow.core.workflow_actions.models import WorkflowAction @@ -183,7 +184,7 @@ class DataProviderType( self, dispatch_context: DispatchContext, workflow_action: WorkflowAction, - result: Any, + dispatch_result: DispatchResult, ) -> None: """ This hook is called after a Workflow Action has been dispatched. It is diff --git a/backend/src/baserow/core/services/handler.py b/backend/src/baserow/core/services/handler.py index 74f8845ec..8713a4a76 100644 --- a/backend/src/baserow/core/services/handler.py +++ b/backend/src/baserow/core/services/handler.py @@ -18,7 +18,7 @@ from baserow.core.storage import ExportZipFile from baserow.core.utils import extract_allowed from .dispatch_context import DispatchContext -from .types import ServiceForUpdate, UpdatedService +from .types import DispatchResult, ServiceForUpdate, UpdatedService class ServiceHandler: @@ -202,7 +202,7 @@ class ServiceHandler: self, service: Service, dispatch_context: DispatchContext, - ) -> Any: + ) -> DispatchResult: """ Dispatch the given service. diff --git a/backend/src/baserow/core/services/registries.py b/backend/src/baserow/core/services/registries.py index ce2223fcf..1dd48d867 100644 --- a/backend/src/baserow/core/services/registries.py +++ b/backend/src/baserow/core/services/registries.py @@ -19,6 +19,7 @@ from baserow.core.registry import ( Registry, ) from baserow.core.services.dispatch_context import DispatchContext +from baserow.core.services.types import DispatchResult from .exceptions import ServiceTypeDoesNotExist from .models import Service @@ -195,13 +196,13 @@ class ServiceType( def dispatch_transform( self, data: Any, - ) -> Any: + ) -> DispatchResult: """ Responsible for taking the `dispatch_data` result and transforming its value for API consumer's consumption. :param data: The `dispatch_data` result. - :return: The transformed `dispatch_transform` result if any. + :return: The transformed `dispatch_transform` result. """ def dispatch_data( @@ -224,7 +225,7 @@ class ServiceType( self, service: ServiceSubClass, dispatch_context: DispatchContext, - ) -> Any: + ) -> DispatchResult: """ Responsible for calling `dispatch_data` and `dispatch_transform` to execute the service's task, and generating the dispatch's response, respectively. diff --git a/backend/src/baserow/core/services/types.py b/backend/src/baserow/core/services/types.py index 789132528..5208afbdd 100644 --- a/backend/src/baserow/core/services/types.py +++ b/backend/src/baserow/core/services/types.py @@ -1,4 +1,4 @@ -from dataclasses import dataclass +from dataclasses import dataclass, field from typing import NewType, Optional, TypedDict, TypeVar from baserow.core.formula.runtime_formula_context import RuntimeFormulaContext @@ -25,6 +25,12 @@ class ServiceSortDict(TypedDict): order: str +@dataclass +class DispatchResult: + data: dict = field(default_factory=dict) + status: int = 200 + + @dataclass class UpdatedService: service: Service diff --git a/backend/tests/baserow/contrib/builder/data_providers/test_data_provider_types.py b/backend/tests/baserow/contrib/builder/data_providers/test_data_provider_types.py index 63f469848..c09163296 100644 --- a/backend/tests/baserow/contrib/builder/data_providers/test_data_provider_types.py +++ b/backend/tests/baserow/contrib/builder/data_providers/test_data_provider_types.py @@ -7,7 +7,6 @@ from django.http import HttpRequest from django.shortcuts import reverse import pytest -from rest_framework.response import Response from baserow.contrib.builder.data_providers.data_provider_types import ( CurrentRecordDataProviderType, @@ -39,6 +38,7 @@ from baserow.contrib.database.fields.handler import FieldHandler from baserow.core.formula.exceptions import InvalidBaserowFormula from baserow.core.formula.registries import DataProviderType from baserow.core.services.exceptions import ServiceImproperlyConfigured +from baserow.core.services.types import DispatchResult from baserow.core.user_sources.constants import DEFAULT_USER_ROLE_PREFIX from baserow.core.user_sources.user_source_user import UserSourceUser from baserow.core.utils import MirrorDict @@ -984,7 +984,7 @@ def test_previous_action_data_provider_post_dispatch_caches_result(): workflow_action.id = 100 mock_cache_key = "mock-cache-key" - mock_result = {"mock-key": "mock-value"} + mock_result = DispatchResult(data={"mock-key": "mock-value"}) previous_action_data_provider.get_dispatch_action_cache_key = MagicMock( return_value=mock_cache_key ) @@ -1001,12 +1001,12 @@ def test_previous_action_data_provider_post_dispatch_caches_result(): ) mock_cache.set.assert_called_once_with( mock_cache_key, - mock_result, + mock_result.data, timeout=settings.BUILDER_DISPATCH_ACTION_CACHE_TTL_SECONDS, ) -def test_previous_action_data_provider_post_dispatch_with_response_doesnt_cache_result(): +def test_previous_action_data_provider_post_dispatch_with_empty_response_cache_result(): """ Ensure that when a current_dispatch_id is present in the request, the provided result is cached. @@ -1026,7 +1026,7 @@ def test_previous_action_data_provider_post_dispatch_with_response_doesnt_cache_ workflow_action.id = 100 mock_cache_key = "mock-cache-key" - mock_result = Response(status=204) + mock_result = DispatchResult(status=204) previous_action_data_provider.get_dispatch_action_cache_key = MagicMock( return_value=mock_cache_key ) diff --git a/backend/tests/baserow/contrib/integrations/local_baserow/service_types/test_delete_row_service_type.py b/backend/tests/baserow/contrib/integrations/local_baserow/service_types/test_delete_row_service_type.py index c723c3f96..d7ee99e21 100644 --- a/backend/tests/baserow/contrib/integrations/local_baserow/service_types/test_delete_row_service_type.py +++ b/backend/tests/baserow/contrib/integrations/local_baserow/service_types/test_delete_row_service_type.py @@ -1,7 +1,6 @@ from unittest.mock import Mock import pytest -from rest_framework.response import Response from baserow.contrib.database.rows.handler import RowHandler from baserow.contrib.integrations.local_baserow.models import LocalBaserowDeleteRow @@ -158,5 +157,4 @@ def test_local_baserow_delete_row_service_dispatch_transform(data_fixture): service_type = LocalBaserowDeleteRowServiceType() dispatch_data = {"data": {}, "baserow_table_model": Mock()} result = service_type.dispatch_transform(dispatch_data) - assert isinstance(result, Response) - assert result.status_code == 204 + assert result.status == 204 diff --git a/backend/tests/baserow/contrib/integrations/local_baserow/service_types/test_get_row_service_type.py b/backend/tests/baserow/contrib/integrations/local_baserow/service_types/test_get_row_service_type.py index 6e8ea0318..66ebb9e6e 100644 --- a/backend/tests/baserow/contrib/integrations/local_baserow/service_types/test_get_row_service_type.py +++ b/backend/tests/baserow/contrib/integrations/local_baserow/service_types/test_get_row_service_type.py @@ -212,7 +212,7 @@ def test_local_baserow_get_row_service_dispatch_transform(data_fixture): ) result = service_type.dispatch_transform(dispatch_data) - assert result == { + assert result.data == { "id": rows[1].id, fields[0].db_column: "Audi", fields[1].db_column: "Orange", @@ -325,7 +325,7 @@ def test_local_baserow_get_row_service_dispatch_data_with_service_integer_search ) result = service_type.dispatch_transform(dispatch_data) - assert result == { + assert result.data == { "id": rows[2].id, fields[0].db_column: "42", "order": AnyStr(), @@ -771,7 +771,7 @@ def test_dispatch_transform_passes_field_ids(mock_get_serializer, field_names): results = service_type.dispatch_transform(dispatch_data) - assert results == mock_serializer_instance.data + assert results.data == mock_serializer_instance.data mock_get_serializer.assert_called_once_with( dispatch_data["baserow_table_model"], RowSerializer, @@ -851,7 +851,7 @@ def test_can_dispatch_interesting_table(data_fixture): # Normal dispatch result = service.get_type().dispatch(service, dispatch_context) - assert len(result.keys()) == table.field_set.count() + 2 + assert len(result.data.keys()) == table.field_set.count() + 2 # Now can we dispatch the table if all fields are hidden? field_names = { @@ -866,7 +866,7 @@ def test_can_dispatch_interesting_table(data_fixture): # means that the enhance_by_field is filtered to only used field. result = service.get_type().dispatch(service, dispatch_context) - assert len(result.keys()) == 1 + 1 # We also have the order at that point + assert len(result.data.keys()) == 1 + 1 # We also have the order at that point # Test with a filter on a single select field. Single select have a select_related single_select_field = table.field_set.get(name="single_select") @@ -879,7 +879,7 @@ def test_can_dispatch_interesting_table(data_fixture): dispatch_context = FakeDispatchContext(public_allowed_properties=field_names) - assert len(result.keys()) == 1 + 1 + assert len(result.data.keys()) == 1 + 1 # Let's remove the filter to not interfer with the sort service_filter.delete() @@ -890,7 +890,7 @@ def test_can_dispatch_interesting_table(data_fixture): ) dispatch_context = FakeDispatchContext(public_allowed_properties=field_names) - assert len(result.keys()) == 1 + 1 + assert len(result.data.keys()) == 1 + 1 service_sort.delete() @@ -899,4 +899,4 @@ def test_can_dispatch_interesting_table(data_fixture): service.save() dispatch_context = FakeDispatchContext(public_allowed_properties=field_names) - assert len(result.keys()) == 1 + 1 + assert len(result.data.keys()) == 1 + 1 diff --git a/backend/tests/baserow/contrib/integrations/local_baserow/service_types/test_list_rows_service_type.py b/backend/tests/baserow/contrib/integrations/local_baserow/service_types/test_list_rows_service_type.py index 1cc042ccf..94e1423c9 100644 --- a/backend/tests/baserow/contrib/integrations/local_baserow/service_types/test_list_rows_service_type.py +++ b/backend/tests/baserow/contrib/integrations/local_baserow/service_types/test_list_rows_service_type.py @@ -231,7 +231,7 @@ def test_local_baserow_list_rows_service_dispatch_transform(data_fixture): ) result = service_type.dispatch_transform(dispatch_data) - assert [dict(r) for r in result["results"]] == [ + assert [dict(r) for r in result.data["results"]] == [ { "id": rows[0].id, fields[0].db_column: "BMW", @@ -245,7 +245,7 @@ def test_local_baserow_list_rows_service_dispatch_transform(data_fixture): "order": AnyStr(), }, ] - assert result["has_next_page"] is False + assert result.data["has_next_page"] is False @pytest.mark.django_db @@ -943,7 +943,7 @@ def test_can_dispatch_table_with_deleted_field(data_fixture): result = service.get_type().dispatch(service, dispatch_context) assert ( - len(result["results"][0].keys()) == 2 + 1 + len(result.data["results"][0].keys()) == 2 + 1 ) # We also have the order at that point @@ -975,8 +975,8 @@ def test_can_dispatch_interesting_table(data_fixture): # Normal dispatch result = service.get_type().dispatch(service, dispatch_context) - assert len(result["results"]) == 2 - assert len(result["results"][0].keys()) == table.field_set.count() + 2 + assert len(result.data["results"]) == 2 + assert len(result.data["results"][0].keys()) == table.field_set.count() + 2 # Now can we dispatch the table if all fields are hidden? field_names = { @@ -992,7 +992,7 @@ def test_can_dispatch_interesting_table(data_fixture): result = service.get_type().dispatch(service, dispatch_context) assert ( - len(result["results"][0].keys()) == 1 + 1 + len(result.data["results"][0].keys()) == 1 + 1 ) # We also have the order at that point # Test with a filter on a single select field. Single select have a select_related @@ -1000,15 +1000,19 @@ def test_can_dispatch_interesting_table(data_fixture): service_filter = data_fixture.create_local_baserow_table_service_filter( service=service, field=single_select_field, - value="'A'", + type="not_equal", + value="'Nothing'", + value_is_formula=True, order=0, ) dispatch_context = FakeDispatchContext(public_allowed_properties=field_names) - assert len(result["results"][0].keys()) == 1 + 1 + result = service.get_type().dispatch(service, dispatch_context) - # Let's remove the filter to not interfer with the sort + assert len(result.data["results"][0].keys()) == 2 + 1 + + # Let's remove the filter to not interfere with the sort service_filter.delete() # Test with a sort @@ -1017,16 +1021,22 @@ def test_can_dispatch_interesting_table(data_fixture): ) dispatch_context = FakeDispatchContext(public_allowed_properties=field_names) - assert len(result["results"][0].keys()) == 1 + 1 + + result = service.get_type().dispatch(service, dispatch_context) + + assert len(result.data["results"][0].keys()) == 2 + 1 service_sort.delete() - # Now with a search - service.search_query = "'A'" + # Now with a search query + service.search_query = "1" service.save() dispatch_context = FakeDispatchContext(public_allowed_properties=field_names) - assert len(result["results"][0].keys()) == 1 + 1 + + result = service.get_type().dispatch(service, dispatch_context) + + assert len(result.data["results"][0].keys()) == 1 + 1 @pytest.mark.parametrize( @@ -1063,7 +1073,7 @@ def test_dispatch_transform_passes_field_ids(mock_get_serializer, field_names): results = service_type.dispatch_transform(dispatch_data) - assert results == { + assert results.data == { "has_next_page": False, "results": mock_serializer_instance.data, } diff --git a/backend/tests/baserow/contrib/integrations/local_baserow/service_types/test_upsert_row_service_type.py b/backend/tests/baserow/contrib/integrations/local_baserow/service_types/test_upsert_row_service_type.py index 29a9247de..c1d8ce9d1 100644 --- a/backend/tests/baserow/contrib/integrations/local_baserow/service_types/test_upsert_row_service_type.py +++ b/backend/tests/baserow/contrib/integrations/local_baserow/service_types/test_upsert_row_service_type.py @@ -361,7 +361,7 @@ def test_local_baserow_upsert_row_service_dispatch_transform( ) serialized_row = service_type.dispatch_transform(dispatch_data) - assert dict(serialized_row) == { + assert dict(serialized_row.data) == { "id": dispatch_data["data"].id, "order": "1.00000000000000000000", ingredient.db_column: str(2), @@ -473,7 +473,7 @@ def test_local_baserow_upsert_row_service_dispatch_data_convert_value(data_fixtu ) serialized_row = service_type.dispatch_transform(dispatch_data) - assert dict(serialized_row) == { + assert dict(serialized_row.data) == { "id": 1, "order": "1.00000000000000000000", # The string 'true' was converted to a boolean value @@ -722,7 +722,7 @@ def test_dispatch_transform_passes_field_ids( results = service_type.dispatch_transform(dispatch_data) - assert results == mock_serializer_instance.data + assert results.data == mock_serializer_instance.data mock_get_serializer.assert_called_once_with( dispatch_data["baserow_table_model"], RowSerializer, diff --git a/enterprise/backend/src/baserow_enterprise/integrations/local_baserow/service_types.py b/enterprise/backend/src/baserow_enterprise/integrations/local_baserow/service_types.py index 2b9583afc..654197005 100644 --- a/enterprise/backend/src/baserow_enterprise/integrations/local_baserow/service_types.py +++ b/enterprise/backend/src/baserow_enterprise/integrations/local_baserow/service_types.py @@ -25,7 +25,7 @@ from baserow.contrib.integrations.local_baserow.service_types import ( from baserow.core.services.dispatch_context import DispatchContext from baserow.core.services.exceptions import ServiceImproperlyConfigured from baserow.core.services.registries import DispatchTypes -from baserow.core.services.types import ServiceSortDictSubClass +from baserow.core.services.types import DispatchResult, ServiceSortDictSubClass from baserow.core.utils import atomic_if_not_already from baserow_enterprise.api.integrations.local_baserow.serializers import ( LocalBaserowTableServiceAggregationGroupBySerializer, @@ -512,5 +512,5 @@ class LocalBaserowGroupedAggregateRowsUserServiceType( def dispatch_transform( self, data: any, - ) -> any: - return data["data"] + ) -> DispatchResult: + return DispatchResult(data=data["data"]) diff --git a/enterprise/backend/tests/baserow_enterprise_tests/integrations/local_baserow/service_types/test_grouped_aggregate_rows_service_type.py b/enterprise/backend/tests/baserow_enterprise_tests/integrations/local_baserow/service_types/test_grouped_aggregate_rows_service_type.py index 161150579..c493737ab 100644 --- a/enterprise/backend/tests/baserow_enterprise_tests/integrations/local_baserow/service_types/test_grouped_aggregate_rows_service_type.py +++ b/enterprise/backend/tests/baserow_enterprise_tests/integrations/local_baserow/service_types/test_grouped_aggregate_rows_service_type.py @@ -953,7 +953,7 @@ def test_grouped_aggregate_rows_service_dispatch(data_fixture): result = ServiceHandler().dispatch_service(service, dispatch_context) - assert result == { + assert result.data == { "result": { f"field_{field.id}": Decimal("20"), f"field_{field_2.id}": Decimal("8"), @@ -1003,7 +1003,7 @@ def test_grouped_aggregate_rows_service_dispatch_with_view(data_fixture): result = ServiceHandler().dispatch_service(service, dispatch_context) - assert result == { + assert result.data == { "result": { f"field_{field.id}": Decimal("6"), f"field_{field_2.id}": Decimal("4"), @@ -1053,7 +1053,7 @@ def test_grouped_aggregate_rows_service_dispatch_with_service_filters(data_fixtu result = ServiceHandler().dispatch_service(service, dispatch_context) - assert result == { + assert result.data == { "result": { f"field_{field.id}": Decimal("6"), f"field_{field_2.id}": Decimal("4"), @@ -1278,7 +1278,7 @@ def test_grouped_aggregate_rows_service_dispatch_with_total_aggregation(data_fix result = ServiceHandler().dispatch_service(service, dispatch_context) - assert result == { + assert result.data == { "result": { f"field_{field.id}": 75.0, f"field_{field_2.id}": 25.0, @@ -1358,7 +1358,7 @@ def test_grouped_aggregate_rows_service_dispatch_group_by(data_fixture): result = ServiceHandler().dispatch_service(service, dispatch_context) - assert result == { + assert result.data == { "result": [ { f"field_{field.id}": Decimal("1"), @@ -1424,7 +1424,7 @@ def test_grouped_aggregate_rows_service_dispatch_group_by_id(data_fixture): result = ServiceHandler().dispatch_service(service, dispatch_context) - assert result == { + assert result.data == { "result": [ { f"field_{field.id}": Decimal("2"), @@ -1554,7 +1554,7 @@ def test_grouped_aggregate_rows_service_dispatch_sort_by_series_with_group_by( result = ServiceHandler().dispatch_service(service, dispatch_context) - assert result == { + assert result.data == { "result": [ { f"field_{field.id}": Decimal("90"), @@ -1655,7 +1655,7 @@ def test_grouped_aggregate_rows_service_dispatch_sort_by_series_with_group_by_ro result = ServiceHandler().dispatch_service(service, dispatch_context) - assert result == { + assert result.data == { "result": [ { f"field_{field.id}": None, @@ -1764,7 +1764,7 @@ def test_grouped_aggregate_rows_service_dispatch_sort_by_series_without_group_by result = ServiceHandler().dispatch_service(service, dispatch_context) # the results are still a dictionary, not sorted on the backend - assert result == { + assert result.data == { "result": { f"field_{field.id}": Decimal("9"), f"field_{field_2.id}": Decimal("14"), @@ -1869,7 +1869,7 @@ def test_grouped_aggregate_rows_service_dispatch_sort_by_group_by_field(data_fix result = ServiceHandler().dispatch_service(service, dispatch_context) - assert result == { + assert result.data == { "result": [ { f"field_{field.id}": None, @@ -1962,7 +1962,7 @@ def test_grouped_aggregate_rows_service_dispatch_sort_by_group_by_row_id(data_fi result = ServiceHandler().dispatch_service(service, dispatch_context) - assert result == { + assert result.data == { "result": [ { f"field_{field.id}": "", @@ -2207,7 +2207,7 @@ def test_grouped_aggregate_rows_service_dispatch_sort_by_series_with_group_by_ig result = ServiceHandler().dispatch_service(service, dispatch_context) - assert result == { + assert result.data == { "result": [ { f"field_{field.id}": None, @@ -2298,7 +2298,7 @@ def test_grouped_aggregate_rows_service_dispatch_max_buckets_sort_on_group_by_fi result = ServiceHandler().dispatch_service(service, dispatch_context) - assert result == { + assert result.data == { "result": [ { f"field_{field.id}": Decimal("10"), @@ -2385,7 +2385,7 @@ def test_grouped_aggregate_rows_service_dispatch_max_buckets_sort_on_series( result = ServiceHandler().dispatch_service(service, dispatch_context) - assert result == { + assert result.data == { "result": [ { f"field_{field.id}": Decimal("10"), @@ -2472,7 +2472,7 @@ def test_grouped_aggregate_rows_service_dispatch_max_buckets_sort_on_primary_fie result = ServiceHandler().dispatch_service(service, dispatch_context) - assert result == { + assert result.data == { "result": [ { f"field_{field.id}": Decimal("10"),