Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fetch HH from matview #1025

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open

Fetch HH from matview #1025

wants to merge 6 commits into from

Conversation

saiprakash-eGov
Copy link
Collaborator

@saiprakash-eGov saiprakash-eGov commented Oct 21, 2024

Fetch HH from matview and sea

Summary by CodeRabbit

  • New Features

    • Introduced a new configuration property to manage materialized view search functionality.
    • Added a repository for managing household data, enhancing data access capabilities.
    • Implemented a RowMapper for mapping SQL results to household objects.
  • Improvements

    • Refactored data handling in the DownsyncService to utilize household objects instead of IDs, improving data processing efficiency.
    • Enhanced search methods to handle client reference IDs and introduced list splitting for large datasets.
    • Improved caching mechanisms for better performance in data retrieval.
  • Documentation

    • Updated application properties for better configuration clarity.

Copy link
Contributor

coderabbitai bot commented Oct 21, 2024

Walkthrough

The pull request introduces several changes to the referral management service, including the addition of a new configuration property in ReferralManagementConfiguration, the creation of a HouseholdRepository for managing household data, and a HouseholdRowMapper for mapping SQL results to household objects. The DownsyncService class has been refactored to utilize these new components, shifting from ID-based handling to object-oriented management of household data. Additionally, a new property is added to the application.properties file to control the new functionality.

Changes

File Change Summary
health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java - Added new private field enableMatviewSearch with @Value annotation for property injection.
health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HouseholdRepository.java - Introduced HouseholdRepository class with method findByView for retrieving household data with pagination.
health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/HouseholdRowMapper.java - Added HouseholdRowMapper class with method mapRow for mapping SQL results to Household objects.
health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java - Refactored DownsyncService to use HouseholdRepository and updated methods to work with Household objects.
health-services/referralmanagement/src/main/resources/application.properties - Added new property egov.enable.matview.search=false and made minor formatting changes to existing properties.

Possibly related PRs

  • HCMPRE-493 Workflow integration changes for plan config #934: The changes in this PR involve adding new configuration properties in a different configuration class, which is conceptually similar to the addition of the enableMatviewSearch property in the main PR's ReferralManagementConfiguration class. Both PRs enhance configuration capabilities by introducing new properties sourced from application settings.
  • Plan status count changes to include all status in the map #1044: This PR adds a new property related to business service search in the Configuration class, which aligns with the main PR's focus on adding configuration properties.

Suggested reviewers

  • sathishp-eGov
  • kavi-egov
  • shashwat-egov

Poem

🐰 In the fields where data flows,
A new path for households grows.
With properties and queries bright,
We hop along, in code delight!
From rows to maps, we weave our tale,
In the world of referrals, we shall prevail! 🌼

✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

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 generate docstrings to generate docstrings for this PR. (Beta)
  • @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.

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.

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

🧹 Outside diff range comments (3)
health-services/referralmanagement/src/main/resources/application.properties (1)

Line range hint 156-159: Remove unnecessary blank lines at the end of the file.

While the formatting changes around project.mdms.module and egov.location.hierarchy.type are fine, it's best to remove the extra blank lines at the end of the file to adhere to best practices for property files.

Consider removing the extra blank lines at the end of the file.

health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java (2)

Line range hint 289-311: Avoid SQL injection by preventing dynamic table and field names in queries.

Using dynamic table names and field names in SQL queries can introduce SQL injection vulnerabilities. The tableName and idListFieldName parameters in getPrimaryIds should not be directly inserted into the query without validation.

Consider refactoring to use an enumeration or a mapping of allowed table and field names to ensure only valid, expected values are used. For example:

// Define enums or constants for table and field names
enum TableName {
    HOUSEHOLD_MEMBER("HOUSEHOLD_MEMBER"),
    PROJECT_BENEFICIARY("PROJECT_BENEFICIARY"),
    PROJECT_TASK("PROJECT_TASK"),
    SIDE_EFFECT("SIDE_EFFECT");

    private final String name;

    TableName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

// Use the enum in the method
private List<String> getPrimaryIds(List<String> idList, String idListFieldName, TableName table, Long lastChangedSince) {
    // Validate idListFieldName against allowed field names
    // Proceed with query construction using validated table.getName()
}

Line range hint 492-508: Use URI builder for constructing URLs to ensure proper encoding.

In appendUrlParams, URL parameters are concatenated as strings, which may lead to encoding issues with special characters. Using a URI builder or utilities provided by the HTTP client library can help prevent such issues.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE

📥 Commits

Files that changed from the base of the PR and between 1ad04ee and 29e951b.

📒 Files selected for processing (5)
  • health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java (1 hunks)
  • health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HouseholdRepository.java (1 hunks)
  • health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/HouseholdRowMapper.java (1 hunks)
  • health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java (10 hunks)
  • health-services/referralmanagement/src/main/resources/application.properties (1 hunks)
🧰 Additional context used
📓 Learnings (1)
health-services/referralmanagement/src/main/resources/application.properties (2)
Learnt from: Priyanka-eGov
PR: egovernments/health-campaign-services#934
File: health-services/plan-service/src/main/resources/application.properties:54-54
Timestamp: 2024-10-03T10:08:20.045Z
Learning: In the 'health-campaign-services' project, it is acceptable to keep the old MDMS endpoint `/egov-mdms-service/v1/_search` in the following files, and updating them is not required:

- `health-services/referralmanagement/src/main/resources/application.properties`
- `health-services/transformer/src/main/resources/application.properties`
- `health-services/stock/src/main/resources/application.properties`
- `health-services/resource-estimation-service/src/main/resources/application.properties`
- `health-services/individual/src/main/resources/application.properties`
- `health-services/product/src/main/resources/application.properties`
- `health-services/project/src/main/resources/application.properties`
- `health-services/household/src/main/resources/application.properties`
- `health-services/facility/src/main/resources/application.properties`
- `core-services/pgr-services/src/main/resources/application.properties`
- `core-services/egov-hrms/src/main/resources/application.properties`
- `core-services/dashboard-analytics/src/main/resources/application.properties`
Learnt from: Priyanka-eGov
PR: egovernments/health-campaign-services#934
File: health-services/plan-service/src/main/resources/application.properties:54-54
Timestamp: 2024-10-08T20:11:12.539Z
Learning: In the 'health-campaign-services' project, it is acceptable to keep the old MDMS endpoint `/egov-mdms-service/v1/_search` in the following files, and updating them is not required:

- `health-services/referralmanagement/src/main/resources/application.properties`
- `health-services/transformer/src/main/resources/application.properties`
- `health-services/stock/src/main/resources/application.properties`
- `health-services/resource-estimation-service/src/main/resources/application.properties`
- `health-services/individual/src/main/resources/application.properties`
- `health-services/product/src/main/resources/application.properties`
- `health-services/project/src/main/resources/application.properties`
- `health-services/household/src/main/resources/application.properties`
- `health-services/facility/src/main/resources/application.properties`
- `core-services/pgr-services/src/main/resources/application.properties`
- `core-services/egov-hrms/src/main/resources/application.properties`
- `core-services/dashboard-analytics/src/main/resources/application.properties`
🔇 Additional comments (7)
health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java (1)

118-119: 🧹 Nitpick (assertive)

Consider using a boolean type and add documentation for the new property.

The new enableMatviewSearch property seems to be a feature flag. However, there are a few points to consider:

  1. Using a String type for what appears to be a boolean flag might not be the most appropriate choice. Consider using a boolean type instead.
  2. There's no documentation explaining the purpose or possible values of this property. Adding a comment would improve clarity.

Consider applying the following changes:

-    @Value("${egov.enable.matview.search}")
-    private String enableMatviewSearch;
+    /**
+     * Flag to enable or disable materialized view search.
+     * Set to true to use materialized view, false to use regular search.
+     */
+    @Value("${egov.enable.matview.search}")
+    private boolean enableMatviewSearch;

To ensure this property is properly set in the application properties, run the following command:

Could you please clarify the intended use of this property and confirm if a boolean type would be more appropriate?

✅ Verification successful

Verified: egov.enable.matview.search Usage

  • The enableMatviewSearch property is defined in ReferralManagementConfiguration.java and is not used elsewhere in the codebase.
  • Changing its type from String to boolean is appropriate and safe.
  • Adding documentation for this property will enhance clarity.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if the new property is defined in application.properties
grep -n "egov.enable.matview.search" $(find . -name "application.properties" -type f)

Length of output: 1361


Script:

#!/bin/bash
# Search for all usages of `enableMatviewSearch` in the codebase
rg "enableMatviewSearch" --context 2

Length of output: 729

health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java (6)

14-14: Import of Tuple class is appropriate.

The addition of import org.egov.common.ds.Tuple; is necessary for handling tuples returned from the repository.


46-46: Import of HouseholdRepository is appropriate.

The HouseholdRepository import is required for accessing household data from the materialized view.


68-68: Declaration of householdRepository is correct.

The private member householdRepository is properly declared for use within the service.


78-87: Constructor updated to include householdRepository.

The HouseholdRepository is correctly injected via the constructor and assigned to the class member.


532-538: Utility method splitList is well implemented.

The splitList method efficiently splits a list into sublists of the specified size, which helps in handling large datasets without overwhelming the system.


246-275: Potential mismatch in field names affecting query results.

In searchMembers, the field name "householdClientReferenceId" is used in the getPrimaryIds method. Ensure that this field name matches the actual column name in the HOUSEHOLD_MEMBER table to prevent incorrect query results.

Run the following script to verify the column name in the HOUSEHOLD_MEMBER table:

@@ -152,6 +152,7 @@ project.document.id.verification.required=false

project.mdms.module=HCM-PROJECT-TYPES
egov.location.hierarchy.type=ADMIN
egov.enable.matview.search=false
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

LGTM. Consider adding documentation for the new property.

The addition of egov.enable.matview.search=false is a good practice for introducing a new feature. Setting it to false by default ensures backward compatibility.

Consider adding a comment above this line to explain the purpose and impact of this property, e.g.:

# Controls whether to use materialized view for search operations. Set to true to enable.
egov.enable.matview.search=false

@Autowired
private HouseholdRowMapper householdRowMapper;

public Tuple<Long, List<Household>> findByView (String localityCode, Integer limit, Integer offset, String tenantId) {
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

Unused parameter tenantId in method findByView

The parameter tenantId is declared but not used within the method. In a multitenant system, it's important to include tenantId in your query to ensure data isolation. Consider removing it if unnecessary or incorporating it into the SQL queries.

public Tuple<Long, List<Household>> findByView (String localityCode, Integer limit, Integer offset, String tenantId) {


String query = "select * from household_address_mv where localitycode=:localitycode and rank between :start and :end ";
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

tenantId is not included in SQL queries

The SQL queries do not filter by tenantId, which could lead to data from other tenants being accessed. Ensure that tenantId is included in the WHERE clause of your queries to maintain proper data segregation.

Also applies to: 35-35


🛠️ Refactor suggestion

Avoid using SELECT * in SQL queries

Using SELECT * can lead to fetching unnecessary data, impacting performance. Specify only the columns that are required for the operation.

Modify the query to include specific columns:

- String query = "select * from household_address_mv where localitycode=:localitycode ORDER BY rank LIMIT :limit OFFSET :offset";
+ String query = "select column1, column2, column3 from household_address_mv where localitycode=:localitycode ORDER BY rank LIMIT :limit OFFSET :offset";

Replace column1, column2, column3 with the actual column names you need.

Committable suggestion was skipped due to low confidence.

Comment on lines +28 to +35
Map<String, Object> paramsMap = new HashMap<>();
paramsMap.put("start", offset);
paramsMap.put("end", offset+limit);
paramsMap.put("localitycode", localityCode);

Map<String, Object> paramsMapCount = new HashMap<>();
paramsMapCount.put("localitycode", localityCode);
Integer maxRank = namedParameterJdbcTemplate.queryForObject("select max(rank) from household_address_mv where localitycode=:localitycode", paramsMapCount, Integer.class);
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

Combine parameter maps to reduce redundancy

Currently, two parameter maps are used (paramsMap and paramsMapCount), both containing localitycode. Combining them simplifies the code and reduces redundancy.

Here's how you can adjust the code:

Map<String, Object> paramsMap = new HashMap<>();
paramsMap.put("localitycode", localityCode);

- paramsMap.put("start", offset);
- paramsMap.put("end", offset+limit);
+ paramsMap.put("limit", limit);
+ paramsMap.put("offset", offset);

- Map<String, Object> paramsMapCount = new HashMap<>();
- paramsMapCount.put("localitycode", localityCode);

- Long totalCount = namedParameterJdbcTemplate.queryForObject("select count(*) from household_address_mv where localitycode=:localitycode", paramsMapCount, Long.class);
+ Long totalCount = namedParameterJdbcTemplate.queryForObject("select count(*) from household_address_mv where localitycode=:localitycode", paramsMap, Long.class);

Now, paramsMap is used for both queries.

Committable suggestion was skipped due to low confidence.

Comment on lines +35 to +36
Integer maxRank = namedParameterJdbcTemplate.queryForObject("select max(rank) from household_address_mv where localitycode=:localitycode", paramsMapCount, Integer.class);
Long totalCount = maxRank == null ? 0L : Long.valueOf(maxRank);
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

Using MAX(rank) may not accurately represent total count

Relying on MAX(rank) assumes that ranks are sequential and without gaps. If there are missing ranks, MAX(rank) will not reflect the actual total number of records. Consider using COUNT(*) to get an accurate total count of records matching the criteria.

Apply this diff to correct the total count calculation:

- Integer maxRank = namedParameterJdbcTemplate.queryForObject("select max(rank) from household_address_mv where localitycode=:localitycode", paramsMapCount, Integer.class);
- Long totalCount = maxRank == null ? 0L : Long.valueOf(maxRank);
+ Long totalCount = namedParameterJdbcTemplate.queryForObject("select count(*) from household_address_mv where localitycode=:localitycode", paramsMapCount, Long.class);
📝 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
Integer maxRank = namedParameterJdbcTemplate.queryForObject("select max(rank) from household_address_mv where localitycode=:localitycode", paramsMapCount, Integer.class);
Long totalCount = maxRank == null ? 0L : Long.valueOf(maxRank);
Long totalCount = namedParameterJdbcTemplate.queryForObject("select count(*) from household_address_mv where localitycode=:localitycode", paramsMapCount, Long.class);

Comment on lines +45 to +46
.additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper.readValue(resultSet
.getString("additionalDetails"), AdditionalFields.class))
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Handle Null Values for AdditionalFields

If additionalDetails in the result set is NULL, objectMapper.readValue() might not be necessary. The current null check could be simplified for clarity.

Consider simplifying the code:

- .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper.readValue(resultSet
-     .getString("additionalDetails"), AdditionalFields.class))
+ .additionalFields(resultSet.getString("additionalDetails") != null ? 
+     objectMapper.readValue(resultSet.getString("additionalDetails"), AdditionalFields.class) : null)
📝 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
.additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper.readValue(resultSet
.getString("additionalDetails"), AdditionalFields.class))
.additionalFields(resultSet.getString("additionalDetails") != null ?
objectMapper.readValue(resultSet.getString("additionalDetails"), AdditionalFields.class) : null)

.latitude(resultSet.getDouble("latitude"))
.longitude(resultSet.getDouble("longitude"))
.locationAccuracy(resultSet.getDouble("locationAccuracy"))
.type(AddressType.fromValue(resultSet.getString("type")))
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

Check for Null Before Using AddressType.fromValue

If resultSet.getString("type") returns null, calling AddressType.fromValue(null) could throw an exception. Add a null check to prevent this.

Apply this diff to handle potential null values:

- .type(AddressType.fromValue(resultSet.getString("type")))
+ .type(resultSet.getString("type") != null ? AddressType.fromValue(resultSet.getString("type")) : null)
📝 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
.type(AddressType.fromValue(resultSet.getString("type")))
.type(resultSet.getString("type") != null ? AddressType.fromValue(resultSet.getString("type")) : null)

Comment on lines +67 to +69
if (household.getAddress().getId() == null) {
household.setAddress(null);
}
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

Prevent Potential NullPointerException When Checking Address ID

If household.getAddress() returns null, calling getId() on it will cause a NullPointerException. Given that the address is always set during the build, verify if the address can be null and adjust the check accordingly.

Apply this diff to ensure safety:

- if (household.getAddress().getId() == null) {
+ if (household.getAddress() == null || household.getAddress().getId() == null) {

Alternatively, if household.getAddress() cannot be null, confirm this assumption and document it to clarify the behavior.

📝 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
if (household.getAddress().getId() == null) {
household.setAddress(null);
}
if (household.getAddress() == null || household.getAddress().getId() == null) {
household.setAddress(null);
}

Comment on lines +52 to +54
.latitude(resultSet.getDouble("latitude"))
.longitude(resultSet.getDouble("longitude"))
.locationAccuracy(resultSet.getDouble("locationAccuracy"))
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

Properly Handle Null Values for Double Fields

Using ResultSet.getDouble() returns 0.0 when the column value is NULL. This might lead to confusion between a genuine 0.0 value and a NULL. Use ResultSet.getObject() to differentiate between them.

Apply this diff to handle null values correctly:

- .latitude(resultSet.getDouble("latitude"))
- .longitude(resultSet.getDouble("longitude"))
- .locationAccuracy(resultSet.getDouble("locationAccuracy"))
+ .latitude(resultSet.getObject("latitude") != null ? resultSet.getDouble("latitude") : null)
+ .longitude(resultSet.getObject("longitude") != null ? resultSet.getDouble("longitude") : null)
+ .locationAccuracy(resultSet.getObject("locationAccuracy") != null ? resultSet.getDouble("locationAccuracy") : null)

Also, update the corresponding fields in the Address class to use Double instead of double:

- private double latitude;
- private double longitude;
- private double locationAccuracy;
+ private Double latitude;
+ private Double longitude;
+ private Double locationAccuracy;
📝 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
.latitude(resultSet.getDouble("latitude"))
.longitude(resultSet.getDouble("longitude"))
.locationAccuracy(resultSet.getDouble("locationAccuracy"))
.latitude(resultSet.getObject("latitude") != null ? resultSet.getDouble("latitude") : null)
.longitude(resultSet.getObject("longitude") != null ? resultSet.getDouble("longitude") : null)
.locationAccuracy(resultSet.getObject("locationAccuracy") != null ? resultSet.getDouble("locationAccuracy") : null)

@@ -63,21 +65,26 @@ public class DownsyncService {

private MasterDataService masterDataService;

private HouseholdRepository householdRepository;

private static final Integer SEARCH_MAX_COUNT = 1000;
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Consider using int instead of Integer for SEARCH_MAX_COUNT.

Since SEARCH_MAX_COUNT is a constant and will not be null, using the primitive type int is more efficient.

@egovernments egovernments deleted a comment from coderabbitai bot Oct 21, 2024
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: 3

🧹 Outside diff range comments (1)
health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java (1)

Line range hint 466-489: Avoid injecting parameters directly into SQL queries to prevent SQL injection risks.

In the getPrimaryIds method, tableName and idListFieldName are directly injected into the SQL query. This practice can lead to SQL injection vulnerabilities if these variables are not strictly controlled.

Consider refactoring the code to use predefined constants for table and field names or to validate the inputs thoroughly.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE

📥 Commits

Files that changed from the base of the PR and between 0ad9a94 and 94fcd8c.

📒 Files selected for processing (1)
  • health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java (10 hunks)
🧰 Additional context used

@@ -104,16 +111,16 @@ public Downsync prepareDownsyncData(DownsyncRequest downsyncRequest) {
LinkedHashMap<String, Object> projectType = masterDataService.getProjectType(downsyncRequest);

/* search household */
householdIds = searchHouseholds(downsyncRequest, downsync);
households = searchHouseholds(downsyncRequest, downsync);
householdClientRefIds = households.stream().map(Household::getClientReferenceId).collect(Collectors.toList());
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

Possible NullPointerException when households is null.

At line 115, householdClientRefIds is assigned by calling households.stream(). If households is null, this will result in a NullPointerException.

Please add a null check for households before calling stream().

Apply this diff to fix the potential issue:

+ if (households != null) {
    householdClientRefIds = households.stream().map(Household::getClientReferenceId).collect(Collectors.toList());
+ } else {
+   householdClientRefIds = Collections.emptyList();
+ }
📝 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
householdClientRefIds = households.stream().map(Household::getClientReferenceId).collect(Collectors.toList());
if (households != null) {
householdClientRefIds = households.stream().map(Household::getClientReferenceId).collect(Collectors.toList());
} else {
householdClientRefIds = Collections.emptyList();
}

Comment on lines +214 to +215
List<Individual> individuals = new ArrayList<>();
List<List<String>> subLists = splitList(individualClientRefIds, SEARCH_MAX_COUNT);
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

Add null check for individualClientRefIds before splitting the list.

In the searchIndividuals method, individualClientRefIds might be null or empty, which could cause a NullPointerException when passing it to splitList.

Please add a null or empty check before calling splitList.

Apply this diff to fix the issue:

+ if (CollectionUtils.isEmpty(individualClientRefIds)) {
+     return Collections.emptyList();
+ }
  List<Individual> individuals = new ArrayList<>();
  List<List<String>> subLists = splitList(individualClientRefIds, SEARCH_MAX_COUNT);
📝 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
List<Individual> individuals = new ArrayList<>();
List<List<String>> subLists = splitList(individualClientRefIds, SEARCH_MAX_COUNT);
if (CollectionUtils.isEmpty(individualClientRefIds)) {
return Collections.emptyList();
}
List<Individual> individuals = new ArrayList<>();
List<List<String>> subLists = splitList(individualClientRefIds, SEARCH_MAX_COUNT);

Comment on lines +535 to +536
for (int i = 0; i < list.size(); i += size) {
subLists.add(list.subList(i, Math.min(i + size, list.size())));
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

Handle possible zero or negative size in splitList method.

The splitList method does not handle cases where size is zero or negative, which could lead to an infinite loop or an exception.

Consider adding validation to ensure that size is greater than zero.

Apply this diff to add validation:

private <T> List<List<T>> splitList(List<T> list, int size) {
+   if (size <= 0) {
+       throw new IllegalArgumentException("Size must be greater than zero");
+   }
    List<List<T>> subLists = new ArrayList<>();
    for (int i = 0; i < list.size(); i += size) {
        subLists.add(list.subList(i, Math.min(i + size, list.size())));
    }
    return subLists;
}

Committable suggestion was skipped due to low confidence.

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

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 94fcd8c and 18fecab.

📒 Files selected for processing (1)
  • health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java (10 hunks)
🔇 Additional comments (4)
health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java (4)

53-53: Consider using int instead of Integer for SEARCH_MAX_COUNT.
Using a primitive type is more efficient for constants that will never be null.


112-112: Possible NullPointerException when households is null.
If searchHouseholds unexpectedly returns null instead of an empty list, calling stream() will throw an NPE. Please add a null check or ensure searchHouseholds never returns null.


213-214: Add a null check for individualClientRefIds before splitting the list.
When individualClientRefIds is null, passing it to splitList will cause a NullPointerException.


534-535: Validate size in splitList to prevent invalid ranges.
If size is zero or negative, the loop can lead to an infinite iteration or an out-of-bounds error. Ensure size > 0 before proceeding.

Comment on lines +86 to +92
String key = downsyncCriteria.getLocality() + downsyncCriteria.getOffset() + downsyncCriteria.getLimit();

Object obj = getFromCache(key);
if (null != obj) {
return (Downsync) obj;
}

Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Incorporate additional parameters into the cache key to avoid collisions.
Right now, the cache key is derived only from locality, offset, and limit. If multiple queries share these same three parameters but differ in others (e.g., tenantId, lastSyncedTime, or matview toggles), they may overwrite each other in the cache. Consider including more fields from downsyncCriteria in the key for uniqueness.

Comment on lines +101 to +104
// removing incremental downsync for matview flow
if (configs.isEnableMatviewSearch()) {
downsyncCriteria.setLastSyncedTime(null);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Review the decision to reset lastSyncedTime when isEnableMatviewSearch is true.
Setting lastSyncedTime to null might skip incremental downsync for matview-based searches, which may be unexpected if partial sync is needed. Consider clarifying or adjusting this logic if incremental sync from matview is a requirement.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants