Skip to content

Conversation

mohitb35
Copy link
Collaborator

@mohitb35 mohitb35 commented Oct 23, 2024

  • Fixes the data explorer queries to handle single tree registrations, and also makes tweaks to exclude deleted interventions, restrict data to single and multi tree registrations
  • Updates the PlantLocationDetails component to handle single tree registrations, and also display a hid to identify the selected plant location

Copy link

vercel bot commented Oct 23, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
planet-webapp-multi-tenancy-setup ✅ Ready (Inspect) Visit Preview 💬 Add feedback Oct 24, 2024 0:49am
2 Skipped Deployments
Name Status Preview Comments Updated (UTC)
planet-webapp ⬜️ Ignored (Inspect) Oct 24, 2024 0:49am
planet-webapp-temp ⬜️ Ignored (Inspect) Oct 24, 2024 0:49am

@mohitb35 mohitb35 changed the title Fix species-planted query for single-tree-registrations Fix data explorer queries for single tree registrations Oct 23, 2024
@mohitb35 mohitb35 force-pushed the hotfix/data-explorer-queries branch 3 times, most recently from 764c275 to ee616fa Compare October 23, 2024 12:37
Copy link
Contributor

coderabbitai bot commented Oct 24, 2024

Walkthrough

The pull request includes significant modifications across several API endpoints related to data retrieval for plant and species information. Key changes involve restructuring SQL queries to improve readability and robustness, particularly through the use of COALESCE for handling null values and enhancing join conditions. Additionally, TypeScript interfaces are updated to accommodate new properties, and SCSS styles are modified to improve the layout of the PlantLocationDetails component. Overall, these changes refine data handling and presentation without altering the core functionality.

Changes

File Change Summary
pages/api/data-explorer/export.ts Restructured SQL query with COALESCE for species handling; improved query readability.
pages/api/data-explorer/map/distinct-species/[projectId].ts New SQL query with additional conditions and joins; utilizes COALESCE for species names.
pages/api/data-explorer/map/plant-location/[plantLocationId].ts Adjusted subquery and joins; used COALESCE for tree counts; updated parameter list.
pages/api/data-explorer/map/plant-location/index.ts Enhanced SQL query with filtering for intervention types; improved query formatting.
pages/api/data-explorer/map/sites/[projectId].ts Reformatted SQL query string for readability; no functional changes.
pages/api/data-explorer/species-planted.ts New SQL query structure using COALESCE and adjusted joins; expanded WHERE clause conditions.
pages/api/data-explorer/total-species-planted.ts Updated SQL query with NULLIF and adjusted join conditions; added filtering for deleted records.
pages/api/data-explorer/total-trees-planted.ts Modified SQL query to filter out deleted records; improved query formatting.
pages/api/data-explorer/trees-planted.ts Added conditions to filter out deleted records; improved SQL query formatting.
src/features/common/types/dataExplorer.d.ts Added PlantLocationProperties interface; updated existing interfaces to allow null values.
src/features/user/TreeMapper/Analytics/components/Map/components/PlantLocationDetails/index.module.scss Added new styles for header layout; introduced nested classes.
src/features/user/TreeMapper/Analytics/components/Map/components/PlantLocationDetails/index.tsx Introduced PlantLocationHeader component; modified rendering logic based on plant location type.

Possibly related PRs

  • Fix tooltip translation bug and update package-lock #2246: The changes in this PR involve modifications to the SQL query logic within the API handler for fetching plant location data, which is directly related to the SQL query enhancements made in the main PR. Both PRs focus on improving data retrieval and handling null values using COALESCE.

Suggested labels

MyForest 2.0, PR: unreviewed

Suggested reviewers

  • sunilsabatp

🐇 In the garden where we play,
SQL blooms in a bright array.
With COALESCE to save the day,
Plant locations find their way.
Styles refreshed, our data's grand,
Hopping forth, we take a stand! 🌱


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

- excludes deleted data and interventions that are not single or multi tree registrations
- also excludes deleted interventions from results
- restricts results to single and multi tree registrations
- also excludes deleted interventions from results
- restricts results to single and multi tree registrations
- Handles `null` value for name by grouping with 'Unknown'
@mohitb35 mohitb35 force-pushed the hotfix/data-explorer-queries branch from 421fa8b to ea14a67 Compare October 24, 2024 05:44
- also excludes deleted interventions from results
- restricts results to single and multi tree registrations
…istrations

- also excludes deleted interventions from results
- restricts results to single and multi tree registrations
- updates API to return correct data for single tree registration
- displays only relevant data for single tree registration
- add header to display selected plant location hid
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

🧹 Outside diff range and nitpick comments (15)
pages/api/data-explorer/export.ts (1)

Line range hint 15-57: Improve error handling and connection management.

The current implementation has several issues:

  1. Redundant database connection termination
  2. Missing error response to the client
  3. No validation of request body parameters

Consider applying these improvements:

 handler.post(async (req, response) => {
   const { projectId, startDate, endDate } = req.body;
+  
+  // Validate required parameters
+  if (!projectId || !startDate || !endDate) {
+    return response.status(400).json({
+      error: 'Missing required parameters',
+    });
+  }
+
   try {
     const query = `...`;
     const res = await db.query<IExportData[]>(query, [
       projectId,
       startDate,
       `${endDate} 23:59:59.999`,
     ]);
-    await db.end();
     response.status(200).json({ data: res });
   } catch (err) {
     console.error('Error fetching export data:', err);
+    response.status(500).json({
+      error: 'Failed to fetch export data',
+    });
   } finally {
     await db.quit();
   }
 });
pages/api/data-explorer/total-trees-planted.ts (1)

Line range hint 66-68: Add proper error response handling.

The catch block only logs the error without sending an error response to the client. This could lead to hanging requests as no response is sent in error scenarios.

Apply this fix:

  } catch (err) {
    console.error('Error fetching total trees planted:', err);
+   response.status(500).json({ error: 'Failed to fetch total trees planted' });
  } finally {
src/features/common/types/dataExplorer.d.ts (1)

133-137: LGTM! Improved null safety for optional data.

The nullable fields appropriately handle cases where sample plant locations might not be available, which is common for single tree registrations.

Consider adding JSDoc comments to document when these fields might be null, helping other developers understand the expected behavior. For example:

/**
 * Details about a plant location including its properties and samples
 * @property samplePlantLocations - Array of sample locations. Null for single tree registrations
 * @property totalSamplePlantLocations - Count of sample locations. Null for single tree registrations
 */
src/features/user/TreeMapper/Analytics/components/Map/components/PlantLocationDetails/index.module.scss (2)

73-84: LGTM! Consider accessibility improvements.

The new header section is well-structured and maintains consistency with the existing design system. The implementation properly handles the layout requirements for displaying the HID.

Consider these accessibility and maintainability improvements:

 .header {
   width: 100%;
   padding: 0 5px;
-  font-size: 12px;
+  font-size: 0.75rem;
   display: flex;
   justify-content: space-between;
   margin-bottom: -8px;

   .hid {
-    font-weight: 500;
+    font-weight: var(--font-weight-medium, 500);
+    // Ensure sufficient color contrast for accessibility
+    color: var(--text-color-primary, #000);
   }
 }

This refactor:

  • Uses relative units (rem) for better accessibility when users modify their browser's font size
  • Introduces CSS variables for better maintainability and theme support
  • Ensures proper color contrast for accessibility

Line range hint 28-39: Consider improving responsive design and accessibility.

The current implementation uses fixed dimensions and absolute positioning which might cause issues on different screen sizes. Additionally, hiding scrollbars can impact accessibility.

Consider these improvements:

  1. Replace fixed dimensions with responsive units:
 .plantLocationDetailsContainer {
   position: absolute;
   top: 15px;
   left: 20px;
   z-index: 2;
-  width: 300px;
+  width: min(300px, 90vw);
-  height: 450px;
+  max-height: 80vh;
   border-radius: 16px;
   background-color: #fff;
   font-size: 10px;
-  ::-webkit-scrollbar {
-    display: none;
-  }
+  // Allow native scrollbar for better accessibility
+  overflow-y: auto;
 }
  1. Consider using CSS Grid or Flexbox for a more flexible layout that adapts to different screen sizes.
  2. Add media queries for better mobile support.
pages/api/data-explorer/trees-planted.ts (2)

Line range hint 144-157: Improve error handling in the API handler.

The current error handling only logs the error but doesn't send an appropriate response to the client. Consider:

  1. Sending proper error responses with status codes
  2. Adding different handling for various error types
  3. Including more detailed error information in logs
 } catch (err) {
   console.error('Error fetching trees planted:', err);
+  const status = err.code === 'ER_NO_SUCH_TABLE' ? 404 : 500;
+  const message = process.env.NODE_ENV === 'development' 
+    ? err.message 
+    : 'An error occurred while fetching data';
+  response.status(status).json({ error: message });
 } finally {
   await db.quit();
 }

Line range hint 17-52: Enhance cache handling robustness.

While the caching implementation is good, consider:

  1. Adding a cache invalidation strategy when data is updated
  2. Handling Redis connection errors gracefully
  3. Adding cache versioning for easier invalidation
+const CACHE_VERSION = '1';
 const CACHE_KEY = `${cacheKeyPrefix}_TREES_PLANTED__${getCachedKey(
+  CACHE_VERSION,
   projectId,
   startDate,
   endDate,
   timeFrame as string
 )}`;

-const cacheHit = await redisClient.get(CACHE_KEY);
+let cacheHit;
+try {
+  cacheHit = await redisClient.get(CACHE_KEY);
+} catch (err) {
+  console.warn('Redis cache error:', err);
+  // Continue without cache on Redis errors
+}
pages/api/data-explorer/map/distinct-species/[projectId].ts (2)

Line range hint 36-39: Fix: Parse cached data before sending response

The cachedDistinctSpecies retrieved from Redis is a JSON string. Before returning it in the response, it should be parsed into an array to maintain consistency with the uncached response.

Apply this diff to parse the cached data:

if (cachedDistinctSpecies) {
-   return response.status(200).json({ data: cachedDistinctSpecies });
+   return response.status(200).json({ data: JSON.parse(cachedDistinctSpecies) });
}

Line range hint 70-71: Ensure error response is sent to client in the catch block

In the catch block, the error is logged, but no response is sent to the client. This can cause the client to hang or timeout. Consider sending an appropriate error response to inform the client about the failure.

Apply this diff to send an error response:

} catch (err) {
  console.error(`Error fetching distinct species for ${projectId}`, err);
+ response.status(500).json({ error: 'Internal server error' });
} finally {
  db.quit();
}
pages/api/data-explorer/total-species-planted.ts (1)

Line range hint 24-27: Parse cached data before returning in the response

When retrieving the cached data, cacheHit is a JSON string. Returning it directly in the response will send the data as a string rather than as an object. Consider parsing cacheHit before returning it to ensure the client receives the expected data format.

Apply this diff to fix the issue:

if (cacheHit) {
-  response.status(200).json({ data: cacheHit });
+  response.status(200).json({ data: JSON.parse(cacheHit) });
  return;
}
pages/api/data-explorer/map/plant-location/index.ts (5)

Line range hint 42-43: Avoid Premature Closing of Database Connection

The call to await db.end(); before sending the response may lead to issues if the response processing requires an active database connection.

Consider removing await db.end(); here and ensure the database connection is properly closed in the finally block.

Apply this diff:

-    await db.end();

    response.setHeader(
      'Cache-Control',
      's-maxage=7200, stale-while-revalidate'
    );

Line range hint 59-61: Use Consistent Method for Closing Database Connection

In the finally block, db.quit(); is used to close the database connection. However, earlier in the code, db.end(); is used. For consistency and to prevent unexpected behavior, use the same method throughout.

Replace db.quit(); with await db.end(); in the finally block.

Apply this diff:

      } catch (err) {
        console.error('Error fetching plant location data:', err);
        response.status(500).json({ error: 'Internal Server Error' });
      } finally {
-       db.quit();
+       await db.end();
      }
    });

Line range hint 46-50: Set Proper Cache-Control Headers Only on Successful Responses

The Cache-Control header is being set regardless of whether the data retrieval is successful or not. If an error occurs, the response should not be cached.

Move the setHeader call to occur only when the data retrieval is successful.

Apply this diff:

    const plantLocations: SinglePlantLocationApiResponse[] = qRes.map(
      (plantLocation) => ({
        type: 'Feature',
        properties: {
          guid: plantLocation.guid,
          treeCount: plantLocation.treeCount,
        },
        geometry: JSON.parse(plantLocation.geometry) as Geometry,
      })
    );

-   await db.end();

    response.setHeader(
      'Cache-Control',
      's-maxage=7200, stale-while-revalidate'
    );

+   await db.end();

Line range hint 52-54: Enhance Error Logging for Better Debugging

The current error logging simply outputs a generic message along with the error. Including more context, such as input parameters, can aid in debugging.

Consider enhancing the error log:

  } catch (err) {
-   console.error('Error fetching plant location data:', err);
+   console.error('Error fetching plant location data for projectId:', projectId, 'with error:', err);
    response.status(500).json({ error: 'Internal Server Error' });
  } finally {

Line range hint 22-50: Consider Using a Query Builder for Improved Maintainability

Building SQL queries using string concatenation can be error-prone and hard to maintain, especially as the complexity grows.

Consider using a query builder like Knex.js to construct SQL queries more safely and readably.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between c91a59b and 40f3a00.

⛔ Files ignored due to path filters (1)
  • public/static/locales/en/treemapperAnalytics.json is excluded by !**/*.json
📒 Files selected for processing (12)
  • pages/api/data-explorer/export.ts (1 hunks)
  • pages/api/data-explorer/map/distinct-species/[projectId].ts (1 hunks)
  • pages/api/data-explorer/map/plant-location/[plantLocationId].ts (3 hunks)
  • pages/api/data-explorer/map/plant-location/index.ts (1 hunks)
  • pages/api/data-explorer/map/sites/[projectId].ts (1 hunks)
  • pages/api/data-explorer/species-planted.ts (1 hunks)
  • pages/api/data-explorer/total-species-planted.ts (1 hunks)
  • pages/api/data-explorer/total-trees-planted.ts (1 hunks)
  • pages/api/data-explorer/trees-planted.ts (1 hunks)
  • src/features/common/types/dataExplorer.d.ts (1 hunks)
  • src/features/user/TreeMapper/Analytics/components/Map/components/PlantLocationDetails/index.module.scss (1 hunks)
  • src/features/user/TreeMapper/Analytics/components/Map/components/PlantLocationDetails/index.tsx (3 hunks)
✅ Files skipped from review due to trivial changes (1)
  • pages/api/data-explorer/map/sites/[projectId].ts
🔇 Additional comments (15)
pages/api/data-explorer/export.ts (1)

18-43: Consider performance optimizations for the query.

The query involves multiple joins and filtering conditions which might impact performance for large datasets. Additionally, there's no pagination which could lead to memory issues with large result sets.

Recommendations:

  1. Add pagination using LIMIT and OFFSET
  2. Consider adding indexes on:
    • intervention.intervention_start_date
    • intervention.type
    • intervention.plant_project_id
    • project.guid
  3. Use EXPLAIN ANALYZE to verify query performance

Let's check if appropriate indexes exist:

src/features/common/types/dataExplorer.d.ts (1)

127-130: LGTM! Well-defined type-safe interface.

The PlantLocationProperties interface correctly defines the structure for plant location types and unique identifiers.

Let's verify the usage of this interface across the codebase:

✅ Verification successful

Based on the search results, I can now generate the final response as we have comprehensive evidence of the interface usage across the codebase.

Type definition is correctly implemented and consistently used

The PlantLocationProperties interface's registration types are consistently used throughout the codebase:

  • Frontend components properly handle both registration types with type guards
  • API endpoints correctly filter by both registration types
  • Type-safe discriminated unions are properly implemented in related files (e.g., plantLocation.d.ts)
  • No instances of typos or inconsistent string literals were found

Reasoning: The search results show that both 'single-tree-registration' and 'multi-tree-registration' are used consistently across the codebase, with proper type checking in components, correct database queries in API endpoints, and consistent type definitions in related interfaces. The implementation aligns perfectly with the type definition, and there are no deviations from the specified literals.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the consistent usage of registration types
# Test: Search for hardcoded registration type strings to ensure they match the interface
rg -g '*.{ts,tsx}' "'single-tree-registration'|'multi-tree-registration'"

Length of output: 6955

pages/api/data-explorer/trees-planted.ts (1)

72-89: Verify week calculations across different MySQL versions.

The WEEK() function behavior can vary based on MySQL version and server settings. Ensure that the week calculations produce consistent results across all environments.

src/features/user/TreeMapper/Analytics/components/Map/components/PlantLocationDetails/index.tsx (2)

6-6: LGTM: Import addition is appropriate

The PlantLocationProperties type import aligns with the new component requirements.


138-148: ⚠️ Potential issue

Add validation for hid formatting

The hid formatting assumes the string is always longer than 3 characters. Consider adding validation to handle edge cases:

Consider this safer implementation:

-  const formattedHid = hid.substring(0, 3) + '-' + hid.substring(3);
+  const formattedHid = hid.length > 3 
+    ? hid.substring(0, 3) + '-' + hid.substring(3)
+    : hid;
pages/api/data-explorer/map/distinct-species/[projectId].ts (1)

47-47: Verify the order of COALESCE arguments

Ensure that the order of the arguments in the COALESCE function reflects the intended priority for species names. Currently, it checks ss.name, then ps.other_species, then iv.other_species, and finally defaults to 'Unknown'. Confirm that this order aligns with the desired business logic.

pages/api/data-explorer/total-species-planted.ts (3)

44-60: LGTM

The SQL query modifications align with the PR objectives and correctly handle the necessary filters for deleted interventions and specific intervention types.


44-60: ⚠️ Potential issue

Ensure error responses are sent to the client

Currently, if an error occurs during query execution, the server logs the error but does not send any response to the client. This could result in the client hanging or not receiving proper feedback. Consider sending an appropriate error response in the catch block.

Apply this diff to send an error response:

} catch (err) {
  console.error('Error fetching total species planted:', err);
+  response.status(500).json({ error: 'Internal Server Error' });
} finally {
  await db.quit();
}

Likely invalid or redundant comment.


59-59: Confirm date handling for endDate parameter

Appending '23:59:59.999' to endDate assumes that endDate does not already include a time component. If endDate includes a time, this could lead to incorrect query results. Verify that endDate is always provided without a time component.

Run the following script to check the usage of endDate in the codebase:

✅ Verification successful

Let me try a different approach to verify the date handling by searching for all usages of endDate with more context.

This will help us understand:

  1. How endDate is being used across the codebase
  2. Any type definitions that might constrain its format
  3. The context around where it's being set or processed

Based on the search results, I can now provide a conclusive response about the date handling:

Appending time to endDate is correct and consistent with codebase usage

The codebase consistently handles endDate as a date-only parameter and explicitly appends the time component 23:59:59.999 when querying the database. This is evidenced by:

  1. The getCachedKey utility formats dates using only 'MM-dd-yyyy' format
  2. Multiple API endpoints (trees-planted.ts, total-trees-planted.ts, species-planted.ts, export.ts) all follow the same pattern of appending 23:59:59.999 to endDate
  3. Frontend components pass endDate without time components
  4. Type definitions and interfaces show endDate being handled as a string or Date object without time specifications

The current implementation is correct and follows the established pattern across the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for usages of `endDate` to confirm it doesn't include a time component.

# Test: Find all assignments to `endDate`. Expect: `endDate` is provided without time.
rg "endDate\s*=\s*['\"]\d{4}-\d{2}-\d{2}['\"]"

Length of output: 52


Script:

#!/bin/bash
# Search for all usages of endDate with surrounding context
rg -A 3 -B 3 "endDate" 

# Also check for date-related type definitions or interfaces
ast-grep --pattern 'interface $_ {
  $$$
  endDate
  $$$
}'

ast-grep --pattern 'type $_ = {
  $$$
  endDate
  $$$
}'

Length of output: 16118

pages/api/data-explorer/species-planted.ts (1)

51-51: Confirm the aggregation logic for tree counts

The aggregation uses SUM(COALESCE(ps.tree_count, iv.trees_planted, 0)) to calculate total_tree_count. Verify that this logic accurately sums the tree counts, especially in scenarios where both ps.tree_count and iv.trees_planted are NULL. This ensures the total reflects the correct number of trees planted.

To verify, check for records where both ps.tree_count and iv.trees_planted might be NULL and ensure the sum correctly accounts for such cases.

pages/api/data-explorer/map/plant-location/index.ts (2)

34-35: Ensure Consistency in Intervention Type Filters

The WHERE clause filters iv.type to include only 'multi-tree-registration' and 'single-tree-registration'. Verify that these are the correct types to include and that no other relevant types are excluded.

Run the following script to list all distinct intervention types:

#!/bin/bash
# Description: List all distinct intervention types in the database.

# Test: Retrieve and display all unique intervention types.
# Expected: Ensure that only the desired types are included or adjust the query accordingly.

sqlite3 your_database.db "SELECT DISTINCT type FROM intervention;"

27-30: Clarify COALESCE Logic for Species Name Retrieval

The current COALESCE function in the SELECT statement may lead to unexpected species names due to the order of evaluation. Specifically, it prioritizes ss.name, then ps.other_species, then iv.other_species, before defaulting to 'Unknown'. Given that iv.scientific_species_id and ps.scientific_species_id are both used in the JOIN with scientific_species ss, it's possible that ss.name could be NULL even if iv.other_species or ps.other_species contain valid data.

Please ensure that the species names are retrieved as intended. You can verify the COALESCE logic with the following script:

✅ Verification successful

Let me analyze the SQL query structure and related files to verify the concern.

The goal is to:

  1. Find similar COALESCE patterns to understand if this is a common pattern
  2. Locate schema definitions to understand the data model
  3. Find related species handling code to verify the logic

This will help us understand if the COALESCE order is intentional and follows the established pattern in the codebase.


Let me analyze the schema to better understand the data model relationships.

This will help us understand:

  1. The data model relationships between intervention, planted_species, and scientific_species
  2. Any constraints or documentation about how species data should be handled
  3. Whether the COALESCE order aligns with the data model design

Based on the analysis of the codebase, I can now provide a final response:

COALESCE Logic for Species Name is Consistently Implemented

The COALESCE pattern COALESCE(ss.name, ps.other_species, iv.other_species, 'Unknown') is consistently used across multiple files in the codebase:

  • pages/api/data-explorer/species-planted.ts
  • pages/api/data-explorer/map/distinct-species/[projectId].ts
  • pages/api/data-explorer/map/plant-location/index.ts
  • pages/api/data-explorer/export.ts

The order of precedence is intentional and follows a clear pattern:

  1. Scientific species name (ss.name) from the scientific_species table
  2. Other species from planted_species (ps.other_species)
  3. Other species from intervention (iv.other_species)
  4. 'Unknown' as fallback

This hierarchy makes sense because:

  • It prioritizes standardized scientific names over custom entries
  • When scientific names aren't available, it uses species information from more specific (planted_species) to more general (intervention) sources
  • The 'Unknown' fallback ensures no null values are returned
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the COALESCE order for species names.

# Test: Check if the COALESCE function retrieves the correct species names.
# Expected: The species name should reflect the correct priority.

# Sample query to test the COALESCE logic
cat <<EOF | sqlite3 your_database.db
SELECT
  COALESCE(ss.name, ps.other_species, iv.other_species, 'Unknown') AS name,
  ss.name AS scientific_name,
  ps.other_species AS planted_species_other,
  iv.other_species AS intervention_other_species
FROM intervention iv
LEFT JOIN planted_species ps ON iv.id = ps.intervention_id
LEFT JOIN scientific_species ss ON COALESCE(iv.scientific_species_id, ps.scientific_species_id) = ss.id
WHERE iv.id = 'sample_intervention_id';
EOF

Length of output: 362


Script:

#!/bin/bash
# Let's check for any similar COALESCE patterns in the codebase
# and understand the data model better

# Search for similar COALESCE patterns
rg -l "COALESCE.*species" --type sql --type ts

# Look for table definitions or schema files
fd -e sql -e prisma schema

# Search for related species handling
rg "scientific_species|planted_species" -A 3 -B 3

Length of output: 9134


Script:

#!/bin/bash
# Let's examine the Prisma schema to understand the relationships
cat prisma/schema.prisma

# Also check if there are any comments or documentation about the species handling
rg -B 2 -A 2 "species.*id|other_species" prisma/schema.prisma

Length of output: 4270

pages/api/data-explorer/map/plant-location/[plantLocationId].ts (3)

29-29: Verify the precedence in the COALESCE function for treeCount

The COALESCE function on line 29 prioritizes ps.tree_count over iv.trees_planted. Please confirm that ps.tree_count should indeed take precedence. This ensures that when ps.tree_count is available, it is used; otherwise, it falls back to iv.trees_planted.


90-90: Ensure the number of placeholders matches the parameters

An additional plantLocationId parameter is added on line 90. Verify that the number of ? placeholders in your SQL query matches the number of parameters provided. There should be five placeholders to correspond with the five plantLocationId entries.


69-69: ⚠️ Potential issue

Changing LEFT JOIN to INNER JOIN may omit records without samples

Lines 69 and 77 change the join from LEFT JOIN to INNER JOIN with intervention siv. This modification will exclude iv records that do not have corresponding siv entries (sample interventions). If there are plant locations without samples, they will be omitted from samplePlantLocations and totalSamplePlantLocations.

Apply this diff if you intend to include all plant locations, even those without samples:

- INNER JOIN intervention siv ON iv.id = siv.parent_id
+ LEFT JOIN intervention siv ON iv.id = siv.parent_id

To confirm the impact of this change, you can run the following script:

This script checks for interventions with the given plantLocationId that have no associated samples. If any are found, they would be excluded by the INNER JOIN.

Also applies to: 77-77

Comment on lines +39 to +42
pp.guid=? AND
iv.type IN ('multi-tree-registration','single-tree-registration') AND
iv.deleted_at IS NULL AND
iv.intervention_start_date BETWEEN ? AND ?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure consistent date-time handling.

The date range filtering is inconsistent - the start date doesn't include a time component while the end date adds it during parameter binding. This could lead to unexpected results at the day boundaries.

Consider modifying the query to handle both dates consistently:

-       iv.intervention_start_date BETWEEN ? AND ?
+       iv.intervention_start_date >= ? 
+       AND iv.intervention_start_date < DATE_ADD(?, INTERVAL 1 DAY)

Then update the parameter binding:

-     `${endDate} 23:59:59.999`,
+     endDate,

Committable suggestion was skipped due to low confidence.

Comment on lines +44 to +53
const query = `
SELECT
COALESCE(SUM(iv.trees_planted), 0) AS totalTreesPlanted
FROM intervention iv
JOIN project pp ON iv.plant_project_id = pp.id
WHERE
iv.deleted_at IS NULL
AND iv.type IN ('single-tree-registration', 'multi-tree-registration')
AND pp.guid = ?
AND iv.intervention_start_date BETWEEN ? AND ?`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Query changes need to be applied consistently across data explorer endpoints

Based on the search results, I found inconsistencies in how deleted records and intervention types are handled across data explorer endpoints:

  • Some files properly filter with both conditions:
    • trees-planted.ts
    • map/distinct-species/[projectId].ts
  • Missing both filters:
    • map/plant-location/index.ts
    • map/plant-location/[plantLocationId].ts
  • Missing intervention type filter:
    • total-species-planted.ts
    • species-planted.ts
    • export.ts

The changes in total-trees-planted.ts are correct, but similar changes should be applied to other data explorer endpoints to maintain consistency in data filtering.

🔗 Analysis chain

LGTM! Query changes align with PR objectives.

The SQL query improvements look good:

  • Properly filters out deleted records
  • Correctly handles single/multi tree registrations
  • Uses COALESCE for null handling
  • Improved readability with proper formatting

Let's verify the intervention types across the codebase:


Let me try a different approach to verify the intervention types usage across data explorer endpoints.

This should help us:

  1. Find all SQL queries in data explorer endpoints that use the intervention table
  2. Find any type definitions or constants that define these intervention types to ensure consistency

Let me try one final search with a simpler pattern to find any SQL queries in the data explorer endpoints:

This will help us understand the structure of data explorer endpoints and their SQL usage patterns.


Let's check the specific SQL queries in these intervention-related files to verify consistency:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify consistency of intervention type filtering across data explorer endpoints
# Expected: All data explorer endpoints should consistently filter deleted records and intervention types

rg -l "intervention.*type.*IN.*('single-tree-registration'|'multi-tree-registration')" pages/api/data-explorer/

Length of output: 125


Script:

#!/bin/bash
# Search for SQL queries in data explorer endpoints
rg -A 5 -B 5 "SELECT.*FROM.*intervention.*" pages/api/data-explorer/

# Also check for any other files that might define these intervention types
ast-grep --pattern 'type.*=.*("single-tree-registration"|"multi-tree-registration")'

Length of output: 157


Script:

#!/bin/bash
# List all files in data explorer directory first
fd . pages/api/data-explorer/

# Then search for any SQL queries with less restrictive pattern
rg -l "SELECT.*FROM" pages/api/data-explorer/

# And specifically look for intervention table usage
rg -l "intervention" pages/api/data-explorer/

Length of output: 1108


Script:

#!/bin/bash
# Check SQL queries in files that use intervention table
echo "=== trees-planted.ts ==="
rg -A 10 "SELECT" pages/api/data-explorer/trees-planted.ts

echo "=== total-species-planted.ts ==="
rg -A 10 "SELECT" pages/api/data-explorer/total-species-planted.ts

echo "=== species-planted.ts ==="
rg -A 10 "SELECT" pages/api/data-explorer/species-planted.ts

echo "=== export.ts ==="
rg -A 10 "SELECT" pages/api/data-explorer/export.ts

echo "=== map/plant-location/index.ts ==="
rg -A 10 "SELECT" pages/api/data-explorer/map/plant-location/index.ts

echo "=== map/plant-location/[plantLocationId].ts ==="
rg -A 10 "SELECT" pages/api/data-explorer/map/plant-location/\[plantLocationId\].ts

echo "=== map/distinct-species/[projectId].ts ==="
rg -A 10 "SELECT" pages/api/data-explorer/map/distinct-species/\[projectId\].ts

Length of output: 8201

Comment on lines +144 to +165
properties: PlantLocationProperties;
plantedSpecies: {
treeCount: number;
scientificName: string;
}[];
totalPlantedTrees: number;
samplePlantLocations: {
tag: string;
guid: string;
species: string;
geometry: {
type: string;
coordinates: number[];
};
measurements: {
width: string;
height: string;
};
}[];
totalSamplePlantLocations: number;
samplePlantLocations:
| null
| {
tag: string;
guid: string;
species: string;
geometry: {
type: string;
coordinates: number[];
};
measurements: {
width: string;
height: string;
};
}[];
totalSamplePlantLocations: null | number;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider extracting the sample location type to improve maintainability.

The nested type definition for samplePlantLocations could be extracted into a separate interface to improve code organization and reusability.

Consider refactoring like this:

interface SampleLocationResponse {
  tag: string;
  guid: string;
  species: string;
  geometry: {
    type: string;
    coordinates: number[];
  };
  measurements: {
    width: string;
    height: string;
  };
}

export interface PlantLocationDetailsApiResponse {
  res: {
    properties: PlantLocationProperties;
    plantedSpecies: {
      treeCount: number;
      scientificName: string;
    }[];
    totalPlantedTrees: number;
    samplePlantLocations: null | SampleLocationResponse[];
    totalSamplePlantLocations: null | number;
  };
}

Comment on lines +93 to +141
query = `
SELECT
LEFT(MONTHNAME(iv.intervention_start_date), 3) AS month,
YEAR(iv.intervention_start_date) AS year,
SUM(iv.trees_planted) AS treesPlanted
FROM intervention iv
JOIN project pp ON iv.plant_project_id = pp.id
WHERE
iv.deleted_at IS NULL AND
iv.type IN ('single-tree-registration', 'multi-tree-registration') AND
pp.guid = ? AND
iv.intervention_start_date BETWEEN ? AND ?
GROUP BY month, year
ORDER BY iv.intervention_start_date
`;
break;

case TIME_FRAME.YEARS:
query =
'SELECT \
YEAR(iv.intervention_start_date) AS year, \
SUM(iv.trees_planted) AS treesPlanted \
FROM intervention iv \
JOIN project pp ON iv.plant_project_id = pp.id \
WHERE pp.guid = ? AND iv.intervention_start_date BETWEEN ? AND ? \
GROUP BY year \
ORDER BY iv.intervention_start_date';
query = `
SELECT
YEAR(iv.intervention_start_date) AS year,
SUM(iv.trees_planted) AS treesPlanted
FROM intervention iv
JOIN project pp ON iv.plant_project_id = pp.id
WHERE
iv.deleted_at IS NULL AND
iv.type IN ('single-tree-registration', 'multi-tree-registration') AND
pp.guid = ? AND
iv.intervention_start_date BETWEEN ? AND ?
GROUP BY year
ORDER BY iv.intervention_start_date
`;
break;

default:
query =
'SELECT \
YEAR(iv.intervention_start_date) AS year, \
SUM(iv.trees_planted) AS treesPlanted \
FROM intervention iv \
JOIN project pp ON iv.plant_project_id = pp.id \
WHERE pp.guid = ? AND iv.intervention_start_date BETWEEN ? AND ? \
GROUP BY year \
ORDER BY iv.intervention_start_date';
query = `
SELECT
YEAR(iv.intervention_start_date) AS year,
SUM(iv.trees_planted) AS treesPlanted
FROM intervention iv
JOIN project pp ON iv.plant_project_id = pp.id
WHERE
iv.deleted_at IS NULL AND
iv.type IN ('single-tree-registration', 'multi-tree-registration') AND
pp.guid = ? AND
iv.intervention_start_date BETWEEN ? AND ?
GROUP BY year
ORDER BY iv.intervention_start_date
`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider refactoring to reduce query duplication.

The SQL queries share common conditions and structures. Consider extracting these into reusable constants or a query builder function.

const COMMON_WHERE_CONDITIONS = `
  iv.deleted_at IS NULL AND
  iv.type IN ('single-tree-registration', 'multi-tree-registration') AND
  pp.guid = ? AND
  iv.intervention_start_date BETWEEN ? AND ?
`;

const buildQuery = (selectClause: string, groupByClause: string) => `
  SELECT ${selectClause}
  FROM intervention iv
  JOIN project pp ON iv.plant_project_id = pp.id
  WHERE ${COMMON_WHERE_CONDITIONS}
  GROUP BY ${groupByClause}
  ORDER BY iv.intervention_start_date
`;

Comment on lines +55 to +68
query = `
SELECT
iv.intervention_start_date AS plantedDate,
SUM(iv.trees_planted) AS treesPlanted
FROM intervention iv
JOIN project pp ON iv.plant_project_id = pp.id
WHERE
iv.deleted_at IS NULL AND
iv.type IN ('single-tree-registration', 'multi-tree-registration') AND
pp.guid = ? AND
iv.intervention_start_date BETWEEN ? AND ?
GROUP BY iv.intervention_start_date
ORDER BY iv.intervention_start_date
`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider adding an index hint for better query performance.

The query looks correct and well-structured. However, for optimal performance, consider adding an index hint for the intervention_start_date column since it's used in both filtering and ordering.

 SELECT
     iv.intervention_start_date AS plantedDate,
     SUM(iv.trees_planted) AS treesPlanted
-FROM intervention iv
+FROM intervention FORCE INDEX (idx_intervention_start_date) iv
 JOIN project pp ON iv.plant_project_id = pp.id

Committable suggestion was skipped due to low confidence.

Comment on lines +155 to 163
const plantLocationType = plantLocationDetails?.properties.type;

const hasData =
plantLocationDetails !== null &&
Boolean(
selectedLayer.treeCount ||
selectedLayer?.density ||
(plantLocationType === 'multi-tree-registration' &&
(selectedLayer.treeCount || selectedLayer.density)) ||
(plantLocationDetails?.plantedSpecies?.length || 0) > 0 ||
(plantLocationDetails?.samplePlantLocations?.length || 0) > 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider extracting complex conditions and using type constants

The hasData condition is complex and uses magic strings. Consider these improvements for better maintainability:

+ const PLANT_LOCATION_TYPES = {
+   MULTI_TREE: 'multi-tree-registration'
+ } as const;
+ 
+ const hasMultiTreeData = (
+   type: string,
+   treeCount?: number,
+   density?: number
+ ) => type === PLANT_LOCATION_TYPES.MULTI_TREE && (treeCount || density);
+ 
+ const hasSpeciesData = (species?: any[]) => (species?.length || 0) > 0;
+ const hasSampleData = (samples?: any[]) => (samples?.length || 0) > 0;
+
  const hasData =
    plantLocationDetails !== null &&
    Boolean(
-     (plantLocationType === 'multi-tree-registration' &&
-       (selectedLayer.treeCount || selectedLayer.density)) ||
-       (plantLocationDetails?.plantedSpecies?.length || 0) > 0 ||
-       (plantLocationDetails?.samplePlantLocations?.length || 0) > 0
+     hasMultiTreeData(plantLocationType, selectedLayer.treeCount, selectedLayer.density) ||
+     hasSpeciesData(plantLocationDetails?.plantedSpecies) ||
+     hasSampleData(plantLocationDetails?.samplePlantLocations)
    );

Committable suggestion was skipped due to low confidence.

SUM(COALESCE(ps.tree_count, iv.trees_planted, 0)) AS total_tree_count
FROM intervention iv
LEFT JOIN planted_species ps ON iv.id = ps.intervention_id
LEFT JOIN scientific_species ss ON COALESCE(iv.scientific_species_id, ps.scientific_species_id) = ss.id
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Adjust the JOIN condition to handle NULL species IDs properly

The LEFT JOIN on scientific_species ss uses COALESCE(iv.scientific_species_id, ps.scientific_species_id) = ss.id. If both iv.scientific_species_id and ps.scientific_species_id are NULL, the condition becomes NULL = ss.id, which will not match any records. This could lead to missing species names in the results.

Consider modifying the JOIN condition to accommodate cases where either species ID is NULL:

- LEFT JOIN scientific_species ss ON COALESCE(iv.scientific_species_id, ps.scientific_species_id) = ss.id
+ LEFT JOIN scientific_species ss ON (iv.scientific_species_id = ss.id OR ps.scientific_species_id = ss.id)

This change ensures that the join will succeed if either of the species IDs matches ss.id.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
LEFT JOIN scientific_species ss ON COALESCE(iv.scientific_species_id, ps.scientific_species_id) = ss.id
LEFT JOIN scientific_species ss ON (iv.scientific_species_id = ss.id OR ps.scientific_species_id = ss.id)

Comment on lines +43 to +64
const query = `
SELECT
ps.other_species,
COALESCE(iv.scientific_species_id,
ps.scientific_species_id) AS scientific_species_id,
COALESCE(ss.name,
ps.other_species,
iv.other_species, 'Unknown') AS name,
SUM(COALESCE(ps.tree_count, iv.trees_planted, 0)) AS total_tree_count
FROM intervention iv
LEFT JOIN planted_species ps ON iv.id = ps.intervention_id
LEFT JOIN scientific_species ss ON COALESCE(iv.scientific_species_id, ps.scientific_species_id) = ss.id
JOIN project pp ON iv.plant_project_id = pp.id
WHERE
iv.deleted_at IS NULL
AND iv.type IN ('single-tree-registration', 'multi-tree-registration')
AND pp.guid = ?
AND iv.intervention_start_date BETWEEN ? AND ?
GROUP BY
COALESCE(iv.scientific_species_id, ps.scientific_species_id),
COALESCE(ss.name, ps.other_species, iv.other_species, 'Unknown')
ORDER BY total_tree_count DESC`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Include ps.other_species in the GROUP BY clause to avoid SQL errors

The query selects ps.other_species without aggregating it or including it in the GROUP BY clause. Some SQL dialects require that all non-aggregated columns in the SELECT clause be included in the GROUP BY clause. Omitting it may lead to SQL errors or unexpected results.

Apply this diff to include ps.other_species in the GROUP BY clause:

         GROUP BY 
             COALESCE(iv.scientific_species_id, ps.scientific_species_id), 
             COALESCE(ss.name, ps.other_species, iv.other_species, 'Unknown')
+            , ps.other_species
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const query = `
SELECT
ps.other_species,
COALESCE(iv.scientific_species_id,
ps.scientific_species_id) AS scientific_species_id,
COALESCE(ss.name,
ps.other_species,
iv.other_species, 'Unknown') AS name,
SUM(COALESCE(ps.tree_count, iv.trees_planted, 0)) AS total_tree_count
FROM intervention iv
LEFT JOIN planted_species ps ON iv.id = ps.intervention_id
LEFT JOIN scientific_species ss ON COALESCE(iv.scientific_species_id, ps.scientific_species_id) = ss.id
JOIN project pp ON iv.plant_project_id = pp.id
WHERE
iv.deleted_at IS NULL
AND iv.type IN ('single-tree-registration', 'multi-tree-registration')
AND pp.guid = ?
AND iv.intervention_start_date BETWEEN ? AND ?
GROUP BY
COALESCE(iv.scientific_species_id, ps.scientific_species_id),
COALESCE(ss.name, ps.other_species, iv.other_species, 'Unknown')
ORDER BY total_tree_count DESC`;
const query = `
SELECT
ps.other_species,
COALESCE(iv.scientific_species_id,
ps.scientific_species_id) AS scientific_species_id,
COALESCE(ss.name,
ps.other_species,
iv.other_species, 'Unknown') AS name,
SUM(COALESCE(ps.tree_count, iv.trees_planted, 0)) AS total_tree_count
FROM intervention iv
LEFT JOIN planted_species ps ON iv.id = ps.intervention_id
LEFT JOIN scientific_species ss ON COALESCE(iv.scientific_species_id, ps.scientific_species_id) = ss.id
JOIN project pp ON iv.plant_project_id = pp.id
WHERE
iv.deleted_at IS NULL
AND iv.type IN ('single-tree-registration', 'multi-tree-registration')
AND pp.guid = ?
AND iv.intervention_start_date BETWEEN ? AND ?
GROUP BY
COALESCE(iv.scientific_species_id, ps.scientific_species_id),
COALESCE(ss.name, ps.other_species, iv.other_species, 'Unknown')
, ps.other_species
ORDER BY total_tree_count DESC`;

Comment on lines +29 to +30
LEFT JOIN planted_species ps ON iv.id = ps.intervention_id
LEFT JOIN scientific_species ss ON COALESCE(iv.scientific_species_id, ps.scientific_species_id) = ss.id
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Potential Performance Issue with COALESCE in JOIN Condition

Using COALESCE in the LEFT JOIN condition may lead to inefficient query execution because it prevents the database from using indexes on iv.scientific_species_id and ps.scientific_species_id.

Consider restructuring the JOIN to improve performance:

-LEFT JOIN scientific_species ss ON COALESCE(iv.scientific_species_id, ps.scientific_species_id) = ss.id
+LEFT JOIN scientific_species ss 
+  ON iv.scientific_species_id = ss.id 
+  OR ps.scientific_species_id = ss.id

This change allows the database to utilize indexes on scientific_species_id, potentially improving query performance.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
LEFT JOIN planted_species ps ON iv.id = ps.intervention_id
LEFT JOIN scientific_species ss ON COALESCE(iv.scientific_species_id, ps.scientific_species_id) = ss.id
LEFT JOIN planted_species ps ON iv.id = ps.intervention_id
LEFT JOIN scientific_species ss
ON iv.scientific_species_id = ss.id
OR ps.scientific_species_id = ss.id

FROM intervention iv
LEFT JOIN intervention siv ON iv.id = siv.parent_id
INNER JOIN intervention siv ON iv.id = siv.parent_id
LEFT JOIN scientific_species ss ON iv.scientific_species_id = ss.id
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Inconsistent usage of COALESCE in JOIN conditions

On line 70, the join condition uses iv.scientific_species_id = ss.id without COALESCE, whereas elsewhere, COALESCE(iv.scientific_species_id, ps.scientific_species_id) is used. For consistency and to handle potential null values in iv.scientific_species_id, consider updating the join condition.

Apply this diff for consistency:

- LEFT JOIN scientific_species ss ON iv.scientific_species_id = ss.id
+ LEFT JOIN scientific_species ss ON COALESCE(iv.scientific_species_id, ps.scientific_species_id) = ss.id

Committable suggestion was skipped due to low confidence.

Copy link
Contributor

@mariahosfeld mariahosfeld left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functionality looks good to me, data makes sense and integration of HID looks good.

Copy link
Contributor

@sunilsabatp sunilsabatp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@mariahosfeld mariahosfeld merged commit 5dd7a55 into develop Oct 28, 2024
9 checks passed
@mariahosfeld mariahosfeld deleted the hotfix/data-explorer-queries branch October 28, 2024 09:49
This was referenced Feb 5, 2025
@coderabbitai coderabbitai bot mentioned this pull request Apr 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants