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. # under the License.
from __future__ import annotations 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.filters import BaseFilter
from flask_appbuilder.models.sqla import Model from flask_appbuilder.models.sqla import Model
@ -30,7 +30,6 @@ from superset.daos.exceptions import (
DAOUpdateFailedError, DAOUpdateFailedError,
) )
from superset.extensions import db from superset.extensions import db
from superset.utils.core import as_list
T = TypeVar("T", bound=Model) T = TypeVar("T", bound=Model)
@ -197,9 +196,9 @@ class BaseDAO(Generic[T]):
return item # type: ignore return item # type: ignore
@classmethod @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 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 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 Subclasses may invoke bulk deletion but are responsible for instrumenting any
post-deletion logic. post-deletion logic.
:param items: The item(s) to delete :param items: The items to delete
:param commit: Whether to commit the transaction :param commit: Whether to commit the transaction
:raises DAODeleteFailedError: If the deletion failed :raises DAODeleteFailedError: If the deletion failed
:see: https://docs.sqlalchemy.org/en/latest/orm/queryguide/dml.html :see: https://docs.sqlalchemy.org/en/latest/orm/queryguide/dml.html
""" """
items = cast(list[T], as_list(item_or_items))
try: try:
for item in items: for item in items:
db.session.delete(item) db.session.delete(item)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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