{"id":25770886,"url":"https://github.com/caknoooo/go-pagination","last_synced_at":"2026-06-09T13:31:36.489Z","repository":{"id":273657043,"uuid":"920374096","full_name":"Caknoooo/go-pagination","owner":"Caknoooo","description":"A dynamic and flexible data querying library for Go with GORM integration. It goes beyond simple pagination by providing search, sorting, dynamic filtering, relationship includes, and multi-database support. Optimized for performance and designed to make building clean, scalable, and secure APIs effortless.","archived":false,"fork":false,"pushed_at":"2025-11-17T08:50:09.000Z","size":148,"stargazers_count":13,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-17T10:23:07.886Z","etag":null,"topics":["generics","gin","go","go-pagination","gorm","library","pagination"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Caknoooo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-01-22T03:16:14.000Z","updated_at":"2025-11-17T08:50:10.000Z","dependencies_parsed_at":"2025-01-22T07:36:19.632Z","dependency_job_id":"82dc0e76-c390-4e2d-9cbd-0cacb2598c23","html_url":"https://github.com/Caknoooo/go-pagination","commit_stats":null,"previous_names":["caknoooo/go-pagination"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/Caknoooo/go-pagination","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Caknoooo%2Fgo-pagination","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Caknoooo%2Fgo-pagination/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Caknoooo%2Fgo-pagination/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Caknoooo%2Fgo-pagination/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Caknoooo","download_url":"https://codeload.github.com/Caknoooo/go-pagination/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Caknoooo%2Fgo-pagination/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34110011,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-09T02:00:06.510Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["generics","gin","go","go-pagination","gorm","library","pagination"],"created_at":"2025-02-27T02:46:14.519Z","updated_at":"2026-06-09T13:31:36.483Z","avatar_url":"https://github.com/Caknoooo.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Go Pagination 🚀\n\nA **powerful, flexible, and production-ready** pagination library for Go with GORM integration. Built with modern Go practices including generics, this library provides multiple patterns to implement pagination in your applications with built-in support for searching, sorting, filtering, relationships, and database security.\n\n## ✨ Key Features\n\n- 🚀 **Generic Support**: Full support for Go generics for type safety\n- 🔍 **Smart Search**: Automatic search across multiple fields with database optimization\n- 🗂️ **Advanced Filtering**: Dynamic filters with custom operators and validation\n- 🔗 **Relationship Support**: Easy preloading with security validation\n- 🛢️ **Multi-Database**: MySQL, PostgreSQL, SQLite, and SQL Server support\n- 🛡️ **Security First**: SQL injection protection and include validation\n- ⚡ **High Performance**: Optimized queries with efficient counting\n- 🧪 **Production Ready**: Comprehensive test coverage and real-world examples\n- 📚 **Multiple Patterns**: From simple one-liners to complex builders\n- 🌐 **API Ready**: Built-in response formatting for REST APIs\n\n## 📦 Installation\n\n```bash\ngo get github.com/Caknoooo/go-pagination\n```\n\n## 📋 Table of Contents\n\n- [Quick Start](#-quick-start)\n- [Advanced Filtering](#-advanced-filtering)\n- [Relationship Loading](#-relationship-loading)\n- [Search Functionality](#-search-functionality)\n- [Sorting Examples](#-sorting-examples)\n- [Security Features](#-security-features)\n- [URL Parameters](#-url-parameters)\n- [Response Format](#-response-format)\n- [Real Examples](#-real-world-examples)\n- [Performance Tips](#-performance-tips)\n\n## 🚀 Quick Start\n\n### 1. Simplest Way - One Line Pagination! \n\nPerfect for getting started quickly with minimal setup:\n\n```go\npackage main\n\nimport (\n    \"github.com/Caknoooo/go-pagination\"\n    \"github.com/gin-gonic/gin\"\n    \"gorm.io/gorm\"\n)\n\ntype User struct {\n    ID    uint   `json:\"id\" gorm:\"primaryKey\"`\n    Name  string `json:\"name\"`\n    Email string `json:\"email\"`\n}\n\nfunc GetUsers(db *gorm.DB) gin.HandlerFunc {\n    return func(c *gin.Context) {\n        // 🎯 One line pagination with automatic search!\n        response := pagination.PaginatedAPIResponse[User](\n            db, c, \"users\", \n            []string{\"name\", \"email\"}, // fields to search in\n            \"Users retrieved successfully\",\n        )\n        c.JSON(response.Code, response)\n    }\n}\n\nfunc main() {\n    r := gin.Default()\n    r.GET(\"/users\", GetUsers(db))\n    r.Run(\":8080\")\n}\n```\n\n**Try these URLs:**\n```bash\n# Basic pagination\ncurl \"http://localhost:8080/users?page=1\u0026per_page=10\"\n\n# Search in name and email fields\ncurl \"http://localhost:8080/users?search=john\u0026page=1\u0026per_page=10\"\n\n# Sort by name descending\ncurl \"http://localhost:8080/users?sort=name,desc\u0026page=1\u0026per_page=10\"\n\n# Combined: search + sort + pagination\ncurl \"http://localhost:8080/users?search=admin\u0026sort=id,desc\u0026page=2\u0026per_page=5\"\n```\n\n## 🗂️ Advanced Filtering\n\n### Custom Filter Pattern with Validation\n\nCreate powerful, reusable filters with automatic validation:\n\n```go\ntype UserFilter struct {\n    pagination.BaseFilter\n    ID       int    `json:\"id\" form:\"id\"`\n    Name     string `json:\"name\" form:\"name\"`\n    Email    string `json:\"email\" form:\"email\"`\n    IsActive *bool  `json:\"is_active\" form:\"is_active\"`\n    Role     string `json:\"role\" form:\"role\"`\n    MinAge   int    `json:\"min_age\" form:\"min_age\"`\n    MaxAge   int    `json:\"max_age\" form:\"max_age\"`\n}\n\n// Custom filter implementation\nfunc (f *UserFilter) ApplyFilters(query *gorm.DB) *gorm.DB {\n    if f.ID \u003e 0 {\n        query = query.Where(\"id = ?\", f.ID)\n    }\n    if f.Name != \"\" {\n        query = query.Where(\"name LIKE ?\", \"%\"+f.Name+\"%\")\n    }\n    if f.Email != \"\" {\n        query = query.Where(\"email LIKE ?\", \"%\"+f.Email+\"%\")\n    }\n    if f.IsActive != nil {\n        query = query.Where(\"is_active = ?\", *f.IsActive)\n    }\n    if f.Role != \"\" {\n        query = query.Where(\"role = ?\", f.Role)\n    }\n    if f.MinAge \u003e 0 {\n        query = query.Where(\"age \u003e= ?\", f.MinAge)\n    }\n    if f.MaxAge \u003e 0 {\n        query = query.Where(\"age \u003c= ?\", f.MaxAge)\n    }\n    return query\n}\n\n// Define searchable fields (will be used for global search)\nfunc (f *UserFilter) GetSearchFields() []string {\n    return []string{\"name\", \"email\", \"phone\"}\n}\n\nfunc (f *UserFilter) GetTableName() string {\n    return \"users\"\n}\n\nfunc (f *UserFilter) GetDefaultSort() string {\n    return \"id asc\"\n}\n\n// Handler using the custom filter\nfunc GetUsersWithFilter(db *gorm.DB) gin.HandlerFunc {\n    return func(c *gin.Context) {\n        var filter UserFilter\n        if err := pagination.BindPagination(c, \u0026filter); err != nil {\n            c.JSON(400, gin.H{\"error\": err.Error()})\n            return\n        }\n\n        users, total, err := pagination.PaginatedQueryWithFilter[User](db, \u0026filter)\n        if err != nil {\n            c.JSON(500, gin.H{\"error\": err.Error()})\n            return\n        }\n\n        paginationResponse := pagination.CalculatePagination(filter.GetPagination(), total)\n        response := pagination.NewPaginatedResponse(200, \"Users retrieved successfully\", users, paginationResponse)\n        c.JSON(200, response)\n    }\n}\n```\n\n**Advanced filtering examples:**\n```bash\n# Filter by specific user ID\ncurl \"http://localhost:8080/users?id=123\"\n\n# Filter by name pattern\ncurl \"http://localhost:8080/users?name=john\u0026page=1\u0026per_page=10\"\n\n# Filter by role and status\ncurl \"http://localhost:8080/users?role=admin\u0026is_active=true\"\n\n# Age range filtering\ncurl \"http://localhost:8080/users?min_age=18\u0026max_age=65\"\n\n# Complex combined filtering\ncurl \"http://localhost:8080/users?role=user\u0026is_active=true\u0026min_age=25\u0026search=developer\u0026sort=name,asc\"\n```\n## 🔗 Relationship Loading\n\n### Basic Relationship Loading with Security\n\n```go\ntype User struct {\n    ID      uint    `json:\"id\" gorm:\"primaryKey\"`\n    Name    string  `json:\"name\"`\n    Email   string  `json:\"email\"`\n    Profile Profile `json:\"profile,omitempty\" gorm:\"foreignKey:UserID\"`\n    Posts   []Post  `json:\"posts,omitempty\" gorm:\"foreignKey:UserID\"`\n    Orders  []Order `json:\"orders,omitempty\" gorm:\"foreignKey:UserID\"`\n}\n\ntype Profile struct {\n    ID     uint   `json:\"id\"`\n    UserID uint   `json:\"user_id\"`\n    Bio    string `json:\"bio\"`\n    Avatar string `json:\"avatar\"`\n}\n\ntype Post struct {\n    ID      uint   `json:\"id\"`\n    UserID  uint   `json:\"user_id\"`\n    Title   string `json:\"title\"`\n    Content string `json:\"content\"`\n}\n\ntype UserFilter struct {\n    pagination.BaseFilter\n    Name   string `json:\"name\" form:\"name\"`\n    Status string `json:\"status\" form:\"status\"`\n}\n\n// Implement IncludableQueryBuilder interface\nfunc (f *UserFilter) GetIncludes() []string {\n    return f.Includes\n}\n\nfunc (f *UserFilter) GetPagination() pagination.PaginationRequest {\n    return f.Pagination\n}\n\nfunc (f *UserFilter) Validate() {\n    var validIncludes []string\n    allowedIncludes := f.GetAllowedIncludes()\n    for _, include := range f.Includes {\n        if allowedIncludes[include] {\n            validIncludes = append(validIncludes, include)\n        }\n    }\n    f.Includes = validIncludes\n}\n\n// 🛡️ Security: Define which relationships can be loaded\nfunc (f *UserFilter) GetAllowedIncludes() map[string]bool {\n    return map[string]bool{\n        \"Profile\": true,  // ✅ Allow loading user profile\n        \"Posts\":   true,  // ✅ Allow loading user posts\n        \"Orders\":  true,  // ✅ Allow loading user orders\n        // \"Secrets\": false, // ❌ Sensitive data - not allowed\n    }\n}\n\nfunc (f *UserFilter) ApplyFilters(query *gorm.DB) *gorm.DB {\n    if f.Name != \"\" {\n        query = query.Where(\"name LIKE ?\", \"%\"+f.Name+\"%\")\n    }\n    if f.Status != \"\" {\n        query = query.Where(\"status = ?\", f.Status)\n    }\n    return query\n}\n\nfunc (f *UserFilter) GetSearchFields() []string {\n    return []string{\"name\", \"email\"}\n}\n\nfunc (f *UserFilter) GetTableName() string {\n    return \"users\"\n}\n\nfunc (f *UserFilter) GetDefaultSort() string {\n    return \"id asc\"\n}\n\n// Handler with automatic include validation\nfunc GetUsersWithRelations(db *gorm.DB) gin.HandlerFunc {\n    return func(c *gin.Context) {\n        filter := \u0026UserFilter{}\n        filter.BindPagination(c)\n        c.ShouldBindQuery(filter)\n\n        // 🔒 Automatically validates includes and loads relationships\n        users, total, err := pagination.PaginatedQueryWithIncludable[User](db, filter)\n        if err != nil {\n            c.JSON(500, gin.H{\"error\": err.Error()})\n            return\n        }\n\n        paginationResponse := pagination.CalculatePagination(filter.GetPagination(), total)\n        response := pagination.NewPaginatedResponse(200, \"Users retrieved successfully\", users, paginationResponse)\n        c.JSON(200, response)\n    }\n}\n```\n\n**Relationship loading examples:**\n```bash\n# Basic pagination without relationships\ncurl \"http://localhost:8080/users?page=1\u0026per_page=10\"\n\n# Load user profiles\ncurl \"http://localhost:8080/users?includes=Profile\u0026page=1\u0026per_page=10\"\n\n# Load multiple relationships\ncurl \"http://localhost:8080/users?includes=Profile,Posts\u0026page=1\u0026per_page=10\"\n\n# Load all allowed relationships\ncurl \"http://localhost:8080/users?includes=Profile,Posts,Orders\u0026page=1\u0026per_page=10\"\n\n# Combine with search and filters\ncurl \"http://localhost:8080/users?includes=Profile,Posts\u0026search=john\u0026status=active\u0026page=1\u0026per_page=10\"\n\n# Try loading unauthorized relationship (will be ignored)\ncurl \"http://localhost:8080/users?includes=Profile,Secrets\u0026page=1\u0026per_page=10\"\n# Only Profile will be loaded, Secrets will be ignored for security\n```\n\n### Advanced Relationships with Nested Loading\n\n```go\ntype UserAdvancedFilter struct {\n    pagination.BaseFilter\n    Name      string `json:\"name\" form:\"name\"`\n    CityName  string `json:\"city_name\" form:\"city_name\"`\n    PostTitle string `json:\"post_title\" form:\"post_title\"`\n}\n\nfunc (f *UserAdvancedFilter) ApplyFilters(query *gorm.DB) *gorm.DB {\n    if f.Name != \"\" {\n        query = query.Where(\"users.name LIKE ?\", \"%\"+f.Name+\"%\")\n    }\n    if f.CityName != \"\" {\n        query = query.Joins(\"JOIN profiles ON profiles.user_id = users.id\").\n               Joins(\"JOIN addresses ON addresses.profile_id = profiles.id\").\n               Where(\"addresses.city LIKE ?\", \"%\"+f.CityName+\"%\")\n    }\n    if f.PostTitle != \"\" {\n        query = query.Joins(\"JOIN posts ON posts.user_id = users.id\").\n               Where(\"posts.title LIKE ?\", \"%\"+f.PostTitle+\"%\")\n    }\n    return query\n}\n\nfunc (f *UserAdvancedFilter) GetSearchFields() []string {\n    return []string{\"users.name\", \"users.email\", \"profiles.bio\"}\n}\n\nfunc (f *UserAdvancedFilter) GetAllowedIncludes() map[string]bool {\n    return map[string]bool{\n        \"Profile\":         true, // Load user profile\n        \"Posts\":           true, // Load user posts\n        \"Profile.Address\": true, // Load nested: profile with address\n        \"Posts.Comments\":  true, // Load nested: posts with comments\n        \"Posts.Tags\":      true, // Load nested: posts with tags\n    }\n}\n```\n\n**Nested relationship examples:**\n```bash\n# Load nested relationships\ncurl \"http://localhost:8080/users/advanced?includes=Profile.Address,Posts.Comments\"\n\n# Complex filtering with nested loading\ncurl \"http://localhost:8080/users/advanced?includes=Profile.Address\u0026city_name=Jakarta\u0026search=developer\"\n\n# Multiple nested relationships\ncurl \"http://localhost:8080/users/advanced?includes=Profile.Address,Posts.Comments,Posts.Tags\u0026page=1\u0026per_page=5\"\n```\n## 🔍 Search Functionality\n\n### Automatic Search with Multiple Fields\n\nThe library provides powerful automatic search functionality across multiple fields:\n\n```go\ntype ProductFilter struct {\n    pagination.BaseFilter\n    CategoryID int     `json:\"category_id\" form:\"category_id\"`\n    MinPrice   float64 `json:\"min_price\" form:\"min_price\"`\n    MaxPrice   float64 `json:\"max_price\" form:\"max_price\"`\n    InStock    *bool   `json:\"in_stock\" form:\"in_stock\"`\n}\n\n// Define which fields should be searchable\nfunc (f *ProductFilter) GetSearchFields() []string {\n    return []string{\"name\", \"description\", \"brand\", \"sku\"}\n}\n\nfunc (f *ProductFilter) ApplyFilters(query *gorm.DB) *gorm.DB {\n    if f.CategoryID \u003e 0 {\n        query = query.Where(\"category_id = ?\", f.CategoryID)\n    }\n    if f.MinPrice \u003e 0 {\n        query = query.Where(\"price \u003e= ?\", f.MinPrice)\n    }\n    if f.MaxPrice \u003e 0 {\n        query = query.Where(\"price \u003c= ?\", f.MaxPrice)\n    }\n    if f.InStock != nil {\n        query = query.Where(\"in_stock = ?\", *f.InStock)\n    }\n    return query\n}\n\nfunc (f *ProductFilter) GetTableName() string {\n    return \"products\"\n}\n\nfunc (f *ProductFilter) GetDefaultSort() string {\n    return \"created_at desc\"\n}\n```\n\n**Search examples:**\n```bash\n# Search across name, description, brand, and sku fields\ncurl \"http://localhost:8080/products?search=laptop\"\n# Automatically generates: WHERE (name LIKE '%laptop%' OR description LIKE '%laptop%' OR brand LIKE '%laptop%' OR sku LIKE '%laptop%')\n\n# Combine search with filters\ncurl \"http://localhost:8080/products?search=gaming\u0026category_id=1\u0026min_price=500\"\n\n# Search with pagination and sorting\ncurl \"http://localhost:8080/products?search=macbook\u0026sort=price,asc\u0026page=1\u0026per_page=10\"\n```\n\n### Database-Specific Search Optimization\n\nThe library automatically optimizes search based on your database:\n\n```go\n// For PostgreSQL - Uses ILIKE for case-insensitive search\n// Automatically generated: WHERE (name ILIKE '%search%' OR description ILIKE '%search%')\n\n// For MySQL/SQLite - Uses LIKE \n// Automatically generated: WHERE (name LIKE '%search%' OR description LIKE '%search%')\n```\n\n### Advanced Search with Relationships\n\n```go\ntype UserSearchFilter struct {\n    pagination.BaseFilter\n    Role       string `json:\"role\" form:\"role\"`\n    Department string `json:\"department\" form:\"department\"`\n}\n\nfunc (f *UserSearchFilter) GetSearchFields() []string {\n    return []string{\n        \"users.name\", \n        \"users.email\", \n        \"profiles.bio\", \n        \"departments.name\",\n    }\n}\n\nfunc (f *UserSearchFilter) ApplyFilters(query *gorm.DB) *gorm.DB {\n    // Join tables for search functionality\n    query = query.Joins(\"LEFT JOIN profiles ON profiles.user_id = users.id\").\n           Joins(\"LEFT JOIN departments ON departments.id = users.department_id\")\n    \n    if f.Role != \"\" {\n        query = query.Where(\"users.role = ?\", f.Role)\n    }\n    if f.Department != \"\" {\n        query = query.Where(\"departments.name = ?\", f.Department)\n    }\n    return query\n}\n```\n\n**Advanced search examples:**\n```bash\n# Search across multiple tables\ncurl \"http://localhost:8080/users/search?search=developer\"\n# Searches in: users.name, users.email, profiles.bio, departments.name\n\n# Search with relationship filters\ncurl \"http://localhost:8080/users/search?search=john\u0026role=admin\u0026department=IT\"\n```\n\n## 🔄 Sorting Examples\n\n### Basic Sorting\n\n```bash\n# Sort by single field ascending (default)\ncurl \"http://localhost:8080/users?sort=name\"\n\n# Sort by single field descending\ncurl \"http://localhost:8080/users?sort=name,desc\"\n\n# Sort by multiple fields\ncurl \"http://localhost:8080/users?sort=role,asc\u0026sort=name,desc\"\n\n# Sort with pagination\ncurl \"http://localhost:8080/users?sort=created_at,desc\u0026page=1\u0026per_page=20\"\n```\n\n\n**Custom sorting examples:**\n```bash\n# Sort by calculated posts count\ncurl \"http://localhost:8080/users?sort=posts_count,desc\"\n\n# Sort by concatenated full name\ncurl \"http://localhost:8080/users?sort=full_name,asc\"\n\n# Sort by related table field\ncurl \"http://localhost:8080/users?sort=latest_login,desc\"\n```\n## 🛡️ Security Features\n\n### Include Validation and SQL Injection Protection\n\n```go\ntype SecureUserFilter struct {\n    pagination.BaseFilter\n    Status string `json:\"status\" form:\"status\"`\n}\n\nfunc (f *SecureUserFilter) GetAllowedIncludes() map[string]bool {\n    return map[string]bool{\n        \"Profile\":        true,  // ✅ Safe to load\n        \"Posts\":          true,  // ✅ Safe to load\n        \"PublicData\":     true,  // ✅ Safe to load\n        \"SensitiveData\":  false, // ❌ Blocked for security\n        \"PrivateNotes\":   false, // ❌ Blocked for security\n        \"AdminData\":      false, // ❌ Blocked for security\n    }\n}\n\nfunc (f *SecureUserFilter) Validate() {\n    // Automatic validation removes unauthorized includes\n    var validIncludes []string\n    allowedIncludes := f.GetAllowedIncludes()\n    \n    for _, include := range f.Includes {\n        // Validate against whitelist\n        if allowedIncludes[include] {\n            // Additional regex validation for SQL injection protection\n            if isValidInclude(include) {\n                validIncludes = append(validIncludes, include)\n            }\n        }\n    }\n    f.Includes = validIncludes\n}\n\n// Built-in regex validation for includes\nfunc isValidInclude(include string) bool {\n    // Only allows alphanumeric, dots, and underscores\n    matched, _ := regexp.MatchString(`^[a-zA-Z0-9_.]+$`, include)\n    return matched\n}\n```\n\n**Security examples:**\n```bash\n# Valid includes - will be processed\ncurl \"http://localhost:8080/users?includes=Profile,Posts\"\n\n# Invalid includes - will be ignored\ncurl \"http://localhost:8080/users?includes=Profile,SensitiveData,AdminData\"\n# Only Profile will be loaded\n\n# SQL injection attempt - will be blocked\ncurl \"http://localhost:8080/users?includes=Profile'; DROP TABLE users; --\"\n# Regex validation will reject this\n```\n\n### Input Validation and Sanitization\n\n```go\ntype ValidatedFilter struct {\n    pagination.BaseFilter\n    Email    string `json:\"email\" form:\"email\" validate:\"email\"`\n    Age      int    `json:\"age\" form:\"age\" validate:\"min=0,max=120\"`\n    Status   string `json:\"status\" form:\"status\" validate:\"oneof=active inactive pending\"`\n}\n\nfunc (f *ValidatedFilter) Validate() error {\n    // Built-in validation\n    if f.Email != \"\" \u0026\u0026 !isValidEmail(f.Email) {\n        return errors.New(\"invalid email format\")\n    }\n    \n    if f.Age \u003c 0 || f.Age \u003e 120 {\n        return errors.New(\"age must be between 0 and 120\")\n    }\n    \n    validStatuses := map[string]bool{\n        \"active\": true, \"inactive\": true, \"pending\": true,\n    }\n    if f.Status != \"\" \u0026\u0026 !validStatuses[f.Status] {\n        return errors.New(\"invalid status value\")\n    }\n    \n    return nil\n}\n\nfunc (f *ValidatedFilter) ApplyFilters(query *gorm.DB) *gorm.DB {\n    // All inputs are already validated\n    if f.Email != \"\" {\n        query = query.Where(\"email = ?\", f.Email) // Safe to use\n    }\n    if f.Age \u003e 0 {\n        query = query.Where(\"age = ?\", f.Age)\n    }\n    if f.Status != \"\" {\n        query = query.Where(\"status = ?\", f.Status)\n    }\n    return query\n}\n```\n\n## URL Parameters Reference\n\n### Core Parameters\n\n| Parameter | Type | Description | Example | Default |\n|-----------|------|-------------|---------|---------|\n| `page` | int | Page number | `page=2` | 1 |\n| `per_page` | int | Alias for per_page | `per_page=25` | 10 |\n| `search` | string | Global search term | `search=john` | \"\" |\n| `sort` | string | Sort field | `sort=name` | \"\" |\n| `order` | string | Sort direction | `order=desc` | \"asc\" |\n| `includes` | string | Comma-separated relations | `includes=profile,posts` | \"\" |\n\n### Sorting Formats\n\n```bash\n# Single field ascending (default)\n?sort=name\n\n# Single field with explicit direction\n?sort=name\u0026order=desc\n\n# Alternative comma format\n?sort=name,desc\n\n# Multiple fields\n?sort=name,asc\u0026sort=created_at,desc\n```\n\n### Complex Query Examples\n\n```bash\n# Basic pagination\nGET /api/users?page=1\u0026per_page=10\n\n# Search with pagination\nGET /api/users?search=developer\u0026page=2\u0026per_page=5\n\n# Filter with specific fields\nGET /api/users?role=admin\u0026status=active\u0026page=1\u0026per_page=20\n\n# Sort with relationships\nGET /api/users?includes=profile,posts\u0026sort=name,asc\u0026page=1\u0026per_page=15\n\n# Complex combined query\nGET /api/users?search=john\u0026role=user\u0026status=active\u0026includes=profile\u0026sort=created_at,desc\u0026page=1\u0026per_page=10\n\n# Date range filtering (custom implementation)\nGET /api/users?created_after=2023-01-01\u0026created_before=2023-12-31\u0026page=1\u0026per_page=10\n\n# Numeric range filtering\nGET /api/products?min_price=100\u0026max_price=500\u0026category_id=1\u0026page=1\u0026per_page=10\n```\n\n## Response Format\n\n### Standard Response Structure\n\n```json\n{\n  \"code\": 200,\n  \"status\": \"success\", \n  \"message\": \"Data retrieved successfully\",\n  \"data\": [\n    {\n      \"id\": 1,\n      \"name\": \"John Doe\",\n      \"email\": \"john@example.com\",\n      \"profile\": {\n        \"id\": 1,\n        \"bio\": \"Software Developer\",\n        \"avatar\": \"avatar.jpg\"\n      },\n      \"posts\": [\n        {\n          \"id\": 1,\n          \"title\": \"My First Post\",\n          \"content\": \"Hello World!\"\n        }\n      ]\n    }\n  ],\n  \"pagination\": {\n    \"page\": 1,\n    \"per_page\": 10,\n    \"max_page\": 15,\n    \"total\": 142\n  }\n}\n```\n\n## 🚀 Running the Examples\n\nThe `examples/` folder contains a complete working implementation:\n\n```bash\n# Navigate to examples directory\ncd examples/\n\n# Install dependencies\ngo mod tidy\n\n# Set up your database (update connection string in main.go)\n# Default expects MySQL at localhost:3306 with database 'sports_db'\n\n# Run the example server\ngo run .\n```\n\nThe example server provides these endpoints:\n\n- `GET /provinces` - Basic province pagination\n- `GET /provinces/with-athletes` - Provinces with athlete relationships\n- `GET /athletes` - Athletes with province/sport filtering\n- `GET /sports` - Sports management\n- `GET /events` - Events with date filtering\n\n**Test the examples:**\n```bash\n# Basic athlete pagination\ncurl \"http://localhost:8080/athletes?page=1\u0026per_page=5\"\n\n# Athletes with relationships\ncurl \"http://localhost:8080/athletes?includes=Province,Sport\u0026page=1\u0026per_page=5\"\n\n# Search athletes by name\ncurl \"http://localhost:8080/athletes?search=john\u0026includes=Province\"\n\n# Filter by province and sport\ncurl \"http://localhost:8080/athletes?province_id=1\u0026sport_id=2\u0026includes=Province,Sport\"\n\n# Provinces with their athletes\ncurl \"http://localhost:8080/provinces/with-athletes?includes=Athletes\u0026page=1\u0026per_page=10\"\n```\n\n## 🤝 Contributing\n\nWe welcome contributions! Here's how you can help:\n\n### Development Setup\n\n```bash\n# Fork and clone the repository\ngit clone https://github.com/yourusername/go-pagination.git\ncd go-pagination\n\n# Install dependencies\ngo mod tidy\n\n# Run tests\ngo test ./...\n\n# Run benchmarks\ngo test -bench=. ./...\n\n# Run examples\ncd examples/\ngo run .\n```\n\n### Contribution Guidelines\n\n1. **Fork the repository**\n2. **Create a feature branch**: `git checkout -b feature/amazing-feature`\n3. **Make your changes**:\n   - Add tests for new functionality\n   - Update documentation\n   - Follow Go conventions\n4. **Run tests**: `go test ./...`\n5. **Commit your changes**: `git commit -m 'feat: add amazing feature'`\n6. **Push to branch**: `git push origin feature/amazing-feature`\n7. **Open a Pull Request**\n\n## 📄 License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## 🙏 Acknowledgments\n\n- **[GORM](https://gorm.io/)** - The fantastic Go ORM that makes database operations elegant\n- **[Gin](https://gin-gonic.com/)** - The high-performance Go web framework\n- **Go Community** - For continuous inspiration and feedback\n- **Contributors** - Everyone who has contributed to making this library better\n\n## 📞 Support\n\n- 📖 **Documentation**: Check this README and examples\n- 🐛 **Issues**: [GitHub Issues](https://github.com/Caknoooo/go-pagination/issues)\n- 💬 **Discussions**: [GitHub Discussions](https://github.com/Caknoooo/go-pagination/discussions)\n- ⭐ **Star the repo** if you find it useful!","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcaknoooo%2Fgo-pagination","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcaknoooo%2Fgo-pagination","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcaknoooo%2Fgo-pagination/lists"}