FindInBatches finds all records in batches of batchSize
(dest interface{}, batchSize int, fc func(tx *DB, batch int) error)
| 184 | |
| 185 | // FindInBatches finds all records in batches of batchSize |
| 186 | func (db *DB) FindInBatches(dest interface{}, batchSize int, fc func(tx *DB, batch int) error) *DB { |
| 187 | var ( |
| 188 | tx = db.Order(clause.OrderByColumn{ |
| 189 | Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey}, |
| 190 | }).Session(&Session{}) |
| 191 | queryDB = tx |
| 192 | rowsAffected int64 |
| 193 | batch int |
| 194 | ) |
| 195 | |
| 196 | // user specified offset or limit |
| 197 | var totalSize int |
| 198 | if c, ok := tx.Statement.Clauses["LIMIT"]; ok { |
| 199 | if limit, ok := c.Expression.(clause.Limit); ok { |
| 200 | if limit.Limit != nil { |
| 201 | totalSize = *limit.Limit |
| 202 | } |
| 203 | |
| 204 | if totalSize > 0 && batchSize > totalSize { |
| 205 | batchSize = totalSize |
| 206 | } |
| 207 | |
| 208 | // reset to offset to 0 in next batch |
| 209 | tx = tx.Offset(-1).Session(&Session{}) |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | for { |
| 214 | result := queryDB.Limit(batchSize).Find(dest) |
| 215 | rowsAffected += result.RowsAffected |
| 216 | batch++ |
| 217 | |
| 218 | if result.Error == nil && result.RowsAffected != 0 { |
| 219 | fcTx := result.Session(&Session{NewDB: true}) |
| 220 | fcTx.RowsAffected = result.RowsAffected |
| 221 | tx.AddError(fc(fcTx, batch)) |
| 222 | } else if result.Error != nil { |
| 223 | tx.AddError(result.Error) |
| 224 | } |
| 225 | |
| 226 | if tx.Error != nil || int(result.RowsAffected) < batchSize { |
| 227 | break |
| 228 | } |
| 229 | |
| 230 | if totalSize > 0 { |
| 231 | if totalSize <= int(rowsAffected) { |
| 232 | break |
| 233 | } |
| 234 | if totalSize/batchSize == batch { |
| 235 | batchSize = totalSize % batchSize |
| 236 | } |
| 237 | } |
| 238 | |
| 239 | // Optimize for-break |
| 240 | resultsValue := reflect.Indirect(reflect.ValueOf(dest)) |
| 241 | if result.Statement.Schema.PrioritizedPrimaryField == nil { |
| 242 | tx.AddError(ErrPrimaryKeyRequired) |
| 243 | break |