package sqlbuilder import ( "github.com/upper/db/v4" ) // BatchInserter provides a helper that can be used to do massive insertions in // batches. type BatchInserter struct { inserter *inserter size int values chan []interface{} err error } func newBatchInserter(inserter *inserter, size int) *BatchInserter { if size < 1 { size = 1 } b := &BatchInserter{ inserter: inserter, size: size, values: make(chan []interface{}, size), } return b } // Values pushes column values to be inserted as part of the batch. func (b *BatchInserter) Values(values ...interface{}) db.BatchInserter { b.values <- values return b } func (b *BatchInserter) nextQuery() *inserter { ins := &inserter{} *ins = *b.inserter i := 0 for values := range b.values { i++ ins = ins.Values(values...).(*inserter) if i == b.size { break } } if i == 0 { return nil } return ins } // NextResult is useful when using PostgreSQL and Returning(), it dumps the // next slice of results to dst, which can mean having the IDs of all inserted // elements in the batch. func (b *BatchInserter) NextResult(dst interface{}) bool { clone := b.nextQuery() if clone == nil { return false } b.err = clone.Iterator().All(dst) return (b.err == nil) } // Done means that no more elements are going to be added. func (b *BatchInserter) Done() { close(b.values) } // Wait blocks until the whole batch is executed. func (b *BatchInserter) Wait() error { for { q := b.nextQuery() if q == nil { break } if _, err := q.Exec(); err != nil { b.err = err break } } return b.Err() } // Err returns any error while executing the batch. func (b *BatchInserter) Err() error { return b.err }