bito-code-review[bot] commented on code in PR #38402:
URL: https://github.com/apache/superset/pull/38402#discussion_r2932101245


##########
superset/mcp_service/chart/validation/schema_validator.py:
##########
@@ -282,6 +286,82 @@ def _pre_validate_pie_config(
 
         return True, None
 
+    @staticmethod
+    def _pre_validate_handlebars_config(
+        config: Dict[str, Any],
+    ) -> Tuple[bool, ChartGenerationError | None]:
+        """Pre-validate handlebars chart configuration."""
+        if "handlebars_template" not in config:
+            return False, ChartGenerationError(
+                error_type="missing_handlebars_template",
+                message="Handlebars chart missing required field: 
handlebars_template",
+                details="Handlebars charts require a 'handlebars_template' 
string "
+                "containing Handlebars HTML template markup",
+                suggestions=[
+                    "Add 'handlebars_template' with a Handlebars HTML 
template",
+                    "Data is available as {{data}} array in the template",
+                    "Example: '<ul>{{#each data}}<li>{{this.name}}: "
+                    "{{this.value}}</li>{{/each}}</ul>'",
+                ],
+                error_code="MISSING_HANDLEBARS_TEMPLATE",
+            )
+
+        template = config.get("handlebars_template")
+        if not isinstance(template, str) or not template.strip():
+            return False, ChartGenerationError(
+                error_type="invalid_handlebars_template",
+                message="Handlebars template must be a non-empty string",
+                details="The 'handlebars_template' field must be a non-empty 
string "
+                "containing valid Handlebars HTML template markup",
+                suggestions=[
+                    "Ensure handlebars_template is a non-empty string",
+                    "Example: '<ul>{{#each 
data}}<li>{{this.name}}</li>{{/each}}</ul>'",
+                ],
+                error_code="INVALID_HANDLEBARS_TEMPLATE",
+            )
+
+        query_mode = config.get("query_mode", "aggregate")
+        if query_mode not in ("aggregate", "raw"):
+            return False, ChartGenerationError(
+                error_type="invalid_query_mode",
+                message="Invalid query_mode for handlebars chart",
+                details="query_mode must be either 'aggregate' or 'raw'",
+                suggestions=[
+                    "Use 'aggregate' for aggregated data (default)",
+                    "Use 'raw' for individual rows",
+                ],
+                error_code="INVALID_QUERY_MODE",
+            )
+
+        if query_mode == "raw" and "columns" not in config:
+            return False, ChartGenerationError(
+                error_type="missing_raw_columns",
+                message="Handlebars chart in 'raw' mode requires 'columns'",
+                details="When query_mode is 'raw', you must specify which 
columns "
+                "to include in the query results",
+                suggestions=[
+                    "Add 'columns': [{'name': 'column_name'}] for raw mode",
+                    "Or use query_mode='aggregate' with 'metrics' "
+                    "and optional 'groupby'",
+                ],
+                error_code="MISSING_RAW_COLUMNS",
+            )
+
+        if query_mode == "aggregate" and "metrics" not in config:
+            return False, ChartGenerationError(

Review Comment:
   <!-- Bito Reply -->
   Yes, the suggestion is valid — it adds a fast-path rejection for missing 
'metrics' key in aggregate mode, with empty lists handled by Pydantic's 
minItems=1 constraint for two-layer validation.



##########
superset/mcp_service/chart/validation/schema_validator.py:
##########
@@ -282,6 +286,82 @@ def _pre_validate_pie_config(
 
         return True, None
 
+    @staticmethod
+    def _pre_validate_handlebars_config(
+        config: Dict[str, Any],
+    ) -> Tuple[bool, ChartGenerationError | None]:
+        """Pre-validate handlebars chart configuration."""
+        if "handlebars_template" not in config:
+            return False, ChartGenerationError(
+                error_type="missing_handlebars_template",
+                message="Handlebars chart missing required field: 
handlebars_template",
+                details="Handlebars charts require a 'handlebars_template' 
string "
+                "containing Handlebars HTML template markup",
+                suggestions=[
+                    "Add 'handlebars_template' with a Handlebars HTML 
template",
+                    "Data is available as {{data}} array in the template",
+                    "Example: '<ul>{{#each data}}<li>{{this.name}}: "
+                    "{{this.value}}</li>{{/each}}</ul>'",
+                ],
+                error_code="MISSING_HANDLEBARS_TEMPLATE",
+            )
+
+        template = config.get("handlebars_template")
+        if not isinstance(template, str) or not template.strip():
+            return False, ChartGenerationError(
+                error_type="invalid_handlebars_template",
+                message="Handlebars template must be a non-empty string",
+                details="The 'handlebars_template' field must be a non-empty 
string "
+                "containing valid Handlebars HTML template markup",
+                suggestions=[
+                    "Ensure handlebars_template is a non-empty string",
+                    "Example: '<ul>{{#each 
data}}<li>{{this.name}}</li>{{/each}}</ul>'",
+                ],
+                error_code="INVALID_HANDLEBARS_TEMPLATE",
+            )
+
+        query_mode = config.get("query_mode", "aggregate")
+        if query_mode not in ("aggregate", "raw"):
+            return False, ChartGenerationError(
+                error_type="invalid_query_mode",
+                message="Invalid query_mode for handlebars chart",
+                details="query_mode must be either 'aggregate' or 'raw'",
+                suggestions=[
+                    "Use 'aggregate' for aggregated data (default)",
+                    "Use 'raw' for individual rows",
+                ],
+                error_code="INVALID_QUERY_MODE",
+            )
+
+        if query_mode == "raw" and "columns" not in config:

Review Comment:
   <!-- Bito Reply -->
   Your explanation is correct. The pre-validation checks for the absence of 
the 'columns' key as a quick reject, while Pydantic's model validator catches 
empty or None 'columns' in raw mode, creating an intentional two-layer 
validation.



-- 
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