chore: Allow only iterables for BaseDAO.delete() (#25844)

This commit is contained in:
John Bodley 2023-11-22 03:52:30 -08:00 committed by GitHub
parent 260d561b9a
commit 843c7ab58a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 12 additions and 14 deletions

View File

@ -16,7 +16,7 @@
# under the License.
from __future__ import annotations
from typing import Any, cast, Generic, get_args, TypeVar
from typing import Any, Generic, get_args, TypeVar
from flask_appbuilder.models.filters import BaseFilter
from flask_appbuilder.models.sqla import Model
@ -30,7 +30,6 @@ from superset.daos.exceptions import (
DAOUpdateFailedError,
)
from superset.extensions import db
from superset.utils.core import as_list
T = TypeVar("T", bound=Model)
@ -197,9 +196,9 @@ class BaseDAO(Generic[T]):
return item # type: ignore
@classmethod
def delete(cls, item_or_items: T | list[T], commit: bool = True) -> None:
def delete(cls, items: list[T], commit: bool = True) -> None:
"""
Delete the specified item(s) including their associated relationships.
Delete the specified items including their associated relationships.
Note that bulk deletion via `delete` is not invoked in the base class as this
does not dispatch the ORM `after_delete` event which may be required to augment
@ -209,12 +208,12 @@ class BaseDAO(Generic[T]):
Subclasses may invoke bulk deletion but are responsible for instrumenting any
post-deletion logic.
:param items: The item(s) to delete
:param items: The items to delete
:param commit: Whether to commit the transaction
:raises DAODeleteFailedError: If the deletion failed
:see: https://docs.sqlalchemy.org/en/latest/orm/queryguide/dml.html
"""
items = cast(list[T], as_list(item_or_items))
try:
for item in items:
db.session.delete(item)

View File

@ -1349,8 +1349,7 @@ class DashboardRestApi(BaseSupersetModelRestApi):
500:
$ref: '#/components/responses/500'
"""
for embedded in dashboard.embedded:
EmbeddedDashboardDAO.delete(embedded)
EmbeddedDashboardDAO.delete(dashboard.embedded)
return self.response(200, message="OK")
@expose("/<id_or_slug>/copy/", methods=("POST",))

View File

@ -38,7 +38,7 @@ class DeleteFilterSetCommand(BaseFilterSetCommand):
assert self._filter_set
try:
FilterSetDAO.delete(self._filter_set)
FilterSetDAO.delete([self._filter_set])
except DAODeleteFailedError as err:
raise FilterSetDeleteFailedError(str(self._filter_set_id), "") from err

View File

@ -44,7 +44,7 @@ class DeleteDatabaseCommand(BaseCommand):
assert self._model
try:
DatabaseDAO.delete(self._model)
DatabaseDAO.delete([self._model])
except DAODeleteFailedError as ex:
logger.exception(ex.exception)
raise DatabaseDeleteFailedError() from ex

View File

@ -43,7 +43,7 @@ class DeleteSSHTunnelCommand(BaseCommand):
assert self._model
try:
SSHTunnelDAO.delete(self._model)
SSHTunnelDAO.delete([self._model])
except DAODeleteFailedError as ex:
raise SSHTunnelDeleteFailedError() from ex

View File

@ -43,7 +43,7 @@ class DeleteDatasetColumnCommand(BaseCommand):
assert self._model
try:
DatasetColumnDAO.delete(self._model)
DatasetColumnDAO.delete([self._model])
except DAODeleteFailedError as ex:
logger.exception(ex.exception)
raise DatasetColumnDeleteFailedError() from ex

View File

@ -43,7 +43,7 @@ class DeleteDatasetMetricCommand(BaseCommand):
assert self._model
try:
DatasetMetricDAO.delete(self._model)
DatasetMetricDAO.delete([self._model])
except DAODeleteFailedError as ex:
logger.exception(ex.exception)
raise DatasetMetricDeleteFailedError() from ex

View File

@ -192,4 +192,4 @@ class TestDashboardDatasetSecurity(DashboardTestCase):
self.assert200(rv)
data = json.loads(rv.data.decode("utf-8"))
self.assertEqual(0, data["count"])
DashboardDAO.delete(dashboard)
DashboardDAO.delete([dashboard])