blob: 38a3dd98e495915d9e9dae5f677af8dae5ef6963 [file] [log] [blame]
// 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)
)