1
0
Fork 0
mirror of https://gitlab.com/bramw/baserow.git synced 2025-03-14 20:52:51 +00:00

Call ViewHandler().field_type_changed() even if the db field representation changes

This commit is contained in:
Petr Stribny 2023-04-12 09:20:29 +00:00 committed by Nigel Gott
parent bf816f5c61
commit 2ca124e802
6 changed files with 103 additions and 5 deletions
backend
src/baserow/contrib/database/fields
tests/baserow/contrib/database/field
changelog/entries/1.16.0/bug

View file

@ -3168,6 +3168,13 @@ class FormulaFieldType(ReadOnlyFieldType):
**kwargs,
)
def has_compatible_model_fields(self, instance, instance2) -> bool:
return (
super().has_compatible_model_fields(instance, instance2)
and instance.formula_type == instance2.formula_type
and instance.array_formula_type == instance.array_formula_type
)
def prepare_value_for_db(self, instance, value):
"""
Since the Formula Field is a read only field, we raise a

View file

@ -413,8 +413,7 @@ class FieldHandler(metaclass=baserow_trace_methods(tracer)):
to_field_type_name = new_type_name or from_field_type.type
# If the provided field type does not match with the current one we need to
# migrate the field to the new type. Because the type has changed we also need
# to remove all view filters.
# migrate the field to the new type.
baserow_field_type_changed = from_field_type.type != to_field_type_name
field_cache = FieldCache()
if baserow_field_type_changed:
@ -431,9 +430,6 @@ class FieldHandler(metaclass=baserow_trace_methods(tracer)):
new_model_class = to_field_type.model_class
field.change_polymorphic_type_to(new_model_class)
# If the field type changes it could be that some dependencies,
# like filters or sortings need to be changed.
ViewHandler().field_type_changed(field)
else:
dependants_broken_due_to_type_change = []
to_field_type = from_field_type
@ -459,6 +455,16 @@ class FieldHandler(metaclass=baserow_trace_methods(tracer)):
from_model_field = from_model._meta.get_field(field.db_column)
to_model_field = to_model._meta.get_field(field.db_column)
# If the field type or the database representation changes it could be
# that some view dependencies like filters or sortings need to be changed.
if (
baserow_field_type_changed
or not from_field_type.has_compatible_model_fields(
from_model_field, to_model_field
)
):
ViewHandler().field_type_changed(field)
# Before a field is updated we are going to call the before_schema_change
# method of the old field because some cleanup of related instances might
# need to happen.

View file

@ -354,6 +354,13 @@ class FieldType(
raise NotImplementedError("Each must have his own get_model_field method.")
def has_compatible_model_fields(self, instance, instance2) -> bool:
"""
Returns True if the provided instances have compatible model fields.
"""
return type(instance) == type(instance2)
def after_model_generation(self, instance, model, field_name, manytomany_models):
"""
After the model is generated the after_model_generation method of each field

View file

@ -40,6 +40,7 @@ from baserow.contrib.database.fields.models import (
from baserow.contrib.database.fields.registries import field_type_registry
from baserow.contrib.database.rows.handler import RowHandler
from baserow.contrib.database.table.models import Table
from baserow.contrib.database.views.models import ViewFilter
from baserow.core.exceptions import UserNotInWorkspace
# You must add --run-disabled-in-ci to pytest to run this test, you can do this in
@ -480,6 +481,43 @@ def test_update_field(send_mock, data_fixture):
assert getattr(field_with_max_length_name, "name") == field_name_with_ok_length
@pytest.mark.django_db
@pytest.mark.field_formula
@patch("baserow.contrib.database.fields.signals.field_updated.send")
def test_update_field_reset_filter_formula_field(send_mock, data_fixture):
"""
When there is a field change changing the underlying database
type of the field, the update_field() method should initiate
a cleanup for affected views. Formula fields can be in this
situation when the formula expression changes.
"""
user = data_fixture.create_user()
table = data_fixture.create_database_table(user=user)
field = data_fixture.create_formula_field(table=table, order=1, formula="today()")
view = data_fixture.create_grid_view(table=table)
# create a view filter that won't be compatible with the new type
data_fixture.create_view_filter(
view=view, field=field, type="date_equals_today", value="UTC?"
)
model = table.get_model()
model.objects.create()
handler = FieldHandler()
field = handler.update_field(
user=user,
field=field,
new_type_name="formula",
formula="1",
)
field.refresh_from_db()
rows = model.objects.all()
assert getattr(rows[0], f"field_{field.id}") == Decimal("1")
# incompatible filter has been removed
assert ViewFilter.objects.filter(view=view).count() == 0
# This failing field type triggers the CannotChangeFieldType error if a field is
# changed into this type.
class FailingFieldType(TextFieldType):

View file

@ -1507,3 +1507,36 @@ def test_user_can_change_date_force_timezone_on_formula(data_fixture, api_client
}
actual = {key: value for key, value in response.json().items() if key in expected}
assert actual == expected
@pytest.mark.django_db
@pytest.mark.field_formula
@pytest.mark.parametrize(
"instance1,instance2,is_compatible",
[
(
FormulaField(formula_type="date", array_formula_type=None),
FormulaField(formula_type="date", array_formula_type=None),
True,
),
(
FormulaField(formula_type="array", array_formula_type="number"),
FormulaField(formula_type="array", array_formula_type="number"),
True,
),
(
FormulaField(formula_type="date", array_formula_type=None),
FormulaField(formula_type="number", array_formula_type=None),
False,
),
(
FormulaField(formula_type="array", array_formula_type="number"),
FormulaField(formula_type="array", array_formula_type="text"),
False,
),
],
)
def test_has_compatible_model_fields(instance1, instance2, is_compatible):
FormulaFieldType().has_compatible_model_fields(
instance1, instance2
) is is_compatible

View file

@ -0,0 +1,7 @@
{
"type": "bug",
"message": "Fix Updating formula field doesn't delete incompatible filters and sorts",
"issue_number": 1608,
"bullet_points": [],
"created_at": "2023-03-31"
}