| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package scalar |
| |
| import ( |
| "fmt" |
| "reflect" |
| "time" |
| "unsafe" |
| |
| "github.com/apache/arrow/go/v10/arrow" |
| ) |
| |
| func temporalToString(s TemporalScalar) string { |
| switch s := s.(type) { |
| case *Date32: |
| return time.Unix(0, 0).UTC().AddDate(0, 0, int(s.Value)).Format("2006-01-02") |
| case *Date64: |
| days := int(int64(s.Value) / (time.Hour * 24).Milliseconds()) |
| return time.Unix(0, 0).UTC().AddDate(0, 0, days).Format("2006-01-02") |
| case *Duration: |
| return fmt.Sprint(time.Duration(s.Value) * s.Unit().Multiplier()) |
| case *Time32: |
| return time.Unix(0, int64(s.Value)*int64(s.Unit().Multiplier())).UTC().Format("15:04:05.999") |
| case *Time64: |
| return time.Unix(0, int64(s.Value)*int64(s.Unit().Multiplier())).UTC().Format("15:04:05.999999999") |
| case *Timestamp: |
| return time.Unix(0, int64(s.Value)*int64(s.Unit().Multiplier())).UTC().Format("2006-01-02 15:04:05.999999999") |
| } |
| return "..." |
| } |
| |
| type TemporalScalar interface { |
| Scalar |
| temporal() |
| } |
| |
| type Duration struct { |
| scalar |
| Value arrow.Duration |
| } |
| |
| func (Duration) temporal() {} |
| func (s *Duration) value() interface{} { return s.Value } |
| func (s *Duration) CastTo(to arrow.DataType) (Scalar, error) { return castTemporal(s, to) } |
| func (s *Duration) String() string { |
| if !s.Valid { |
| return "null" |
| } |
| val, err := s.CastTo(arrow.BinaryTypes.String) |
| if err != nil { |
| return "..." |
| } |
| return string(val.(*String).Value.Bytes()) |
| } |
| |
| func (s *Duration) equals(rhs Scalar) bool { |
| return s.Value == rhs.(*Duration).Value |
| } |
| |
| func (s *Duration) Unit() arrow.TimeUnit { |
| return s.DataType().(*arrow.TimestampType).Unit |
| } |
| func (s *Duration) Data() []byte { |
| return (*[arrow.DurationSizeBytes]byte)(unsafe.Pointer(&s.Value))[:] |
| } |
| |
| func NewDurationScalar(val arrow.Duration, typ arrow.DataType) *Duration { |
| return &Duration{scalar{typ, true}, val} |
| } |
| |
| type DateScalar interface { |
| TemporalScalar |
| date() |
| } |
| |
| type TimeScalar interface { |
| TemporalScalar |
| Unit() arrow.TimeUnit |
| time() |
| } |
| |
| type IntervalScalar interface { |
| TemporalScalar |
| interval() |
| } |
| |
| const millisecondsInDay = (time.Hour * 24) / time.Millisecond |
| |
| func castTemporal(from TemporalScalar, to arrow.DataType) (Scalar, error) { |
| if arrow.TypeEqual(from.DataType(), to) { |
| return from, nil |
| } |
| |
| if !from.IsValid() { |
| return MakeNullScalar(to), nil |
| } |
| |
| if r, ok := numericMap[to.ID()]; ok { |
| return convertToNumeric(reflect.ValueOf(from.value()), r.valueType, r.scalarFunc), nil |
| } |
| |
| if to.ID() == arrow.STRING { |
| return NewStringScalar(temporalToString(from)), nil |
| } |
| |
| switch s := from.(type) { |
| case DateScalar: |
| if to.ID() == arrow.TIMESTAMP { |
| var newValue int64 |
| switch s := s.(type) { |
| case *Date32: |
| newValue = int64(s.Value) * int64(millisecondsInDay) |
| case *Date64: |
| newValue = int64(s.Value) |
| } |
| return NewTimestampScalar(arrow.Timestamp(arrow.ConvertTimestampValue(arrow.Millisecond, to.(*arrow.TimestampType).Unit, newValue)), to), nil |
| } |
| |
| switch s := s.(type) { |
| case *Date32: |
| if to.ID() == arrow.DATE64 { |
| return NewDate64Scalar(arrow.Date64(s.Value) * arrow.Date64(millisecondsInDay)), nil |
| } |
| case *Date64: |
| if to.ID() == arrow.DATE32 { |
| return NewDate32Scalar(arrow.Date32(s.Value / arrow.Date64(millisecondsInDay))), nil |
| } |
| } |
| case *Timestamp: |
| switch to := to.(type) { |
| case *arrow.TimestampType: |
| return NewTimestampScalar(arrow.Timestamp(arrow.ConvertTimestampValue(s.Unit(), to.Unit, int64(s.Value))), to), nil |
| case *arrow.Date32Type: |
| millis := arrow.ConvertTimestampValue(s.Unit(), arrow.Millisecond, int64(s.Value)) |
| return NewDate32Scalar(arrow.Date32(millis / int64(millisecondsInDay))), nil |
| case *arrow.Date64Type: |
| millis := arrow.ConvertTimestampValue(s.Unit(), arrow.Millisecond, int64(s.Value)) |
| return NewDate64Scalar(arrow.Date64(millis - millis%int64(millisecondsInDay))), nil |
| } |
| case TimeScalar: |
| switch to := to.(type) { |
| case *arrow.Time32Type: |
| return NewTime32Scalar(arrow.Time32(arrow.ConvertTimestampValue(s.Unit(), to.Unit, int64(s.value().(arrow.Time64)))), to), nil |
| case *arrow.Time64Type: |
| return NewTime64Scalar(arrow.Time64(arrow.ConvertTimestampValue(s.Unit(), to.Unit, int64(s.value().(arrow.Time32)))), to), nil |
| } |
| |
| case *Duration: |
| switch to := to.(type) { |
| case *arrow.StringType: |
| |
| case *arrow.DurationType: |
| return NewDurationScalar(arrow.Duration(arrow.ConvertTimestampValue(s.Unit(), to.Unit, int64(s.Value))), to), nil |
| } |
| } |
| |
| return nil, fmt.Errorf("") |
| } |
| |
| type Date32 struct { |
| scalar |
| Value arrow.Date32 |
| } |
| |
| func (Date32) temporal() {} |
| func (Date32) date() {} |
| func (s *Date32) value() interface{} { return s.Value } |
| func (s *Date32) Data() []byte { |
| return (*[arrow.Date32SizeBytes]byte)(unsafe.Pointer(&s.Value))[:] |
| } |
| func (s *Date32) equals(rhs Scalar) bool { |
| return s.Value == rhs.(*Date32).Value |
| } |
| func (s *Date32) CastTo(to arrow.DataType) (Scalar, error) { return castTemporal(s, to) } |
| func (s *Date32) String() string { |
| if !s.Valid { |
| return "null" |
| } |
| val, err := s.CastTo(arrow.BinaryTypes.String) |
| if err != nil { |
| return "..." |
| } |
| return string(val.(*String).Value.Bytes()) |
| } |
| |
| func NewDate32Scalar(val arrow.Date32) *Date32 { |
| return &Date32{scalar{arrow.FixedWidthTypes.Date32, true}, val} |
| } |
| |
| type Date64 struct { |
| scalar |
| Value arrow.Date64 |
| } |
| |
| func (Date64) temporal() {} |
| func (Date64) date() {} |
| func (s *Date64) value() interface{} { return s.Value } |
| func (s *Date64) CastTo(to arrow.DataType) (Scalar, error) { return castTemporal(s, to) } |
| func (s *Date64) Data() []byte { |
| return (*[arrow.Date64SizeBytes]byte)(unsafe.Pointer(&s.Value))[:] |
| } |
| func (s *Date64) equals(rhs Scalar) bool { |
| return s.Value == rhs.(*Date64).Value |
| } |
| func (s *Date64) String() string { |
| if !s.Valid { |
| return "null" |
| } |
| val, err := s.CastTo(arrow.BinaryTypes.String) |
| if err != nil { |
| return "..." |
| } |
| return string(val.(*String).Value.Bytes()) |
| } |
| |
| func NewDate64Scalar(val arrow.Date64) *Date64 { |
| return &Date64{scalar{arrow.FixedWidthTypes.Date64, true}, val} |
| } |
| |
| type Time32 struct { |
| scalar |
| Value arrow.Time32 |
| } |
| |
| func (Time32) temporal() {} |
| func (Time32) time() {} |
| func (s *Time32) value() interface{} { return s.Value } |
| func (s *Time32) CastTo(to arrow.DataType) (Scalar, error) { return castTemporal(s, to) } |
| func (s *Time32) Unit() arrow.TimeUnit { |
| return s.DataType().(*arrow.Time32Type).Unit |
| } |
| func (s *Time32) equals(rhs Scalar) bool { |
| return s.Value == rhs.(*Time32).Value |
| } |
| func (s *Time32) String() string { |
| if !s.Valid { |
| return "null" |
| } |
| val, err := s.CastTo(arrow.BinaryTypes.String) |
| if err != nil { |
| return "..." |
| } |
| return string(val.(*String).Value.Bytes()) |
| } |
| |
| func (s *Time32) Data() []byte { |
| return (*[arrow.Time32SizeBytes]byte)(unsafe.Pointer(&s.Value))[:] |
| } |
| |
| func NewTime32Scalar(val arrow.Time32, typ arrow.DataType) *Time32 { |
| return &Time32{scalar{typ, true}, val} |
| } |
| |
| type Time64 struct { |
| scalar |
| Value arrow.Time64 |
| } |
| |
| func (Time64) temporal() {} |
| func (Time64) time() {} |
| func (s *Time64) value() interface{} { return s.Value } |
| func (s *Time64) CastTo(to arrow.DataType) (Scalar, error) { return castTemporal(s, to) } |
| func (s *Time64) Unit() arrow.TimeUnit { |
| return s.DataType().(*arrow.Time64Type).Unit |
| } |
| func (s *Time64) Data() []byte { |
| return (*[arrow.Time64SizeBytes]byte)(unsafe.Pointer(&s.Value))[:] |
| } |
| func (s *Time64) equals(rhs Scalar) bool { |
| return s.Value == rhs.(*Time64).Value |
| } |
| func (s *Time64) String() string { |
| if !s.Valid { |
| return "null" |
| } |
| val, err := s.CastTo(arrow.BinaryTypes.String) |
| if err != nil { |
| return "..." |
| } |
| return string(val.(*String).Value.Bytes()) |
| } |
| |
| func NewTime64Scalar(val arrow.Time64, typ arrow.DataType) *Time64 { |
| return &Time64{scalar{typ, true}, val} |
| } |
| |
| type Timestamp struct { |
| scalar |
| Value arrow.Timestamp |
| } |
| |
| func (Timestamp) temporal() {} |
| func (Timestamp) time() {} |
| func (s *Timestamp) value() interface{} { return s.Value } |
| func (s *Timestamp) CastTo(to arrow.DataType) (Scalar, error) { return castTemporal(s, to) } |
| func (s *Timestamp) Unit() arrow.TimeUnit { |
| return s.DataType().(*arrow.TimestampType).Unit |
| } |
| func (s *Timestamp) Data() []byte { |
| return (*[arrow.TimestampSizeBytes]byte)(unsafe.Pointer(&s.Value))[:] |
| } |
| func (s *Timestamp) equals(rhs Scalar) bool { |
| return s.Value == rhs.(*Timestamp).Value |
| } |
| func (s *Timestamp) String() string { |
| if !s.Valid { |
| return "null" |
| } |
| val, err := s.CastTo(arrow.BinaryTypes.String) |
| if err != nil { |
| return "..." |
| } |
| return string(val.(*String).Value.Bytes()) |
| } |
| |
| func NewTimestampScalar(val arrow.Timestamp, typ arrow.DataType) *Timestamp { |
| return &Timestamp{scalar{typ, true}, val} |
| } |
| |
| type MonthInterval struct { |
| scalar |
| Value arrow.MonthInterval |
| } |
| |
| func (MonthInterval) temporal() {} |
| func (MonthInterval) interval() {} |
| func (s *MonthInterval) value() interface{} { return s.Value } |
| func (s *MonthInterval) CastTo(to arrow.DataType) (Scalar, error) { |
| if !s.Valid { |
| return MakeNullScalar(to), nil |
| } |
| |
| if !arrow.TypeEqual(s.DataType(), to) { |
| return nil, fmt.Errorf("non-null monthinterval scalar cannot be cast to anything other than monthinterval") |
| } |
| |
| return s, nil |
| } |
| func (s *MonthInterval) String() string { |
| if !s.Valid { |
| return "null" |
| } |
| val, err := s.CastTo(arrow.BinaryTypes.String) |
| if err != nil { |
| return "..." |
| } |
| return string(val.(*String).Value.Bytes()) |
| } |
| func (s *MonthInterval) equals(rhs Scalar) bool { |
| return s.Value == rhs.(*MonthInterval).Value |
| } |
| func (s *MonthInterval) Data() []byte { |
| return (*[arrow.MonthIntervalSizeBytes]byte)(unsafe.Pointer(&s.Value))[:] |
| } |
| |
| func NewMonthIntervalScalar(val arrow.MonthInterval) *MonthInterval { |
| return &MonthInterval{scalar{arrow.FixedWidthTypes.MonthInterval, true}, val} |
| } |
| |
| type DayTimeInterval struct { |
| scalar |
| Value arrow.DayTimeInterval |
| } |
| |
| func (DayTimeInterval) temporal() {} |
| func (DayTimeInterval) interval() {} |
| func (s *DayTimeInterval) value() interface{} { return s.Value } |
| func (s *DayTimeInterval) Data() []byte { |
| return (*[arrow.DayTimeIntervalSizeBytes]byte)(unsafe.Pointer(&s.Value))[:] |
| } |
| func (s *DayTimeInterval) String() string { |
| if !s.Valid { |
| return "null" |
| } |
| val, err := s.CastTo(arrow.BinaryTypes.String) |
| if err != nil { |
| return "..." |
| } |
| return string(val.(*String).Value.Bytes()) |
| } |
| |
| func (s *DayTimeInterval) CastTo(to arrow.DataType) (Scalar, error) { |
| if !s.Valid { |
| return MakeNullScalar(to), nil |
| } |
| |
| if !arrow.TypeEqual(s.DataType(), to) { |
| return nil, fmt.Errorf("non-null daytimeinterval scalar cannot be cast to anything other than monthinterval") |
| } |
| |
| return s, nil |
| } |
| |
| func (s *DayTimeInterval) equals(rhs Scalar) bool { |
| return s.Value == rhs.(*DayTimeInterval).Value |
| } |
| |
| func NewDayTimeIntervalScalar(val arrow.DayTimeInterval) *DayTimeInterval { |
| return &DayTimeInterval{scalar{arrow.FixedWidthTypes.DayTimeInterval, true}, val} |
| } |
| |
| type MonthDayNanoInterval struct { |
| scalar |
| Value arrow.MonthDayNanoInterval |
| } |
| |
| func (MonthDayNanoInterval) temporal() {} |
| func (MonthDayNanoInterval) interval() {} |
| func (s *MonthDayNanoInterval) value() interface{} { return s.Value } |
| func (s *MonthDayNanoInterval) Data() []byte { |
| return (*[arrow.MonthDayNanoIntervalSizeBytes]byte)(unsafe.Pointer(&s.Value))[:] |
| } |
| func (s *MonthDayNanoInterval) String() string { |
| if !s.Valid { |
| return "null" |
| } |
| val, err := s.CastTo(arrow.BinaryTypes.String) |
| if err != nil { |
| return "..." |
| } |
| return string(val.(*String).Value.Bytes()) |
| } |
| |
| func (s *MonthDayNanoInterval) CastTo(to arrow.DataType) (Scalar, error) { |
| if !s.Valid { |
| return MakeNullScalar(to), nil |
| } |
| |
| if !arrow.TypeEqual(s.DataType(), to) { |
| return nil, fmt.Errorf("non-null month_day_nano_interval scalar cannot be cast to anything other than monthinterval") |
| } |
| |
| return s, nil |
| } |
| |
| func (s *MonthDayNanoInterval) equals(rhs Scalar) bool { |
| return s.Value == rhs.(*MonthDayNanoInterval).Value |
| } |
| |
| func NewMonthDayNanoIntervalScalar(val arrow.MonthDayNanoInterval) *MonthDayNanoInterval { |
| return &MonthDayNanoInterval{scalar{arrow.FixedWidthTypes.MonthDayNanoInterval, true}, val} |
| } |
| |
| var ( |
| _ Scalar = (*Date32)(nil) |
| ) |