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

BE-636 | Add pipeline package #570

Merged
merged 12 commits into from
Nov 29, 2024
Merged

BE-636 | Add pipeline package #570

merged 12 commits into from
Nov 29, 2024

Conversation

deividaspetraitis
Copy link
Collaborator

@deividaspetraitis deividaspetraitis commented Nov 28, 2024

This PR represents a smaller, more focused part of bigger PR #553 implementing sorting, filtering, pagination and search functionality for /pools endpoint. For bigger implementation picture refer to mentioned PR and for more context please refer to BE-636.

PR introduces pipeline package allowing to manipulate data in various ways including filtering, sorting, paginating and iterating. Such functionality originally is utilized in /pools endpoint used here.

Additionally this PR as dependency introduces some proto files, specifically for generating PaginationRequest used by pipeline.Paginator.

Summary by CodeRabbit

  • New Features

    • Introduced an Iterator interface for structured data iteration.
    • Added a Paginator for flexible paginated data retrieval.
    • Launched a Transformer framework for data filtering, sorting, and key retrieval.
    • Implemented a pagination mechanism for API requests, supporting both page-based and cursor-based strategies.
    • Defined a protocol buffer for pagination in SQS queries, including pagination strategies and request/response structures.
    • Added configuration files for protocol buffer generation and project setup.
    • Introduced a Makefile for managing Protobuf-related tasks.
  • Improvements

    • Enhanced concurrent data handling with SyncMapIterator and SyncMapTransformer.
    • Improved formatting and organization of protocol buffer files.

Adds pipeline package allowing to manipulate data in various ways including
filtering, sorting, paginating and iterating.
Copy link
Contributor

coderabbitai bot commented Nov 28, 2024

Caution

Review failed

The pull request is closed.

Walkthrough

The changes introduce several new functionalities within the pipeline package, including an Iterator interface and a SyncMapIterator for iterating over sync.Map. A Paginator type is added to manage paginated data retrieval, utilizing the Iterator. The Transformer interface and SyncMapTransformer struct enable filtering, sorting, and managing keys in a concurrent-safe manner. Additionally, pagination logic is encapsulated in the PaginationRequest struct, which is enhanced for API requests. New configuration files for protocol buffer generation and project dependencies are also introduced.

Changes

File Path Change Summary
domain/pipeline/iterator.go Added Iterator interface and SyncMapIterator struct with methods: Next, SetOffset, HasNext, Reset.
domain/pipeline/paginator.go Introduced Paginator type and methods: NewPaginator, GetPage, FetchPageByPageNumber, FetchPageByCursor.
domain/pipeline/transformer.go Defined Transformer interface and SyncMapTransformer struct with methods: Count, Range, Filter, Sort, Keys, Data, Clone, load.
pkg/api/v1beta1/pagination.go Enhanced PaginationRequest struct with methods: IsPresent, UnmarshalHTTPRequest, Validate, CalculateNextCursor, and added constants and error variables for pagination.
proto/sqs/query/v1beta1/pagination.proto Added PaginationStrategy enum and PaginationRequest and PaginationResponse message structures for handling pagination in API requests.
proto/buf.yaml New configuration file for buf build system, specifying project details and dependencies.
proto/buf.gen.gogo.yaml New configuration file for protocol buffer generation, including plugins for gocosmos and grpc-gateway.
proto/buf.gen.swagger.yaml Added plugin configuration for openapiv2 to generate OpenAPI documentation.
proto/Dockerfile Dockerfile for generating protocol buffers, specifying base images and installation steps for necessary tools.

Possibly related PRs

Suggested reviewers

  • PaddyMc
  • cryptomatictrader

Poem

In the pipeline where data flows,
Iterators dance, and pagination grows.
Transformers twist, with keys in their grip,
Concurrency sings on this wondrous trip!
A rabbit's cheer for the code so bright,
Hopping along in the soft moonlight! 🐇✨

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 buf (1.47.2)
sqsdomain/proto/ingest.proto

An unexpected error occurred while running buf.

🔧 golangci-lint (1.62.2)

level=warning msg="The linter 'exportloopref' is deprecated (since v1.60.2) due to: Since Go1.22 (loopvar) this linter is no longer relevant. Replaced by copyloopvar."


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.

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

🧹 Outside diff range and nitpick comments (4)
domain/pipeline/iterator.go (1)

22-27: Consider thread safety for index field

The index field could be accessed concurrently through Next(), SetOffset(), and Reset() methods. Consider using atomic operations or mutex protection.

 type SyncMapIterator[K, V any] struct {
 	data  *sync.Map
 	keys  []K
-	index int
+	mu    sync.RWMutex
+	index atomic.Int64
 }
domain/pipeline/paginator.go (1)

19-20: Update function names in the comment to match the actual methods

The comment mentions GetPageBasedPage and GetCursorBasedPage, but the actual method names are FetchPageByPageNumber and FetchPageByCursor. Please update the comment for consistency.

Apply this diff to correct the comment:

-// Under the hood it calls either GetPageBasedPage or GetCursorBasedPage.
+// Under the hood it calls either FetchPageByPageNumber or FetchPageByCursor.
domain/pipeline/transformer.go (2)

74-96: Refine sorting logic to properly handle multiple criteria

In the Sort method, when multiple comparison functions are provided, the current implementation returns based on the first criterion only. This may not correctly handle secondary sorting conditions.

Modify the sorting logic to consider all provided criteria:

 sort.Slice(dt.keys, func(i, j int) bool {
 	vi, _ := dt.load(dt.keys[i])
 	vj, _ := dt.load(dt.keys[j])

 	for _, lessFn := range less {
-		return lessFn(vi, vj)
+		if lessFn(vi, vj) {
+			return true
+		}
+		if lessFn(vj, vi) {
+			return false
+		}
 	}
 	return false
 })

This approach checks each sorting criterion in order and only moves to the next criterion if the current one deems the elements equal.


125-137: Simplify the load method using inline type assertions

The load method can be simplified for clarity and conciseness.

Simplify the method as follows:

 func (dt *SyncMapTransformer[K, V]) load(key K) (V, bool) {
-	mv, ok := dt.data.Load(key)
-	if !ok {
-		return *new(V), false
-	}
-	v, ok := mv.(V)
-	if !ok {
-		return *new(V), false
-	}
-	return v, true
+	if mv, ok := dt.data.Load(key); ok {
+		if v, ok := mv.(V); ok {
+			return v, true
+		}
+	}
+	var zeroValue V
+	return zeroValue, false
 }

This makes the method more readable by reducing nesting and using inline type assertions.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between abb1e56 and a4395a9.

⛔ Files ignored due to path filters (3)
  • domain/pipeline/iterator_test.go is excluded by !**/*_test.go
  • domain/pipeline/paginator_test.go is excluded by !**/*_test.go
  • domain/pipeline/transformer_test.go is excluded by !**/*_test.go
📒 Files selected for processing (3)
  • domain/pipeline/iterator.go (1 hunks)
  • domain/pipeline/paginator.go (1 hunks)
  • domain/pipeline/transformer.go (1 hunks)
🧰 Additional context used
🪛 GitHub Check: build
domain/pipeline/paginator.go

[failure] 3-3:
no required module provides package github.com/osmosis-labs/sqs/pkg/api/v1beta1; to add it:

🔇 Additional comments (2)
domain/pipeline/iterator.go (2)

1-3: LGTM!

Package name and import are appropriate for the functionality.


1-65: Verify integration with pagination package

Since this iterator is part of a larger pagination system, we should verify its integration with the paginator package.

✅ Verification successful

Let me search for more context about the pagination integration.


Let me check the paginator implementation to verify the integration.


Integration with pagination package is properly implemented

The Iterator interface is correctly integrated with the pagination system:

  • The Paginator struct properly composes the Iterator interface
  • Both page-based and cursor-based pagination strategies utilize all required Iterator methods (Next, HasNext, SetOffset, Reset)
  • Comprehensive test coverage demonstrates the integration works as expected with different pagination scenarios
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for usage of Iterator interface in paginator package
ast-grep --pattern 'type $_ struct {
  $$$
  iterator Iterator[$_, $_]
  $$$
}'

# Search for SyncMapIterator instantiation
rg -A 5 'NewSyncMapIterator'

Length of output: 1117


Script:

#!/bin/bash
# Search for files containing "paginator" or "pagination"
fd -t f -e go . | xargs rg -l "pagin"

# Search for any struct implementing the Iterator interface
ast-grep --pattern 'type $name struct {
  $$$
}

func ($recv *$name) Next() ($_, bool) { $$$ }
func ($recv *$name) HasNext() bool { $$$ }
func ($recv *$name) SetOffset(offset int) { $$$ }
func ($recv *$name) Reset() { $$$ }'

# Search for any usage of Iterator interface
rg "Iterator\[.*\]"

Length of output: 1534


Script:

#!/bin/bash
# Check paginator implementation
cat domain/pipeline/paginator.go

# Check paginator tests
cat domain/pipeline/paginator_test.go

Length of output: 6206

domain/pipeline/iterator.go Outdated Show resolved Hide resolved
domain/pipeline/iterator.go Outdated Show resolved Hide resolved
domain/pipeline/iterator.go Outdated Show resolved Hide resolved
domain/pipeline/iterator.go Show resolved Hide resolved
domain/pipeline/paginator.go Show resolved Hide resolved
domain/pipeline/paginator.go Show resolved Hide resolved
domain/pipeline/paginator.go Outdated Show resolved Hide resolved
domain/pipeline/transformer.go Outdated Show resolved Hide resolved
domain/pipeline/transformer.go Outdated Show resolved Hide resolved
domain/pipeline/transformer.go Show resolved Hide resolved
@deividaspetraitis
Copy link
Collaborator Author

deividaspetraitis commented Nov 28, 2024

Note: Sonarcloud is complaining regarding coverage because of generated pkg/api/v1beta1/pagination.pb.go file. Security "issues" are related with protobuf gen Dockerfile, nothing serious IMHO.

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

🧹 Outside diff range and nitpick comments (6)
proto/buf.yaml (2)

4-8: Consider pinning specific versions for all dependencies

While cometbft is pinned to a specific commit, other dependencies like gogo-proto, cosmos-proto, and googleapis don't specify versions. This could lead to unexpected breaking changes if these dependencies are updated.

Consider pinning specific versions for all dependencies. For example:

   - buf.build/cometbft/cometbft:4a62c99d422068a5165429b62a7eb824df46cca9
-  - buf.build/cosmos/gogo-proto
+  - buf.build/cosmos/gogo-proto:v1.3.2
   - buf.build/cosmos/cosmos-sdk:v0.47.0
-  - buf.build/cosmos/cosmos-proto
-  - buf.build/googleapis/googleapis
+  - buf.build/cosmos/cosmos-proto:v1.0.0
+  - buf.build/googleapis/googleapis:v0.1.0
🧰 Tools
🪛 yamllint (1.35.1)

[error] 4-4: trailing spaces

(trailing-spaces)


17-34: Consider documenting the rationale for lint exceptions

The configuration disables numerous lint rules. While these exceptions might be necessary, it would be valuable to document why these specific rules are being disabled to help maintain the codebase's quality standards in the long term.

Consider either:

  1. Adding comments explaining the rationale for each exception group, or
  2. Creating a separate documentation file explaining the protobuf style guide and lint configuration decisions.

This will help future contributors understand the reasoning behind these exceptions and prevent unnecessary rule re-enabling.

proto/sqs/query/v1beta1/pagination.proto (1)

43-54: Review numeric type consistency

There's an inconsistency in numeric types:

  • next_cursor uses int64 (signed)
  • Other pagination fields use uint64 (unsigned)

While using -1 as a sentinel value for next_cursor is a valid pattern, consider:

  1. Using a separate boolean field has_more instead
  2. Using consistent unsigned types throughout
  3. Documenting this design decision
message PaginationResponse {
-  int64 next_cursor = 1;
+  uint64 next_cursor = 1;
+  bool has_more = 3;  // true if more results are available
   uint64 total_items = 2;
}
pkg/api/v1beta1/pagination.go (3)

49-49: Typo in method comment: 'imlpements' should be 'implements'

The comment for UnmarshalHTTPRequest contains a typographical error.

Apply this diff to correct the typo:

-// UnmarshalHTTPRequest imlpements RequestUnmarshaler interface.
+// UnmarshalHTTPRequest implements RequestUnmarshaler interface.

58-77: Refactor repetitive code when parsing query parameters

The code for parsing pageParam, limitParam, and cursorParam is repetitive. Refactoring it can reduce duplication and enhance maintainability.

You can create a helper function:

func parseUintQueryParam(c echo.Context, paramName string) (uint64, error) {
    param := c.QueryParam(paramName)
    if param != "" {
        return strconv.ParseUint(param, 10, 64)
    }
    return 0, nil
}

Modify UnmarshalHTTPRequest accordingly:

 func (r *PaginationRequest) UnmarshalHTTPRequest(c echo.Context) error {
     var err error

-    // Fetch query parameters
-    pageParam := c.QueryParam(queryPageNumber)
-    limitParam := c.QueryParam(queryPageSize)
-    cursorParam := c.QueryParam(queryPageCursor)
-
-    if pageParam != "" {
-        r.Page, err = strconv.ParseUint(pageParam, 10, 64)
-        if err != nil {
-            return err
-        }
-    }
-
-    if limitParam != "" {
-        r.Limit, err = strconv.ParseUint(limitParam, 10, 64)
-        if err != nil {
-            return err
-        }
-    }
-
-    if cursorParam != "" {
-        r.Cursor, err = strconv.ParseUint(cursorParam, 10, 64)
-        if err != nil {
-            return err
-        }
-    }
+    if r.Page, err = parseUintQueryParam(c, queryPageNumber); err != nil {
+        return fmt.Errorf("invalid value for parameter %s: %w", queryPageNumber, err)
+    }
+    if r.Limit, err = parseUintQueryParam(c, queryPageSize); err != nil {
+        return fmt.Errorf("invalid value for parameter %s: %w", queryPageSize, err)
+    }
+    if r.Cursor, err = parseUintQueryParam(c, queryPageCursor); err != nil {
+        return fmt.Errorf("invalid value for parameter %s: %w", queryPageCursor, err)
+    }

This refactoring reduces duplication and enhances error messages.


60-61: Include parameter names in parsing error messages

When parsing query parameters, wrapping errors with parameter names provides better context for debugging.

Apply this diff to improve error messages:

 if pageParam != "" {
     r.Page, err = strconv.ParseUint(pageParam, 10, 64)
     if err != nil {
-        return err
+        return fmt.Errorf("invalid value for parameter %s: %w", queryPageNumber, err)
     }
 }

 if limitParam != "" {
     r.Limit, err = strconv.ParseUint(limitParam, 10, 64)
     if err != nil {
-        return err
+        return fmt.Errorf("invalid value for parameter %s: %w", queryPageSize, err)
     }
 }

 if cursorParam != "" {
     r.Cursor, err = strconv.ParseUint(cursorParam, 10, 64)
     if err != nil {
-        return err
+        return fmt.Errorf("invalid value for parameter %s: %w", queryPageCursor, err)
     }
 }

This enhancement provides clearer error information to the caller.

Also applies to: 67-68, 74-75

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between a4395a9 and f0c4fa0.

⛔ Files ignored due to path filters (3)
  • pkg/api/v1beta1/pagination.pb.go is excluded by !**/*.pb.go
  • pkg/api/v1beta1/pagination_test.go is excluded by !**/*_test.go
  • proto/buf.lock is excluded by !**/*.lock
📒 Files selected for processing (6)
  • pkg/api/v1beta1/pagination.go (1 hunks)
  • proto/Dockerfile (1 hunks)
  • proto/buf.gen.gogo.yaml (1 hunks)
  • proto/buf.gen.swagger.yaml (1 hunks)
  • proto/buf.yaml (1 hunks)
  • proto/sqs/query/v1beta1/pagination.proto (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • proto/Dockerfile
  • proto/buf.gen.gogo.yaml
  • proto/buf.gen.swagger.yaml
🧰 Additional context used
🪛 yamllint (1.35.1)
proto/buf.yaml

[error] 4-4: trailing spaces

(trailing-spaces)

🔇 Additional comments (3)
proto/sqs/query/v1beta1/pagination.proto (3)

1-4: LGTM! Package declaration follows best practices.

The package declaration and versioning strategy (v1beta1) align well with protocol buffer best practices.


18-22: Clarify cursor invalidation strategy

The comment mentions that clients should re-request all data if it changes, but doesn't specify:

  1. How clients detect that data has changed
  2. How cursor invalidation is communicated to clients
  3. Whether there's a mechanism to prevent stale cursors from being used

Consider adding these details to the documentation or implementing a cursor validation mechanism.


1-54: Verify consistent pagination implementation

Let's verify that:

  1. All endpoints using pagination implement both strategies consistently
  2. Error handling for invalid pagination parameters is implemented
  3. Documentation exists for pagination usage
✅ Verification successful

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

Pagination implementation is well-structured and consistent

The codebase shows a robust pagination implementation with:

  • Comprehensive validation in PaginationRequest.Validate() that checks for invalid page numbers, limits, and strategies
  • Consistent handling of both PAGE and CURSOR strategies in the Paginator implementation
  • Thorough test coverage demonstrating proper handling of edge cases
  • Clean integration with the Echo web framework for HTTP request parsing

The implementation includes proper error handling for:

  • Invalid page numbers
  • Exceeding maximum page/limit values
  • Unsupported pagination strategies
  • Out-of-range cursor values
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for consistent pagination usage
echo "Checking endpoint implementations..."
rg -A 10 "PaginationRequest|PaginationStrategy" --type go

echo "Checking error handling..."
rg -A 5 "invalid.*pagination|pagination.*invalid" --type go

echo "Checking documentation..."
fd -e md -x grep -l "pagination" {}

Length of output: 40338


Script:

#!/bin/bash
# Let's check for actual usage of pagination in API endpoints
echo "Checking API endpoints using pagination..."
rg -A 5 "func.*\(.*PaginationRequest" --type go

echo "Checking for pagination validation..."
ast-grep --pattern 'func $_(p *PaginationRequest) Validate() error {
  $$$
}'

echo "Checking for pagination documentation in API docs..."
fd -g "*.md" -x cat {} | grep -A 5 -B 5 "pagination"

Length of output: 7446

proto/buf.yaml Show resolved Hide resolved
proto/sqs/query/v1beta1/pagination.proto Show resolved Hide resolved
pkg/api/v1beta1/pagination.go Show resolved Hide resolved
pkg/api/v1beta1/pagination.go Outdated Show resolved Hide resolved
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: 4

🧹 Outside diff range and nitpick comments (5)
domain/pipeline/paginator.go (2)

1-68: Improve error handling throughout the package

Consider returning errors instead of using panic for validation failures. This would allow better error handling by the caller.

Would you like me to provide an example of how to implement proper error handling throughout the package?


1-68: Add comprehensive test coverage

As this is a critical pagination component, please ensure comprehensive test coverage including:

  • Edge cases for both pagination strategies
  • Validation error scenarios
  • Iterator error handling
  • Boundary conditions for page/cursor/limit values

Would you like me to help generate a test suite for this package?

pkg/api/v1beta1/pagination.go (2)

5-5: Remove unnecessary alias for the math package

The alias math "math" is unnecessary since it doesn't change the package name. You can import the package directly without an alias.

Apply this diff to remove the alias:

-import (
-	"fmt"
-	math "math"
-	"strconv"
-
-	"github.com/labstack/echo/v4"
-)
+import (
+	"fmt"
+	"math"
+	"strconv"
+
+	"github.com/labstack/echo/v4"
+)

50-50: Fix typo in comment: 'imlpements' should be 'implements'

There is a typographical error in the comment.

Apply this diff to correct the typo:

-// UnmarshalHTTPRequest imlpements RequestUnmarshaler interface.
+// UnmarshalHTTPRequest implements RequestUnmarshaler interface.
domain/pipeline/iterator.go (1)

10-10: Update the comment for Next() to reflect return values

The comment for the Next() method states that it returns "a value and a bool indicating if it's valid," but the method signature returns (V, error). Please update the comment to accurately describe the return types.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between f0c4fa0 and c68f2d2.

⛔ Files ignored due to path filters (2)
  • domain/pipeline/iterator_test.go is excluded by !**/*_test.go
  • ingest/usecase/plugins/orderbook/claimbot/export_test.go is excluded by !**/*_test.go
📒 Files selected for processing (4)
  • domain/pipeline/iterator.go (1 hunks)
  • domain/pipeline/paginator.go (1 hunks)
  • domain/pipeline/transformer.go (1 hunks)
  • pkg/api/v1beta1/pagination.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • domain/pipeline/transformer.go
🔇 Additional comments (8)
domain/pipeline/paginator.go (3)

3-3: Fix the import path or add the missing module dependency

The package github.com/osmosis-labs/sqs/pkg/api/v1beta1 appears to be missing from the module dependencies.


6-15: LGTM! Well-structured initialization with proper nil handling

The function is well-implemented with:

  • Proper nil check for pagination request
  • Clean use of generics
  • Clear initialization pattern

17-21: LGTM! Clean struct definition with good documentation

The struct is well-designed with appropriate use of generics and clear field definitions.

pkg/api/v1beta1/pagination.go (3)

66-71: Set a default limit when none is provided

If the limit parameter is not specified, r.Limit remains zero, causing Validate to return ErrLimitNotValid. Consider setting a default limit to improve user experience.

The previous review comment regarding setting a default limit when none is provided is still applicable.


81-87: Handle conflicting pagination parameters

Currently, if both cursorParam and pageParam are provided, the PaginationStrategy defaults to CURSOR. This may lead to unexpected behavior if the client unintentionally provides both.

Consider adding validation to ensure only one pagination strategy is used at a time.

	if cursorParam != "" && pageParam != "" {
		return fmt.Errorf("cannot use both cursor and page pagination simultaneously")
	}

Alternatively, prioritize one strategy over the other but document this behavior clearly.


132-134: ⚠️ Potential issue

Avoid potential overflow when converting uint64 to int64

Converting uint64 to int64 may result in negative values if the value exceeds math.MaxInt64. This could cause unexpected behavior when nextCursor becomes negative unintentionally.

Consider changing the return type of CalculateNextCursor to uint64 and using a pointer or an additional boolean to indicate the absence of the next cursor:

-func (r *PaginationRequest) CalculateNextCursor(totalItems uint64) (nextCursor int64) {
+func (r *PaginationRequest) CalculateNextCursor(totalItems uint64) (nextCursor uint64, hasNext bool) {
     // Existing checks...
-	nextCursor = int64(r.Cursor + r.Limit)
+	nextCursor = r.Cursor + r.Limit
+	hasNext = true
 	return nextCursor
 }

Update the calling code to handle the new return values accordingly.

Alternatively, ensure that r.Cursor + r.Limit does not exceed math.MaxInt64 before conversion:

	if r.Cursor + r.Limit > math.MaxInt64 {
		return -1 // value too large for int64
	}
	nextCursor = int64(r.Cursor + r.Limit)

Likely invalid or redundant comment.

domain/pipeline/iterator.go (2)

9-14: Consider adding Length() method to support pagination

To facilitate effective pagination, clients might need to know the total number of items. Consider adding a Length() int method to the Iterator interface.

Here's how you might modify the interface:

 type Iterator[K, V any] interface {
 	Next() (V, error)     // Retrieves the next element and an error if any
 	HasNext() bool        // Checks if there are more elements
 	SetOffset(offset int) // Sets the offset for starting point of iteration
 	Reset()               // Resets the iterator to the start
+	Length() int          // Returns total number of items
 }

And implement it in SyncMapIterator:

 type SyncMapIterator[K, V any] struct {
 	data  *sync.Map
 	keys  []K
 	index int
 }

+// Length returns the total number of items in the iterator
+func (it *SyncMapIterator[K, V]) Length() int {
+	return len(it.keys)
+}

17-23: 🛠️ Refactor suggestion

Add input validation in NewSyncMapIterator

The constructor should validate that neither the data map nor the keys slice is nil to prevent potential panics during iteration.

Here is how you might add the input validation:

 func NewSyncMapIterator[K, V any](data *sync.Map, keys []K) *SyncMapIterator[K, V] {
+	if data == nil {
+		panic("data map cannot be nil")
+	}
+	if keys == nil {
+		panic("keys slice cannot be nil")
+	}
 	return &SyncMapIterator[K, V]{
 		data:  data,
 		keys:  keys,
 		index: 0,
 	}
 }

domain/pipeline/paginator.go Show resolved Hide resolved
domain/pipeline/paginator.go Show resolved Hide resolved
domain/pipeline/paginator.go Show resolved Hide resolved
pkg/api/v1beta1/pagination.go Show resolved Hide resolved
Copy link
Member

@p0mvn p0mvn left a comment

Choose a reason for hiding this comment

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

LGTM nice work!

domain/pipeline/iterator.go Show resolved Hide resolved
domain/pipeline/iterator_test.go Show resolved Hide resolved
domain/pipeline/transformer_test.go Outdated Show resolved Hide resolved
proto/Dockerfile Show resolved Hide resolved
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
2 Security Hotspots
28.4% Coverage on New Code (required ≥ 50%)

See analysis details on SonarQube Cloud

@deividaspetraitis deividaspetraitis merged commit 29d0280 into v27.x Nov 29, 2024
8 of 9 checks passed
@deividaspetraitis deividaspetraitis deleted the BE-636-pipeline branch November 29, 2024 09:22
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