Skip to content

Conversation

@h3n4l
Copy link
Member

@h3n4l h3n4l commented Jan 22, 2026

Summary

  • Add WithMaxRows(n) execute option to limit maximum rows returned
  • Uses functional options pattern for extensibility
  • Applies min(queryLimit, maxRows) at driver level for find() and countDocuments()
  • Aggregate operations intentionally unaffected (use $limit stage instead)

Usage

// Cap results at 1000 rows
result, err := gc.Execute(ctx, "mydb", `db.users.find()`, gomongo.WithMaxRows(1000))

Test plan

  • Test MaxRows caps results when no query limit
  • Test query limit takes precedence when smaller than MaxRows
  • Test MaxRows takes precedence when smaller than query limit
  • Test backward compatibility (Execute without options)
  • Test countDocuments respects MaxRows

🤖 Generated with Claude Code

Add functional options pattern to Execute() with WithMaxRows(n) that
caps find() and countDocuments() results at the driver level.

- Add ExecuteOption type and WithMaxRows() function
- Apply min(queryLimit, maxRows) in executeFind and executeCountDocuments
- Aggregate operations intentionally not affected
- Add comprehensive tests for all limit scenarios

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings January 22, 2026 10:24
@d-bytebase d-bytebase merged commit d4856f4 into main Jan 22, 2026
6 checks passed
@d-bytebase d-bytebase deleted the vk/92d3-we-had-implement branch January 22, 2026 10:26
Copy link

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 pull request adds a WithMaxRows execute option to limit the maximum number of rows returned by find() and countDocuments() operations. The feature uses the functional options pattern for extensibility and applies min(queryLimit, maxRows) at the driver level.

Changes:

  • Adds WithMaxRows(n) functional option to cap results for find() and countDocuments()
  • Implements computeEffectiveLimit helper to calculate min(queryLimit, maxRows)
  • Threads maxRows parameter through executor to affected operations (aggregate intentionally excluded)

Reviewed changes

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

Show a summary per file
File Description
client.go Adds ExecuteOption pattern with WithMaxRows function and executeConfig
executor.go Updates execute function to accept and pass maxRows parameter
internal/executor/executor.go Threads maxRows parameter to executeFind and executeCountDocuments
internal/executor/collection.go Implements computeEffectiveLimit helper and applies maxRows in find/count operations
collection_test.go Adds comprehensive tests for maxRows behavior and backward compatibility
README.md Documents WithMaxRows option with usage examples and behavior details

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +36 to +38
// limit is min(N, maxRows). Aggregate operations are not affected.
func WithMaxRows(n int64) ExecuteOption {
return func(c *executeConfig) {
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

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

The WithMaxRows function should validate that the input is positive. Negative or zero values don't make semantic sense for limiting maximum rows and could lead to unexpected behavior. Consider adding validation to reject n <= 0 or documenting that negative/zero values are allowed and their semantics.

Suggested change
// limit is min(N, maxRows). Aggregate operations are not affected.
func WithMaxRows(n int64) ExecuteOption {
return func(c *executeConfig) {
// limit is min(N, maxRows). Aggregate operations are not affected. If n <= 0,
// this option is ignored.
func WithMaxRows(n int64) ExecuteOption {
return func(c *executeConfig) {
if n <= 0 {
// Ignore non-positive values to avoid nonsensical limits.
return
}

Copilot uses AI. Check for mistakes.
Comment on lines +2157 to +2284
func TestWithMaxRowsCapsResults(t *testing.T) {
client := testutil.GetClient(t)
dbName := "testdb_maxrows_cap"
defer testutil.CleanupDatabase(t, client, dbName)

ctx := context.Background()

// Insert 20 documents
collection := client.Database(dbName).Collection("items")
docs := make([]any, 20)
for i := 0; i < 20; i++ {
docs[i] = bson.M{"index": i}
}
_, err := collection.InsertMany(ctx, docs)
require.NoError(t, err)

gc := gomongo.NewClient(client)

// Without MaxRows - returns all 20
result, err := gc.Execute(ctx, dbName, "db.items.find()")
require.NoError(t, err)
require.Equal(t, 20, result.RowCount)

// With MaxRows(10) - caps at 10
result, err = gc.Execute(ctx, dbName, "db.items.find()", gomongo.WithMaxRows(10))
require.NoError(t, err)
require.Equal(t, 10, result.RowCount)
}

func TestWithMaxRowsQueryLimitTakesPrecedence(t *testing.T) {
client := testutil.GetClient(t)
dbName := "testdb_maxrows_query_limit"
defer testutil.CleanupDatabase(t, client, dbName)

ctx := context.Background()

// Insert 20 documents
collection := client.Database(dbName).Collection("items")
docs := make([]any, 20)
for i := 0; i < 20; i++ {
docs[i] = bson.M{"index": i}
}
_, err := collection.InsertMany(ctx, docs)
require.NoError(t, err)

gc := gomongo.NewClient(client)

// Query limit(5) is smaller than MaxRows(100) - should return 5
result, err := gc.Execute(ctx, dbName, "db.items.find().limit(5)", gomongo.WithMaxRows(100))
require.NoError(t, err)
require.Equal(t, 5, result.RowCount)
}

func TestWithMaxRowsTakesPrecedenceOverLargerLimit(t *testing.T) {
client := testutil.GetClient(t)
dbName := "testdb_maxrows_precedence"
defer testutil.CleanupDatabase(t, client, dbName)

ctx := context.Background()

// Insert 20 documents
collection := client.Database(dbName).Collection("items")
docs := make([]any, 20)
for i := 0; i < 20; i++ {
docs[i] = bson.M{"index": i}
}
_, err := collection.InsertMany(ctx, docs)
require.NoError(t, err)

gc := gomongo.NewClient(client)

// Query limit(100) is larger than MaxRows(5) - should return 5
result, err := gc.Execute(ctx, dbName, "db.items.find().limit(100)", gomongo.WithMaxRows(5))
require.NoError(t, err)
require.Equal(t, 5, result.RowCount)
}

func TestExecuteBackwardCompatibility(t *testing.T) {
client := testutil.GetClient(t)
dbName := "testdb_backward_compat"
defer testutil.CleanupDatabase(t, client, dbName)

ctx := context.Background()

collection := client.Database(dbName).Collection("items")
_, err := collection.InsertMany(ctx, []any{
bson.M{"name": "a"},
bson.M{"name": "b"},
bson.M{"name": "c"},
})
require.NoError(t, err)

gc := gomongo.NewClient(client)

// Execute without options should work (backward compatible)
result, err := gc.Execute(ctx, dbName, "db.items.find()")
require.NoError(t, err)
require.Equal(t, 3, result.RowCount)
}

func TestCountDocumentsWithMaxRows(t *testing.T) {
client := testutil.GetClient(t)
dbName := "testdb_count_maxrows"
defer testutil.CleanupDatabase(t, client, dbName)

ctx := context.Background()

// Insert 100 documents
collection := client.Database(dbName).Collection("items")
docs := make([]any, 100)
for i := 0; i < 100; i++ {
docs[i] = bson.M{"index": i}
}
_, err := collection.InsertMany(ctx, docs)
require.NoError(t, err)

gc := gomongo.NewClient(client)

// Without MaxRows - counts all 100
result, err := gc.Execute(ctx, dbName, "db.items.countDocuments()")
require.NoError(t, err)
require.Equal(t, "100", result.Rows[0])

// With MaxRows(50) - counts up to 50
result, err = gc.Execute(ctx, dbName, "db.items.countDocuments()", gomongo.WithMaxRows(50))
require.NoError(t, err)
require.Equal(t, "50", result.Rows[0])
}
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

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

Consider adding test coverage for edge cases such as WithMaxRows(0), WithMaxRows with negative values, and combining maxRows with skip operations. These edge cases could expose unexpected behavior and help validate the API's robustness.

Copilot uses AI. Check for mistakes.
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.

3 participants