Skip to content

Comments

feat: Unified Paginator[T] API with Fetcher pattern and functional options#16

Merged
josemarluedke merged 1 commit intomainfrom
feat/align-implementations
Dec 16, 2025
Merged

feat: Unified Paginator[T] API with Fetcher pattern and functional options#16
josemarluedke merged 1 commit intomainfrom
feat/align-implementations

Conversation

@josemarluedke
Copy link
Member

Overview

This PR unifies all three pagination strategies (offset, cursor, quotafill) around a common Paginator[T] interface with the Fetcher pattern and functional options. This is a major API improvement that makes the library more consistent, flexible, and easier to use.

Breaking Changes

1. Unified Paginator[T] Interface

All strategies now implement the same interface:

type Paginator[T any] interface {
    Paginate(ctx context.Context, args *PageArgs, opts ...PaginateOption) (*Page[T], error)
}

2. Fetcher Pattern

All constructors now take Fetcher[T] as the first parameter:

  • offset.New(fetcher)
  • cursor.New(fetcher, schema)
  • quotafill.New(fetcher, filter, schema, opts...)

3. Functional Options

Page size limits moved from constructors to Paginate() options:

  • paging.WithMaxSize(100) - cap maximum page size
  • paging.WithDefaultSize(25) - set default when First is nil

4. Page[T] Result Type

Paginate() returns *Page[T] with:

  • Nodes - the actual items
  • PageInfo - pagination metadata
  • Metadata - observability data (strategy, timing, offset, etc.)

5. Simplified BuildConnection

All BuildConnection functions now take the *Page[T] result:

  • offset.BuildConnection(page, transform)
  • cursor.BuildConnection(page, schema, args, transform)
  • quotafill.BuildConnection(page, schema, args, transform)

Removed/Deprecated

  • offset: QueryMods() method removed (use Paginate() instead)
  • cursor: BuildFetchParams() deprecated (use Paginate() instead)
  • quotafill: WithPageConfig() option removed (use Paginate() options)

Benefits

Consistent API - All three strategies work the same way
Reusable fetchers - Define once, use across multiple requests
Per-request configuration - Page size limits via functional options
Rich metadata - Observability data for monitoring and debugging
Easier testing - Mockable Fetcher[T] interface
Simpler strategy switching - Change 3 lines of code to switch strategies

Migration Example

Before (v0.3.0)

totalCount, _ := models.Users().Count(ctx, r.DB)
paginator := offset.New(page, totalCount)
dbUsers, _ := models.Users(paginator.QueryMods()...).All(ctx, r.DB)
conn, _ := offset.BuildConnection(paginator, dbUsers, toDomainUser)

After (v2.0)

fetcher := sqlboiler.NewFetcher(queryFunc, countFunc, sqlboiler.OffsetToQueryMods)
paginator := offset.New(fetcher)
result, _ := paginator.Paginate(ctx, page, paging.WithMaxSize(100))
conn, _ := offset.BuildConnection(result, toDomainUser)

Testing

204 tests passing across all packages:

  • Root package: 48 passed
  • Cursor: 41 passed
  • Offset: 10 passed
  • Quotafill: 23 passed
  • SQLBoiler: 32 passed
  • Integration tests: 50 passed

Documentation

  • ✅ README.md updated with new API examples
  • ✅ MIGRATION.md updated with comprehensive migration guide from v0.3.0 to v2.0
  • ✅ All code examples updated to show unified API pattern
  • ✅ Added "API Design Philosophy" section explaining the design decisions

Files Changed

Core API:

  • interfaces.go - Added Offset to Metadata, updated Paginator[T] interface
  • page_args.go - Added PaginateOption types and functional options

Offset Strategy:

  • offset/paginator.go - Implemented Paginator[T], added Fetcher pattern
  • offset/paginator_test.go - Updated tests for new API

Cursor Strategy:

  • cursor/paginator.go - Implemented Paginator[T], added Fetcher pattern
  • cursor/paginator_test.go - Updated tests for new API

Quotafill Strategy:

  • quotafill/quotafill.go - Updated to use PaginateOption

Tests:

  • connection_test.go - Updated BuildConnection tests
  • tests/offset_integration_test.go - Rewritten for new API
  • tests/cursor_integration_test.go - Updated for new API
  • tests/security_test.go - Updated for new API

Documentation:

  • README.md - Complete rewrite with unified API examples
  • MIGRATION.md - Detailed v0.3.0 → v2.0 migration guide

Reviewers

This is a major breaking change. Please review:

  1. API design consistency across all three strategies
  2. Migration guide completeness
  3. Test coverage for new API
  4. Documentation clarity

See MIGRATION.md for the complete migration guide.

…tions

BREAKING CHANGES:

This release unifies all three pagination strategies (offset, cursor, quotafill)
around a common Paginator[T] interface with the Fetcher pattern.

## API Changes

1. **Unified Paginator[T] Interface**
   - All strategies implement Paginate(ctx, args, opts...) method
   - Consistent API across offset, cursor, and quotafill

2. **Fetcher Pattern**
   - All constructors take Fetcher[T] as first parameter
   - offset.New(fetcher)
   - cursor.New(fetcher, schema)
   - quotafill.New(fetcher, filter, schema, opts...)

3. **Functional Options for Page Size**
   - Page size limits moved from constructors to Paginate() options
   - paging.WithMaxSize(100) - cap maximum page size
   - paging.WithDefaultSize(25) - set default when First is nil

4. **Page[T] Result Type**
   - Paginate() returns *Page[T] with Nodes, PageInfo, and Metadata
   - Metadata includes strategy name, timing, and strategy-specific info
   - Offset stored in Metadata.Offset for accurate cursor generation

5. **Simplified BuildConnection**
   - offset.BuildConnection(page, transform)
   - cursor.BuildConnection(page, schema, args, transform)
   - quotafill.BuildConnection(page, schema, args, transform)

## Removed/Deprecated

- offset: QueryMods() method removed (use Paginate() instead)
- cursor: BuildFetchParams() deprecated (use Paginate() instead)
- quotafill: WithPageConfig() option removed (use Paginate() options)

## Benefits

- Consistent API across all three strategies
- Reusable fetchers across multiple requests
- Per-request page size configuration
- Rich metadata for observability
- Easier testing with mockable Fetcher[T]
- Simpler strategy switching

## Testing

- All 204 tests passing across all packages
- Integration tests updated for new API
- Security tests updated and passing

See MIGRATION.md for detailed migration guide from v0.3.0 to v2.0.
@josemarluedke josemarluedke merged commit 71725ae into main Dec 16, 2025
1 of 2 checks passed
@josemarluedke josemarluedke deleted the feat/align-implementations branch December 16, 2025 03:43
@josemarluedke josemarluedke added the Type: Enhancement New feature or request label Dec 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Type: Enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant