Skip to content

Commit 9845d2f

Browse files
paljortpicklepete
andauthored
Safely decode FormulaField value to JSON (baserow#4403)
* Add error handling when checking if db value is serializable. * Add changelog * Simplify test * Rename _value_is_serialized_object to _deserialize_baserow_object --------- Co-authored-by: peter_baserow <peter@baserow.io>
1 parent 4883984 commit 9845d2f

File tree

3 files changed

+53
-5
lines changed

3 files changed

+53
-5
lines changed

backend/src/baserow/core/formula/field.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import json
22
import logging
3-
from typing import Dict, List, Union
3+
from typing import Any, Dict, List, Optional, Union
44

55
from django.db import connection, models
66

@@ -41,8 +41,29 @@ def __init__(self, *args, **kwargs):
4141
self.null = True
4242
self.blank = True
4343

44-
def _value_is_serialized_object(self, value: FormulaFieldDatabaseValue) -> bool:
45-
return isinstance(value, str) and value[:1] == "{" and value[-1:] == "}"
44+
def _deserialize_baserow_object(
45+
self, value: FormulaFieldDatabaseValue
46+
) -> Optional[Dict[str, Any]]:
47+
"""
48+
Given a value from the database, attempts to deserialize it into a dictionary
49+
representing a Baserow formula object. If the value is not a valid JSON string
50+
representing a Baserow formula object, returns None.
51+
52+
:param value: The value from the database to deserialize.
53+
:return: A dictionary representing the Baserow formula object, or None if
54+
deserialization fails.
55+
"""
56+
57+
if not isinstance(value, str):
58+
return None
59+
60+
if not (value.startswith("{") and value.endswith("}")):
61+
return None
62+
63+
try:
64+
return json.loads(value)
65+
except (TypeError, json.JSONDecodeError):
66+
return None
4667

4768
def _transform_db_value_to_dict(
4869
self, value: FormulaFieldDatabaseValue
@@ -65,9 +86,8 @@ def _transform_db_value_to_dict(
6586
# receive an integer, we convert it to a string.
6687
value = str(value)
6788
# We could encounter a serialized object...
68-
if self._value_is_serialized_object(value):
89+
if context := self._deserialize_baserow_object(value):
6990
# If we have, then we can parse it and return the `BaserowFormulaObject`
70-
context = json.loads(value)
7191
return BaserowFormulaObject(
7292
mode=context["m"], version=context["v"], formula=context["f"]
7393
)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from baserow.core.formula.field import FormulaField
2+
3+
4+
def test_deserialize_baserow_object_valid():
5+
field = FormulaField()
6+
7+
valid_json = '{"m": "simple", "v": "0.1", "f": "test formula"}'
8+
result = field._deserialize_baserow_object(valid_json)
9+
10+
assert result == {"m": "simple", "v": "0.1", "f": "test formula"}
11+
12+
13+
def test_deserialize_baserow_object_invalid():
14+
field = FormulaField()
15+
16+
invalid_json = "{foo}"
17+
result = field._deserialize_baserow_object(invalid_json)
18+
19+
assert result is None
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"type": "bug",
3+
"message": "Improved error handling when FormulaField value is not JSON serializable.",
4+
"issue_origin": "github",
5+
"issue_number": 4402,
6+
"domain": "core",
7+
"bullet_points": [],
8+
"created_at": "2025-12-05"
9+
}

0 commit comments

Comments
 (0)