Gorm是一个非常棒的ORM。今天,我将向您展示如何使用Gorm Scopes创建分页。
Scopes可以实现一些逻辑的复用,这些逻辑需要定义为如下格式:
func(*gorm.DB) *gorm.DB
首先创建一个Pagination结构体:
type Pagination struct {
PageSize int `json:"pageSize,omitempty" form:"pageSize"`
PageIndex int `json:"pageIndex,omitempty" form:"pageIndex"`
Sort string `json:"sort,omitempty" form:"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.PageSize == 0 {
p.PageSize = 10
}
return p.PageSize
}
func (p *Pagination) GetPage() int {
if p.PageIndex == 0 {
p.PageIndex = 1
}
return p.PageIndex
}
func (p *Pagination) GetSort() string {
if p.Sort == "" {
p.Sort = "Id desc"
}
return p.Sort
}
然后创建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())
}
}
然后将Gorm scope用在你的代码中使用,如下所示:
package pagination
import (
"log"
"math"
"awesomeProject/pkg"
"github.com/gin-gonic/gin"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
type CategoryGorm struct {
db *gorm.DB
}
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.PageSize)))
pagination.TotalPages = totalPages
return func(db *gorm.DB) *gorm.DB {
return db.Offset(pagination.GetOffset()).Limit(pagination.GetLimit()).Order(pagination.GetSort())
}
}
type Category struct {
Id int `json:"id"`
Type string `json:"type"`
}
func Server() {
db, err := gorm.Open(sqlite.Open("category.db"), &gorm.Config{})
if err != nil {
panic(err)
}
err = db.AutoMigrate(&Category{})
if err != nil {
panic(err)
}
c := CategoryGorm{db: db}
var engine = gin.Default()
engine.POST("/api/v1/category", c.AddCategory)
engine.GET("/api/v1/category", c.CategoryList)
panic(engine.Run(":9000"))
}
func (g CategoryGorm) AddCategory(c *gin.Context) {
var req Category
err := c.Bind(&req)
if err != nil {
log.Printf("parameters err for: %s", err.Error())
}
err = g.db.Model(&Category{}).Create(&req).Error
if err != nil {
log.Printf("insert category into db failed for: %s", err)
return
}
c.JSON(200, "success")
}
func (cg *CategoryGorm) CategoryList(c *gin.Context) {
var req pkg.Pagination
err := c.Bind(&req)
if err != nil {
log.Printf("parameters error %s", err)
return
}
list, err := cg.List(req)
if err != nil {
log.Printf("query category list failed for: %s", err)
}
c.JSON(200, list)
}
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
}
这里只是为了演示分页效果,使用简单的demo来完成。我们的代码里面是用了sqlite数据库,无需安装只需要本地创建文件即可。
运行以上代码,首先我们调用以下POST请求创建多个数据库category对象共查询:
接着调用以下分页查询看看效果:
http://localhost:9000/api/v1/category?pageIndex=1&pageSize=3
输出:
{
"pageSize": 3,
"pageIndex": 1,
"sort": "Id desc",
"total_rows": 7,
"total_pages": 3,
"rows": [
{
"id": 8,
"type": "desk"
},
{
"id": 7,
"type": "joy"
},
{
"id": 6,
"type": "hat"
}
]
}
达到分页效果。
网友评论