acmestack / gorm-plus

Gorm-plus是基于Gorm的增强版,类似Mybatis-plus语法。Gorm-plus is based on an enhanced version of Gorm, similar to Mybatis-plus syntax.
https://github.com/acmestack/gorm-plus/wiki
Apache License 2.0
276 stars 41 forks source link

提供一种基于流式分页的分页函数 #71

Open PhoenixL0911 opened 12 months ago

PhoenixL0911 commented 12 months ago

在一些不需要跳页的场景下使用,相比于offset具有更好的性能。 伪代码如下:

type Comparable interface {
    ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~float32 | ~float64 | time.Time
}

type StreamingPage[T any, V Comparable] struct {
    Column     string `json:"column"`     // 进行分页的列字段
    StartValue T      `json:"startValue"` // 分页起始值
    Limit      int    `json:"limit"`      // 页大小
    Forward    bool   `json:"forward"`    // 上下页翻页标识
    Total      int64  `json:"total"`      // 总记录数
    Records    []*T   `json:"records"`    // 查询记录
    RecordsMap []T    `json:"recordsMap"` // 查询记录Map
}

// StreamingPaginate 流式分页,根据自增ID、雪花ID、时间等数值类型或者时间类型分页
// Tips: 相比于 offset 分页性能更好,走的是 range,缺点是没办法跳页查询
func StreamingPaginate[T any, V Comparable](p *StreamingPage[T, V]) func(db *gorm.DB) *gorm.DB {
    return func(db *gorm.DB) *gorm.DB {
        // 下一页
        if p.Forward {
            return db.Where(fmt.Sprintf("%v > ?", p.Column), p.StartValue).Limit(p.Limit)
        }
        // 上一页
        return db.Where(fmt.Sprintf("%v < ?", p.Column), p.StartValue).Order(fmt.Sprintf("%v DESC", p.Column)).Limit(p.Limit)
    }
}
0x457 commented 10 months ago

在一些不需要跳页的场景下使用,相比于offset具有更好的性能。 伪代码如下:

type Comparable interface {
  ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~float32 | ~float64 | time.Time
}

type StreamingPage[T any, V Comparable] struct {
  Column     string `json:"column"`     // 进行分页的列字段
  StartValue T      `json:"startValue"` // 分页起始值
  Limit      int    `json:"limit"`      // 页大小
  Forward    bool   `json:"forward"`    // 上下页翻页标识
  Total      int64  `json:"total"`      // 总记录数
  Records    []*T   `json:"records"`    // 查询记录
  RecordsMap []T    `json:"recordsMap"` // 查询记录Map
}

// StreamingPaginate 流式分页,根据自增ID、雪花ID、时间等数值类型或者时间类型分页
// Tips: 相比于 offset 分页性能更好,走的是 range,缺点是没办法跳页查询
func StreamingPaginate[T any, V Comparable](p *StreamingPage[T, V]) func(db *gorm.DB) *gorm.DB {
  return func(db *gorm.DB) *gorm.DB {
      // 下一页
      if p.Forward {
          return db.Where(fmt.Sprintf("%v > ?", p.Column), p.StartValue).Limit(p.Limit)
      }
      // 上一页
      return db.Where(fmt.Sprintf("%v < ?", p.Column), p.StartValue).Order(fmt.Sprintf("%v DESC", p.Column)).Limit(p.Limit)
  }
}

上一页有order,下一页怎么没有了?对于一些字段是无序的,很明显下一页与上一页结果应该不一致,会乱掉;另外order 也有可能是多个字段