fix(sql lab): deleting the last saved query or the last executed from history (#19225)

* fix: fix issue when deleting the last saved query or the last executed query

* merge migration
This commit is contained in:
Diego Medina 2022-03-17 17:01:18 -04:00 committed by GitHub
parent 51061f0d67
commit aa5c80bda6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 93 additions and 1 deletions

View File

@ -0,0 +1,66 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""add_on_saved_query_delete_tab_state_null_constraint"
Revision ID: 58df9d617f14
Revises: 6766938c6065
Create Date: 2022-03-16 23:24:40.278937
"""
# revision identifiers, used by Alembic.
revision = "58df9d617f14"
down_revision = "6766938c6065"
import sqlalchemy as sa
from alembic import op
from superset.utils.core import generic_find_fk_constraint_name
def upgrade():
bind = op.get_bind()
insp = sa.engine.reflection.Inspector.from_engine(bind)
with op.batch_alter_table("tab_state") as batch_op:
batch_op.drop_constraint(
generic_find_fk_constraint_name("tab_state", {"id"}, "saved_query", insp),
type_="foreignkey",
)
batch_op.create_foreign_key(
"saved_query_id",
"saved_query",
["saved_query_id"],
["id"],
ondelete="SET NULL",
)
def downgrade():
bind = op.get_bind()
insp = sa.engine.reflection.Inspector.from_engine(bind)
with op.batch_alter_table("tab_state") as batch_op:
batch_op.drop_constraint(
generic_find_fk_constraint_name("tab_state", {"id"}, "saved_query", insp),
type_="foreignkey",
)
batch_op.create_foreign_key(
"saved_query_id", "saved_query", ["saved_query_id"], ["id"],
)

View File

@ -291,7 +291,9 @@ class TabState(Model, AuditMixinNullable, ExtraJSONMixin):
hide_left_bar = Column(Boolean, default=False)
# any saved queries that are associated with the Tab State
saved_query_id = Column(Integer, ForeignKey("saved_query.id"), nullable=True)
saved_query_id = Column(
Integer, ForeignKey("saved_query.id", ondelete="SET NULL"), nullable=True
)
saved_query = relationship("SavedQuery", foreign_keys=[saved_query_id])
def to_dict(self) -> Dict[str, Any]:

View File

@ -20,6 +20,7 @@ from flask_appbuilder import expose
from flask_appbuilder.models.sqla.interface import SQLAInterface
from flask_appbuilder.security.decorators import has_access, has_access_api
from flask_babel import lazy_gettext as _
from sqlalchemy import and_
from superset import db, is_feature_enabled
from superset.constants import MODEL_VIEW_RW_METHOD_PERMISSION_MAP, RouteMethod
@ -228,6 +229,29 @@ class TabStateView(BaseSupersetView):
def delete_query( # pylint: disable=no-self-use
self, tab_state_id: int, client_id: str
) -> FlaskResponse:
# Before deleting the query, ensure it's not tied to any
# active tab as the last query. If so, replace the query
# with the latest one created in that tab
tab_state_query = db.session.query(TabState).filter_by(
id=tab_state_id, latest_query_id=client_id
)
if tab_state_query.count():
query = (
db.session.query(Query)
.filter(
and_(
Query.client_id != client_id,
Query.user_id == g.user.get_id(),
Query.sql_editor_id == str(tab_state_id),
),
)
.order_by(Query.id.desc())
.first()
)
tab_state_query.update(
{"latest_query_id": query.client_id if query else None}
)
db.session.query(Query).filter_by(
client_id=client_id,
user_id=g.user.get_id(),