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

maximebeauchemin pushed a commit to branch folder-api
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/folder-api by this push:
     new 165a1cd6d3 feat: export/import for dataset folders (#32534)
165a1cd6d3 is described below

commit 165a1cd6d3fa9eed70942604f89e5a79ef3818e0
Author: Beto Dealmeida <[email protected]>
AuthorDate: Thu Apr 10 13:57:47 2025 -0400

    feat: export/import for dataset folders (#32534)
    
    Co-authored-by: Maxime Beauchemin <[email protected]>
---
 superset/commands/dataset/update.py                |  19 ++-
 superset/connectors/sqla/models.py                 |   1 +
 superset/datasets/schemas.py                       |   6 +-
 ...25-03-03_20-52_94e7a3499973_add_folder_table.py |  42 ++++++
 tests/integration_tests/datasets/api_tests.py      |  14 ++
 tests/integration_tests/datasets/commands_tests.py |   2 +
 tests/unit_tests/commands/dataset/test_update.py   |  96 ++++++++++++
 tests/unit_tests/datasets/commands/export_test.py  |  67 +++++++++
 .../datasets/commands/importers/v1/import_test.py  | 166 +++++++++++++++++++++
 9 files changed, 407 insertions(+), 6 deletions(-)

diff --git a/superset/commands/dataset/update.py 
b/superset/commands/dataset/update.py
index 7f6134d20a..e36fbc0bf1 100644
--- a/superset/commands/dataset/update.py
+++ b/superset/commands/dataset/update.py
@@ -222,8 +222,8 @@ def validate_folders(  # noqa: C901
         raise ValidationError("Dataset folders are not enabled")
 
     existing = {
-        *[metric.uuid for metric in metrics],
-        *[column.uuid for column in columns],
+        "metric": {metric.uuid: metric.metric_name for metric in metrics},
+        "column": {column.uuid: column.column_name for column in columns},
     }
 
     queue: list[tuple[FolderSchema, list[str]]] = [(folder, []) for folder in 
folders]
@@ -231,7 +231,7 @@ def validate_folders(  # noqa: C901
     seen_fqns = set()  # fully qualified folder names
     while queue:
         obj, path = queue.pop(0)
-        uuid, name = obj["uuid"], obj.get("name")
+        uuid, name, type = obj["uuid"], obj.get("name"), obj["type"]
 
         if uuid in path:
             raise ValidationError(f"Cycle detected: {uuid} appears in its 
ancestry")
@@ -243,13 +243,22 @@ def validate_folders(  # noqa: C901
         # folders can have duplicate name as long as they're not siblings
         if name:
             fqn = tuple(path + [name])
-            if name and fqn in seen_fqns:
+            if type == "folder" and fqn in seen_fqns:
                 raise ValidationError(f"Duplicate folder name: {name}")
             seen_fqns.add(fqn)
 
-            if name.lower() in {"metrics", "columns"}:
+            if type == "folder" and name.lower() in {
+                "metrics",
+                "columns",
+            }:
                 raise ValidationError(f"Folder cannot have name '{name}'")
 
+            if type in {"metric", "column"}:
+                if uuid not in existing[type]:
+                    raise ValidationError(f"Invalid UUID for {type} '{name}': 
{uuid}")
+                if name != existing[type][uuid]:
+                    raise ValidationError(f"Mismatched name '{name}' for UUID 
'{uuid}'")
+
         # check if metric/column UUID exists
         elif not name and uuid not in existing:
             raise ValidationError(f"Invalid UUID: {uuid}")
diff --git a/superset/connectors/sqla/models.py 
b/superset/connectors/sqla/models.py
index b143e09805..d74b2ef5c0 100644
--- a/superset/connectors/sqla/models.py
+++ b/superset/connectors/sqla/models.py
@@ -1220,6 +1220,7 @@ class SqlaTable(
         "extra",
         "normalize_columns",
         "always_filter_main_dttm",
+        "folders",
     ]
     update_from_object_fields = [f for f in export_fields if f != 
"database_id"]
     export_parent = "database"
diff --git a/superset/datasets/schemas.py b/superset/datasets/schemas.py
index deb6d4a355..c6e13325dd 100644
--- a/superset/datasets/schemas.py
+++ b/superset/datasets/schemas.py
@@ -20,7 +20,7 @@ from typing import Any
 from dateutil.parser import isoparse
 from flask_babel import lazy_gettext as _
 from marshmallow import fields, pre_load, Schema, validates_schema, 
ValidationError
-from marshmallow.validate import Length
+from marshmallow.validate import Length, OneOf
 
 from superset.exceptions import SupersetMarshmallowValidationError
 from superset.utils import json
@@ -90,6 +90,10 @@ class DatasetMetricsPutSchema(Schema):
 
 class FolderSchema(Schema):
     uuid = fields.UUID(required=True)
+    type = fields.String(
+        required=False,
+        validate=OneOf(["metric", "column", "folder"]),
+    )
     name = fields.String(required=False, validate=Length(1, 250))
     description = fields.String(
         required=False,
diff --git 
a/superset/migrations/versions/2025-03-03_20-52_94e7a3499973_add_folder_table.py
 
b/superset/migrations/versions/2025-03-03_20-52_94e7a3499973_add_folder_table.py
new file mode 100644
index 0000000000..e95e3bbac1
--- /dev/null
+++ 
b/superset/migrations/versions/2025-03-03_20-52_94e7a3499973_add_folder_table.py
@@ -0,0 +1,42 @@
+# 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 folder table
+
+Revision ID: 94e7a3499973
+Revises: 74ad1125881c
+Create Date: 2025-03-03 20:52:24.585143
+
+"""
+
+import sqlalchemy as sa
+from alembic import op
+from sqlalchemy.types import JSON
+
+# revision identifiers, used by Alembic.
+revision = "94e7a3499973"
+down_revision = "74ad1125881c"
+
+
+def upgrade():
+    op.add_column(
+        "tables",
+        sa.Column("folders", JSON, nullable=True),
+    )
+
+
+def downgrade():
+    op.drop_column("tables", "folders")
diff --git a/tests/integration_tests/datasets/api_tests.py 
b/tests/integration_tests/datasets/api_tests.py
index 97f22bbdd2..cb05260460 100644
--- a/tests/integration_tests/datasets/api_tests.py
+++ b/tests/integration_tests/datasets/api_tests.py
@@ -1574,24 +1574,31 @@ class TestDatasetApi(SupersetTestCase):
         dataset_data = {
             "folders": [
                 {
+                    "type": "folder",
                     "uuid": "b49ac3dd-c79b-42a4-9082-39ee74f3b369",
                     "name": "My metrics",
                     "children": [
                         {
+                            "type": "metric",
                             "uuid": dataset.metrics[0].uuid,
+                            "name": dataset.metrics[0].metric_name,
                         },
                     ],
                 },
                 {
+                    "type": "folder",
                     "uuid": "f5db85fa-75d6-45e5-bdce-c6194db80642",
                     "name": "My columns",
                     "children": [
                         {
+                            "type": "folder",
                             "uuid": "b5330233-e323-4157-b767-98b16f00ca93",
                             "name": "Dimensions",
                             "children": [
                                 {
+                                    "type": "column",
                                     "uuid": dataset.columns[1].uuid,
+                                    "name": dataset.columns[1].column_name,
                                 },
                             ],
                         },
@@ -1608,23 +1615,30 @@ class TestDatasetApi(SupersetTestCase):
         assert model.folders == [
             {
                 "uuid": "b49ac3dd-c79b-42a4-9082-39ee74f3b369",
+                "type": "folder",
                 "name": "My metrics",
                 "children": [
                     {
                         "uuid": str(dataset.metrics[0].uuid),
+                        "type": "metric",
+                        "name": "count",
                     }
                 ],
             },
             {
                 "uuid": "f5db85fa-75d6-45e5-bdce-c6194db80642",
+                "type": "folder",
                 "name": "My columns",
                 "children": [
                     {
                         "uuid": "b5330233-e323-4157-b767-98b16f00ca93",
+                        "type": "folder",
                         "name": "Dimensions",
                         "children": [
                             {
                                 "uuid": str(dataset.columns[1].uuid),
+                                "type": "column",
+                                "name": "name",
                             }
                         ],
                     }
diff --git a/tests/integration_tests/datasets/commands_tests.py 
b/tests/integration_tests/datasets/commands_tests.py
index 2c0a9ce618..fb802bd1bf 100644
--- a/tests/integration_tests/datasets/commands_tests.py
+++ b/tests/integration_tests/datasets/commands_tests.py
@@ -171,6 +171,7 @@ class TestExportDatasetsCommand(SupersetTestCase):
                     "warning_text": None,
                 },
             ],
+            "folders": None,
             "normalize_columns": False,
             "always_filter_main_dttm": False,
             "offset": 0,
@@ -235,6 +236,7 @@ class TestExportDatasetsCommand(SupersetTestCase):
             "extra",
             "normalize_columns",
             "always_filter_main_dttm",
+            "folders",
             "uuid",
             "metrics",
             "columns",
diff --git a/tests/unit_tests/commands/dataset/test_update.py 
b/tests/unit_tests/commands/dataset/test_update.py
index 66dc1414c4..c38f978728 100644
--- a/tests/unit_tests/commands/dataset/test_update.py
+++ b/tests/unit_tests/commands/dataset/test_update.py
@@ -83,16 +83,23 @@ def test_validate_folders(mocker: MockerFixture) -> None:
         [
             {
                 "uuid": "uuid4",
+                "type": "folder",
                 "name": "My folder",
                 "children": [
                     {
                         "uuid": "uuid1",
+                        "type": "metric",
+                        "name": "metric1",
                     },
                     {
                         "uuid": "uuid2",
+                        "type": "column",
+                        "name": "column1",
                     },
                     {
                         "uuid": "uuid3",
+                        "type": "column",
+                        "name": "column2",
                     },
                 ],
             },
@@ -111,14 +118,17 @@ def test_validate_folders_cycle(mocker: MockerFixture) -> 
None:
         [
             {
                 "uuid": "uuid1",
+                "type": "folder",
                 "name": "My folder",
                 "children": [
                     {
                         "uuid": "uuid2",
+                        "type": "folder",
                         "name": "My other folder",
                         "children": [
                             {
                                 "uuid": "uuid1",
+                                "type": "folder",
                                 "name": "My folder",
                                 "children": [],
                             },
@@ -144,10 +154,12 @@ def test_validate_folders_inter_cycle(mocker: 
MockerFixture) -> None:
         [
             {
                 "uuid": "uuid1",
+                "type": "folder",
                 "name": "My folder",
                 "children": [
                     {
                         "uuid": "uuid2",
+                        "type": "folder",
                         "name": "My other folder",
                         "children": [],
                     },
@@ -155,10 +167,12 @@ def test_validate_folders_inter_cycle(mocker: 
MockerFixture) -> None:
             },
             {
                 "uuid": "uuid2",
+                "type": "folder",
                 "name": "My other folder",
                 "children": [
                     {
                         "uuid": "uuid1",
+                        "type": "folder",
                         "name": "My folder",
                         "children": [],
                     },
@@ -183,19 +197,25 @@ def test_validate_folders_duplicates(mocker: 
MockerFixture) -> None:
         [
             {
                 "uuid": "uuid1",
+                "type": "folder",
                 "name": "My folder",
                 "children": [
                     {
                         "uuid": "uuid2",
+                        "type": "metric",
+                        "name": "count",
                     },
                 ],
             },
             {
                 "uuid": "uuid2",
+                "type": "folder",
                 "name": "My other folder",
                 "children": [
                     {
                         "uuid": "uuid2",
+                        "type": "metric",
+                        "name": "count",
                     },
                 ],
             },
@@ -217,10 +237,12 @@ def 
test_validate_folders_duplicate_name_not_siblings(mocker: MockerFixture) ->
         [
             {
                 "uuid": "uuid1",
+                "type": "folder",
                 "name": "Sales",
                 "children": [
                     {
                         "uuid": "uuid2",
+                        "type": "folder",
                         "name": "Core",
                         "children": [],
                     },
@@ -228,10 +250,12 @@ def 
test_validate_folders_duplicate_name_not_siblings(mocker: MockerFixture) ->
             },
             {
                 "uuid": "uuid3",
+                "type": "folder",
                 "name": "Engineering",
                 "children": [
                     {
                         "uuid": "uuid4",
+                        "type": "folder",
                         "name": "Core",
                         "children": [],
                     },
@@ -253,10 +277,12 @@ def test_validate_folders_duplicate_name_siblings(mocker: 
MockerFixture) -> None
         [
             {
                 "uuid": "uuid1",
+                "type": "folder",
                 "name": "Sales",
                 "children": [
                     {
                         "uuid": "uuid2",
+                        "type": "folder",
                         "name": "Core",
                         "children": [],
                     },
@@ -264,10 +290,12 @@ def test_validate_folders_duplicate_name_siblings(mocker: 
MockerFixture) -> None
             },
             {
                 "uuid": "uuid3",
+                "type": "folder",
                 "name": "Sales",
                 "children": [
                     {
                         "uuid": "uuid4",
+                        "type": "folder",
                         "name": "Other",
                         "children": [],
                     },
@@ -291,6 +319,7 @@ def test_validate_folders_invalid_names(mocker: 
MockerFixture) -> None:
         [
             {
                 "uuid": "uuid1",
+                "type": "folder",
                 "name": "Metrics",
                 "children": [],
             },
@@ -301,6 +330,7 @@ def test_validate_folders_invalid_names(mocker: 
MockerFixture) -> None:
         [
             {
                 "uuid": "uuid1",
+                "type": "folder",
                 "name": "Columns",
                 "children": [],
             },
@@ -314,3 +344,69 @@ def test_validate_folders_invalid_names(mocker: 
MockerFixture) -> None:
     with pytest.raises(ValidationError) as excinfo:
         validate_folders(folders=folders_with_columns, metrics=[], columns=[])
     assert str(excinfo.value) == "Folder cannot have name 'Columns'"
+
+
+@with_feature_flags(DATASET_FOLDERS=True)
+def test_validate_folders_invalid_uuid(mocker: MockerFixture) -> None:
+    """
+    Test that we can detect invalid UUIDs.
+    """
+    metrics = [mocker.MagicMock(metric_name="metric1", uuid="uuid1")]
+    columns = [
+        mocker.MagicMock(column_name="column1", uuid="uuid2"),
+        mocker.MagicMock(column_name="column2", uuid="uuid3"),
+    ]
+    folders = cast(
+        list[FolderSchema],
+        [
+            {
+                "uuid": "uuid4",
+                "type": "folder",
+                "name": "My folder",
+                "children": [
+                    {
+                        "uuid": "uuid2",
+                        "type": "metric",
+                        "name": "metric1",
+                    },
+                ],
+            },
+        ],
+    )
+
+    with pytest.raises(ValidationError) as excinfo:
+        validate_folders(folders=folders, metrics=metrics, columns=columns)
+    assert str(excinfo.value) == "Invalid UUID for metric 'metric1': uuid2"
+
+
+@with_feature_flags(DATASET_FOLDERS=True)
+def test_validate_folders_mismatched_name(mocker: MockerFixture) -> None:
+    """
+    Test that we can detect mismatched names.
+    """
+    metrics = [mocker.MagicMock(metric_name="metric1", uuid="uuid1")]
+    columns = [
+        mocker.MagicMock(column_name="column1", uuid="uuid2"),
+        mocker.MagicMock(column_name="column2", uuid="uuid3"),
+    ]
+    folders = cast(
+        list[FolderSchema],
+        [
+            {
+                "uuid": "uuid4",
+                "type": "folder",
+                "name": "My folder",
+                "children": [
+                    {
+                        "uuid": "uuid1",
+                        "type": "metric",
+                        "name": "metric2",
+                    },
+                ],
+            },
+        ],
+    )
+
+    with pytest.raises(ValidationError) as excinfo:
+        validate_folders(folders=folders, metrics=metrics, columns=columns)
+    assert str(excinfo.value) == "Mismatched name 'metric2' for UUID 'uuid1'"
diff --git a/tests/unit_tests/datasets/commands/export_test.py 
b/tests/unit_tests/datasets/commands/export_test.py
index f42bbfc9cb..04bc989ba5 100644
--- a/tests/unit_tests/datasets/commands/export_test.py
+++ b/tests/unit_tests/datasets/commands/export_test.py
@@ -16,6 +16,8 @@
 # under the License.
 # pylint: disable=import-outside-toplevel, unused-argument, unused-import
 
+from uuid import UUID
+
 from sqlalchemy.orm.session import Session
 
 from superset import db
@@ -47,6 +49,7 @@ def test_export(session: Session) -> None:
             type="INTEGER",
             expression="revenue-expenses",
             extra=json.dumps({"certified_by": "User"}),
+            uuid=UUID("00000000-0000-0000-0000-000000000005"),
         ),
     ]
     metrics = [
@@ -54,6 +57,7 @@ def test_export(session: Session) -> None:
             metric_name="cnt",
             expression="COUNT(*)",
             extra=json.dumps({"warning_markdown": None}),
+            uuid=UUID("00000000-0000-0000-0000-000000000004"),
         ),
     ]
 
@@ -61,6 +65,46 @@ def test_export(session: Session) -> None:
         table_name="my_table",
         columns=columns,
         metrics=metrics,
+        folders=[
+            {
+                "uuid": "00000000-0000-0000-0000-000000000000",
+                "type": "folder",
+                "name": "Engineering",
+                "children": [
+                    {
+                        "uuid": "00000000-0000-0000-0000-000000000001",
+                        "type": "folder",
+                        "name": "Core",
+                        "children": [
+                            {
+                                "uuid": "00000000-0000-0000-0000-000000000004",
+                                "type": "metric",
+                                "name": "cnt",
+                            },
+                        ],
+                    },
+                ],
+            },
+            {
+                "uuid": "00000000-0000-0000-0000-000000000002",
+                "type": "folder",
+                "name": "Sales",
+                "children": [
+                    {
+                        "uuid": "00000000-0000-0000-0000-000000000003",
+                        "type": "folder",
+                        "name": "Core",
+                        "children": [
+                            {
+                                "uuid": "00000000-0000-0000-0000-000000000005",
+                                "type": "column",
+                                "name": "profit",
+                            },
+                        ],
+                    },
+                ],
+            },
+        ],
         main_dttm_col="ds",
         database=database,
         offset=-8,
@@ -126,6 +170,29 @@ extra:
   warning_markdown: '*WARNING*'
 normalize_columns: false
 always_filter_main_dttm: false
+folders:
+- uuid: 00000000-0000-0000-0000-000000000000
+  type: folder
+  name: Engineering
+  children:
+  - uuid: 00000000-0000-0000-0000-000000000001
+    type: folder
+    name: Core
+    children:
+    - uuid: 00000000-0000-0000-0000-000000000004
+      type: metric
+      name: cnt
+- uuid: 00000000-0000-0000-0000-000000000002
+  type: folder
+  name: Sales
+  children:
+  - uuid: 00000000-0000-0000-0000-000000000003
+    type: folder
+    name: Core
+    children:
+    - uuid: 00000000-0000-0000-0000-000000000005
+      type: column
+      name: profit
 uuid: {payload["uuid"]}
 metrics:
 - metric_name: cnt
diff --git a/tests/unit_tests/datasets/commands/importers/v1/import_test.py 
b/tests/unit_tests/datasets/commands/importers/v1/import_test.py
index 6bba6f039d..2d8c0ede4d 100644
--- a/tests/unit_tests/datasets/commands/importers/v1/import_test.py
+++ b/tests/unit_tests/datasets/commands/importers/v1/import_test.py
@@ -89,6 +89,7 @@ def test_import_dataset(mocker: MockerFixture, session: 
Session) -> None:
                 "d3format": None,
                 "extra": {"warning_markdown": None},
                 "warning_text": None,
+                "uuid": "00000000-0000-0000-0000-000000000001",
             }
         ],
         "columns": [
@@ -106,8 +107,49 @@ def test_import_dataset(mocker: MockerFixture, session: 
Session) -> None:
                 "extra": {
                     "certified_by": "User",
                 },
+                "uuid": "00000000-0000-0000-0000-000000000002",
             }
         ],
+        "folders": [
+            {
+                "uuid": "00000000-0000-0000-0000-000000000000",
+                "type": "folder",
+                "name": "Engineering",
+                "children": [
+                    {
+                        "uuid": "00000000-0000-0000-0000-000000000001",
+                        "type": "folder",
+                        "name": "Core",
+                        "children": [
+                            {
+                                "uuid": "00000000-0000-0000-0000-000000000004",
+                                "type": "metric",
+                                "name": "cnt",
+                            },
+                        ],
+                    },
+                ],
+            },
+            {
+                "uuid": "00000000-0000-0000-0000-000000000002",
+                "type": "folder",
+                "name": "Sales",
+                "children": [
+                    {
+                        "uuid": "00000000-0000-0000-0000-000000000003",
+                        "type": "folder",
+                        "name": "Core",
+                        "children": [
+                            {
+                                "uuid": "00000000-0000-0000-0000-000000000005",
+                                "type": "column",
+                                "name": "profit",
+                            },
+                        ],
+                    },
+                ],
+            },
+        ],
         "database_uuid": database.uuid,
         "database_id": database.id,
     }
@@ -139,6 +181,9 @@ def test_import_dataset(mocker: MockerFixture, session: 
Session) -> None:
     assert sqla_table.metrics[0].d3format is None
     assert sqla_table.metrics[0].extra == '{"warning_markdown": null}'
     assert sqla_table.metrics[0].warning_text is None
+    assert sqla_table.metrics[0].uuid == uuid.UUID(
+        "00000000-0000-0000-0000-000000000001"
+    )
     assert len(sqla_table.columns) == 1
     assert sqla_table.columns[0].column_name == "profit"
     assert sqla_table.columns[0].verbose_name is None
@@ -151,10 +196,131 @@ def test_import_dataset(mocker: MockerFixture, session: 
Session) -> None:
     assert sqla_table.columns[0].description is None
     assert sqla_table.columns[0].python_date_format is None
     assert sqla_table.columns[0].extra == '{"certified_by": "User"}'
+    assert sqla_table.columns[0].uuid == uuid.UUID(
+        "00000000-0000-0000-0000-000000000002"
+    )
+    assert sqla_table.folders == [
+        {
+            "uuid": "00000000-0000-0000-0000-000000000000",
+            "type": "folder",
+            "name": "Engineering",
+            "children": [
+                {
+                    "uuid": "00000000-0000-0000-0000-000000000001",
+                    "type": "folder",
+                    "name": "Core",
+                    "children": [
+                        {
+                            "uuid": "00000000-0000-0000-0000-000000000004",
+                            "type": "metric",
+                            "name": "cnt",
+                        },
+                    ],
+                },
+            ],
+        },
+        {
+            "uuid": "00000000-0000-0000-0000-000000000002",
+            "type": "folder",
+            "name": "Sales",
+            "children": [
+                {
+                    "uuid": "00000000-0000-0000-0000-000000000003",
+                    "type": "folder",
+                    "name": "Core",
+                    "children": [
+                        {
+                            "uuid": "00000000-0000-0000-0000-000000000005",
+                            "type": "column",
+                            "name": "profit",
+                        },
+                    ],
+                },
+            ],
+        },
+    ]
     assert sqla_table.database.uuid == database.uuid
     assert sqla_table.database.id == database.id
 
 
+def test_import_dataset_no_folder(mocker: MockerFixture, session: Session) -> 
None:
+    """
+    Test importing a dataset that was exported without folders.
+    """
+    from superset import security_manager
+    from superset.commands.dataset.importers.v1.utils import import_dataset
+    from superset.connectors.sqla.models import SqlaTable
+    from superset.models.core import Database
+
+    mocker.patch.object(security_manager, "can_access", return_value=True)
+
+    engine = db.session.get_bind()
+    SqlaTable.metadata.create_all(engine)  # pylint: disable=no-member
+
+    database = Database(database_name="my_database", 
sqlalchemy_uri="sqlite://")
+    db.session.add(database)
+    db.session.flush()
+
+    dataset_uuid = uuid.uuid4()
+    config = {
+        "table_name": "my_table",
+        "main_dttm_col": "ds",
+        "description": "This is the description",
+        "default_endpoint": None,
+        "offset": -8,
+        "cache_timeout": 3600,
+        "catalog": "public",
+        "schema": "my_schema",
+        "sql": None,
+        "params": {
+            "remote_id": 64,
+            "database_name": "examples",
+            "import_time": 1606677834,
+        },
+        "template_params": {
+            "answer": "42",
+        },
+        "filter_select_enabled": True,
+        "fetch_values_predicate": "foo IN (1, 2)",
+        "extra": {"warning_markdown": "*WARNING*"},
+        "uuid": dataset_uuid,
+        "metrics": [
+            {
+                "metric_name": "cnt",
+                "verbose_name": None,
+                "metric_type": None,
+                "expression": "COUNT(*)",
+                "description": None,
+                "d3format": None,
+                "extra": {"warning_markdown": None},
+                "warning_text": None,
+            }
+        ],
+        "columns": [
+            {
+                "column_name": "profit",
+                "verbose_name": None,
+                "is_dttm": None,
+                "is_active": None,
+                "type": "INTEGER",
+                "groupby": None,
+                "filterable": None,
+                "expression": "revenue-expenses",
+                "description": None,
+                "python_date_format": None,
+                "extra": {
+                    "certified_by": "User",
+                },
+            }
+        ],
+        "database_uuid": database.uuid,
+        "database_id": database.id,
+    }
+
+    sqla_table = import_dataset(config)
+    assert sqla_table.folders is None
+
+
 def test_import_dataset_duplicate_column(
     mocker: MockerFixture, session: Session
 ) -> None:

Reply via email to