github.com/apache/arrow/go/v16@v16.1.0/arrow/array/timestamp.go (about)

     1  // Licensed to the Apache Software Foundation (ASF) under one
     2  // or more contributor license agreements.  See the NOTICE file
     3  // distributed with this work for additional information
     4  // regarding copyright ownership.  The ASF licenses this file
     5  // to you under the Apache License, Version 2.0 (the
     6  // "License"); you may not use this file except in compliance
     7  // with the License.  You may obtain a copy of the License at
     8  //
     9  // http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing, software
    12  // distributed under the License is distributed on an "AS IS" BASIS,
    13  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  // See the License for the specific language governing permissions and
    15  // limitations under the License.
    16  
    17  package array
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"reflect"
    23  	"strings"
    24  	"sync/atomic"
    25  	"time"
    26  
    27  	"github.com/apache/arrow/go/v16/arrow"
    28  	"github.com/apache/arrow/go/v16/arrow/bitutil"
    29  	"github.com/apache/arrow/go/v16/arrow/internal/debug"
    30  	"github.com/apache/arrow/go/v16/arrow/memory"
    31  	"github.com/apache/arrow/go/v16/internal/json"
    32  )
    33  
    34  // Timestamp represents an immutable sequence of arrow.Timestamp values.
    35  type Timestamp struct {
    36  	array
    37  	values []arrow.Timestamp
    38  }
    39  
    40  // NewTimestampData creates a new Timestamp from Data.
    41  func NewTimestampData(data arrow.ArrayData) *Timestamp {
    42  	a := &Timestamp{}
    43  	a.refCount = 1
    44  	a.setData(data.(*Data))
    45  	return a
    46  }
    47  
    48  // Reset resets the array for re-use.
    49  func (a *Timestamp) Reset(data *Data) {
    50  	a.setData(data)
    51  }
    52  
    53  // Value returns the value at the specified index.
    54  func (a *Timestamp) Value(i int) arrow.Timestamp { return a.values[i] }
    55  
    56  // TimestampValues returns the values.
    57  func (a *Timestamp) TimestampValues() []arrow.Timestamp { return a.values }
    58  
    59  // String returns a string representation of the array.
    60  func (a *Timestamp) String() string {
    61  	o := new(strings.Builder)
    62  	o.WriteString("[")
    63  	for i, v := range a.values {
    64  		if i > 0 {
    65  			fmt.Fprintf(o, " ")
    66  		}
    67  		switch {
    68  		case a.IsNull(i):
    69  			o.WriteString(NullValueStr)
    70  		default:
    71  			fmt.Fprintf(o, "%v", v)
    72  		}
    73  	}
    74  	o.WriteString("]")
    75  	return o.String()
    76  }
    77  
    78  func (a *Timestamp) setData(data *Data) {
    79  	a.array.setData(data)
    80  	vals := data.buffers[1]
    81  	if vals != nil {
    82  		a.values = arrow.TimestampTraits.CastFromBytes(vals.Bytes())
    83  		beg := a.array.data.offset
    84  		end := beg + a.array.data.length
    85  		a.values = a.values[beg:end]
    86  	}
    87  }
    88  
    89  func (a *Timestamp) ValueStr(i int) string {
    90  	if a.IsNull(i) {
    91  		return NullValueStr
    92  	}
    93  
    94  	toTime, _ := a.DataType().(*arrow.TimestampType).GetToTimeFunc()
    95  	return toTime(a.values[i]).Format("2006-01-02 15:04:05.999999999Z0700")
    96  }
    97  
    98  func (a *Timestamp) GetOneForMarshal(i int) interface{} {
    99  	if val := a.ValueStr(i); val != NullValueStr {
   100  		return val
   101  	}
   102  	return nil
   103  }
   104  
   105  func (a *Timestamp) MarshalJSON() ([]byte, error) {
   106  	vals := make([]interface{}, a.Len())
   107  	for i := range a.values {
   108  		vals[i] = a.GetOneForMarshal(i)
   109  	}
   110  
   111  	return json.Marshal(vals)
   112  }
   113  
   114  func arrayEqualTimestamp(left, right *Timestamp) bool {
   115  	for i := 0; i < left.Len(); i++ {
   116  		if left.IsNull(i) {
   117  			continue
   118  		}
   119  		if left.Value(i) != right.Value(i) {
   120  			return false
   121  		}
   122  	}
   123  	return true
   124  }
   125  
   126  type TimestampBuilder struct {
   127  	builder
   128  
   129  	dtype   *arrow.TimestampType
   130  	data    *memory.Buffer
   131  	rawData []arrow.Timestamp
   132  }
   133  
   134  func NewTimestampBuilder(mem memory.Allocator, dtype *arrow.TimestampType) *TimestampBuilder {
   135  	return &TimestampBuilder{builder: builder{refCount: 1, mem: mem}, dtype: dtype}
   136  }
   137  
   138  func (b *TimestampBuilder) Type() arrow.DataType { return b.dtype }
   139  
   140  // Release decreases the reference count by 1.
   141  // When the reference count goes to zero, the memory is freed.
   142  func (b *TimestampBuilder) Release() {
   143  	debug.Assert(atomic.LoadInt64(&b.refCount) > 0, "too many releases")
   144  
   145  	if atomic.AddInt64(&b.refCount, -1) == 0 {
   146  		if b.nullBitmap != nil {
   147  			b.nullBitmap.Release()
   148  			b.nullBitmap = nil
   149  		}
   150  		if b.data != nil {
   151  			b.data.Release()
   152  			b.data = nil
   153  			b.rawData = nil
   154  		}
   155  	}
   156  }
   157  
   158  func (b *TimestampBuilder) AppendTime(t time.Time) {
   159  	ts, err := arrow.TimestampFromTime(t, b.dtype.Unit)
   160  	if err != nil {
   161  		panic(err)
   162  	}
   163  	b.Append(ts)
   164  }
   165  
   166  func (b *TimestampBuilder) Append(v arrow.Timestamp) {
   167  	b.Reserve(1)
   168  	b.UnsafeAppend(v)
   169  }
   170  
   171  func (b *TimestampBuilder) AppendNull() {
   172  	b.Reserve(1)
   173  	b.UnsafeAppendBoolToBitmap(false)
   174  }
   175  
   176  func (b *TimestampBuilder) AppendNulls(n int) {
   177  	for i := 0; i < n; i++ {
   178  		b.AppendNull()
   179  	}
   180  }
   181  
   182  func (b *TimestampBuilder) AppendEmptyValue() {
   183  	b.Append(0)
   184  }
   185  
   186  func (b *TimestampBuilder) AppendEmptyValues(n int) {
   187  	for i := 0; i < n; i++ {
   188  		b.AppendEmptyValue()
   189  	}
   190  }
   191  
   192  func (b *TimestampBuilder) UnsafeAppend(v arrow.Timestamp) {
   193  	bitutil.SetBit(b.nullBitmap.Bytes(), b.length)
   194  	b.rawData[b.length] = v
   195  	b.length++
   196  }
   197  
   198  func (b *TimestampBuilder) UnsafeAppendBoolToBitmap(isValid bool) {
   199  	if isValid {
   200  		bitutil.SetBit(b.nullBitmap.Bytes(), b.length)
   201  	} else {
   202  		b.nulls++
   203  	}
   204  	b.length++
   205  }
   206  
   207  // AppendValues will append the values in the v slice. The valid slice determines which values
   208  // in v are valid (not null). The valid slice must either be empty or be equal in length to v. If empty,
   209  // all values in v are appended and considered valid.
   210  func (b *TimestampBuilder) AppendValues(v []arrow.Timestamp, valid []bool) {
   211  	if len(v) != len(valid) && len(valid) != 0 {
   212  		panic("len(v) != len(valid) && len(valid) != 0")
   213  	}
   214  
   215  	if len(v) == 0 {
   216  		return
   217  	}
   218  
   219  	b.Reserve(len(v))
   220  	arrow.TimestampTraits.Copy(b.rawData[b.length:], v)
   221  	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
   222  }
   223  
   224  func (b *TimestampBuilder) init(capacity int) {
   225  	b.builder.init(capacity)
   226  
   227  	b.data = memory.NewResizableBuffer(b.mem)
   228  	bytesN := arrow.TimestampTraits.BytesRequired(capacity)
   229  	b.data.Resize(bytesN)
   230  	b.rawData = arrow.TimestampTraits.CastFromBytes(b.data.Bytes())
   231  }
   232  
   233  // Reserve ensures there is enough space for appending n elements
   234  // by checking the capacity and calling Resize if necessary.
   235  func (b *TimestampBuilder) Reserve(n int) {
   236  	b.builder.reserve(n, b.Resize)
   237  }
   238  
   239  // Resize adjusts the space allocated by b to n elements. If n is greater than b.Cap(),
   240  // additional memory will be allocated. If n is smaller, the allocated memory may reduced.
   241  func (b *TimestampBuilder) Resize(n int) {
   242  	nBuilder := n
   243  	if n < minBuilderCapacity {
   244  		n = minBuilderCapacity
   245  	}
   246  
   247  	if b.capacity == 0 {
   248  		b.init(n)
   249  	} else {
   250  		b.builder.resize(nBuilder, b.init)
   251  		b.data.Resize(arrow.TimestampTraits.BytesRequired(n))
   252  		b.rawData = arrow.TimestampTraits.CastFromBytes(b.data.Bytes())
   253  	}
   254  }
   255  
   256  // NewArray creates a Timestamp array from the memory buffers used by the builder and resets the TimestampBuilder
   257  // so it can be used to build a new array.
   258  func (b *TimestampBuilder) NewArray() arrow.Array {
   259  	return b.NewTimestampArray()
   260  }
   261  
   262  // NewTimestampArray creates a Timestamp array from the memory buffers used by the builder and resets the TimestampBuilder
   263  // so it can be used to build a new array.
   264  func (b *TimestampBuilder) NewTimestampArray() (a *Timestamp) {
   265  	data := b.newData()
   266  	a = NewTimestampData(data)
   267  	data.Release()
   268  	return
   269  }
   270  
   271  func (b *TimestampBuilder) newData() (data *Data) {
   272  	bytesRequired := arrow.TimestampTraits.BytesRequired(b.length)
   273  	if bytesRequired > 0 && bytesRequired < b.data.Len() {
   274  		// trim buffers
   275  		b.data.Resize(bytesRequired)
   276  	}
   277  	data = NewData(b.dtype, b.length, []*memory.Buffer{b.nullBitmap, b.data}, nil, b.nulls, 0)
   278  	b.reset()
   279  
   280  	if b.data != nil {
   281  		b.data.Release()
   282  		b.data = nil
   283  		b.rawData = nil
   284  	}
   285  
   286  	return
   287  }
   288  
   289  func (b *TimestampBuilder) AppendValueFromString(s string) error {
   290  	if s == NullValueStr {
   291  		b.AppendNull()
   292  		return nil
   293  	}
   294  
   295  	loc, err := b.dtype.GetZone()
   296  	if err != nil {
   297  		return err
   298  	}
   299  
   300  	v, _, err := arrow.TimestampFromStringInLocation(s, b.dtype.Unit, loc)
   301  	if err != nil {
   302  		b.AppendNull()
   303  		return err
   304  	}
   305  	b.Append(v)
   306  	return nil
   307  }
   308  
   309  func (b *TimestampBuilder) UnmarshalOne(dec *json.Decoder) error {
   310  	t, err := dec.Token()
   311  	if err != nil {
   312  		return err
   313  	}
   314  
   315  	switch v := t.(type) {
   316  	case nil:
   317  		b.AppendNull()
   318  	case string:
   319  		loc, _ := b.dtype.GetZone()
   320  		tm, _, err := arrow.TimestampFromStringInLocation(v, b.dtype.Unit, loc)
   321  		if err != nil {
   322  			return &json.UnmarshalTypeError{
   323  				Value:  v,
   324  				Type:   reflect.TypeOf(arrow.Timestamp(0)),
   325  				Offset: dec.InputOffset(),
   326  			}
   327  		}
   328  
   329  		b.Append(tm)
   330  	case json.Number:
   331  		n, err := v.Int64()
   332  		if err != nil {
   333  			return &json.UnmarshalTypeError{
   334  				Value:  v.String(),
   335  				Type:   reflect.TypeOf(arrow.Timestamp(0)),
   336  				Offset: dec.InputOffset(),
   337  			}
   338  		}
   339  		b.Append(arrow.Timestamp(n))
   340  	case float64:
   341  		b.Append(arrow.Timestamp(v))
   342  
   343  	default:
   344  		return &json.UnmarshalTypeError{
   345  			Value:  fmt.Sprint(t),
   346  			Type:   reflect.TypeOf(arrow.Timestamp(0)),
   347  			Offset: dec.InputOffset(),
   348  		}
   349  	}
   350  
   351  	return nil
   352  }
   353  
   354  func (b *TimestampBuilder) Unmarshal(dec *json.Decoder) error {
   355  	for dec.More() {
   356  		if err := b.UnmarshalOne(dec); err != nil {
   357  			return err
   358  		}
   359  	}
   360  	return nil
   361  }
   362  
   363  func (b *TimestampBuilder) UnmarshalJSON(data []byte) error {
   364  	dec := json.NewDecoder(bytes.NewReader(data))
   365  	t, err := dec.Token()
   366  	if err != nil {
   367  		return err
   368  	}
   369  
   370  	if delim, ok := t.(json.Delim); !ok || delim != '[' {
   371  		return fmt.Errorf("binary builder must unpack from json array, found %s", delim)
   372  	}
   373  
   374  	return b.Unmarshal(dec)
   375  }
   376  
   377  var (
   378  	_ arrow.Array = (*Timestamp)(nil)
   379  	_ Builder     = (*TimestampBuilder)(nil)
   380  )