gitea源码

list.go 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. // Copyright 2020 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package db
  4. import (
  5. "context"
  6. "code.gitea.io/gitea/modules/setting"
  7. "xorm.io/builder"
  8. "xorm.io/xorm"
  9. )
  10. const (
  11. // DefaultMaxInSize represents default variables number on IN () in SQL
  12. DefaultMaxInSize = 50
  13. defaultFindSliceSize = 10
  14. )
  15. // Paginator is the base for different ListOptions types
  16. type Paginator interface {
  17. GetSkipTake() (skip, take int)
  18. IsListAll() bool
  19. }
  20. // SetSessionPagination sets pagination for a database session
  21. func SetSessionPagination(sess Engine, p Paginator) *xorm.Session {
  22. skip, take := p.GetSkipTake()
  23. return sess.Limit(take, skip)
  24. }
  25. // ListOptions options to paginate results
  26. type ListOptions struct {
  27. PageSize int
  28. Page int // start from 1
  29. ListAll bool // if true, then PageSize and Page will not be taken
  30. }
  31. var ListOptionsAll = ListOptions{ListAll: true}
  32. var (
  33. _ Paginator = &ListOptions{}
  34. _ FindOptions = ListOptions{}
  35. )
  36. // GetSkipTake returns the skip and take values
  37. func (opts *ListOptions) GetSkipTake() (skip, take int) {
  38. opts.SetDefaultValues()
  39. return (opts.Page - 1) * opts.PageSize, opts.PageSize
  40. }
  41. func (opts ListOptions) GetPage() int {
  42. return opts.Page
  43. }
  44. func (opts ListOptions) GetPageSize() int {
  45. return opts.PageSize
  46. }
  47. // IsListAll indicates PageSize and Page will be ignored
  48. func (opts ListOptions) IsListAll() bool {
  49. return opts.ListAll
  50. }
  51. // SetDefaultValues sets default values
  52. func (opts *ListOptions) SetDefaultValues() {
  53. if opts.PageSize <= 0 {
  54. opts.PageSize = setting.API.DefaultPagingNum
  55. }
  56. if opts.PageSize > setting.API.MaxResponseItems {
  57. opts.PageSize = setting.API.MaxResponseItems
  58. }
  59. if opts.Page <= 0 {
  60. opts.Page = 1
  61. }
  62. }
  63. func (opts ListOptions) ToConds() builder.Cond {
  64. return builder.NewCond()
  65. }
  66. // AbsoluteListOptions absolute options to paginate results
  67. type AbsoluteListOptions struct {
  68. skip int
  69. take int
  70. }
  71. var _ Paginator = &AbsoluteListOptions{}
  72. // NewAbsoluteListOptions creates a list option with applied limits
  73. func NewAbsoluteListOptions(skip, take int) *AbsoluteListOptions {
  74. if skip < 0 {
  75. skip = 0
  76. }
  77. if take <= 0 {
  78. take = setting.API.DefaultPagingNum
  79. }
  80. if take > setting.API.MaxResponseItems {
  81. take = setting.API.MaxResponseItems
  82. }
  83. return &AbsoluteListOptions{skip, take}
  84. }
  85. // IsListAll will always return false
  86. func (opts *AbsoluteListOptions) IsListAll() bool {
  87. return false
  88. }
  89. // GetSkipTake returns the skip and take values
  90. func (opts *AbsoluteListOptions) GetSkipTake() (skip, take int) {
  91. return opts.skip, opts.take
  92. }
  93. // FindOptions represents a find options
  94. type FindOptions interface {
  95. GetPage() int
  96. GetPageSize() int
  97. IsListAll() bool
  98. ToConds() builder.Cond
  99. }
  100. type JoinFunc func(sess Engine) error
  101. type FindOptionsJoin interface {
  102. ToJoins() []JoinFunc
  103. }
  104. type FindOptionsOrder interface {
  105. ToOrders() string
  106. }
  107. // Find represents a common find function which accept an options interface
  108. func Find[T any](ctx context.Context, opts FindOptions) ([]*T, error) {
  109. sess := GetEngine(ctx).Where(opts.ToConds())
  110. if joinOpt, ok := opts.(FindOptionsJoin); ok {
  111. for _, joinFunc := range joinOpt.ToJoins() {
  112. if err := joinFunc(sess); err != nil {
  113. return nil, err
  114. }
  115. }
  116. }
  117. if orderOpt, ok := opts.(FindOptionsOrder); ok {
  118. if order := orderOpt.ToOrders(); order != "" {
  119. sess.OrderBy(order)
  120. }
  121. }
  122. page, pageSize := opts.GetPage(), opts.GetPageSize()
  123. if !opts.IsListAll() && pageSize > 0 {
  124. if page == 0 {
  125. page = 1
  126. }
  127. sess.Limit(pageSize, (page-1)*pageSize)
  128. }
  129. findPageSize := defaultFindSliceSize
  130. if pageSize > 0 {
  131. findPageSize = pageSize
  132. }
  133. objects := make([]*T, 0, findPageSize)
  134. if err := sess.Find(&objects); err != nil {
  135. return nil, err
  136. }
  137. return objects, nil
  138. }
  139. // Count represents a common count function which accept an options interface
  140. func Count[T any](ctx context.Context, opts FindOptions) (int64, error) {
  141. sess := GetEngine(ctx).Where(opts.ToConds())
  142. if joinOpt, ok := opts.(FindOptionsJoin); ok {
  143. for _, joinFunc := range joinOpt.ToJoins() {
  144. if err := joinFunc(sess); err != nil {
  145. return 0, err
  146. }
  147. }
  148. }
  149. var object T
  150. return sess.Count(&object)
  151. }
  152. // FindAndCount represents a common findandcount function which accept an options interface
  153. func FindAndCount[T any](ctx context.Context, opts FindOptions) ([]*T, int64, error) {
  154. sess := GetEngine(ctx).Where(opts.ToConds())
  155. page, pageSize := opts.GetPage(), opts.GetPageSize()
  156. if !opts.IsListAll() && pageSize > 0 && page >= 1 {
  157. sess.Limit(pageSize, (page-1)*pageSize)
  158. }
  159. if joinOpt, ok := opts.(FindOptionsJoin); ok {
  160. for _, joinFunc := range joinOpt.ToJoins() {
  161. if err := joinFunc(sess); err != nil {
  162. return nil, 0, err
  163. }
  164. }
  165. }
  166. if orderOpt, ok := opts.(FindOptionsOrder); ok {
  167. if order := orderOpt.ToOrders(); order != "" {
  168. sess.OrderBy(order)
  169. }
  170. }
  171. findPageSize := defaultFindSliceSize
  172. if pageSize > 0 {
  173. findPageSize = pageSize
  174. }
  175. objects := make([]*T, 0, findPageSize)
  176. cnt, err := sess.FindAndCount(&objects)
  177. if err != nil {
  178. return nil, 0, err
  179. }
  180. return objects, cnt, nil
  181. }