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


##########
superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/transformProps.ts:
##########
@@ -88,20 +98,63 @@ export default function transformProps(chartProps: 
ChartProps<QueryFormData>) {
     emitCrossFilters,
     theme,
   } = chartProps;
-  const {
-    data,
-    colnames,
-    coltypes,
-    detected_currency: detectedCurrency,
-  } = queriesData[0];
+  const groupbyCombinations = buildGroupbyCombinations(
+    formData as PivotTableQueryFormData,
+  );
+  const metricsArr = ensureIsArray(formData.metrics);
+  let data: QueryData[];
+  if (allMetricsAdditive(metricsArr)) {
+    // Additive fast-path: a single full-detail query was issued; synthesize
+    // each rollup level by reducing the leaf rows on the client (see SIP.md).
+    const leafRows = queriesData[0].data;
+    const metricReducers: Record<string, RollupReducer> = {};
+    metricsArr.forEach(metric => {
+      metricReducers[getMetricLabel(metric)] = additiveReducerFor(metric);
+    });
+    const labelLevels = groupbyCombinations.map(combination => ({
+      rows: combination.rows.map(getColumnLabel),
+      columns: combination.columns.map(getColumnLabel),
+    }));
+    const synthesized = synthesizeAdditiveLevels(
+      leafRows,
+      labelLevels,
+      metricReducers,
+    );

Review Comment:
   **Suggestion:** The new additive fast-path is enabled for MIN/MAX metrics 
too, but the reducer pipeline it calls coerces metric values to numbers; 
MIN/MAX over non-numeric data (for example strings or temporal values) will 
therefore synthesize wrong/null totals. Restrict the fast-path to numeric-safe 
aggregates or preserve native value types when reducing MIN/MAX. [type error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ❌ MIN/MAX rollup totals null for temporal/string metrics.
   - ⚠️ Pivot table diverges from backend MIN/MAX semantics.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Create a Pivot Table chart whose metrics include a MIN or MAX over a 
non-numeric
   column, for example `MIN(event_time)` on a temporal column; the chart form 
data is sent to
   the frontend as `formData.metrics` in `ChartProps` consumed by 
`transformProps` at
   
`superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/transformProps.ts:54-100`.
   
   2. In `transformProps`, `metricsArr` is constructed with 
`ensureIsArray(formData.metrics)`
   at line 104, and `allMetricsAdditive(metricsArr)` at line 106 calls 
`isAdditiveMetric` in
   
`superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/utilities.ts:36-41`,
 which
   treats SIMPLE metrics with aggregate `MIN` or `MAX` as additive regardless 
of the
   underlying value type; thus `allMetricsAdditive` returns true when all 
metrics are
   SUM/COUNT/MIN/MAX, including MIN/MAX over temporal or string columns.
   
   3. Because `allMetricsAdditive(metricsArr)` is true, the additive fast-path 
block at
   `transformProps.ts:106-123` runs: it builds `metricReducers` using
   `additiveReducerFor(metric)` (utilities.ts:58-63, returning 
`'min'`/`'max'`), constructs
   `labelLevels`, and calls `synthesizeAdditiveLevels(leafRows, labelLevels, 
metricReducers)`
   (utilities.ts:83-123) to synthesize rollup rows from the full-detail
   `queriesData[0].data`.
   
   4. Inside `synthesizeAdditiveLevels` (`plugin/utilities.ts:111-119`), each 
metric value is
   converted with `Number(v)` and filtered so only entries where `Number(v)` is 
not `NaN` are
   kept; for MIN/MAX metrics over temporal or string values, every value fails 
this numeric
   check and `values` becomes empty, so `out[metricKey]` is set to `null` for 
all
   totals/subtotals. The resulting `data: QueryData[]` (built at 
`transformProps.ts:123-126`)
   is passed to `PivotTableChart`, which then renders rollup-level cells for 
these MIN/MAX
   metrics as null/blank, even though the backend could compute correct MIN/MAX 
totals over
   non-numeric types via GROUPING SETS.
   ```
   </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=b9e3ec7e855b43e68f9fb8a941e696f6&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=b9e3ec7e855b43e68f9fb8a941e696f6&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-frontend/plugins/plugin-chart-pivot-table/src/plugin/transformProps.ts
   **Line:** 106:122
   **Comment:**
        *Type Error: The new additive fast-path is enabled for MIN/MAX metrics 
too, but the reducer pipeline it calls coerces metric values to numbers; 
MIN/MAX over non-numeric data (for example strings or temporal values) will 
therefore synthesize wrong/null totals. Restrict the fast-path to numeric-safe 
aggregates or preserve native value types when reducing MIN/MAX.
   
   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%2F41184&comment_hash=7c80a70dad5f4c0ba97ecb84eedf4ebf2638d53c7289ad60fad18c03a0afb521&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41184&comment_hash=7c80a70dad5f4c0ba97ecb84eedf4ebf2638d53c7289ad60fad18c03a0afb521&reaction=dislike'>👎</a>



##########
superset-frontend/plugins/plugin-chart-pivot-table/src/PivotTableChart.tsx:
##########
@@ -383,22 +338,45 @@ export default function PivotTableChart(props: 
PivotTableProps) {
 
   const unpivotedData = useMemo(
     () =>
-      data.reduce(
-        (acc: DataRecord[], record: DataRecord) => [
-          ...acc,
-          ...metricNames
+      // `data` is now one entry per rollup level. Tag every record with the
+      // row/column dimension labels of the level that produced it (mirroring
+      // the METRIC_KEY injection used for the full rows/cols below) so
+      // PivotData can slot each pre-computed value without re-aggregating.
+      // buildGroupbyCombinations already applied transposePivot, so the 
level's
+      // groupby is display-oriented and is not transposed again here.
+      data.flatMap((query: QueryData) => {
+        let levelRows = query.groupby.rows.map(getColumnLabel);
+        let levelCols = query.groupby.columns.map(getColumnLabel);
+        if (metricsLayout === MetricsLayoutEnum.ROWS) {
+          levelRows = combineMetric
+            ? [...levelRows, METRIC_KEY]
+            : [METRIC_KEY, ...levelRows];
+        } else {
+          levelCols = combineMetric
+            ? [...levelCols, METRIC_KEY]
+            : [METRIC_KEY, ...levelCols];
+        }
+        return query.data.flatMap((record: DataRecord) =>
+          metricNames
             .map((name: string) => ({
               ...record,
               [METRIC_KEY]: name,
               value: record[name],
               // Mark currency column for per-cell currency detection in 
aggregators
               __currencyColumn: currencyCodeColumn,
+              // The level this record belongs to (used by PivotData 
placement).
+              // Namespaced with a `__` prefix (like `__metricKey` below) so it
+              // can't collide with a real dataset column named 
`rows`/`columns`.
+              __rows: levelRows,
+              __columns: levelCols,
+              // Identify the metric pseudo-dimension so PivotData can feed the
+              // metric-collapsed totals (the opposite "Total" axis + corner).
+              __metricKey: METRIC_KEY,
             }))
-            .filter(record => record.value !== null),
-        ],
-        [],
-      ),
-    [data, metricNames, currencyCodeColumn],
+            .filter(r => r.value !== null),

Review Comment:
   **Suggestion:** Filtering out records where metric value is null drops those 
rows from pivot ingestion entirely, so dimension members with null metrics 
disappear instead of rendering as empty cells. Keep null-valued records and let 
the cell formatter render blank/null output so row/column headers and totals 
remain complete. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ❌ Pivot table hides groups with all-null metric values.
   - ⚠️ Totals/subtotals omit null-only dimension members.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Configure a Pivot Table chart in Superset with any groupby rows/columns 
and a metric
   that can legitimately evaluate to NULL for some dimension combinations (e.g. 
a ratio
   metric or a MIN/MAX over sparse data), then run the chart so the backend 
returns grouped
   data to the pivot plugin (handled by `transformProps` at
   
`superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/transformProps.ts:54-144`).
   
   2. On the client, `transformProps` builds the rollup-level `data: 
QueryData[]` and passes
   it as props into `PivotTableChart` (constructor at
   
`superset-frontend/plugins/plugin-chart-pivot-table/src/PivotTableChart.tsx:223-257`),
   where each `QueryData` entry contains rows for one rollup level, including 
rows whose
   metric values are `null`.
   
   3. Inside `PivotTableChart`, the `unpivotedData` memo at 
`PivotTableChart.tsx:339-377`
   expands each `QueryData` into per-metric records, assigning `value: 
record[name]` and
   tagging the rollup level with `__rows`/`__columns`/`__metricKey` (lines 
360-374), then
   applies `.filter(r => r.value !== null)` at line 376; any record where the 
metric value is
   `null` is removed entirely from `unpivotedData`.
   
   4. The `PivotTable` component (from `./react-pivottable`) feeds 
`unpivotedData` into
   `PivotData.processRecord` (see
   
`superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/utilities.ts:1119-1223`),
   which creates rowKeys/colKeys only for dimension combinations that have at 
least one
   record; combinations whose metric is `null` for all metrics now have no 
records at all and
   therefore no rowKey/colKey, so the corresponding row/column headers 
disappear from the
   rendered pivot instead of showing empty/null cells.
   ```
   </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=812b9d9d27a04f2ab1e1c7a35848a18b&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=812b9d9d27a04f2ab1e1c7a35848a18b&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-frontend/plugins/plugin-chart-pivot-table/src/PivotTableChart.tsx
   **Line:** 376:376
   **Comment:**
        *Logic Error: Filtering out records where metric value is null drops 
those rows from pivot ingestion entirely, so dimension members with null 
metrics disappear instead of rendering as empty cells. Keep null-valued records 
and let the cell formatter render blank/null output so row/column headers and 
totals remain complete.
   
   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%2F41184&comment_hash=71f9ec7cb498c02e03979057750ff1c08d1028f181894d59a1f94be99031c6cb&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41184&comment_hash=71f9ec7cb498c02e03979057750ff1c08d1028f181894d59a1f94be99031c6cb&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