mirror of
https://gitlab.com/bramw/baserow.git
synced 2025-04-10 15:47:32 +00:00
Not possible to change field type with active sort
This commit is contained in:
parent
ece699f44f
commit
adf3fc482a
4 changed files with 98 additions and 7 deletions
backend
src/baserow/contrib/database
tests/baserow/contrib/database/api/fields
changelog/entries/unreleased/bug
|
@ -363,7 +363,7 @@ class FieldHandler(metaclass=baserow_trace_methods(tracer)):
|
|||
# already exists. If so the field cannot be created and an exception is raised.
|
||||
if primary and Field.objects.filter(table=table, primary=True).exists():
|
||||
raise PrimaryFieldAlreadyExists(
|
||||
f"A primary field already exists for the " f"table {table}."
|
||||
f"A primary field already exists for the table {table}."
|
||||
)
|
||||
|
||||
# Figure out which model to use and which field types are allowed for the given
|
||||
|
@ -579,6 +579,7 @@ class FieldHandler(metaclass=baserow_trace_methods(tracer)):
|
|||
raise IncompatiblePrimaryFieldTypeError(to_field_type_name)
|
||||
|
||||
if baserow_field_type_changed:
|
||||
ViewHandler().before_field_type_change(field)
|
||||
dependants_broken_due_to_type_change = (
|
||||
from_field_type.get_dependants_which_will_break_when_field_type_changes(
|
||||
field, to_field_type, field_cache
|
||||
|
|
|
@ -222,6 +222,41 @@ class ViewIndexingHandler(metaclass=baserow_trace_methods(tracer)):
|
|||
|
||||
return f"i{table_id}:"
|
||||
|
||||
@classmethod
|
||||
def before_field_type_change(cls, field: Field, model=None):
|
||||
"""
|
||||
Remove all the indexes for the views that have a sort on the field
|
||||
that is being changed.
|
||||
|
||||
:param field: The field that is being changed.
|
||||
:param model: The model to use for the table. If not provided it will be
|
||||
taken from the field.
|
||||
"""
|
||||
|
||||
views = View.objects.filter(
|
||||
id__in=ViewSort.objects.filter(field=field).values("view_id"),
|
||||
db_index_name__isnull=False,
|
||||
)
|
||||
if not views:
|
||||
return
|
||||
|
||||
if model is None:
|
||||
model = field.table.get_model()
|
||||
|
||||
dropped_indexes = set()
|
||||
for view in views:
|
||||
if view.db_index_name in dropped_indexes:
|
||||
continue
|
||||
|
||||
cls.drop_index(
|
||||
view=view,
|
||||
db_index=django_models.Index("id", name=view.db_index_name),
|
||||
model=model,
|
||||
)
|
||||
dropped_indexes.add(view.db_index_name)
|
||||
|
||||
View.objects.filter(id__in=[v.id for v in views]).update(db_index_name=None)
|
||||
|
||||
@classmethod
|
||||
def _get_index_hash(
|
||||
cls, field_order_bys: List[OptionallyAnnotatedOrderBy]
|
||||
|
@ -447,6 +482,12 @@ class ViewIndexingHandler(metaclass=baserow_trace_methods(tracer)):
|
|||
):
|
||||
return current_index_name
|
||||
|
||||
cls.drop_index(view, db_index, model)
|
||||
|
||||
return current_index_name
|
||||
|
||||
@classmethod
|
||||
def drop_index(cls, view, db_index, model=None):
|
||||
if model is None:
|
||||
model = view.table.get_model()
|
||||
|
||||
|
@ -459,8 +500,6 @@ class ViewIndexingHandler(metaclass=baserow_trace_methods(tracer)):
|
|||
view_table_id=view.table_id,
|
||||
)
|
||||
|
||||
return current_index_name
|
||||
|
||||
@classmethod
|
||||
def update_index_by_view_id(cls, view_id: int, nowait=True):
|
||||
"""
|
||||
|
@ -598,6 +637,16 @@ class ViewHandler(metaclass=baserow_trace_methods(tracer)):
|
|||
)
|
||||
return views
|
||||
|
||||
def before_field_type_change(self, field: Field):
|
||||
"""
|
||||
Allow trigger custom logic before field is changed.
|
||||
By default it calls ViewIndexingHandler.before_field_type_change.
|
||||
|
||||
:param field: The field that is being changed.
|
||||
"""
|
||||
|
||||
ViewIndexingHandler.before_field_type_change(field)
|
||||
|
||||
def list_workspace_views(
|
||||
self,
|
||||
user: AbstractUser,
|
||||
|
|
|
@ -15,6 +15,8 @@ from rest_framework.status import (
|
|||
from baserow.contrib.database.fields.models import Field, NumberField, TextField
|
||||
from baserow.contrib.database.fields.registries import field_type_registry
|
||||
from baserow.contrib.database.tokens.handler import TokenHandler
|
||||
from baserow.contrib.database.views.handler import ViewIndexingHandler
|
||||
from baserow.contrib.database.views.models import ViewSort
|
||||
from baserow.core.db import specific_iterator
|
||||
from baserow.test_utils.helpers import (
|
||||
independent_test_db_connection,
|
||||
|
@ -519,7 +521,7 @@ def test_update_field(api_client, data_fixture):
|
|||
url,
|
||||
{"name": existing_field.name},
|
||||
format="json",
|
||||
HTTP_AUTHORIZATION=f"JWT" f" {token}",
|
||||
HTTP_AUTHORIZATION=f"JWT {token}",
|
||||
)
|
||||
assert response.status_code == HTTP_400_BAD_REQUEST
|
||||
assert response.json()["error"] == "ERROR_FIELD_WITH_SAME_NAME_ALREADY_EXISTS"
|
||||
|
@ -530,7 +532,7 @@ def test_update_field(api_client, data_fixture):
|
|||
url,
|
||||
{"name": too_long_field_name},
|
||||
format="json",
|
||||
HTTP_AUTHORIZATION=f"JWT" f" {token}",
|
||||
HTTP_AUTHORIZATION=f"JWT {token}",
|
||||
)
|
||||
assert response.status_code == HTTP_400_BAD_REQUEST
|
||||
assert response.json()["error"] == "ERROR_REQUEST_BODY_VALIDATION"
|
||||
|
@ -717,6 +719,38 @@ def test_update_field_number_type_deprecation_error(api_client, data_fixture):
|
|||
)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_change_field_type_with_active_sort_on_field(api_client, data_fixture):
|
||||
import uuid
|
||||
|
||||
user, token = data_fixture.create_user_and_token()
|
||||
table = data_fixture.create_database_table(user=user)
|
||||
text_field = data_fixture.create_text_field(table=table, name=uuid.uuid4())
|
||||
|
||||
grid = data_fixture.create_grid_view(table=table)
|
||||
|
||||
sort = data_fixture.create_view_sort(view=grid, field=text_field, order="ASC")
|
||||
ViewIndexingHandler.update_index(view=grid)
|
||||
|
||||
grid.refresh_from_db()
|
||||
assert grid.db_index_name is not None
|
||||
|
||||
# Change the field type from text to number
|
||||
url = reverse("api:database:fields:item", kwargs={"field_id": text_field.id})
|
||||
response = api_client.patch(
|
||||
url, {"type": "number"}, format="json", HTTP_AUTHORIZATION=f"JWT {token}"
|
||||
)
|
||||
|
||||
assert response.status_code == HTTP_200_OK
|
||||
|
||||
# Sort is not removed
|
||||
assert ViewSort.objects.filter(id=sort.id).exists()
|
||||
|
||||
# Sort index is removed
|
||||
grid.refresh_from_db()
|
||||
assert grid.db_index_name is None
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_delete_field(api_client, data_fixture):
|
||||
user, token = data_fixture.create_user_and_token()
|
||||
|
@ -858,8 +892,7 @@ def test_update_field_returns_with_error_if_cant_lock_field_if_locked_for_update
|
|||
with conn.cursor() as cursor:
|
||||
# nosec
|
||||
cursor.execute(
|
||||
f"SELECT * FROM database_field where id = {text_field.id} "
|
||||
f"FOR UPDATE"
|
||||
f"SELECT * FROM database_field where id = {text_field.id} FOR UPDATE"
|
||||
)
|
||||
response = api_client.patch(
|
||||
url,
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"type": "bug",
|
||||
"message": "Allow change field type with active sort",
|
||||
"domain": "database",
|
||||
"issue_number": 3519,
|
||||
"bullet_points": [],
|
||||
"created_at": "2025-03-18"
|
||||
}
|
Loading…
Add table
Reference in a new issue