korbit-ai[bot] commented on code in PR #34296:
URL: https://github.com/apache/superset/pull/34296#discussion_r2227369508


##########
superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/buildQuery.ts:
##########
@@ -39,28 +39,37 @@ export default function buildQuery(formData: QueryFormData) 
{
     ? ensureIsArray(getXAxisColumn(formData))
     : [];
 
-  return buildQueryContext(formData, baseQueryObject => [
-    {
-      ...baseQueryObject,
-      columns: [...timeColumn],
-      ...(timeColumn.length ? {} : { is_timeseries: true }),
-      post_processing: [
-        pivotOperator(formData, baseQueryObject),
-        rollingWindowOperator(formData, baseQueryObject),
-        resampleOperator(formData, baseQueryObject),
-        flattenOperator(formData, baseQueryObject),
-      ],
-    },
-    {
-      ...baseQueryObject,
-      columns: [...(isRawMetric ? [] : timeColumn)],
-      is_timeseries: !isRawMetric,
-      post_processing: isRawMetric
-        ? []
-        : [
-            pivotOperator(formData, baseQueryObject),
-            aggregationOperator(formData, baseQueryObject),
-          ],
-    },
-  ]);
+  return buildQueryContext(formData, baseQueryObject => {
+    const queries = [
+      {
+        ...baseQueryObject,
+        columns: [...timeColumn],
+        ...(timeColumn.length ? {} : { is_timeseries: true }),
+        post_processing: [
+          pivotOperator(formData, baseQueryObject),
+          rollingWindowOperator(formData, baseQueryObject),
+          resampleOperator(formData, baseQueryObject),
+          flattenOperator(formData, baseQueryObject),
+        ].filter(Boolean),
+      },
+    ];
+
+    // Only add second query for raw metrics which need different query 
structure
+    // All other aggregations (sum, mean, min, max, median, LAST_VALUE) can be 
computed client-side from trendline data
+    if (formData.aggregation === 'raw') {
+      queries.push({
+        ...baseQueryObject,
+        columns: [...(isRawMetric ? [] : timeColumn)],
+        is_timeseries: !isRawMetric,
+        post_processing: isRawMetric
+          ? []
+          : ([
+              pivotOperator(formData, baseQueryObject),
+              aggregationOperator(formData, baseQueryObject),
+            ].filter(Boolean) as any[]),
+      });
+    }

Review Comment:
   ### Inconsistent Raw Metric Check <sub>![category 
Functionality](https://img.shields.io/badge/Functionality-0284c7)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   The conditional logic for adding the second query uses both 
formData.aggregation === 'raw' and isRawMetric, which is redundant since 
isRawMetric is already defined as formData.aggregation === 'raw'
   
   
   ###### Why this matters
   This redundancy could lead to confusion and potential bugs if one of these 
conditions is updated without updating the other. The code flow is also less 
clear due to the nested ternary using the same condition.
   
   ###### Suggested change ∙ *Feature Preview*
   Simplify the logic by using only isRawMetric and removing the redundant 
checks:
   
   ```typescript
   if (isRawMetric) {
     queries.push({
       ...baseQueryObject,
       columns: [],
       is_timeseries: false,
       post_processing: [],
     });
   }
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/👍%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/36e6a0f2-5c99-40b2-b3c1-5d769e48bcf2/upvote)
 
[![Incorrect](https://img.shields.io/badge/👎%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/36e6a0f2-5c99-40b2-b3c1-5d769e48bcf2?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/👎%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/36e6a0f2-5c99-40b2-b3c1-5d769e48bcf2?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/👎%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/36e6a0f2-5c99-40b2-b3c1-5d769e48bcf2?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/👎%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/36e6a0f2-5c99-40b2-b3c1-5d769e48bcf2)
   </details>
   
   <sub>
   
   💬 Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:6bbac259-79fd-45ae-8cf9-4aae253f7924 -->
   
   
   [](6bbac259-79fd-45ae-8cf9-4aae253f7924)



##########
superset-frontend/src/explore/components/controls/ViewQuery.tsx:
##########
@@ -147,44 +140,57 @@ const ViewQuery: FC<ViewQueryProps> = props => {
   }, [sql]);
 
   return (
-    <StyledSyntaxContainer key={sql}>
-      <StyledHeaderMenuContainer>
-        <StyledHeaderActionContainer>
-          <CopyToClipboard
-            text={currentSQL}
-            shouldShowText={false}
-            copyNode={
-              <CopyButtonViewQuery
-                buttonSize="small"
-                icon={<Icons.CopyOutlined />}
-              >
-                {t('Copy')}
-              </CopyButtonViewQuery>
-            }
-          />
-          <Button onClick={navToSQLLab}>{t('View in SQL Lab')}</Button>
-        </StyledHeaderActionContainer>
-        <StyledHeaderActionContainer>
-          <Switch
-            id="formatSwitch"
-            checked={!showFormatSQL}
-            onChange={formatCurrentQuery}
-          />
-          <StyledLabel htmlFor="formatSwitch">
-            {t('Show original SQL')}
-          </StyledLabel>
-        </StyledHeaderActionContainer>
-      </StyledHeaderMenuContainer>
-      {!formattedSQL && <Skeleton active />}
-      {formattedSQL && (
-        <StyledThemedSyntaxHighlighter
-          language={language}
-          customStyle={{ flex: 1 }}
+    <Card bodyStyle={{ padding: theme.sizeUnit * 4 }}>
+      <StyledSyntaxContainer key={sql}>
+        {!formattedSQL && <Skeleton active />}
+        {formattedSQL && (
+          <StyledThemedSyntaxHighlighter
+            language={language}
+            customStyle={{ flex: 1, marginBottom: 12 }}
+          >
+            {currentSQL}
+          </StyledThemedSyntaxHighlighter>
+        )}
+
+        <div
+          style={{
+            display: 'flex',
+            justifyContent: 'space-between',
+            alignItems: 'center',
+          }}

Review Comment:
   ### Inconsistent Styling Pattern <sub>![category 
Design](https://img.shields.io/badge/Design-0d9488)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   Inline styles are used instead of styled-components, breaking the pattern 
established earlier in the code where styled-components were used for styling.
   
   
   ###### Why this matters
   Inconsistent styling patterns make the code harder to maintain and update. 
Inline styles also lack the benefits of styled-components like theme support 
and style reuse.
   
   ###### Suggested change ∙ *Feature Preview*
   Extract inline styles into styled-components, following the existing pattern:
   ```typescript
   const StyledActionContainer = styled.div`
     display: flex;
     justify-content: space-between;
     align-items: center;
   `;
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/👍%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/7de51f28-5fa2-438a-8431-8ca2369724e9/upvote)
 
[![Incorrect](https://img.shields.io/badge/👎%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/7de51f28-5fa2-438a-8431-8ca2369724e9?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/👎%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/7de51f28-5fa2-438a-8431-8ca2369724e9?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/👎%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/7de51f28-5fa2-438a-8431-8ca2369724e9?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/👎%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/7de51f28-5fa2-438a-8431-8ca2369724e9)
   </details>
   
   <sub>
   
   💬 Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:54c0c80d-15fd-4e24-acca-f048bb82d1e2 -->
   
   
   [](54c0c80d-15fd-4e24-acca-f048bb82d1e2)



##########
superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.ts:
##########
@@ -43,6 +43,43 @@ const formatPercentChange = getNumberFormatter(
   NumberFormats.PERCENT_SIGNED_1_POINT,
 );
 
+// Client-side aggregation functions
+function computeClientSideAggregation(
+  data: [number | null, number | null][],
+  aggregation: string,
+): number | null {

Review Comment:
   ### Missing purpose in client-side aggregation function <sub>![category 
Documentation](https://img.shields.io/badge/Documentation-7c3aed)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   The function computeClientSideAggregation lacks documentation explaining the 
purpose and assumptions behind the client-side aggregation strategy.
   
   
   ###### Why this matters
   The function's purpose and the rationale for using client-side aggregation 
vs server-side aggregation is not immediately clear, which could lead to misuse 
or confusion during maintenance.
   
   ###### Suggested change ∙ *Feature Preview*
   /**
    * Performs client-side aggregation as a primary computation strategy, 
falling back to server-side
    * aggregation only when necessary. This approach ensures consistent 
aggregation behavior
    * across all data presentations.
    * 
    * @param data - Array of timestamp-value pairs [timestamp, value]
    * @param aggregation - Type of aggregation to perform ('sum', 'mean', 
'min', 'max', 'median', 'raw', 'LAST_VALUE')
    * @returns The aggregated value or null if no valid values exist
    */
   function computeClientSideAggregation(
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/👍%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/bee6bb66-5e61-491a-9733-73db8709bd04/upvote)
 
[![Incorrect](https://img.shields.io/badge/👎%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/bee6bb66-5e61-491a-9733-73db8709bd04?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/👎%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/bee6bb66-5e61-491a-9733-73db8709bd04?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/👎%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/bee6bb66-5e61-491a-9733-73db8709bd04?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/👎%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/bee6bb66-5e61-491a-9733-73db8709bd04)
   </details>
   
   <sub>
   
   💬 Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:9276f1a6-0038-49a0-92c2-c1847581026f -->
   
   
   [](9276f1a6-0038-49a0-92c2-c1847581026f)



##########
superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.ts:
##########
@@ -43,6 +43,43 @@
   NumberFormats.PERCENT_SIGNED_1_POINT,
 );
 
+// Client-side aggregation functions
+function computeClientSideAggregation(
+  data: [number | null, number | null][],
+  aggregation: string,
+): number | null {
+  if (!data.length) return null;
+
+  const validValues = data
+    .map(([, value]) => value)
+    .filter((value): value is number => value !== null);
+
+  if (!validValues.length) return null;
+
+  switch (aggregation) {
+    case 'sum':
+      return validValues.reduce((a, b) => a + b, 0);

Review Comment:
   ### Sum Aggregation Overflow Risk <sub>![category 
Functionality](https://img.shields.io/badge/Functionality-0284c7)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   The sum aggregation function may lead to arithmetic overflow with large 
numbers due to using a simple reduce operation without safeguards.
   
   
   ###### Why this matters
   When dealing with large numbers, summing them directly can exceed 
JavaScript's Number.MAX_SAFE_INTEGER (2^53 - 1), leading to precision loss or 
incorrect results.
   
   ###### Suggested change ∙ *Feature Preview*
   Implement a safe sum operation with overflow checks:
   ```typescript
   case 'sum': {
     return validValues.reduce((a, b) => {
       const sum = a + b;
       if (!Number.isSafeInteger(sum)) {
         console.warn('Sum operation exceeds safe integer bounds');
       }
       return sum;
     }, 0);
   }
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/👍%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/bb9e3fc2-ed2d-4323-bd7d-090ecbd65a0d/upvote)
 
[![Incorrect](https://img.shields.io/badge/👎%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/bb9e3fc2-ed2d-4323-bd7d-090ecbd65a0d?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/👎%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/bb9e3fc2-ed2d-4323-bd7d-090ecbd65a0d?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/👎%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/bb9e3fc2-ed2d-4323-bd7d-090ecbd65a0d?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/👎%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/bb9e3fc2-ed2d-4323-bd7d-090ecbd65a0d)
   </details>
   
   <sub>
   
   💬 Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:8b008133-0cce-4cdb-85ba-c49d6929db7c -->
   
   
   [](8b008133-0cce-4cdb-85ba-c49d6929db7c)



##########
superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.ts:
##########
@@ -43,6 +43,43 @@
   NumberFormats.PERCENT_SIGNED_1_POINT,
 );
 
+// Client-side aggregation functions
+function computeClientSideAggregation(
+  data: [number | null, number | null][],
+  aggregation: string,
+): number | null {
+  if (!data.length) return null;
+
+  const validValues = data
+    .map(([, value]) => value)
+    .filter((value): value is number => value !== null);
+
+  if (!validValues.length) return null;
+
+  switch (aggregation) {
+    case 'sum':
+      return validValues.reduce((a, b) => a + b, 0);
+    case 'mean':
+      return validValues.reduce((a, b) => a + b, 0) / validValues.length;
+    case 'min':
+      return Math.min(...validValues);
+    case 'max':
+      return Math.max(...validValues);
+    case 'median': {
+      const sorted = [...validValues].sort((a, b) => a - b);

Review Comment:
   ### Inefficient Median Calculation <sub>![category 
Performance](https://img.shields.io/badge/Performance-4f46e5)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   Creating a new array and sorting it for median calculation has O(n log n) 
time complexity and O(n) space complexity.
   
   
   ###### Why this matters
   For large datasets, this operation can be expensive and consume unnecessary 
memory. A selection algorithm could find the median in O(n) time with O(1) 
space.
   
   ###### Suggested change ∙ *Feature Preview*
   Use QuickSelect algorithm for finding the median. Here's a basic 
implementation:
   ```typescript
   function quickSelect(arr: number[], k: number): number {
     // QuickSelect implementation that modifies array in-place
     // and returns kth smallest element in O(n) average time
   }
   
   case 'median': {
     const k = Math.floor(validValues.length / 2);
     return validValues.length % 2 === 0
       ? (quickSelect(validValues, k - 1) + quickSelect(validValues, k)) / 2
       : quickSelect(validValues, k);
   }
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/👍%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/4b273408-9bbf-4c57-936e-f485eefe9797/upvote)
 
[![Incorrect](https://img.shields.io/badge/👎%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/4b273408-9bbf-4c57-936e-f485eefe9797?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/👎%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/4b273408-9bbf-4c57-936e-f485eefe9797?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/👎%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/4b273408-9bbf-4c57-936e-f485eefe9797?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/👎%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/4b273408-9bbf-4c57-936e-f485eefe9797)
   </details>
   
   <sub>
   
   💬 Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:bda31217-9e02-47fb-88b7-4cb7872ff334 -->
   
   
   [](bda31217-9e02-47fb-88b7-4cb7872ff334)



##########
superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.ts:
##########
@@ -43,6 +43,43 @@
   NumberFormats.PERCENT_SIGNED_1_POINT,
 );
 
+// Client-side aggregation functions
+function computeClientSideAggregation(
+  data: [number | null, number | null][],
+  aggregation: string,
+): number | null {
+  if (!data.length) return null;
+
+  const validValues = data
+    .map(([, value]) => value)
+    .filter((value): value is number => value !== null);
+
+  if (!validValues.length) return null;
+
+  switch (aggregation) {
+    case 'sum':
+      return validValues.reduce((a, b) => a + b, 0);
+    case 'mean':
+      return validValues.reduce((a, b) => a + b, 0) / validValues.length;
+    case 'min':
+      return Math.min(...validValues);
+    case 'max':
+      return Math.max(...validValues);
+    case 'median': {
+      const sorted = [...validValues].sort((a, b) => a - b);
+      const mid = Math.floor(sorted.length / 2);
+      return sorted.length % 2 === 0
+        ? (sorted[mid - 1] + sorted[mid]) / 2
+        : sorted[mid];
+    }

Review Comment:
   ### Median Calculation Overflow Risk <sub>![category 
Functionality](https://img.shields.io/badge/Functionality-0284c7)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   The median calculation doesn't handle potential numeric overflow when 
averaging the two middle values for even-length arrays.
   
   
   ###### Why this matters
   When calculating the median for even-length arrays, adding two potentially 
large numbers before division could cause overflow, leading to incorrect 
results.
   
   ###### Suggested change ∙ *Feature Preview*
   Implement a safe median calculation with overflow protection:
   ```typescript
   case 'median': {
     const sorted = [...validValues].sort((a, b) => a - b);
     const mid = Math.floor(sorted.length / 2);
     if (sorted.length % 2 === 0) {
       return sorted[mid - 1] / 2 + sorted[mid] / 2; // Divide first to prevent 
overflow
     }
     return sorted[mid];
   }
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/👍%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/d30b1c45-a590-4c55-8282-d4486d2880f1/upvote)
 
[![Incorrect](https://img.shields.io/badge/👎%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/d30b1c45-a590-4c55-8282-d4486d2880f1?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/👎%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/d30b1c45-a590-4c55-8282-d4486d2880f1?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/👎%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/d30b1c45-a590-4c55-8282-d4486d2880f1?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/👎%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/d30b1c45-a590-4c55-8282-d4486d2880f1)
   </details>
   
   <sub>
   
   💬 Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:d253eb02-64b9-4574-b39a-b494c1b7d243 -->
   
   
   [](d253eb02-64b9-4574-b39a-b494c1b7d243)



-- 
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: notifications-unsubscr...@superset.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscr...@superset.apache.org
For additional commands, e-mail: notifications-h...@superset.apache.org

Reply via email to