1
0
Fork 0
mirror of https://gitlab.com/bramw/baserow.git synced 2025-04-07 22:35:36 +00:00

Merge branch 'ab-final-fix-for-service-responses' into 'develop'

Final fix for service responses

See merge request 
This commit is contained in:
Jérémie Pardou 2025-02-17 09:19:24 +00:00
commit 5a7376fa63
19 changed files with 111 additions and 89 deletions
backend
src/baserow
contrib
builder
api/workflow_actions
data_providers
data_sources
workflow_actions
dashboard/data_sources
integrations/local_baserow
core
tests/baserow/contrib
enterprise/backend
src/baserow_enterprise/integrations/local_baserow
tests/baserow_enterprise_tests/integrations/local_baserow/service_types

View file

@ -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)

View file

@ -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,
)

View file

@ -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]

View file

@ -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.
"""

View file

@ -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

View file

@ -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,
)

View file

@ -307,7 +307,7 @@ class DashboardDataSourceHandler:
data_source.service.specific, dispatch_context
)
return service_dispatch
return service_dispatch.data
def export_data_source(
self,

View file

@ -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,

View file

@ -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

View file

@ -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.

View file

@ -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.

View file

@ -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

View file

@ -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
)

View file

@ -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

View file

@ -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

View file

@ -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,
}

View file

@ -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,

View file

@ -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"])

View file

@ -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"),