Pagination using Gorm scopes

Gorm is a fantastic ORM writen in Go for gophers.


Today I will show you how to create pagination using Gorm Scopes.

Scopes allow you to re-use commonly used logic, the shared logic needs to be defined as type

func(*gorm.DB) *gorm.DB

The first step is create a Pagination struct.


//pkg.pagination    
package pkg 
type Pagination struct {    
    Limit        int         `json:"limit,omitempty;query:limit"`   
    Page         int         `json:"page,omitempty;query:page"` 
    Sort         string      `json:"sort,omitempty;query:sort"` 
    TotalRows    int64       `json:"total_rows"`    
    TotalPages   int         `json:"total_pages"`   
    Rows         interface{} `json:"rows"`  
}   
func (p *Pagination) GetOffset() int {  
    return (p.GetPage() - 1) * p.GetLimit() 
}   
func (p *Pagination) GetLimit() int {   
    if p.Limit == 0 {   
        p.Limit = 10    
    }   
    return p.Limit  
}   
func (p *Pagination) GetPage() int {    
    if p.Page == 0 {    
        p.Page = 1  
    }   
    return p.Page   
}   
func (p *Pagination) GetSort() string { 
    if p.Sort == "" {   
        p.Sort = "Id desc"  
    }   
    return p.Sort   
}


Second step is create a Gorm Scope.

func paginate(value interface{}, pagination *pkg.Pagination, db *gorm.DB) func(db *gorm.DB) *gorm.DB {  
    var totalRows int64 
    db.Model(value).Count(&totalRows)   
    pagination.TotalRows = totalRows    
    totalPages := int(math.Ceil(float64(totalRows) / float64(pagination.Limit)))    
    pagination.TotalPages = totalPages  
    return func(db *gorm.DB) *gorm.DB { 
        return db.Offset(pagination.GetOffset()).Limit(pagination.GetLimit()).Order(pagination.GetSort())   
    }   
}


The third step is use Gorm scope in your repository.

type CategoryGorm struct {  
    db *gorm.DB 
}   
func (cg *CategoryGorm) List(pagination pkg.Pagination) (*pkg.Pagination, error) {  
    var categories []*Category  
    cg.db.Scopes(paginate(categories,&pagination, cg.db)).Find(&categories) 
    pagination.Rows = categories    

    return &pagination, nil 
}

Rest Example

I won't talk about how you could implement your handles or access the repository, maybe another time.


The most important thing you need is to return the pkg.pagination for you client.


In a rest application, if I send

http://localhost:3000/categories?limit=10&page=5

Then the output would be:

{   
  "limit": 10,  
  "page": 5,    
  "sort": "Id desc",    
  "total_rows": 41, 
  "total_pages": 5, 
  "rows": [ 
    {   
      "id": "0acd5600-51b9-42e9-9fd0-ff422a6de1d1", 
      "category": "example41"   
    }   
  ] 
}

78