github.com/ecodeclub/eorm@v0.0.2-0.20231001112437-dae71da914d0/internal/merger/pagedmerger/merger.go (about) 1 // Copyright 2021 ecodeclub 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package pagedmerger 16 17 import ( 18 "context" 19 "database/sql" 20 "sync" 21 22 "github.com/ecodeclub/eorm/internal/rows" 23 24 "github.com/ecodeclub/eorm/internal/merger" 25 "github.com/ecodeclub/eorm/internal/merger/internal/errs" 26 ) 27 28 type Merger struct { 29 m merger.Merger 30 limit int 31 offset int 32 } 33 34 func NewMerger(m merger.Merger, offset int, limit int) (*Merger, error) { 35 if offset < 0 || limit <= 0 { 36 return nil, errs.ErrMergerInvalidLimitOrOffset 37 } 38 39 return &Merger{ 40 m: m, 41 limit: limit, 42 offset: offset, 43 }, nil 44 } 45 46 func (m *Merger) Merge(ctx context.Context, results []rows.Rows) (rows.Rows, error) { 47 rs, err := m.m.Merge(ctx, results) 48 if err != nil { 49 return nil, err 50 } 51 err = m.nextOffset(ctx, rs) 52 if err != nil { 53 return nil, err 54 } 55 return &Rows{ 56 rows: rs, 57 mu: &sync.RWMutex{}, 58 limit: m.limit, 59 }, nil 60 } 61 62 // nextOffset 会把游标挪到 offset 所指定的位置。 63 func (m *Merger) nextOffset(ctx context.Context, rows rows.Rows) error { 64 offset := m.offset 65 for i := 0; i < offset; i++ { 66 if ctx.Err() != nil { 67 return ctx.Err() 68 } 69 // 如果偏移量超过rows结果集返回的行数,不会报错。用户最终查到0行 70 if !rows.Next() { 71 return rows.Err() 72 } 73 } 74 return nil 75 } 76 77 type Rows struct { 78 rows rows.Rows 79 limit int 80 cnt int 81 lastErr error 82 closed bool 83 mu *sync.RWMutex 84 } 85 86 func (*Rows) NextResultSet() bool { 87 return false 88 } 89 90 func (r *Rows) Next() bool { 91 r.mu.Lock() 92 if r.closed { 93 r.mu.Unlock() 94 return false 95 } 96 if r.cnt >= r.limit || r.lastErr != nil { 97 r.mu.Unlock() 98 _ = r.Close() 99 return false 100 } 101 canNext, err := r.nextVal() 102 if err != nil { 103 r.lastErr = err 104 r.mu.Unlock() 105 _ = r.Close() 106 return false 107 } 108 if !canNext { 109 r.mu.Unlock() 110 _ = r.Close() 111 return canNext 112 } 113 r.cnt++ 114 r.mu.Unlock() 115 return canNext 116 } 117 func (r *Rows) nextVal() (bool, error) { 118 if r.rows.Next() { 119 return true, nil 120 } 121 if r.rows.Err() != nil { 122 return false, r.rows.Err() 123 } 124 return false, nil 125 } 126 127 func (r *Rows) Scan(dest ...any) error { 128 r.mu.RLock() 129 defer r.mu.RUnlock() 130 if r.lastErr != nil { 131 return r.lastErr 132 } 133 if r.closed { 134 return errs.ErrMergerRowsClosed 135 } 136 return r.rows.Scan(dest...) 137 } 138 139 func (r *Rows) Close() error { 140 r.mu.Lock() 141 defer r.mu.Unlock() 142 r.closed = true 143 return r.rows.Close() 144 } 145 146 func (r *Rows) ColumnTypes() ([]*sql.ColumnType, error) { 147 return r.rows.ColumnTypes() 148 } 149 func (r *Rows) Columns() ([]string, error) { 150 return r.rows.Columns() 151 } 152 153 func (r *Rows) Err() error { 154 r.mu.RLock() 155 defer r.mu.RUnlock() 156 return r.lastErr 157 }