@@ -23,6 +23,7 @@ import (
2323
2424 "github.com/apache/arrow/go/arrow"
2525 "github.com/apache/arrow/go/arrow/internal/debug"
26+ "github.com/apache/arrow/go/arrow/memory"
2627)
2728
2829// RecordReader reads a stream of records.
@@ -115,6 +116,8 @@ type Record interface {
115116
116117 NumRows () int64
117118 NumCols () int64
119+
120+ Columns () []Interface
118121 Column (i int ) Interface
119122 ColumnName (i int ) string
120123
@@ -217,6 +220,7 @@ func (rec *simpleRecord) Release() {
217220func (rec * simpleRecord ) Schema () * arrow.Schema { return rec .schema }
218221func (rec * simpleRecord ) NumRows () int64 { return rec .rows }
219222func (rec * simpleRecord ) NumCols () int64 { return int64 (len (rec .arrs )) }
223+ func (rec * simpleRecord ) Columns () []Interface { return rec .arrs }
220224func (rec * simpleRecord ) Column (i int ) Interface { return rec .arrs [i ] }
221225func (rec * simpleRecord ) ColumnName (i int ) string { return rec .schema .Field (i ).Name }
222226
@@ -239,6 +243,91 @@ func (rec *simpleRecord) NewSlice(i, j int64) Record {
239243 return NewRecord (rec .schema , arrs , j - i )
240244}
241245
246+ // RecordBuilder eases the process of building a Record, iteratively, from
247+ // a known Schema.
248+ type RecordBuilder struct {
249+ refCount int64
250+ mem memory.Allocator
251+ schema * arrow.Schema
252+ fields []Builder
253+ }
254+
255+ // NewRecordBuilder returns a builder, using the provided memory allocator and a schema.
256+ func NewRecordBuilder (mem memory.Allocator , schema * arrow.Schema ) * RecordBuilder {
257+ b := & RecordBuilder {
258+ refCount : 1 ,
259+ mem : mem ,
260+ schema : schema ,
261+ fields : make ([]Builder , len (schema .Fields ())),
262+ }
263+
264+ for i , f := range schema .Fields () {
265+ b .fields [i ] = newBuilder (b .mem , f .Type )
266+ }
267+
268+ return b
269+ }
270+
271+ // Retain increases the reference count by 1.
272+ // Retain may be called simultaneously from multiple goroutines.
273+ func (b * RecordBuilder ) Retain () {
274+ atomic .AddInt64 (& b .refCount , 1 )
275+ }
276+
277+ // Release decreases the reference count by 1.
278+ func (b * RecordBuilder ) Release () {
279+ debug .Assert (atomic .LoadInt64 (& b .refCount ) > 0 , "too many releases" )
280+
281+ for _ , f := range b .fields {
282+ f .Release ()
283+ }
284+
285+ if atomic .AddInt64 (& b .refCount , - 1 ) == 0 {
286+ b .fields = nil
287+ }
288+ }
289+
290+ func (b * RecordBuilder ) Schema () * arrow.Schema { return b .schema }
291+ func (b * RecordBuilder ) Fields () []Builder { return b .fields }
292+ func (b * RecordBuilder ) Field (i int ) Builder { return b .fields [i ] }
293+
294+ func (b * RecordBuilder ) Reserve (size int ) {
295+ for _ , f := range b .fields {
296+ f .Reserve (size )
297+ }
298+ }
299+
300+ // NewRecord creates a new record from the memory buffers and resets the
301+ // RecordBuilder so it can be used to build a new record.
302+ //
303+ // The returned Record must be Release()'d after use.
304+ //
305+ // NewRecord panics if the fields' builder do not have the same length.
306+ func (b * RecordBuilder ) NewRecord () Record {
307+ cols := make ([]Interface , len (b .fields ))
308+ rows := int64 (0 )
309+
310+ defer func (cols []Interface ) {
311+ for _ , col := range cols {
312+ if col == nil {
313+ continue
314+ }
315+ col .Release ()
316+ }
317+ }(cols )
318+
319+ for i , f := range b .fields {
320+ cols [i ] = f .NewArray ()
321+ irow := int64 (cols [i ].Len ())
322+ if i > 0 && irow != rows {
323+ panic (fmt .Errorf ("arrow/array: field %d has %d rows. want=%d" , i , irow , rows ))
324+ }
325+ rows = irow
326+ }
327+
328+ return NewRecord (b .schema , cols , rows )
329+ }
330+
242331var (
243332 _ Record = (* simpleRecord )(nil )
244333 _ RecordReader = (* simpleRecords )(nil )
0 commit comments