Skip to content

[ATTRIBUTES][ENDPOINT] Row-Based filtering for attributes#464

Open
ChanukaUOJ wants to merge 7 commits intoLDFLK:mainfrom
ChanukaUOJ:feature-row-base-filtering-attributes
Open

[ATTRIBUTES][ENDPOINT] Row-Based filtering for attributes#464
ChanukaUOJ wants to merge 7 commits intoLDFLK:mainfrom
ChanukaUOJ:feature-row-base-filtering-attributes

Conversation

@ChanukaUOJ
Copy link
Member

Description

This PR introduces a new functionality that enables row-based filtering in the OpenGIN Read API service. The implementation allows clients to apply filtering conditions when retrieving attribute data.

The targeted API endpoint for this feature is:

/entities/{entityId}/attributes/{attributeName}

This endpoint has been updated according to the Read API contract to support the new filtering capability.

Changes

  • Updated the contract of the targeted API endpoint.
  • Changed the API method from GET to POST to support filter payloads.
  • Updated read_api_service.bal to implement the new endpoint behavior.
  • Updated types.bal with the required type definitions for filtering.
  • Added new tests in read_api_service_test.bal.
  • Updated the service and data_handler implementations in the core service.
  • Added new tests in data_handler_test.go.

Testing

  • The core service and read service were tested independently with their respective databases.
  • Existing end-to-end (e2e) tests were updated to reflect the API changes.
  • Additional tests were added to cover the new row-based filtering functionality.
  • All tests are passing.

Additional Information

This PR closes #461.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the OpenGIN Read API by introducing row-based filtering capabilities for attribute data. This allows clients to retrieve highly specific subsets of attribute information by applying detailed filter conditions directly to the data rows, improving data access precision and efficiency. The change involved updating the API contract, modifying the core service to handle and apply these filters, and expanding the test suite to ensure robustness.

Highlights

  • Row-Based Filtering: Introduced row-based filtering for attribute data in the OpenGIN Read API, allowing clients to apply detailed conditions when retrieving information.
  • API Endpoint Update: Converted the /entities/{entityId}/attributes/{attributeName} endpoint from a GET request to a POST request to support the new filter payloads.
  • Core Service Enhancements: Implemented server-side logic in the core service to process and apply diverse row-based filter conditions, including equality, inequality, range, and containment operators.
  • Expanded Test Coverage: Added new unit tests in the core service and new end-to-end tests to validate the functionality of the new row-based filtering feature.
Changelog
  • opengin/contracts/rest/read_api.yaml
    • Updated API contract to change the /entities/{entityId}/attributes/{attributeName} endpoint from GET to POST.
    • Added a requestBody schema to the /entities/{entityId}/attributes/{attributeName} endpoint for row-based filtering, defining field_name, operator (eq, neq, gt, lt, gte, lte, contains, notcontains), and value.
    • Removed a trailing newline character.
  • opengin/core-api/README.md
    • Updated the go test command to include -count=1 -p=1 and added a comment about cleaning databases.
  • opengin/core-api/cmd/server/service.go
    • Modified extractFieldsFromAttributes to return both fields and a slice of postgres.RecordFilter.
    • Updated ReadEntity to extract and pass record_filters to engine.NewReadOptions.
    • Added a new helper function extractRowsFromTabularAttributes to parse row filters from anypb.Any values.
  • opengin/core-api/db/repository/postgres/data_handler.go
    • Defined a new RecordFilter struct to represent row-level filter conditions.
    • Enhanced the GetData function to interpret and apply record_filters from the filters map, translating operators (eq, neq, gt, lt, gte, lte, contains, notcontains) into SQL WHERE clauses.
    • Added debug logging for the generated SQL query and arguments.
  • opengin/core-api/db/repository/postgres/data_handler_test.go
    • Introduced TestGetDataWithRowFiltering with nine sub-tests covering various single and multiple row-based filter scenarios (equality, inequality, range, contains, not contains).
  • opengin/read-api/read_api_service.bal
    • Reordered import statements.
    • Changed the resource function for /entities/{entityId}/attributes/{attributeName} from get to post.
    • Added @http:Payload attributes_attributeName_body payload to the post resource function parameters.
    • Extracted recordsToUse from the payload and passed it to the attributeValueFilter as rows.
    • Updated return types for attribute retrieval to RecordStringStartStringendStringvalueRecordStringStartStringendStringvalueArrayOk for consistency.
    • Adjusted comments and minor formatting.
  • opengin/read-api/tests/read_api_service_test.bal
    • Reordered import statements.
    • Modified testEntityAttributeRetrieval to use an empty rows array in attributeValueFilter.
    • Added two new test functions: testEntityAttributeRetrievalWithSingleColumnFilter and testEntityAttributeRetrievalWithMultipleColumnFilter to validate the new row-based filtering logic.
    • Updated comments and cleaned up trailing newlines.
  • opengin/read-api/types.bal
    • Removed copyright header.
    • Updated comments for id and kind fields in entities_search_body and entitiessearch_kind to clarify required conditions.
    • Removed the RecordStringrelatedEntityIdStringstartTimeStringendTimeStringidStringnameArrayOk type.
    • Added new types attributes_attributeName_body (defining the structure for record filters) and RecordStringStartStringendStringvalueRecordStringStartStringendStringvalueArrayOk.
  • opengin/tests/e2e/basic_read_tests.py
    • Modified test_api_endpoint_with_validation to accept a body parameter and use requests.post with json=body and Content-Type header.
    • Updated existing calls to test_api_endpoint_with_validation to pass an empty body dictionary.
    • Added two new examples (Example 4 and Example 5) in test_generic_validation_examples to test row-based filtering with contains and combined gt/gte operators.
    • Updated test_attribute_fields_combinations, test_update_entity_attribute, and test_attribute_lookup to use requests.post and pass an empty json={} for consistency with the API change.
Activity
  • ChanukaUOJ created the pull request to introduce row-based filtering for attributes.
  • The pull request addresses and closes issue [ATTRIBUTES][ENDPOINT] Row-Based filtering for attributes #461.
  • All existing and new tests are reported as passing, including independent core and read service tests, updated e2e tests, and additional tests for the new filtering functionality.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces row-level filtering for tabular attributes in the ReadEntity API. The /entities/{entityId}/attributes/{attributeName} endpoint in read_api.yaml was changed from GET to POST and now accepts a request body for records to specify row filters. The core-api was updated to extract these record filters from attributes and pass them to the GetData repository method, which now includes logic to construct SQL WHERE clauses based on these filters and their operators (e.g., eq, neq, gt, lt, gte, lte, contains, notcontains). Corresponding test cases were added in data_handler_test.go to validate the new row filtering functionality. The read-api service was updated to handle the new POST request and integrate the row filters into the ReadEntityRequest. Review comments highlight the need for input validation in extractRowsFromTabularAttributes to prevent invalid SQL queries, a bug in a test assertion in data_handler_test.go, and several instances of logging potentially sensitive user-supplied data (record filters, general filters, SQL arguments) which should be removed or masked. Additionally, there's a suggestion to refactor duplicated test setup code in read_api_service_test.bal for better maintainability and to reduce verbose debug logging in data_handler.go.

@ChanukaUOJ ChanukaUOJ requested review from vibhatha and zaeema-n March 10, 2026 07:56
@vibhatha
Copy link
Member

@ChanukaUOJ first comment is this change is too big to review. Is it possible to do the following.
Can we break it down into two. First PR changes the core API, a follow up PR changes the read API.

Is this possible? If possible, I would rather go with that approach.

@CLAassistant
Copy link

CLAassistant commented Mar 10, 2026

CLA assistant check
All committers have signed the CLA.

items:
type: string
default: ["*"]
requestBody:
Copy link
Member

Choose a reason for hiding this comment

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

Put a description for the request body. You can explain how to use it for filtering and what are the accepted filter operators. This will show in the swagger documentation

var filters []postgres.RecordFilter
for _, val := range listValue.Values {
datum := val.GetStructValue()
if datum == nil {
Copy link
Member

Choose a reason for hiding this comment

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

how would we get a nil datum here?

Copy link
Member Author

Choose a reason for hiding this comment

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

val.GetStructValue() return nil if the val is not an object. This is for nil safety

Comment on lines +643 to +645
FieldName string
Operator string
Value string
Copy link
Member

Choose a reason for hiding this comment

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

Maybe define the Operator specifically? (What can you pass here, etc?)

Copy link
Member

Choose a reason for hiding this comment

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

I mean add documentation.

}

// Default: simple equality filter
whereClauses = append(whereClauses, fmt.Sprintf("%s = $%d", commons.SanitizeIdentifier(key), argCount))
Copy link
Member

Choose a reason for hiding this comment

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

keeping this would be redundant?

Copy link
Member Author

Choose a reason for hiding this comment

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

If any case key != "record_filters", it perform this as a fallback.

Copy link
Member

@vibhatha vibhatha left a comment

Choose a reason for hiding this comment

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

@ChanukaUOJ I added some comments regarding the core API changes. Let's fix those and move forward to the other Read API.

assert.Len(t, filteredRows, 1)
assert.Equal(t, expectedRows[0], filteredRows[0].([]interface{}))
}

Copy link
Member

Choose a reason for hiding this comment

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

Test for trying to compare something that is not a string? What would happen?

Copy link
Member Author

@ChanukaUOJ ChanukaUOJ Mar 20, 2026

Choose a reason for hiding this comment

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

Since Value in recordFilter struct is defined as string. always it should be a string.

}

// extractRowsFromTabularAttributes extracts row filters from a tabular attribute value
func extractRowsFromTabularAttributes(anyValue *anypb.Any) ([]postgres.RecordFilter, error) {
Copy link
Member

Choose a reason for hiding this comment

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

I am not sure about this name. This function is extracting the filters passed by the user, it's not technically the "rows". Even though from the read api the param is named rows

Copy link
Member Author

Choose a reason for hiding this comment

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

changed into extractRecordFiltersFromTabularAttributes

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.

[ATTRIBUTES][ENDPOINT] Row-Based filtering for attributes

4 participants