codeant-ai-for-open-source[bot] commented on code in PR #40912:
URL: https://github.com/apache/superset/pull/40912#discussion_r3493574372


##########
superset/dashboards/api.py:
##########
@@ -528,6 +531,126 @@ def get(
         )
         return self.response(200, result=result)
 
+    @expose("/<id_or_slug>/lineage", methods=("GET",))
+    @protect()
+    @safe
+    @statsd_metrics
+    @with_dashboard
+    @event_logger.log_this_with_context(
+        action=lambda self, *args, **kwargs: 
f"{self.__class__.__name__}.lineage",
+        log_to_statsd=False,
+    )
+    # pylint: disable=arguments-differ,arguments-renamed
+    def lineage(self, dash: Dashboard) -> Response:
+        """Get lineage information for a dashboard.
+        ---
+        get:
+          summary: Get lineage information for a dashboard
+          description: >-
+            Returns upstream (charts, datasets, databases) lineage information
+            for a dashboard
+          parameters:
+          - in: path
+            name: id_or_slug
+            schema:
+              type: string
+            description: Either the id of the dashboard, or its slug
+          responses:
+            200:
+              description: Lineage information
+              content:
+                application/json:
+                  schema:
+                    $ref: "#/components/schemas/DashboardLineageResponseSchema"
+            401:
+              $ref: '#/components/responses/401'
+            404:
+              $ref: '#/components/responses/404'
+            500:
+              $ref: '#/components/responses/500'
+        """
+        dashboard_info = {
+            "id": dash.id,
+            "title": dash.dashboard_title,
+            "slug": dash.slug,
+            "published": dash.published,
+        }
+
+        # Get upstream (charts, datasets, databases) information
+        charts = []
+        dataset_map = {}
+        database_map = {}
+
+        for chart in dash.slices:
+            charts.append(
+                {
+                    "id": chart.id,
+                    "slice_name": chart.slice_name,
+                    "viz_type": chart.viz_type,
+                    "dataset_id": chart.datasource_id,
+                }
+            )
+
+            # Collect dataset information. Schema/table/database details are
+            # only exposed to users who can access the underlying datasource;
+            # otherwise they are redacted so lineage never leaks datasource
+            # internals (the dataset id/name are kept so the graph still
+            # renders).
+            dataset = chart.datasource

Review Comment:
   **Suggestion:** This loop can trigger an N+1 query pattern because each 
iteration dereferences `chart.datasource` (and then `dataset.database`) lazily, 
causing one query per chart on large dashboards. Eager-load slices with their 
datasource/database (for example via joinedload/selectinload in the dashboard 
fetch) before iterating. [performance]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ Dashboard lineage endpoint issues extra database queries.
   - ⚠️ Large dashboards may show slower lineage responses.
   - ⚠️ Additional load on metadata database under heavy usage.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Open a dashboard with many charts in the UI; this triggers 
`useDashboardLineage()` in
   `superset-frontend/src/hooks/apiResources/lineage.ts:147`, which calls `GET
   /api/v1/dashboard/<id_or_slug>/lineage`.
   
   2. The request is routed to `DashboardRestApi.lineage()` in
   `superset/dashboards/api.py:35-45`, where the `@with_dashboard` decorator 
resolves the
   `Dashboard` instance and passes it as `dash` into the method.
   
   3. Inside `DashboardRestApi.lineage()` at 
`superset/dashboards/api.py:584-599`, the code
   iterates `for chart in dash.slices:` and accesses `chart.datasource` (via the
   `Slice.datasource` property in `superset/models/slice.py:145-147`) and then
   `dataset.database` (SQLAlchemy relationship on `SqlaTable.database` in
   `superset/connectors/sqla/models.py:40-50`).
   
   4. While `Slice.datasource` uses `lazy="subquery"` (avoiding one query per 
chart), each
   distinct dataset still lazily loads its `database` via a separate `SELECT`, 
so dashboards
   with many datasets incur an extra query per dataset; fixing this by 
eager-loading
   `database` for all datasets used in the dashboard would reduce these 
additional
   round-trips.
   ```
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=e56e0fb932e24a3f90f52ca126eb22f9&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=e56e0fb932e24a3f90f52ca126eb22f9&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/dashboards/api.py
   **Line:** 584:599
   **Comment:**
        *Performance: This loop can trigger an N+1 query pattern because each 
iteration dereferences `chart.datasource` (and then `dataset.database`) lazily, 
causing one query per chart on large dashboards. Eager-load slices with their 
datasource/database (for example via joinedload/selectinload in the dashboard 
fetch) before iterating.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40912&comment_hash=0c7cd8ee8ee55a3531b0a052caf9c2a5ea6b19ca19d6891fe5a3820715334378&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40912&comment_hash=0c7cd8ee8ee55a3531b0a052caf9c2a5ea6b19ca19d6891fe5a3820715334378&reaction=dislike'>👎</a>



##########
superset/datasets/api.py:
##########
@@ -855,6 +858,130 @@ def related_objects(self, id_or_uuid: str) -> Response:
             dashboards={"count": len(dashboards), "result": dashboards},
         )
 
+    @expose("/<id_or_uuid>/lineage", methods=("GET",))
+    @protect()
+    @safe
+    @statsd_metrics
+    @event_logger.log_this_with_context(
+        action=lambda self, *args, **kwargs: 
f"{self.__class__.__name__}.lineage",
+        log_to_statsd=False,
+    )
+    def lineage(self, id_or_uuid: str) -> Response:
+        """Get lineage information for a dataset.
+        ---
+        get:
+          summary: Get lineage information for a dataset
+          description: >-
+            Returns upstream (database) and downstream (charts, dashboards) 
lineage
+            information for a dataset
+          parameters:
+          - in: path
+            name: id_or_uuid
+            schema:
+              type: string
+            description: Either the id of the dataset, or its uuid
+          responses:
+            200:
+              description: Lineage information
+              content:
+                application/json:
+                  schema:
+                    $ref: "#/components/schemas/DatasetLineageResponseSchema"
+            401:
+              $ref: '#/components/responses/401'
+            404:
+              $ref: '#/components/responses/404'
+            500:
+              $ref: '#/components/responses/500'
+        """
+        dataset = DatasetDAO.find_by_id_or_uuid(id_or_uuid)
+        if not dataset:
+            return self.response_404()
+
+        dataset_info = {
+            "id": dataset.id,
+            "name": dataset.name,
+            "database_id": dataset.database_id,
+            "database_name": (
+                dataset.database.database_name if dataset.database else None
+            ),
+            "schema": dataset.schema,
+            "table_name": dataset.table_name,
+        }
+
+        # Get upstream (database) information
+        upstream: dict[str, Any] = {}
+        if dataset.database:
+            upstream["database"] = {
+                "id": dataset.database.id,
+                "database_name": dataset.database.database_name,
+                "backend": dataset.database.backend,
+            }
+        else:
+            upstream["database"] = None
+
+        # Get downstream (charts and dashboards) information
+        related_data = DatasetDAO.get_related_objects(dataset.id)
+
+        # Build chart information with dashboard IDs, filtering both the charts
+        # and their linked dashboards by the current user's permissions so
+        # lineage never exposes assets the user cannot access.
+        charts: list[dict[str, Any]] = []
+        for chart in related_data["charts"]:
+            if not security_manager.can_access_chart(chart):
+                continue
+            dashboard_ids = [
+                d.id
+                for d in chart.dashboards
+                if security_manager.can_access_dashboard(d)
+            ]

Review Comment:
   **Suggestion:** This per-chart access to `chart.dashboards` can issue an 
additional query for each chart, producing N+1 behavior when a dataset has many 
related charts. Preload chart-dashboard relationships in the DAO query (or 
bulk-build a chart→dashboard map) before this loop. [performance]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ Dataset lineage endpoint performs N+1 dashboard queries.
   - ⚠️ Datasets feeding many charts incur noticeable latency.
   - ⚠️ Extra database load when lineage is viewed frequently.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Create or identify a dataset used by many charts; the dataset editor and 
lineage tab
   use `useDatasetLineage()` in 
`superset-frontend/src/hooks/apiResources/lineage.ts:125`,
   which calls `GET /api/v1/dataset/<id_or_uuid>/lineage`.
   
   2. The request reaches `DatasetRestApi.lineage()` in 
`superset/datasets/api.py:42-50`,
   which looks up the dataset via `DatasetDAO.find_by_id_or_uuid()` and then 
calls
   `DatasetDAO.get_related_objects(dataset.id)` at 
`superset/datasets/api.py:104-105`.
   
   3. `DatasetDAO.get_related_objects()` in `superset/daos/dataset.py:124-144` 
loads all
   related `Slice` objects into `related_data["charts"]` and all dashboards via 
a separate
   query, but does not eager-load the `Slice.dashboards` relationship.
   
   4. Back in `DatasetRestApi.lineage()` at `superset/datasets/api.py:930-937`, 
the loop `for
   chart in related_data["charts"]:` accesses `chart.dashboards`; this backref 
relationship
   is defined via `Dashboard.slices` in `superset/models/dashboard.py:145-147` 
with default
   lazy loading, so each chart triggers its own query to fetch dashboards, 
producing an N+1
   pattern proportional to the number of charts for the dataset.
   ```
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=cad836b1c07549dbb781905da0ec4b60&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=cad836b1c07549dbb781905da0ec4b60&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/datasets/api.py
   **Line:** 930:937
   **Comment:**
        *Performance: This per-chart access to `chart.dashboards` can issue an 
additional query for each chart, producing N+1 behavior when a dataset has many 
related charts. Preload chart-dashboard relationships in the DAO query (or 
bulk-build a chart→dashboard map) before this loop.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40912&comment_hash=b8d22c4077a96c1ef73a9ea55fdfd8904a01754d13c977604f12e8021663adcd&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40912&comment_hash=b8d22c4077a96c1ef73a9ea55fdfd8904a01754d13c977604f12e8021663adcd&reaction=dislike'>👎</a>



##########
superset/datasets/schemas.py:
##########
@@ -250,6 +250,60 @@ class DatasetRelatedObjectsResponse(Schema):
     dashboards = fields.Nested(DatasetRelatedDashboards)
 
 
+class DatasetLineageDatasetSchema(Schema):
+    id = fields.Integer()
+    name = fields.String()
+    database_id = fields.Integer()
+    database_name = fields.String()

Review Comment:
   **Suggestion:** This field is declared as always present, but the lineage 
endpoint explicitly returns null when the dataset has no attached database 
object. The schema should allow null here so OpenAPI and any schema-based 
consumers match real responses. [api mismatch]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   ⚠️ Dataset lineage spec misstates database_name nullability.
   ⚠️ Strict clients may treat missing database_name as error.
   ⚠️ Schema-based tooling reports inconsistent API response contract.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Inspect the dataset lineage implementation in 
`superset/datasets/api.py:22-45, 58-71`
   (loaded via BulkRead). In `DatasetRestApi.lineage`, `dataset_info` is built 
as `{"id":
   dataset.id, "name": dataset.name, "database_id": dataset.database_id, 
"database_name":
   (dataset.database.database_name if dataset.database else None), "schema": 
dataset.schema,
   "table_name": dataset.table_name}`; the conditional clearly allows 
`database_name` to be
   `None` when `dataset.database` is missing.
   
   2. Note that the upstream section is guarded by `if dataset.database:` at
   `superset/datasets/api.py:73-80`, but `dataset_info["database_name"]` can 
still be `None`
   because it is always included in the `result["dataset"]` payload regardless 
of whether
   `dataset.database` exists.
   
   3. Inspect the response schema in `superset/datasets/schemas.py:253-260`, 
where `class
   DatasetLineageDatasetSchema(Schema)` declares `database_name = 
fields.String()` on line
   257 in the PR hunk, without `allow_none=True`, thereby documenting 
`database_name` as a
   non-null string in the `DatasetLineageResponseSchema` used by OpenAPI at
   `superset/datasets/api.py:45-50`.
   
   4. For a dataset whose `database` relationship is missing (for example, an 
orphaned
   dataset after its database was removed or an invalid import), call `GET
   /api/v1/dataset/{id_or_uuid}/lineage` on `DatasetRestApi.lineage`. The 
actual JSON
   response includes `"database_name": null` inside `result.dataset`, while the 
schema
   declares `database_name` as a non-null string, so any strict schema-based 
client or
   validator will detect and report this mismatch.
   ```
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=e08298d405f74b86a180883fba24456a&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=e08298d405f74b86a180883fba24456a&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/datasets/schemas.py
   **Line:** 257:257
   **Comment:**
        *Api Mismatch: This field is declared as always present, but the 
lineage endpoint explicitly returns null when the dataset has no attached 
database object. The schema should allow null here so OpenAPI and any 
schema-based consumers match real responses.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40912&comment_hash=05b05f442c5cb52b4869aa6f75705bb517d4c3b1fbd17f31c9d1efe34caba5c5&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40912&comment_hash=05b05f442c5cb52b4869aa6f75705bb517d4c3b1fbd17f31c9d1efe34caba5c5&reaction=dislike'>👎</a>



##########
superset/datasets/api.py:
##########
@@ -855,6 +858,130 @@ def related_objects(self, id_or_uuid: str) -> Response:
             dashboards={"count": len(dashboards), "result": dashboards},
         )
 
+    @expose("/<id_or_uuid>/lineage", methods=("GET",))
+    @protect()
+    @safe
+    @statsd_metrics
+    @event_logger.log_this_with_context(
+        action=lambda self, *args, **kwargs: 
f"{self.__class__.__name__}.lineage",
+        log_to_statsd=False,
+    )
+    def lineage(self, id_or_uuid: str) -> Response:
+        """Get lineage information for a dataset.
+        ---
+        get:
+          summary: Get lineage information for a dataset
+          description: >-
+            Returns upstream (database) and downstream (charts, dashboards) 
lineage
+            information for a dataset
+          parameters:
+          - in: path
+            name: id_or_uuid
+            schema:
+              type: string
+            description: Either the id of the dataset, or its uuid
+          responses:
+            200:
+              description: Lineage information
+              content:
+                application/json:
+                  schema:
+                    $ref: "#/components/schemas/DatasetLineageResponseSchema"
+            401:
+              $ref: '#/components/responses/401'
+            404:
+              $ref: '#/components/responses/404'
+            500:
+              $ref: '#/components/responses/500'
+        """
+        dataset = DatasetDAO.find_by_id_or_uuid(id_or_uuid)
+        if not dataset:
+            return self.response_404()
+
+        dataset_info = {
+            "id": dataset.id,
+            "name": dataset.name,
+            "database_id": dataset.database_id,
+            "database_name": (
+                dataset.database.database_name if dataset.database else None
+            ),
+            "schema": dataset.schema,
+            "table_name": dataset.table_name,
+        }
+
+        # Get upstream (database) information
+        upstream: dict[str, Any] = {}
+        if dataset.database:
+            upstream["database"] = {
+                "id": dataset.database.id,
+                "database_name": dataset.database.database_name,
+                "backend": dataset.database.backend,
+            }
+        else:
+            upstream["database"] = None
+
+        # Get downstream (charts and dashboards) information
+        related_data = DatasetDAO.get_related_objects(dataset.id)
+
+        # Build chart information with dashboard IDs, filtering both the charts
+        # and their linked dashboards by the current user's permissions so
+        # lineage never exposes assets the user cannot access.
+        charts: list[dict[str, Any]] = []
+        for chart in related_data["charts"]:
+            if not security_manager.can_access_chart(chart):
+                continue
+            dashboard_ids = [
+                d.id
+                for d in chart.dashboards
+                if security_manager.can_access_dashboard(d)
+            ]
+            charts.append(
+                {
+                    "id": chart.id,
+                    "slice_name": chart.slice_name,
+                    "viz_type": chart.viz_type,
+                    "dashboard_ids": dashboard_ids,
+                }
+            )
+
+        # Build dashboard information with chart IDs
+        dashboards: list[dict[str, Any]] = []
+        for dashboard in related_data["dashboards"]:
+            if not security_manager.can_access_dashboard(dashboard):
+                continue
+            chart_ids = [
+                chart.id
+                for chart in dashboard.slices
+                if chart.datasource_id == dataset.id
+                and security_manager.can_access_chart(chart)
+            ]

Review Comment:
   **Suggestion:** This dashboard loop can also trigger N+1 queries because 
`dashboard.slices` is lazily loaded per dashboard. For datasets used by many 
dashboards, this causes many round-trips; preload slices for all dashboards in 
one query or reuse already-fetched chart relationships. [performance]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ Dataset lineage endpoint performs N+1 chart-list queries.
   - ⚠️ Datasets used by many dashboards suffer slower lineage.
   - ⚠️ Increased database load when lineage view is popular.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Using the same dataset-lineage flow as above, call `GET
   /api/v1/dataset/<id_or_uuid>/lineage` via `useDatasetLineage()` (frontend 
hook in
   `superset-frontend/src/hooks/apiResources/lineage.ts:125`).
   
   2. `DatasetRestApi.lineage()` in `superset/datasets/api.py:50-77` resolves 
the dataset and
   obtains `related_data = DatasetDAO.get_related_objects(dataset.id)` at
   `superset/datasets/api.py:104-105`, which returns both charts and dashboards.
   
   3. `DatasetDAO.get_related_objects()` in `superset/daos/dataset.py:124-144` 
loads
   dashboards with 
`db.session.query(Dashboard).join(Dashboard.slices)...all()`, but does not
   mark `Dashboard.slices` as eagerly loaded (no `joinedload` or 
`contains_eager`), so the
   `Dashboard.slices` relationship remains lazily loaded.
   
   4. In `DatasetRestApi.lineage()` at `superset/datasets/api.py:949-957`, the 
loop `for
   dashboard in related_data["dashboards"]:` accesses `dashboard.slices` to 
compute
   `chart_ids`; because `Dashboard.slices` (relationship defined in
   `superset/models/dashboard.py:145-147`) is lazy, each dashboard triggers a 
separate query
   to fetch its slices, resulting in an N+1 query pattern proportional to the 
number of
   dashboards linked to the dataset.
   ```
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=77933bd1a4094dc0826ed75ce908768d&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=77933bd1a4094dc0826ed75ce908768d&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/datasets/api.py
   **Line:** 949:957
   **Comment:**
        *Performance: This dashboard loop can also trigger N+1 queries because 
`dashboard.slices` is lazily loaded per dashboard. For datasets used by many 
dashboards, this causes many round-trips; preload slices for all dashboards in 
one query or reuse already-fetched chart relationships.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40912&comment_hash=18074f08e7f53569669458c1a4e08780ab6dffa84b96c6c30a66eb0ef996ea48&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40912&comment_hash=18074f08e7f53569669458c1a4e08780ab6dffa84b96c6c30a66eb0ef996ea48&reaction=dislike'>👎</a>



##########
superset/datasets/schemas.py:
##########
@@ -250,6 +250,60 @@ class DatasetRelatedObjectsResponse(Schema):
     dashboards = fields.Nested(DatasetRelatedDashboards)
 
 
+class DatasetLineageDatasetSchema(Schema):
+    id = fields.Integer()
+    name = fields.String()
+    database_id = fields.Integer()
+    database_name = fields.String()
+    schema = fields.String(allow_none=True)
+    table_name = fields.String()
+
+
+class DatasetLineageDatabaseSchema(Schema):
+    id = fields.Integer()
+    database_name = fields.String()
+    backend = fields.String()
+
+
+class DatasetLineageChartSchema(Schema):
+    id = fields.Integer()
+    slice_name = fields.String()
+    viz_type = fields.String()
+    dashboard_ids = fields.List(fields.Integer())
+
+
+class DatasetLineageDashboardSchema(Schema):
+    id = fields.Integer()
+    title = fields.String()
+    slug = fields.String()

Review Comment:
   **Suggestion:** The dashboard slug is nullable in the model, but this 
response schema declares it as a non-null string. When lineage includes 
dashboards without a slug, the documented contract becomes incorrect and any 
strict schema-based client/validation will fail. Mark this field as nullable to 
match actual API output. [api mismatch]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   ⚠️ Dataset lineage spec misstates dashboard slug nullability.
   ⚠️ Strict OpenAPI clients may reject null slug.
   ⚠️ Downstream validation tools report schema-contract violations.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Inspect the Dashboard model in `superset/models/dashboard.py:134-145`, 
where `slug =
   Column(String(255), unique=True)` is defined without `nullable=False`, 
meaning the
   database column and ORM attribute `Dashboard.slug` are allowed to be null 
and slugs are
   optional (also evidenced by `Dashboard.url` at 
`superset/models/dashboard.py:199-205`
   using `slug or id_`).
   
   2. Inspect the dataset lineage implementation in 
`superset/datasets/api.py:940-965`
   (loaded via BulkRead), where the downstream dashboards payload is built: for 
each
   dashboard in `related_data["dashboards"]`, the code appends `{"id": 
dashboard.id, "title":
   dashboard.dashboard_title, "slug": dashboard.slug, "chart_ids": chart_ids}`. 
If a
   dashboard has no slug, `dashboard.slug` is `None`, and the response includes 
`"slug":
   null`.
   
   3. Inspect the response schema in `superset/datasets/schemas.py:275-280`, 
where `class
   DatasetLineageDashboardSchema(Schema)` declares `slug = fields.String()` 
(line 278 in the
   PR hunk), without `allow_none=True`, documenting the field as a non-null 
string in the
   OpenAPI components via `DatasetLineageResponseSchema`.
   
   4. Call the lineage endpoint for any dataset that is related to a dashboard 
without a slug
   (e.g., `GET /api/v1/dataset/{id_or_uuid}/lineage`, implemented by 
`DatasetRestApi.lineage`
   at `superset/datasets/api.py:22-45, 58-71, 940-965`); observe the JSON 
payload contains
   `null` for `downstream.dashboards[*].slug`, while the documented schema
   `DatasetLineageDashboardSchema.slug` is non-null, causing schema-based 
clients or
   validators to flag a contract mismatch.
   ```
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=66cd9e83cb9a43669251da5bcfb5286a&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=66cd9e83cb9a43669251da5bcfb5286a&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/datasets/schemas.py
   **Line:** 278:278
   **Comment:**
        *Api Mismatch: The dashboard slug is nullable in the model, but this 
response schema declares it as a non-null string. When lineage includes 
dashboards without a slug, the documented contract becomes incorrect and any 
strict schema-based client/validation will fail. Mark this field as nullable to 
match actual API output.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40912&comment_hash=ee1abe435010f35bdcb00de1ea1c8cdd5e72735acf80681ce542ab38f78b6270&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40912&comment_hash=ee1abe435010f35bdcb00de1ea1c8cdd5e72735acf80681ce542ab38f78b6270&reaction=dislike'>👎</a>



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to