Skip to content

Conversation

@Jalina2007
Copy link

@Jalina2007 Jalina2007 commented Oct 27, 2025

Related Issue

API resource filter is not working. #24875

Description

To handle the sorting issue, I changed the constants in the class SQLConstants.java which was enough to fix the sorting. This, however introduced another issue in the pagination logic, as that depended on the sorting to be done by CURSOR_KEY which the fix changed to be done by NAME. The pagination logic send the CURSOR_KEY of the last element of the current page to do the filtering at the SQL query, but since I changed the sorting to be done by NAME, sending the CURSOR_KEY does not make sense. So, I changed that logic in the PR link. This created another problem in the class FilterTreeBuilder.java, which checked pagination filters for the operator "pr". This worked earlier because CURSOR_KEY is an integer, but now since it contains text, parts of the NAME values got matched as operators. So I put a regex pattern there to make sure it matches that operator check only when it's at the end of the string. Other operators shouldn't cause this issue because they have spaces on both sides of the matching text. So, I left them untouched.

The fix for case insensitive sorting was straightforeward. I changed the SQL queries by adding the LOWER() function within the query in the file FilterQueriesUtil.java.

Before Change:
Screenshot 2025-10-27 114940
Screenshot 2025-10-27 115005

After Change:
Screenshot 2025-10-27 115330

Screenshot 2025-10-27 115350

Follow up actions

I have run related tests in my local environment. If possible, please run any related tests to see if this breaks any other parts of the code, since I have applied changes to some core parts of the system. Please let me know if I have missed anything.

Developer Checklist

  • [Behavioural Change] Does this change introduce a behavioral change to the product?
  • ↳ Approved by team lead
  • ↳ Label impact/behavioral-change added
  • [Migration Impact] Does this change have a migration impact?
  • ↳ Migration label added (e.g., 7.2.0-migration)
  • ↳ Migration issues created and linked
  • [New Configuration] Does this change introduce a new configuration?
  • ↳ Label config added
  • ↳ Configuration is properly documented

Checklist (for reviewing)

General

  • Is this PR explained thoroughly? All code changes must be accounted for in the PR description.
  • Is the PR labeled correctly?

Functionality

  • Are all requirements met? Compare implemented functionality with the requirements specification.
  • Does the UI work as expected? There should be no Javascript errors in the console; all resources should load. There should be no unexpected errors. Deliberately try to break the feature to find out if there are corner cases that are not handled.

Code

  • Do you fully understand the introduced changes to the code? If not ask for clarification, it might uncover ways to solve a problem in a more elegant and efficient way.
  • Does the PR introduce any inefficient database requests? Use the debug server to check for duplicate requests.
  • Are all necessary strings marked for translation? All strings that are exposed to users via the UI must be marked for translation.

Tests

  • Are there sufficient test cases? Ensure that all components are tested individually; models, forms, and serializers should be tested in isolation even if a test for a view covers these components.
  • If this is a bug fix, are tests for the issue in place? There must be a test case for the bug to ensure the issue won’t regress. Make sure that the tests break without the new code to fix the issue.
  • If this is a new feature or a significant change to an existing feature? has the manual testing spreadsheet been updated with instructions for manual testing?

Security

  • Confirm this PR doesn't commit any keys, passwords, tokens, usernames, or other secrets.
  • Are all UI and API inputs run through forms or serializers?
  • Are all external inputs validated and sanitized appropriately?
  • Does all branching logic have a default case?
  • Does this solution handle outliers and edge cases gracefully?
  • Are all external communications secured and restricted to SSL?

Documentation

  • Are changes to the UI documented in the platform docs? If this PR introduces new platform site functionality or changes existing ones, the changes should be documented.
  • Are changes to the API documented in the API docs? If this PR introduces new API functionality or changes existing ones, the changes must be documented.
  • Are reusable components documented? If this PR introduces components that are relevant to other developers (for instance a mixin for a view or a generic form) they should be documented in the Wiki.

Summary by CodeRabbit

  • Bug Fixes
    • Improved search and filter functionality to support case-insensitive matching, enabling users to find results without needing to match exact capitalization.

Comment on lines 241 to 247
} else if (Pattern.compile(" pr$", Pattern.CASE_INSENSITIVE).matcher(filterString).find()) {
//with filter PR, there should not be whitespace after.
filterParts = trimmedFilter.split(" pr| PR| pR| Pr");
if (filterParts.length >= 2) {
filterParts = trimmedFilter.split("(?i) pr$");
if (filterParts.length >= 1) {
setExpressionNodeValues(filterParts[0], " pr", null, expressionNode);
}
} else if (Pattern.compile(Pattern.quote(" gt "), Pattern.CASE_INSENSITIVE).matcher(filterString).find()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Log Improvement Suggestion No: 1

Suggested change
} else if (Pattern.compile(" pr$", Pattern.CASE_INSENSITIVE).matcher(filterString).find()) {
//with filter PR, there should not be whitespace after.
filterParts = trimmedFilter.split(" pr| PR| pR| Pr");
if (filterParts.length >= 2) {
filterParts = trimmedFilter.split("(?i) pr$");
if (filterParts.length >= 1) {
setExpressionNodeValues(filterParts[0], " pr", null, expressionNode);
}
} else if (Pattern.compile(Pattern.quote(" gt "), Pattern.CASE_INSENSITIVE).matcher(filterString).find()) {
} else if (Pattern.compile(" pr$", Pattern.CASE_INSENSITIVE).matcher(filterString).find()) {
//with filter PR, there should not be whitespace after.
filterParts = trimmedFilter.split("(?i) pr$");
if (filterParts.length >= 1) {
log.debug("Processing PR filter with attribute: " + filterParts[0]);
setExpressionNodeValues(filterParts[0], " pr", null, expressionNode);
}
} else if (Pattern.compile(Pattern.quote(" gt "), Pattern.CASE_INSENSITIVE).matcher(filterString).find()) {

Copy link
Contributor

@wso2-engineering wso2-engineering bot left a comment

Choose a reason for hiding this comment

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

AI Agent Log Improvement Checklist

⚠️ Warning: AI-Generated Review Comments

  • The log-related comments and suggestions in this review were generated by an AI tool to assist with identifying potential improvements. Purpose of reviewing the code for log improvements is to improve the troubleshooting capabilities of our products.
  • Please make sure to manually review and validate all suggestions before applying any changes. Not every code suggestion would make sense or add value to our purpose. Therefore, you have the freedom to decide which of the suggestions are helpful.

✅ Before merging this pull request:

  • Review all AI-generated comments for accuracy and relevance.
  • Complete and verify the table below. We need your feedback to measure the accuracy of these suggestions and the value they add. If you are rejecting a certain code suggestion, please mention the reason briefly in the suggestion for us to capture it.
Comment Accepted (Y/N) Reason
#### Log Improvement Suggestion No: 1

@Jalina2007 Jalina2007 marked this pull request as ready for review October 28, 2025 02:27
Copilot AI review requested due to automatic review settings October 28, 2025 02:27
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements case-insensitive searching and sorting by API name in the API Resource Management UI. The changes address a bug where the API resource filter was not working correctly and sorting was based on CURSOR_KEY instead of NAME.

Key changes:

  • Modified SQL queries to sort by NAME instead of CURSOR_KEY across all database vendors
  • Implemented case-insensitive filtering using LOWER() function in SQL queries
  • Fixed pagination attribute mapping to use NAME instead of CURSOR_KEY
  • Updated regex pattern in FilterTreeBuilder to handle "pr" operator correctly when NAME contains text

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
FilterTreeBuilder.java Fixed regex pattern for "pr" operator to match only at end of string and adjusted split logic for single-part filters
FilterQueriesUtil.java Added LOWER() function to both attribute name and parameter value for case-insensitive filtering in LIKE queries
SQLConstants.java Changed ORDER BY clause from CURSOR_KEY to NAME across all database-specific query constants
APIResourceManagementConstants.java Updated pagination attribute mappings from CURSOR_KEY to NAME for BEFORE and AFTER filters

Comment on lines 194 to 196
String filterString = " LIKE LOWER(?) AND ";
String attributeNameWithLowerCaseFunction = "LOWER(" + attributeName + ")";
filter.append(attributeNameWithLowerCaseFunction).append(filterString);
Copy link

Copilot AI Oct 28, 2025

Choose a reason for hiding this comment

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

The LOWER() function is incorrectly applied. The parameter placeholder ? should not be wrapped in LOWER() in the SQL string. Instead, the parameter value should be lowercased in Java before being set. Change filterString to " LIKE ? AND " and lowercase the value parameter in setFilterAttributeValue() calls using .toLowerCase().

Copilot uses AI. Check for mistakes.
Comment on lines 203 to 205
String filterString = " LIKE LOWER(?) AND ";
String attributeNameWithLowerCaseFunction = "LOWER(" + attributeName + ")";
filter.append(attributeNameWithLowerCaseFunction).append(filterString);
Copy link

Copilot AI Oct 28, 2025

Choose a reason for hiding this comment

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

The LOWER() function is incorrectly applied. The parameter placeholder ? should not be wrapped in LOWER() in the SQL string. Instead, the parameter value should be lowercased in Java before being set. Change filterString to " LIKE ? AND " and lowercase the value parameter in setFilterAttributeValue() calls using .toLowerCase().

Copilot uses AI. Check for mistakes.
Comment on lines 212 to 214
String filterString = " LIKE LOWER(?) AND ";
String attributeNameWithLowerCaseFunction = "LOWER(" + attributeName + ")";
filter.append(attributeNameWithLowerCaseFunction).append(filterString);
Copy link

Copilot AI Oct 28, 2025

Choose a reason for hiding this comment

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

The LOWER() function is incorrectly applied. The parameter placeholder ? should not be wrapped in LOWER() in the SQL string. Instead, the parameter value should be lowercased in Java before being set. Change filterString to " LIKE ? AND " and lowercase the value parameter in setFilterAttributeValue() calls using .toLowerCase().

Copilot uses AI. Check for mistakes.
Comment on lines 243 to 244
filterParts = trimmedFilter.split("(?i) pr$");
if (filterParts.length >= 1) {
Copy link

Copilot AI Oct 28, 2025

Choose a reason for hiding this comment

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

The split operation with pattern "(?i) pr$" will always produce at least one element even when " pr" is not present in the string. The condition filterParts.length >= 1 is always true and doesn't validate that the "pr" operator was actually found. This could lead to incorrect filter processing. Consider checking if the pattern actually matches before splitting, or verify that the split produced meaningful parts.

Copilot uses AI. Check for mistakes.
@Malith-19
Copy link
Contributor

Malith-19 commented Oct 31, 2025

@Jalina2007 Can you check the copilot suggestions and this filtering issue is only exists for the particular databases. In that case, normally we prepare the queries separately for those to avoid these kind of issues. Can we also look in to that possibility too?

@codecov
Copy link

codecov bot commented Oct 31, 2025

Codecov Report

❌ Patch coverage is 57.14286% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 50.62%. Comparing base (1c09879) to head (9857889).
⚠️ Report is 42 commits behind head on master.

Files with missing lines Patch % Lines
...ntity/api/resource/mgt/util/FilterQueriesUtil.java 66.66% 3 Missing ⚠️
.../carbon/identity/core/model/FilterTreeBuilder.java 0.00% 3 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master    #7578      +/-   ##
============================================
- Coverage     50.65%   50.62%   -0.03%     
- Complexity    19196    19201       +5     
============================================
  Files          2093     2093              
  Lines        123006   124169    +1163     
  Branches      25594    25839     +245     
============================================
+ Hits          62306    62860     +554     
- Misses        52716    53312     +596     
- Partials       7984     7997      +13     
Flag Coverage Δ
unit 35.29% <57.14%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Jalina2007
Copy link
Author

Jalina2007 commented Oct 31, 2025

Hi @Malith-19, I assume by the "filtering issue", you meant the main issue that we're addressing (case insensitive filtering). The problem is that some databases (MySQL, SQLite) are case-insensitive for the LIKE operator, but databases like PostgreSQL, Oracle, and H2 (which is the one used for testing) are case-sensitive for the same operator. The filter for the filtering is prepared for all platforms, and I found no reasonable way to "know" which database system is currently being used within the FilterQueriesUtil class (please correct me if I'm wrong). So the best way I found to fix this is to use explicit lowercasing of the values without depending on database-specific features.
I've also reviewed the Copilot suggestions and updated the code with the suggested improvements.
Please let me know if anything needs to be corrected

@shashimalcse
Copy link
Contributor

Hi @Jalina2007 did you test you solution on all the DB types?

@Jalina2007
Copy link
Author

Jalina2007 commented Nov 6, 2025

Hi @shashimalcse , I ran the server on H2, MySQL, PostgreSQL, and OracleDB XE - everything worked as expected. However, when testing with Microsoft SQL Server XE, the server appeared to hang during startup. This might be a local environment issue on my machine. I’ll test it on another system and let you know.

@Jalina2007
Copy link
Author

Hi again, @shashimalcse , I managed to run the server with Microsoft SQL server and it worked as expected. The issue happened to be a configuration issue of the database side. Please let me know if I missed anything.

@shashimalcse
Copy link
Contributor

We need to find another way to handle ordering because your approach might cause pagination issues, and we need to think it through for other resources that use cursor-based pagination. Can we scope this PR to only address the search?

@pavinduLakshan
Copy link
Member

We need to find another way to handle ordering because your approach might cause pagination issues, and we need to think it through for other resources that use cursor-based pagination. Can we scope this PR to only address the search?

@shashimalcse how about conditionally applying the resource name for the cursor when the configured DB is case-sensitive?

@coderabbitai
Copy link

coderabbitai bot commented Nov 8, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Three private filter builder methods in FilterQueriesUtil were modified to apply LOWER() SQL functions to attribute names and convert filter values to lowercase, enabling case-insensitive LIKE pattern matching in database queries.

Changes

Cohort / File(s) Summary
Case-insensitive filter matching updates
components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/util/FilterQueriesUtil.java
Updated three private filter builder methods (startWithFilterBuilder, endWithFilterBuilder, containsFilterBuilder) to wrap attribute names with LOWER() SQL function and convert filter values to lowercase before constructing LIKE patterns for case-insensitive matching.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Verify LOWER() function compatibility with the target database systems
  • Confirm lowercase value conversion doesn't introduce unintended behavior with special characters or locale-specific data
  • Check if any existing tests cover these filter methods and whether they still pass

Poem

🐰 A lowercase leap through SQL's domain,
Where LOWER() functions gently reign,
No case shall hide, no match shall fail,
Filters now whisper, silent and pale.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title mentions 'case insensitive searching and sorting' but the raw summary shows only case-insensitive searching changes in FilterQueriesUtil.java; sorting mentions in title may overstate scope per reviewer concerns. Clarify whether sorting changes are included or if the title should focus only on 'case insensitive searching' to match the actual code changes being reviewed.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The description provides related issue link, implementation details with before/after screenshots, and includes developer/review checklists, but is missing several template sections like Approach clarity, User stories, Release note, and complete Security checks.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Jalina2007 Jalina2007 force-pushed the fix/product-is-24875-api-resource-search-fix branch 2 times, most recently from dceed48 to 237f450 Compare November 10, 2025 06:32
@Jalina2007
Copy link
Author

Hi @shashimalcse , I have removed the commits that tries to fix the ordering and narrowed the PRs scope to only fix the searching. Please let me know if anything needs to be changed.

@shashimalcse
Copy link
Contributor

Hi @Jalina2007 i still see the changes related to ordering in components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/constant/SQLConstants.java please check

@Jalina2007 Jalina2007 force-pushed the fix/product-is-24875-api-resource-search-fix branch 3 times, most recently from 30affd7 to 683b422 Compare November 10, 2025 08:17
@Jalina2007 Jalina2007 force-pushed the fix/product-is-24875-api-resource-search-fix branch from 683b422 to 1cdf659 Compare November 10, 2025 16:50
@sonarqubecloud
Copy link

Copy link

@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: 0

🧹 Nitpick comments (2)
components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/util/FilterQueriesUtil.java (2)

195-197: Consider using Locale.ROOT for consistent case conversion.

For database-agnostic behavior, consider using value.toLowerCase(Locale.ROOT) instead of value.toLowerCase(). This ensures consistent case conversion regardless of the JVM's default locale, though for typical ASCII API names this distinction is minor.

Example for line 197:

-        filterQueryBuilder.setFilterAttributeValue(count, value.toLowerCase() + "%");
+        filterQueryBuilder.setFilterAttributeValue(count, value.toLowerCase(Locale.ROOT) + "%");

Apply the same pattern to lines 206 and 215.

Also applies to: 204-206, 213-215


195-196: Be aware of potential index performance impact.

Wrapping column names in LOWER() prevents the database from using standard indexes on those columns. For efficient case-insensitive searches at scale, the database would need function-based or expression indexes on LOWER(column_name). Consider documenting this requirement for production deployments or providing database-specific migration scripts to add appropriate indexes.

Also applies to: 204-205, 213-214

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 683b422 and 1cdf659.

📒 Files selected for processing (1)
  • components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/util/FilterQueriesUtil.java (1 hunks)
🔇 Additional comments (2)
components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/util/FilterQueriesUtil.java (2)

191-198: Case-insensitive search implementation looks correct.

The approach of applying LOWER() to the column name in SQL while lowercasing the value in Java before parameter binding is correct and addresses the past Copilot concerns. The placeholder ? is not wrapped in LOWER(), which is the proper way to implement case-insensitive LIKE matching.


195-197: Case-insensitivity inconsistency appears intentional and consistent across codebase.

After verifying the FilterQueriesUtil.java implementation, I found that the distinction between case-sensitive equality filters (EQ, NE) and case-insensitive pattern filters (SW, EW, CO) is intentional and consistent across three independent components:

  • FilterQueriesUtil.java: EQ/NE case-sensitive; SW/EW/CO case-insensitive
  • RoleDAOImpl.java: Same pattern
  • FilterQueryBuilderUtil.java: Same pattern

Each component implements equality operators without the LOWER() function, while pattern-matching operators use LOWER() on both attribute and value. This suggests a deliberate architectural decision to treat exact equality differently from pattern matching.

However, no code comments or documentation explain the rationale for this distinction. Verify with the team whether this design aligns with the API resource filtering requirements—specifically whether equality comparisons should be case-sensitive (e.g., "Admin" ≠ "admin") while pattern matches are case-insensitive.

@Jalina2007
Copy link
Author

Hi @shashimalcse , I'm sorry about the earlier confusion. I have updated it to only include the necessary commits for sorting.

@Jalina2007
Copy link
Author

Jalina2007 commented Nov 17, 2025

Hi @shashimalcse , Just checking in to see whether you need anything else from my side for the PR. Please let me know if I need to change anything. Thank you.

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.

4 participants