You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ju...@apache.org on 2023/08/11 20:23:14 UTC

[superset] branch master updated: chore(sqllab): Relocate get bootstrap data logic (#24936)

This is an automated email from the ASF dual-hosted git repository.

justinpark pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new a44c99899a chore(sqllab): Relocate get bootstrap data logic (#24936)
a44c99899a is described below

commit a44c99899a66980934ae5459c28720063fc0abab
Author: JUST.in DO IT <ju...@airbnb.com>
AuthorDate: Fri Aug 11 13:23:07 2023 -0700

    chore(sqllab): Relocate get bootstrap data logic (#24936)
---
 superset-frontend/src/SqlLab/actions/sqlLab.js     |  9 +--
 .../SqlLab/components/TabbedSqlEditors/index.jsx   |  2 +-
 .../src/SqlLab/reducers/getInitialState.js         |  3 +-
 .../src/SqlLab/reducers/getInitialState.test.ts    |  1 -
 superset/sqllab/utils.py                           | 63 ++++++++++++++++++++
 superset/views/base.py                             |  1 +
 superset/views/core.py                             | 67 +---------------------
 tests/integration_tests/core_tests.py              |  4 +-
 8 files changed, 74 insertions(+), 76 deletions(-)

diff --git a/superset-frontend/src/SqlLab/actions/sqlLab.js b/superset-frontend/src/SqlLab/actions/sqlLab.js
index 5d9ecdacdf..8d39d3bbdb 100644
--- a/superset-frontend/src/SqlLab/actions/sqlLab.js
+++ b/superset-frontend/src/SqlLab/actions/sqlLab.js
@@ -570,15 +570,10 @@ export function addQueryEditor(queryEditor) {
 export function addNewQueryEditor() {
   return function (dispatch, getState) {
     const {
-      sqlLab: {
-        queryEditors,
-        tabHistory,
-        unsavedQueryEditor,
-        defaultDbId,
-        databases,
-      },
+      sqlLab: { queryEditors, tabHistory, unsavedQueryEditor, databases },
       common,
     } = getState();
+    const defaultDbId = common.conf.SQLLAB_DEFAULT_DBID;
     const activeQueryEditor = queryEditors.find(
       qe => qe.id === tabHistory[tabHistory.length - 1],
     );
diff --git a/superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx b/superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx
index d914715630..95d0c2529b 100644
--- a/superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx
+++ b/superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx
@@ -340,7 +340,7 @@ function mapStateToProps({ sqlLab, common }) {
     queries: sqlLab.queries,
     tabHistory: sqlLab.tabHistory,
     tables: sqlLab.tables,
-    defaultDbId: sqlLab.defaultDbId,
+    defaultDbId: common.conf.SQLLAB_DEFAULT_DBID,
     displayLimit: common.conf.DISPLAY_MAX_ROW,
     offline: sqlLab.offline,
     defaultQueryLimit: common.conf.DEFAULT_SQLLAB_LIMIT,
diff --git a/superset-frontend/src/SqlLab/reducers/getInitialState.js b/superset-frontend/src/SqlLab/reducers/getInitialState.js
index edb778fcfa..1e3ac94d11 100644
--- a/superset-frontend/src/SqlLab/reducers/getInitialState.js
+++ b/superset-frontend/src/SqlLab/reducers/getInitialState.js
@@ -28,7 +28,6 @@ export function dedupeTabHistory(tabHistory) {
 }
 
 export default function getInitialState({
-  defaultDbId,
   common,
   active_tab: activeTab,
   tab_state_ids: tabStateIds = [],
@@ -55,7 +54,7 @@ export default function getInitialState({
     latestQueryId: null,
     autorun: false,
     templateParams: null,
-    dbId: defaultDbId,
+    dbId: common.conf.SQLLAB_DEFAULT_DBID,
     queryLimit: common.conf.DEFAULT_SQLLAB_LIMIT,
     validationResult: {
       id: null,
diff --git a/superset-frontend/src/SqlLab/reducers/getInitialState.test.ts b/superset-frontend/src/SqlLab/reducers/getInitialState.test.ts
index c06633c6f5..a3c71cbd88 100644
--- a/superset-frontend/src/SqlLab/reducers/getInitialState.test.ts
+++ b/superset-frontend/src/SqlLab/reducers/getInitialState.test.ts
@@ -20,7 +20,6 @@
 import getInitialState, { dedupeTabHistory } from './getInitialState';
 
 const apiData = {
-  defaultDbId: 1,
   common: {
     conf: {
       DEFAULT_SQLLAB_LIMIT: 1,
diff --git a/superset/sqllab/utils.py b/superset/sqllab/utils.py
index abceaaf136..d308bd4639 100644
--- a/superset/sqllab/utils.py
+++ b/superset/sqllab/utils.py
@@ -14,11 +14,31 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
+from __future__ import annotations
+
 from typing import Any
 
 import pyarrow as pa
 
+from superset import db, is_feature_enabled
 from superset.common.db_query_status import QueryStatus
+from superset.daos.database import DatabaseDAO
+from superset.models.sql_lab import Query, TabState
+
+DATABASE_KEYS = [
+    "allow_file_upload",
+    "allow_ctas",
+    "allow_cvas",
+    "allow_dml",
+    "allow_run_async",
+    "allows_subquery",
+    "backend",
+    "database_name",
+    "expose_in_sqllab",
+    "force_ctas_schema",
+    "id",
+    "disable_data_preview",
+]
 
 
 def apply_display_max_row_configuration_if_require(  # pylint: disable=invalid-name
@@ -56,3 +76,46 @@ def write_ipc_buffer(table: pa.Table) -> pa.Buffer:
         writer.write_table(table)
 
     return sink.getvalue()
+
+
+def bootstrap_sqllab_data(user_id: int | None) -> dict[str, Any]:
+    # send list of tab state ids
+    tabs_state = (
+        db.session.query(TabState.id, TabState.label).filter_by(user_id=user_id).all()
+    )
+    tab_state_ids = [str(tab_state[0]) for tab_state in tabs_state]
+    # return first active tab, or fallback to another one if no tab is active
+    active_tab = (
+        db.session.query(TabState)
+        .filter_by(user_id=user_id)
+        .order_by(TabState.active.desc())
+        .first()
+    )
+
+    databases: dict[int, Any] = {}
+    for database in DatabaseDAO.find_all():
+        databases[database.id] = {
+            k: v for k, v in database.to_json().items() if k in DATABASE_KEYS
+        }
+        databases[database.id]["backend"] = database.backend
+    queries: dict[str, Any] = {}
+
+    # These are unnecessary if sqllab backend persistence is disabled
+    if is_feature_enabled("SQLLAB_BACKEND_PERSISTENCE"):
+        # return all user queries associated with existing SQL editors
+        user_queries = (
+            db.session.query(Query)
+            .filter_by(user_id=user_id)
+            .filter(Query.sql_editor_id.in_(tab_state_ids))
+            .all()
+        )
+        queries = {
+            query.client_id: dict(query.to_dict().items()) for query in user_queries
+        }
+
+    return {
+        "tab_state_ids": tabs_state,
+        "active_tab": active_tab.to_dict() if active_tab else None,
+        "databases": databases,
+        "queries": queries,
+    }
diff --git a/superset/views/base.py b/superset/views/base.py
index 34232a6e34..a2c62df41b 100644
--- a/superset/views/base.py
+++ b/superset/views/base.py
@@ -95,6 +95,7 @@ FRONTEND_CONF_KEYS = (
     "SQL_MAX_ROW",
     "SUPERSET_WEBSERVER_DOMAINS",
     "SQLLAB_SAVE_WARNING_MESSAGE",
+    "SQLLAB_DEFAULT_DBID",
     "DISPLAY_MAX_ROW",
     "GLOBAL_ASYNC_QUERIES_TRANSPORT",
     "GLOBAL_ASYNC_QUERIES_POLLING_DELAY",
diff --git a/superset/views/core.py b/superset/views/core.py
index 0394c90dd3..d377f94d65 100755
--- a/superset/views/core.py
+++ b/superset/views/core.py
@@ -48,7 +48,6 @@ from superset.common.chart_data import ChartDataResultFormat, ChartDataResultTyp
 from superset.connectors.base.models import BaseDatasource
 from superset.connectors.sqla.models import SqlaTable
 from superset.daos.chart import ChartDAO
-from superset.daos.database import DatabaseDAO
 from superset.daos.datasource import DatasourceDAO
 from superset.dashboards.commands.importers.v0 import ImportDashboardsCommand
 from superset.dashboards.permalink.commands.get import GetDashboardPermalinkCommand
@@ -69,8 +68,9 @@ from superset.extensions import async_query_manager, cache_manager
 from superset.models.core import Database
 from superset.models.dashboard import Dashboard
 from superset.models.slice import Slice
-from superset.models.sql_lab import Query, TabState
+from superset.models.sql_lab import Query
 from superset.models.user_attributes import UserAttribute
+from superset.sqllab.utils import bootstrap_sqllab_data
 from superset.superset_typing import FlaskResponse
 from superset.tasks.async_queries import load_explore_json_into_cache
 from superset.utils import core as utils
@@ -115,21 +115,6 @@ SQLLAB_QUERY_COST_ESTIMATE_TIMEOUT = config["SQLLAB_QUERY_COST_ESTIMATE_TIMEOUT"
 stats_logger = config["STATS_LOGGER"]
 logger = logging.getLogger(__name__)
 
-DATABASE_KEYS = [
-    "allow_file_upload",
-    "allow_ctas",
-    "allow_cvas",
-    "allow_dml",
-    "allow_run_async",
-    "allows_subquery",
-    "backend",
-    "database_name",
-    "expose_in_sqllab",
-    "force_ctas_schema",
-    "id",
-    "disable_data_preview",
-]
-
 DATASOURCE_MISSING_ERR = __("The data source seems to have been deleted")
 USER_MISSING_ERR = __("The user seems to have been deleted")
 PARAMETER_MISSING_ERR = __(
@@ -1019,51 +1004,6 @@ class Superset(BaseSupersetView):  # pylint: disable=too-many-public-methods
             ),
         )
 
-    @staticmethod
-    def _get_sqllab_tabs(user_id: int | None) -> dict[str, Any]:
-        # send list of tab state ids
-        tabs_state = (
-            db.session.query(TabState.id, TabState.label)
-            .filter_by(user_id=user_id)
-            .all()
-        )
-        tab_state_ids = [str(tab_state[0]) for tab_state in tabs_state]
-        # return first active tab, or fallback to another one if no tab is active
-        active_tab = (
-            db.session.query(TabState)
-            .filter_by(user_id=user_id)
-            .order_by(TabState.active.desc())
-            .first()
-        )
-
-        databases: dict[int, Any] = {}
-        for database in DatabaseDAO.find_all():
-            databases[database.id] = {
-                k: v for k, v in database.to_json().items() if k in DATABASE_KEYS
-            }
-            databases[database.id]["backend"] = database.backend
-        queries: dict[str, Any] = {}
-
-        # These are unnecessary if sqllab backend persistence is disabled
-        if is_feature_enabled("SQLLAB_BACKEND_PERSISTENCE"):
-            # return all user queries associated with existing SQL editors
-            user_queries = (
-                db.session.query(Query)
-                .filter_by(user_id=user_id)
-                .filter(Query.sql_editor_id.in_(tab_state_ids))
-                .all()
-            )
-            queries = {
-                query.client_id: dict(query.to_dict().items()) for query in user_queries
-            }
-
-        return {
-            "tab_state_ids": tabs_state,
-            "active_tab": active_tab.to_dict() if active_tab else None,
-            "databases": databases,
-            "queries": queries,
-        }
-
     @has_access
     @event_logger.log_this
     @expose(
@@ -1076,9 +1016,8 @@ class Superset(BaseSupersetView):  # pylint: disable=too-many-public-methods
     def sqllab(self) -> FlaskResponse:
         """SQL Editor"""
         payload = {
-            "defaultDbId": config["SQLLAB_DEFAULT_DBID"],
             "common": common_bootstrap_payload(g.user),
-            **self._get_sqllab_tabs(get_user_id()),
+            **bootstrap_sqllab_data(get_user_id()),
         }
 
         if form_data := request.form.get("form_data"):
diff --git a/tests/integration_tests/core_tests.py b/tests/integration_tests/core_tests.py
index e036602d0f..ddcfa189b2 100644
--- a/tests/integration_tests/core_tests.py
+++ b/tests/integration_tests/core_tests.py
@@ -52,6 +52,7 @@ from superset.models.dashboard import Dashboard
 from superset.models.slice import Slice
 from superset.models.sql_lab import Query
 from superset.result_set import SupersetResultSet
+from superset.sqllab.utils import bootstrap_sqllab_data
 from superset.utils import core as utils
 from superset.utils.core import backend
 from superset.utils.database import get_example_database
@@ -1135,7 +1136,8 @@ class TestCore(SupersetTestCase, InsertChartMixin):
 
         # we should have only 1 query returned, since the second one is not
         # associated with any tabs
-        payload = views.Superset._get_sqllab_tabs(user_id=user_id)
+        # TODO: replaces this spec by api/v1/sqllab spec later
+        payload = bootstrap_sqllab_data(user_id)
         self.assertEqual(len(payload["queries"]), 1)
 
     @mock.patch.dict(