This is an automated email from the ASF dual-hosted git repository.
zeroshade pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/master by this push:
new ac12a7a ARROW-13789: [Go] Implement Scalar Values for Go
ac12a7a is described below
commit ac12a7aa21feda67ee342367e7447d2f1315bb11
Author: Matthew Topol <[email protected]>
AuthorDate: Fri Sep 24 15:25:31 2021 -0400
ARROW-13789: [Go] Implement Scalar Values for Go
In preparation for trying to expose the Compute APIs vs CGO, first we need
to have Scalar values implemented. After this, we can implement compatible
Expression tree handling for serializing between the C++ and the Golang
Closes #11024 from zeroshade/scalars
Lead-authored-by: Matthew Topol <[email protected]>
Co-authored-by: Matt Topol <[email protected]>
Signed-off-by: Matthew Topol <[email protected]>
---
go/arrow/datatype_fixedwidth.go | 5 +
go/arrow/datatype_nested.go | 5 +
go/arrow/doc.go | 1 +
go/arrow/go.sum | 1 -
go/arrow/scalar/binary.go | 159 +++++++
go/arrow/scalar/compare.go | 44 ++
go/arrow/scalar/nested.go | 308 +++++++++++++
go/arrow/scalar/numeric.gen.go | 697 ++++++++++++++++++++++++++++
go/arrow/scalar/numeric.gen.go.tmpl | 98 ++++
go/arrow/scalar/numeric.gen.go.tmpldata | 52 +++
go/arrow/scalar/numeric.gen_test.go | 377 +++++++++++++++
go/arrow/scalar/numeric.gen_test.go.tmpl | 63 +++
go/arrow/scalar/parse.go | 336 ++++++++++++++
go/arrow/scalar/scalar.go | 612 ++++++++++++++++++++++++
go/arrow/scalar/scalar_test.go | 769 +++++++++++++++++++++++++++++++
go/arrow/scalar/temporal.go | 469 +++++++++++++++++++
16 files changed, 3995 insertions(+), 1 deletion(-)
diff --git a/go/arrow/datatype_fixedwidth.go b/go/arrow/datatype_fixedwidth.go
index c90ee68..d2e9304 100644
--- a/go/arrow/datatype_fixedwidth.go
+++ b/go/arrow/datatype_fixedwidth.go
@@ -19,6 +19,7 @@ package arrow
import (
"fmt"
"strconv"
+ "time"
)
type BooleanType struct{}
@@ -59,6 +60,10 @@ const (
Second
)
+func (u TimeUnit) Multiplier() time.Duration {
+ return [...]time.Duration{time.Nanosecond, time.Microsecond,
time.Millisecond, time.Second}[uint(u)&3]
+}
+
func (u TimeUnit) String() string { return [...]string{"ns", "us", "ms",
"s"}[uint(u)&3] }
// TimestampType is encoded as a 64-bit signed integer since the UNIX epoch
(2017-01-01T00:00:00Z).
diff --git a/go/arrow/datatype_nested.go b/go/arrow/datatype_nested.go
index 9350c35..c4f5557 100644
--- a/go/arrow/datatype_nested.go
+++ b/go/arrow/datatype_nested.go
@@ -148,6 +148,11 @@ func (t *StructType) FieldByName(name string) (Field,
bool) {
return t.fields[i], true
}
+func (t *StructType) FieldIdx(name string) (int, bool) {
+ i, ok := t.index[name]
+ return i, ok
+}
+
type MapType struct {
value *ListType
KeysSorted bool
diff --git a/go/arrow/doc.go b/go/arrow/doc.go
index 10ddda9..bfa210d 100644
--- a/go/arrow/doc.go
+++ b/go/arrow/doc.go
@@ -33,6 +33,7 @@ package arrow
//go:generate go run _tools/tmpl/main.go -i -data=numeric.tmpldata
type_traits_numeric.gen.go.tmpl type_traits_numeric.gen_test.go.tmpl
array/numeric.gen.go.tmpl array/numericbuilder.gen.go.tmpl
array/bufferbuilder_numeric.gen.go.tmpl
//go:generate go run _tools/tmpl/main.go -i
-data=datatype_numeric.gen.go.tmpldata datatype_numeric.gen.go.tmpl
tensor/numeric.gen.go.tmpl tensor/numeric.gen_test.go.tmpl
+//go:generate go run _tools/tmpl/main.go -i
-data=scalar/numeric.gen.go.tmpldata scalar/numeric.gen.go.tmpl
scalar/numeric.gen_test.go.tmpl
//go:generate go run ./gen-flatbuffers.go
// stringer
diff --git a/go/arrow/go.sum b/go/arrow/go.sum
index 207218e..49f3a31 100644
--- a/go/arrow/go.sum
+++ b/go/arrow/go.sum
@@ -76,7 +76,6 @@ github.com/pmezard/go-difflib v1.0.0
h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod
h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/fastuuid v1.2.0/go.mod
h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
-github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod
h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
github.com/stretchr/objx v0.1.0/go.mod
h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod
h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.5.1/go.mod
h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
diff --git a/go/arrow/scalar/binary.go b/go/arrow/scalar/binary.go
new file mode 100644
index 0000000..62bbfab
--- /dev/null
+++ b/go/arrow/scalar/binary.go
@@ -0,0 +1,159 @@
+// 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 (
+ "bytes"
+ "unicode/utf8"
+
+ "github.com/apache/arrow/go/arrow"
+ "github.com/apache/arrow/go/arrow/memory"
+ "golang.org/x/xerrors"
+)
+
+type BinaryScalar interface {
+ Scalar
+
+ Retain()
+ Release()
+ Data() []byte
+}
+
+type Binary struct {
+ scalar
+
+ Value *memory.Buffer
+}
+
+func (b *Binary) Retain() { b.Value.Retain() }
+func (b *Binary) Release() { b.Value.Release() }
+func (b *Binary) value() interface{} { return b.Value }
+func (b *Binary) Data() []byte { return b.Value.Bytes() }
+func (b *Binary) equals(rhs Scalar) bool {
+ return bytes.Equal(b.Value.Bytes(), rhs.(BinaryScalar).Data())
+}
+func (b *Binary) String() string {
+ if !b.Valid {
+ return "null"
+ }
+
+ return string(b.Value.Bytes())
+}
+
+func (b *Binary) CastTo(to arrow.DataType) (Scalar, error) {
+ if !b.Valid {
+ return MakeNullScalar(to), nil
+ }
+
+ switch to.ID() {
+ case arrow.BINARY:
+ return b, nil
+ case arrow.STRING:
+ return NewStringScalarFromBuffer(b.Value), nil
+ case arrow.FIXED_SIZE_BINARY:
+ if b.Value.Len() == to.(*arrow.FixedSizeBinaryType).ByteWidth {
+ return NewFixedSizeBinaryScalar(b.Value, to), nil
+ }
+ }
+
+ return nil, xerrors.Errorf("cannot cast non-null binary scalar to type
%s", to)
+}
+
+func (b *Binary) Validate() (err error) {
+ err = b.scalar.Validate()
+ if err == nil {
+ err = validateOptional(&b.scalar, b.Value, "value")
+ }
+ return
+}
+
+func (b *Binary) ValidateFull() error {
+ return b.Validate()
+}
+
+func NewBinaryScalar(val *memory.Buffer, typ arrow.DataType) *Binary {
+ return &Binary{scalar{typ, true}, val}
+}
+
+type String struct {
+ *Binary
+}
+
+func (s *String) Validate() error {
+ return s.Binary.Validate()
+}
+
+func (s *String) ValidateFull() (err error) {
+ if err = s.Validate(); err != nil {
+ return
+ }
+ if s.Valid && !utf8.ValidString(string(s.Value.Bytes())) {
+ err = xerrors.Errorf("%s scalar contains invalid utf8 data",
s.Type)
+ }
+ return
+}
+
+func (s *String) CastTo(to arrow.DataType) (Scalar, error) {
+ if !s.Valid {
+ return MakeNullScalar(to), nil
+ }
+
+ if to.ID() == arrow.FIXED_SIZE_BINARY {
+ if s.Value.Len() == to.(*arrow.FixedSizeBinaryType).ByteWidth {
+ return NewFixedSizeBinaryScalar(s.Value, to), nil
+ }
+ return nil, xerrors.Errorf("cannot convert string scalar of %s
to type %s", string(s.Value.Bytes()), to)
+ }
+
+ return ParseScalar(to, string(s.Value.Bytes()))
+}
+
+func NewStringScalar(val string) *String {
+ buf := memory.NewBufferBytes([]byte(val))
+ defer buf.Release()
+ return NewStringScalarFromBuffer(buf)
+}
+
+func NewStringScalarFromBuffer(val *memory.Buffer) *String {
+ val.Retain()
+ return &String{NewBinaryScalar(val, arrow.BinaryTypes.String)}
+}
+
+type FixedSizeBinary struct {
+ *Binary
+}
+
+func (b *FixedSizeBinary) Validate() (err error) {
+ if err = b.Binary.Validate(); err != nil {
+ return
+ }
+
+ if b.Valid {
+ width := b.Type.(*arrow.FixedSizeBinaryType).ByteWidth
+ if b.Value.Len() != width {
+ err = xerrors.Errorf("%s scalar should have a value of
size %d, got %d", b.Type, width, b.Value.Len())
+ }
+ }
+ return
+}
+
+func (b *FixedSizeBinary) ValidateFull() error { return b.Validate() }
+
+func NewFixedSizeBinaryScalar(val *memory.Buffer, typ arrow.DataType)
*FixedSizeBinary {
+ val.Retain()
+ return &FixedSizeBinary{NewBinaryScalar(val, typ)}
+}
diff --git a/go/arrow/scalar/compare.go b/go/arrow/scalar/compare.go
new file mode 100644
index 0000000..1d7fcf4
--- /dev/null
+++ b/go/arrow/scalar/compare.go
@@ -0,0 +1,44 @@
+// 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 "github.com/apache/arrow/go/arrow"
+
+//TODO(zeroshade): approxequals
+// tracked in https://issues.apache.org/jira/browse/ARROW-13980
+
+// Equals returns true if two scalars are equal, which means they have the same
+// datatype, validity and value.
+func Equals(left, right Scalar) bool {
+ if left == right {
+ return true
+ }
+
+ if !arrow.TypeEqual(left.DataType(), right.DataType()) {
+ return false
+ }
+
+ if left.IsValid() != right.IsValid() {
+ return false
+ }
+
+ if !left.IsValid() {
+ return true
+ }
+
+ return left.equals(right)
+}
diff --git a/go/arrow/scalar/nested.go b/go/arrow/scalar/nested.go
new file mode 100644
index 0000000..4caa0b4
--- /dev/null
+++ b/go/arrow/scalar/nested.go
@@ -0,0 +1,308 @@
+// 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 (
+ "bytes"
+ "fmt"
+
+ "github.com/apache/arrow/go/arrow"
+ "github.com/apache/arrow/go/arrow/array"
+ "github.com/apache/arrow/go/arrow/internal/debug"
+ "github.com/apache/arrow/go/arrow/memory"
+ "golang.org/x/xerrors"
+)
+
+type ListScalar interface {
+ Scalar
+ List() array.Interface
+}
+
+type List struct {
+ scalar
+ Value array.Interface
+}
+
+func (l *List) value() interface{} { return l.Value }
+func (l *List) List() array.Interface { return l.Value }
+func (l *List) equals(rhs Scalar) bool {
+ return array.ArrayEqual(l.Value, rhs.(ListScalar).List())
+}
+func (l *List) Validate() (err error) {
+ if err = l.scalar.Validate(); err != nil {
+ return
+ }
+ if err = validateOptional(&l.scalar, l.Value, "value"); err != nil {
+ return
+ }
+
+ if !l.Valid {
+ return
+ }
+
+ var (
+ valueType arrow.DataType
+ )
+
+ switch dt := l.Type.(type) {
+ case *arrow.ListType:
+ valueType = dt.Elem()
+ case *arrow.FixedSizeListType:
+ valueType = dt.Elem()
+ case *arrow.MapType:
+ valueType = dt.ValueType()
+ }
+ listType := l.Type
+
+ if !arrow.TypeEqual(l.Value.DataType(), valueType) {
+ err = xerrors.Errorf("%s scalar should have a value of type %s,
got %s",
+ listType, valueType, l.Value.DataType())
+ }
+ return
+}
+
+func (l *List) ValidateFull() error { return l.Validate() }
+func (l *List) CastTo(to arrow.DataType) (Scalar, error) {
+ if !l.Valid {
+ return MakeNullScalar(to), nil
+ }
+
+ if arrow.TypeEqual(l.Type, to) {
+ return l, nil
+ }
+
+ if to.ID() == arrow.STRING {
+ var bld bytes.Buffer
+ fmt.Fprint(&bld, l.Value)
+ buf := memory.NewBufferBytes(bld.Bytes())
+ defer buf.Release()
+ return NewStringScalarFromBuffer(buf), nil
+ }
+
+ return nil, xerrors.Errorf("cannot convert non-nil list scalar to type
%s", to)
+}
+
+func (l *List) String() string {
+ if !l.Valid {
+ return "null"
+ }
+ val, err := l.CastTo(arrow.BinaryTypes.String)
+ if err != nil {
+ return "..."
+ }
+ return string(val.(*String).Value.Bytes())
+}
+
+func NewListScalar(val array.Interface) *List {
+ return &List{scalar{arrow.ListOf(val.DataType()), true}, val}
+}
+
+func makeMapType(typ *arrow.StructType) *arrow.MapType {
+ debug.Assert(len(typ.Fields()) == 2, "must pass struct with only 2
fields for MapScalar")
+ return arrow.MapOf(typ.Field(0).Type, typ.Field(1).Type)
+}
+
+type Map struct {
+ *List
+}
+
+func NewMapScalar(val array.Interface) *Map {
+ return
&Map{&List{scalar{makeMapType(val.DataType().(*arrow.StructType)), true}, val}}
+}
+
+type FixedSizeList struct {
+ *List
+}
+
+func (f *FixedSizeList) Validate() (err error) {
+ if err = f.List.Validate(); err != nil {
+ return
+ }
+
+ if f.Valid {
+ listType := f.Type.(*arrow.FixedSizeListType)
+ if f.Value.Len() != int(listType.Len()) {
+ return xerrors.Errorf("%s scalar should have a child
value of length %d, got %d",
+ f.Type, listType.Len(), f.Value.Len())
+ }
+ }
+ return
+}
+
+func (f *FixedSizeList) ValidateFull() error { return f.Validate() }
+
+func NewFixedSizeListScalar(val array.Interface) *FixedSizeList {
+ return NewFixedSizeListScalarWithType(val,
arrow.FixedSizeListOf(int32(val.Len()), val.DataType()))
+}
+
+func NewFixedSizeListScalarWithType(val array.Interface, typ arrow.DataType)
*FixedSizeList {
+ debug.Assert(val.Len() == int(typ.(*arrow.FixedSizeListType).Len()),
"length of value for fixed size list scalar must match type")
+ return &FixedSizeList{&List{scalar{typ, true}, val}}
+}
+
+type Vector []Scalar
+
+type Struct struct {
+ scalar
+ Value Vector
+}
+
+func (s *Struct) Field(name string) (Scalar, error) {
+ idx, ok := s.Type.(*arrow.StructType).FieldIdx(name)
+ if !ok {
+ return nil, xerrors.Errorf("no field named %s found in struct
scalar %s", name, s.Type)
+ }
+
+ return s.Value[idx], nil
+}
+
+func (s *Struct) value() interface{} { return s.Value }
+
+func (s *Struct) 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 *Struct) CastTo(to arrow.DataType) (Scalar, error) {
+ if !s.Valid {
+ return MakeNullScalar(to), nil
+ }
+
+ if to.ID() != arrow.STRING {
+ return nil, xerrors.Errorf("cannot cast non-null struct scalar
to type %s", to)
+ }
+
+ var bld bytes.Buffer
+ st := s.Type.(*arrow.StructType)
+ bld.WriteByte('{')
+ for i, v := range s.Value {
+ if i > 0 {
+ bld.WriteString(", ")
+ }
+ bld.WriteString(fmt.Sprintf("%s:%s = %s", st.Field(i).Name,
st.Field(i).Type, v.String()))
+ }
+ bld.WriteByte('}')
+ buf := memory.NewBufferBytes(bld.Bytes())
+ defer buf.Release()
+ return NewStringScalarFromBuffer(buf), nil
+}
+
+func (s *Struct) equals(rhs Scalar) bool {
+ right := rhs.(*Struct)
+ if len(s.Value) != len(right.Value) {
+ return false
+ }
+
+ for i := range s.Value {
+ if !Equals(s.Value[i], right.Value[i]) {
+ return false
+ }
+ }
+ return true
+}
+
+func (s *Struct) Validate() (err error) {
+ if err = s.scalar.Validate(); err != nil {
+ return
+ }
+
+ if !s.Valid {
+ if len(s.Value) != 0 {
+ err = xerrors.Errorf("%s scalar is marked null but has
child values", s.Type)
+ }
+ return
+ }
+
+ st := s.Type.(*arrow.StructType)
+ num := len(st.Fields())
+ if len(s.Value) != num {
+ return xerrors.Errorf("non-null %s scalar should have %d child
values, got %d", s.Type, num, len(s.Value))
+ }
+
+ for i, f := range st.Fields() {
+ if s.Value[i] == nil {
+ return xerrors.Errorf("non-null %s scalar has missing
child value at index %d", s.Type, i)
+ }
+
+ err = s.Value[i].Validate()
+ if err != nil {
+ return xerrors.Errorf("%s scalar fails validation for
child at index %d: %w", s.Type, i, err)
+ }
+
+ if !arrow.TypeEqual(s.Value[i].DataType(), f.Type) {
+ return xerrors.Errorf("%s scalar should have a child
value of type %s at index %d, got %s", s.Type, f.Type, i, s.Value[i].DataType())
+ }
+ }
+ return
+}
+
+func (s *Struct) ValidateFull() (err error) {
+ if err = s.scalar.ValidateFull(); err != nil {
+ return
+ }
+
+ if !s.Valid {
+ if len(s.Value) != 0 {
+ err = xerrors.Errorf("%s scalar is marked null but has
child values", s.Type)
+ }
+ return
+ }
+
+ st := s.Type.(*arrow.StructType)
+ num := len(st.Fields())
+ if len(s.Value) != num {
+ return xerrors.Errorf("non-null %s scalar should have %d child
values, got %d", s.Type, num, len(s.Value))
+ }
+
+ for i, f := range st.Fields() {
+ if s.Value[i] == nil {
+ return xerrors.Errorf("non-null %s scalar has missing
child value at index %d", s.Type, i)
+ }
+
+ err = s.Value[i].ValidateFull()
+ if err != nil {
+ return xerrors.Errorf("%s scalar fails validation for
child at index %d: %w", s.Type, i, err)
+ }
+
+ if !arrow.TypeEqual(s.Value[i].DataType(), f.Type) {
+ return xerrors.Errorf("%s scalar should have a child
value of type %s at index %d, got %s", s.Type, f.Type, i, s.Value[i].DataType())
+ }
+ }
+ return
+}
+
+func NewStructScalar(val []Scalar, typ arrow.DataType) *Struct {
+ return &Struct{scalar{typ, true}, val}
+}
+
+func NewStructScalarWithNames(val []Scalar, names []string) (*Struct, error) {
+ if len(val) != len(names) {
+ return nil, xerrors.New("mismatching number of field names and
child scalars")
+ }
+
+ fields := make([]arrow.Field, len(names))
+ for i, n := range names {
+ fields[i] = arrow.Field{Name: n, Type: val[i].DataType(),
Nullable: true}
+ }
+ return NewStructScalar(val, arrow.StructOf(fields...)), nil
+}
diff --git a/go/arrow/scalar/numeric.gen.go b/go/arrow/scalar/numeric.gen.go
new file mode 100644
index 0000000..788904d
--- /dev/null
+++ b/go/arrow/scalar/numeric.gen.go
@@ -0,0 +1,697 @@
+// Code generated by scalar/numeric.gen.go.tmpl. DO NOT EDIT.
+
+// 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"
+ "unsafe"
+
+ "github.com/apache/arrow/go/arrow"
+ "golang.org/x/xerrors"
+)
+
+type Int8 struct {
+ scalar
+ Value int8
+}
+
+func (s *Int8) Data() []byte {
+ return (*[arrow.Int8SizeBytes]byte)(unsafe.Pointer(&s.Value))[:]
+}
+
+func (s *Int8) equals(rhs Scalar) bool {
+ return s.Value == rhs.(*Int8).Value
+}
+
+func (s *Int8) value() interface{} {
+ return s.Value
+}
+
+func (s *Int8) 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 *Int8) CastTo(dt arrow.DataType) (Scalar, error) {
+ if !s.Valid {
+ return MakeNullScalar(dt), nil
+ }
+
+ r, ok := numericMap[dt.ID()]
+ if ok {
+ return convertToNumeric(reflect.ValueOf(s.Value), r.valueType,
r.scalarFunc), nil
+ }
+
+ switch dt := dt.(type) {
+ case *arrow.BooleanType:
+ return NewBooleanScalar(s.Value != 0), nil
+ case *arrow.Date32Type:
+ return NewDate32Scalar(arrow.Date32(s.Value)), nil
+ case *arrow.Date64Type:
+ return NewDate64Scalar(arrow.Date64(s.Value)), nil
+ case *arrow.Time32Type:
+ return NewTime32Scalar(arrow.Time32(s.Value), dt), nil
+ case *arrow.Time64Type:
+ return NewTime64Scalar(arrow.Time64(s.Value), dt), nil
+ case *arrow.TimestampType:
+ return NewTimestampScalar(arrow.Timestamp(s.Value), dt), nil
+ case *arrow.MonthIntervalType:
+ return NewMonthIntervalScalar(arrow.MonthInterval(s.Value)), nil
+ case *arrow.StringType:
+ return NewStringScalar(fmt.Sprintf("%v", s.Value)), nil
+ }
+
+ return nil, xerrors.Errorf("invalid scalar cast from type int8 to type
%s", dt)
+}
+
+func NewInt8Scalar(val int8) *Int8 {
+ return &Int8{scalar{Type: arrow.PrimitiveTypes.Int8, Valid: true}, val}
+}
+
+type Int16 struct {
+ scalar
+ Value int16
+}
+
+func (s *Int16) Data() []byte {
+ return (*[arrow.Int16SizeBytes]byte)(unsafe.Pointer(&s.Value))[:]
+}
+
+func (s *Int16) equals(rhs Scalar) bool {
+ return s.Value == rhs.(*Int16).Value
+}
+
+func (s *Int16) value() interface{} {
+ return s.Value
+}
+
+func (s *Int16) 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 *Int16) CastTo(dt arrow.DataType) (Scalar, error) {
+ if !s.Valid {
+ return MakeNullScalar(dt), nil
+ }
+
+ r, ok := numericMap[dt.ID()]
+ if ok {
+ return convertToNumeric(reflect.ValueOf(s.Value), r.valueType,
r.scalarFunc), nil
+ }
+
+ switch dt := dt.(type) {
+ case *arrow.BooleanType:
+ return NewBooleanScalar(s.Value != 0), nil
+ case *arrow.Date32Type:
+ return NewDate32Scalar(arrow.Date32(s.Value)), nil
+ case *arrow.Date64Type:
+ return NewDate64Scalar(arrow.Date64(s.Value)), nil
+ case *arrow.Time32Type:
+ return NewTime32Scalar(arrow.Time32(s.Value), dt), nil
+ case *arrow.Time64Type:
+ return NewTime64Scalar(arrow.Time64(s.Value), dt), nil
+ case *arrow.TimestampType:
+ return NewTimestampScalar(arrow.Timestamp(s.Value), dt), nil
+ case *arrow.MonthIntervalType:
+ return NewMonthIntervalScalar(arrow.MonthInterval(s.Value)), nil
+ case *arrow.StringType:
+ return NewStringScalar(fmt.Sprintf("%v", s.Value)), nil
+ }
+
+ return nil, xerrors.Errorf("invalid scalar cast from type int16 to type
%s", dt)
+}
+
+func NewInt16Scalar(val int16) *Int16 {
+ return &Int16{scalar{Type: arrow.PrimitiveTypes.Int16, Valid: true},
val}
+}
+
+type Int32 struct {
+ scalar
+ Value int32
+}
+
+func (s *Int32) Data() []byte {
+ return (*[arrow.Int32SizeBytes]byte)(unsafe.Pointer(&s.Value))[:]
+}
+
+func (s *Int32) equals(rhs Scalar) bool {
+ return s.Value == rhs.(*Int32).Value
+}
+
+func (s *Int32) value() interface{} {
+ return s.Value
+}
+
+func (s *Int32) 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 *Int32) CastTo(dt arrow.DataType) (Scalar, error) {
+ if !s.Valid {
+ return MakeNullScalar(dt), nil
+ }
+
+ r, ok := numericMap[dt.ID()]
+ if ok {
+ return convertToNumeric(reflect.ValueOf(s.Value), r.valueType,
r.scalarFunc), nil
+ }
+
+ switch dt := dt.(type) {
+ case *arrow.BooleanType:
+ return NewBooleanScalar(s.Value != 0), nil
+ case *arrow.Date32Type:
+ return NewDate32Scalar(arrow.Date32(s.Value)), nil
+ case *arrow.Date64Type:
+ return NewDate64Scalar(arrow.Date64(s.Value)), nil
+ case *arrow.Time32Type:
+ return NewTime32Scalar(arrow.Time32(s.Value), dt), nil
+ case *arrow.Time64Type:
+ return NewTime64Scalar(arrow.Time64(s.Value), dt), nil
+ case *arrow.TimestampType:
+ return NewTimestampScalar(arrow.Timestamp(s.Value), dt), nil
+ case *arrow.MonthIntervalType:
+ return NewMonthIntervalScalar(arrow.MonthInterval(s.Value)), nil
+ case *arrow.StringType:
+ return NewStringScalar(fmt.Sprintf("%v", s.Value)), nil
+ }
+
+ return nil, xerrors.Errorf("invalid scalar cast from type int32 to type
%s", dt)
+}
+
+func NewInt32Scalar(val int32) *Int32 {
+ return &Int32{scalar{Type: arrow.PrimitiveTypes.Int32, Valid: true},
val}
+}
+
+type Int64 struct {
+ scalar
+ Value int64
+}
+
+func (s *Int64) Data() []byte {
+ return (*[arrow.Int64SizeBytes]byte)(unsafe.Pointer(&s.Value))[:]
+}
+
+func (s *Int64) equals(rhs Scalar) bool {
+ return s.Value == rhs.(*Int64).Value
+}
+
+func (s *Int64) value() interface{} {
+ return s.Value
+}
+
+func (s *Int64) 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 *Int64) CastTo(dt arrow.DataType) (Scalar, error) {
+ if !s.Valid {
+ return MakeNullScalar(dt), nil
+ }
+
+ r, ok := numericMap[dt.ID()]
+ if ok {
+ return convertToNumeric(reflect.ValueOf(s.Value), r.valueType,
r.scalarFunc), nil
+ }
+
+ switch dt := dt.(type) {
+ case *arrow.BooleanType:
+ return NewBooleanScalar(s.Value != 0), nil
+ case *arrow.Date32Type:
+ return NewDate32Scalar(arrow.Date32(s.Value)), nil
+ case *arrow.Date64Type:
+ return NewDate64Scalar(arrow.Date64(s.Value)), nil
+ case *arrow.Time32Type:
+ return NewTime32Scalar(arrow.Time32(s.Value), dt), nil
+ case *arrow.Time64Type:
+ return NewTime64Scalar(arrow.Time64(s.Value), dt), nil
+ case *arrow.TimestampType:
+ return NewTimestampScalar(arrow.Timestamp(s.Value), dt), nil
+ case *arrow.MonthIntervalType:
+ return NewMonthIntervalScalar(arrow.MonthInterval(s.Value)), nil
+ case *arrow.StringType:
+ return NewStringScalar(fmt.Sprintf("%v", s.Value)), nil
+ }
+
+ return nil, xerrors.Errorf("invalid scalar cast from type int64 to type
%s", dt)
+}
+
+func NewInt64Scalar(val int64) *Int64 {
+ return &Int64{scalar{Type: arrow.PrimitiveTypes.Int64, Valid: true},
val}
+}
+
+type Uint8 struct {
+ scalar
+ Value uint8
+}
+
+func (s *Uint8) Data() []byte {
+ return (*[arrow.Uint8SizeBytes]byte)(unsafe.Pointer(&s.Value))[:]
+}
+
+func (s *Uint8) equals(rhs Scalar) bool {
+ return s.Value == rhs.(*Uint8).Value
+}
+
+func (s *Uint8) value() interface{} {
+ return s.Value
+}
+
+func (s *Uint8) 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 *Uint8) CastTo(dt arrow.DataType) (Scalar, error) {
+ if !s.Valid {
+ return MakeNullScalar(dt), nil
+ }
+
+ r, ok := numericMap[dt.ID()]
+ if ok {
+ return convertToNumeric(reflect.ValueOf(s.Value), r.valueType,
r.scalarFunc), nil
+ }
+
+ switch dt := dt.(type) {
+ case *arrow.BooleanType:
+ return NewBooleanScalar(s.Value != 0), nil
+ case *arrow.Date32Type:
+ return NewDate32Scalar(arrow.Date32(s.Value)), nil
+ case *arrow.Date64Type:
+ return NewDate64Scalar(arrow.Date64(s.Value)), nil
+ case *arrow.Time32Type:
+ return NewTime32Scalar(arrow.Time32(s.Value), dt), nil
+ case *arrow.Time64Type:
+ return NewTime64Scalar(arrow.Time64(s.Value), dt), nil
+ case *arrow.TimestampType:
+ return NewTimestampScalar(arrow.Timestamp(s.Value), dt), nil
+ case *arrow.MonthIntervalType:
+ return NewMonthIntervalScalar(arrow.MonthInterval(s.Value)), nil
+ case *arrow.StringType:
+ return NewStringScalar(fmt.Sprintf("%v", s.Value)), nil
+ }
+
+ return nil, xerrors.Errorf("invalid scalar cast from type uint8 to type
%s", dt)
+}
+
+func NewUint8Scalar(val uint8) *Uint8 {
+ return &Uint8{scalar{Type: arrow.PrimitiveTypes.Uint8, Valid: true},
val}
+}
+
+type Uint16 struct {
+ scalar
+ Value uint16
+}
+
+func (s *Uint16) Data() []byte {
+ return (*[arrow.Uint16SizeBytes]byte)(unsafe.Pointer(&s.Value))[:]
+}
+
+func (s *Uint16) equals(rhs Scalar) bool {
+ return s.Value == rhs.(*Uint16).Value
+}
+
+func (s *Uint16) value() interface{} {
+ return s.Value
+}
+
+func (s *Uint16) 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 *Uint16) CastTo(dt arrow.DataType) (Scalar, error) {
+ if !s.Valid {
+ return MakeNullScalar(dt), nil
+ }
+
+ r, ok := numericMap[dt.ID()]
+ if ok {
+ return convertToNumeric(reflect.ValueOf(s.Value), r.valueType,
r.scalarFunc), nil
+ }
+
+ switch dt := dt.(type) {
+ case *arrow.BooleanType:
+ return NewBooleanScalar(s.Value != 0), nil
+ case *arrow.Date32Type:
+ return NewDate32Scalar(arrow.Date32(s.Value)), nil
+ case *arrow.Date64Type:
+ return NewDate64Scalar(arrow.Date64(s.Value)), nil
+ case *arrow.Time32Type:
+ return NewTime32Scalar(arrow.Time32(s.Value), dt), nil
+ case *arrow.Time64Type:
+ return NewTime64Scalar(arrow.Time64(s.Value), dt), nil
+ case *arrow.TimestampType:
+ return NewTimestampScalar(arrow.Timestamp(s.Value), dt), nil
+ case *arrow.MonthIntervalType:
+ return NewMonthIntervalScalar(arrow.MonthInterval(s.Value)), nil
+ case *arrow.StringType:
+ return NewStringScalar(fmt.Sprintf("%v", s.Value)), nil
+ }
+
+ return nil, xerrors.Errorf("invalid scalar cast from type uint16 to
type %s", dt)
+}
+
+func NewUint16Scalar(val uint16) *Uint16 {
+ return &Uint16{scalar{Type: arrow.PrimitiveTypes.Uint16, Valid: true},
val}
+}
+
+type Uint32 struct {
+ scalar
+ Value uint32
+}
+
+func (s *Uint32) Data() []byte {
+ return (*[arrow.Uint32SizeBytes]byte)(unsafe.Pointer(&s.Value))[:]
+}
+
+func (s *Uint32) equals(rhs Scalar) bool {
+ return s.Value == rhs.(*Uint32).Value
+}
+
+func (s *Uint32) value() interface{} {
+ return s.Value
+}
+
+func (s *Uint32) 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 *Uint32) CastTo(dt arrow.DataType) (Scalar, error) {
+ if !s.Valid {
+ return MakeNullScalar(dt), nil
+ }
+
+ r, ok := numericMap[dt.ID()]
+ if ok {
+ return convertToNumeric(reflect.ValueOf(s.Value), r.valueType,
r.scalarFunc), nil
+ }
+
+ switch dt := dt.(type) {
+ case *arrow.BooleanType:
+ return NewBooleanScalar(s.Value != 0), nil
+ case *arrow.Date32Type:
+ return NewDate32Scalar(arrow.Date32(s.Value)), nil
+ case *arrow.Date64Type:
+ return NewDate64Scalar(arrow.Date64(s.Value)), nil
+ case *arrow.Time32Type:
+ return NewTime32Scalar(arrow.Time32(s.Value), dt), nil
+ case *arrow.Time64Type:
+ return NewTime64Scalar(arrow.Time64(s.Value), dt), nil
+ case *arrow.TimestampType:
+ return NewTimestampScalar(arrow.Timestamp(s.Value), dt), nil
+ case *arrow.MonthIntervalType:
+ return NewMonthIntervalScalar(arrow.MonthInterval(s.Value)), nil
+ case *arrow.StringType:
+ return NewStringScalar(fmt.Sprintf("%v", s.Value)), nil
+ }
+
+ return nil, xerrors.Errorf("invalid scalar cast from type uint32 to
type %s", dt)
+}
+
+func NewUint32Scalar(val uint32) *Uint32 {
+ return &Uint32{scalar{Type: arrow.PrimitiveTypes.Uint32, Valid: true},
val}
+}
+
+type Uint64 struct {
+ scalar
+ Value uint64
+}
+
+func (s *Uint64) Data() []byte {
+ return (*[arrow.Uint64SizeBytes]byte)(unsafe.Pointer(&s.Value))[:]
+}
+
+func (s *Uint64) equals(rhs Scalar) bool {
+ return s.Value == rhs.(*Uint64).Value
+}
+
+func (s *Uint64) value() interface{} {
+ return s.Value
+}
+
+func (s *Uint64) 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 *Uint64) CastTo(dt arrow.DataType) (Scalar, error) {
+ if !s.Valid {
+ return MakeNullScalar(dt), nil
+ }
+
+ r, ok := numericMap[dt.ID()]
+ if ok {
+ return convertToNumeric(reflect.ValueOf(s.Value), r.valueType,
r.scalarFunc), nil
+ }
+
+ switch dt := dt.(type) {
+ case *arrow.BooleanType:
+ return NewBooleanScalar(s.Value != 0), nil
+ case *arrow.Date32Type:
+ return NewDate32Scalar(arrow.Date32(s.Value)), nil
+ case *arrow.Date64Type:
+ return NewDate64Scalar(arrow.Date64(s.Value)), nil
+ case *arrow.Time32Type:
+ return NewTime32Scalar(arrow.Time32(s.Value), dt), nil
+ case *arrow.Time64Type:
+ return NewTime64Scalar(arrow.Time64(s.Value), dt), nil
+ case *arrow.TimestampType:
+ return NewTimestampScalar(arrow.Timestamp(s.Value), dt), nil
+ case *arrow.MonthIntervalType:
+ return NewMonthIntervalScalar(arrow.MonthInterval(s.Value)), nil
+ case *arrow.StringType:
+ return NewStringScalar(fmt.Sprintf("%v", s.Value)), nil
+ }
+
+ return nil, xerrors.Errorf("invalid scalar cast from type uint64 to
type %s", dt)
+}
+
+func NewUint64Scalar(val uint64) *Uint64 {
+ return &Uint64{scalar{Type: arrow.PrimitiveTypes.Uint64, Valid: true},
val}
+}
+
+type Float32 struct {
+ scalar
+ Value float32
+}
+
+func (s *Float32) Data() []byte {
+ return (*[arrow.Float32SizeBytes]byte)(unsafe.Pointer(&s.Value))[:]
+}
+
+func (s *Float32) equals(rhs Scalar) bool {
+ return s.Value == rhs.(*Float32).Value
+}
+
+func (s *Float32) value() interface{} {
+ return s.Value
+}
+
+func (s *Float32) 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 *Float32) CastTo(dt arrow.DataType) (Scalar, error) {
+ if !s.Valid {
+ return MakeNullScalar(dt), nil
+ }
+
+ r, ok := numericMap[dt.ID()]
+ if ok {
+ return convertToNumeric(reflect.ValueOf(s.Value), r.valueType,
r.scalarFunc), nil
+ }
+
+ switch dt := dt.(type) {
+ case *arrow.BooleanType:
+ return NewBooleanScalar(s.Value != 0), nil
+ case *arrow.Date32Type:
+ return NewDate32Scalar(arrow.Date32(s.Value)), nil
+ case *arrow.Date64Type:
+ return NewDate64Scalar(arrow.Date64(s.Value)), nil
+ case *arrow.Time32Type:
+ return NewTime32Scalar(arrow.Time32(s.Value), dt), nil
+ case *arrow.Time64Type:
+ return NewTime64Scalar(arrow.Time64(s.Value), dt), nil
+ case *arrow.TimestampType:
+ return NewTimestampScalar(arrow.Timestamp(s.Value), dt), nil
+ case *arrow.MonthIntervalType:
+ return NewMonthIntervalScalar(arrow.MonthInterval(s.Value)), nil
+ case *arrow.StringType:
+ return NewStringScalar(fmt.Sprintf("%v", s.Value)), nil
+ }
+
+ return nil, xerrors.Errorf("invalid scalar cast from type float32 to
type %s", dt)
+}
+
+func NewFloat32Scalar(val float32) *Float32 {
+ return &Float32{scalar{Type: arrow.PrimitiveTypes.Float32, Valid:
true}, val}
+}
+
+type Float64 struct {
+ scalar
+ Value float64
+}
+
+func (s *Float64) Data() []byte {
+ return (*[arrow.Float64SizeBytes]byte)(unsafe.Pointer(&s.Value))[:]
+}
+
+func (s *Float64) equals(rhs Scalar) bool {
+ return s.Value == rhs.(*Float64).Value
+}
+
+func (s *Float64) value() interface{} {
+ return s.Value
+}
+
+func (s *Float64) 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 *Float64) CastTo(dt arrow.DataType) (Scalar, error) {
+ if !s.Valid {
+ return MakeNullScalar(dt), nil
+ }
+
+ r, ok := numericMap[dt.ID()]
+ if ok {
+ return convertToNumeric(reflect.ValueOf(s.Value), r.valueType,
r.scalarFunc), nil
+ }
+
+ switch dt := dt.(type) {
+ case *arrow.BooleanType:
+ return NewBooleanScalar(s.Value != 0), nil
+ case *arrow.Date32Type:
+ return NewDate32Scalar(arrow.Date32(s.Value)), nil
+ case *arrow.Date64Type:
+ return NewDate64Scalar(arrow.Date64(s.Value)), nil
+ case *arrow.Time32Type:
+ return NewTime32Scalar(arrow.Time32(s.Value), dt), nil
+ case *arrow.Time64Type:
+ return NewTime64Scalar(arrow.Time64(s.Value), dt), nil
+ case *arrow.TimestampType:
+ return NewTimestampScalar(arrow.Timestamp(s.Value), dt), nil
+ case *arrow.MonthIntervalType:
+ return NewMonthIntervalScalar(arrow.MonthInterval(s.Value)), nil
+ case *arrow.StringType:
+ return NewStringScalar(fmt.Sprintf("%v", s.Value)), nil
+ }
+
+ return nil, xerrors.Errorf("invalid scalar cast from type float64 to
type %s", dt)
+}
+
+func NewFloat64Scalar(val float64) *Float64 {
+ return &Float64{scalar{Type: arrow.PrimitiveTypes.Float64, Valid:
true}, val}
+}
+
+var numericMap = map[arrow.Type]struct {
+ scalarFunc reflect.Value
+ valueType reflect.Type
+}{
+ arrow.INT8: {scalarFunc: reflect.ValueOf(NewInt8Scalar), valueType:
reflect.TypeOf(int8(0))},
+ arrow.INT16: {scalarFunc: reflect.ValueOf(NewInt16Scalar), valueType:
reflect.TypeOf(int16(0))},
+ arrow.INT32: {scalarFunc: reflect.ValueOf(NewInt32Scalar), valueType:
reflect.TypeOf(int32(0))},
+ arrow.INT64: {scalarFunc: reflect.ValueOf(NewInt64Scalar), valueType:
reflect.TypeOf(int64(0))},
+ arrow.UINT8: {scalarFunc: reflect.ValueOf(NewUint8Scalar), valueType:
reflect.TypeOf(uint8(0))},
+ arrow.UINT16: {scalarFunc: reflect.ValueOf(NewUint16Scalar),
valueType: reflect.TypeOf(uint16(0))},
+ arrow.UINT32: {scalarFunc: reflect.ValueOf(NewUint32Scalar),
valueType: reflect.TypeOf(uint32(0))},
+ arrow.UINT64: {scalarFunc: reflect.ValueOf(NewUint64Scalar),
valueType: reflect.TypeOf(uint64(0))},
+ arrow.FLOAT32: {scalarFunc: reflect.ValueOf(NewFloat32Scalar),
valueType: reflect.TypeOf(float32(0))},
+ arrow.FLOAT64: {scalarFunc: reflect.ValueOf(NewFloat64Scalar),
valueType: reflect.TypeOf(float64(0))},
+}
+
+var (
+ _ Scalar = (*Int8)(nil)
+ _ Scalar = (*Int16)(nil)
+ _ Scalar = (*Int32)(nil)
+ _ Scalar = (*Int64)(nil)
+ _ Scalar = (*Uint8)(nil)
+ _ Scalar = (*Uint16)(nil)
+ _ Scalar = (*Uint32)(nil)
+ _ Scalar = (*Uint64)(nil)
+ _ Scalar = (*Float32)(nil)
+ _ Scalar = (*Float64)(nil)
+)
diff --git a/go/arrow/scalar/numeric.gen.go.tmpl
b/go/arrow/scalar/numeric.gen.go.tmpl
new file mode 100644
index 0000000..272b637
--- /dev/null
+++ b/go/arrow/scalar/numeric.gen.go.tmpl
@@ -0,0 +1,98 @@
+// 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
+
+{{range .In}}
+type {{.Name}} struct {
+ scalar
+ Value {{.Type}}
+}
+
+func (s *{{.Name}}) Data() []byte {
+ return (*[arrow.{{.Name}}SizeBytes]byte)(unsafe.Pointer(&s.Value))[:]
+}
+
+func (s *{{.Name}}) equals(rhs Scalar) bool {
+ return s.Value == rhs.(*{{.Name}}).Value
+}
+
+func (s *{{.Name}}) value() interface{} {
+ return s.Value
+}
+
+func (s *{{.Name}}) 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 *{{.Name}}) CastTo(dt arrow.DataType) (Scalar, error) {
+ if !s.Valid {
+ return MakeNullScalar(dt), nil
+ }
+
+ r, ok := numericMap[dt.ID()]
+ if ok {
+ return convertToNumeric(reflect.ValueOf(s.Value), r.valueType,
r.scalarFunc), nil
+ }
+
+ switch dt := dt.(type) {
+ case *arrow.BooleanType:
+ return NewBooleanScalar(s.Value != 0), nil
+ case *arrow.Date32Type:
+ return NewDate32Scalar(arrow.Date32(s.Value)), nil
+ case *arrow.Date64Type:
+ return NewDate64Scalar(arrow.Date64(s.Value)), nil
+ case *arrow.Time32Type:
+ return NewTime32Scalar(arrow.Time32(s.Value), dt), nil
+ case *arrow.Time64Type:
+ return NewTime64Scalar(arrow.Time64(s.Value), dt), nil
+ case *arrow.TimestampType:
+ return NewTimestampScalar(arrow.Timestamp(s.Value), dt), nil
+ case *arrow.MonthIntervalType:
+ return NewMonthIntervalScalar(arrow.MonthInterval(s.Value)), nil
+ case *arrow.StringType:
+ return NewStringScalar(fmt.Sprintf("%v", s.Value)), nil
+ }
+
+ return nil, xerrors.Errorf("invalid scalar cast from type {{.Type}} to
type %s", dt)
+}
+
+func New{{.Name}}Scalar(val {{.Type}}) *{{.Name}} {
+ return &{{.Name}}{scalar{Type: arrow.PrimitiveTypes.{{.Name}}, Valid:
true}, val}
+}
+{{end}}
+
+var numericMap = map[arrow.Type]struct{
+ scalarFunc reflect.Value
+ valueType reflect.Type
+}{
+{{range .In -}}
+ arrow.{{.Name|upper}}: {scalarFunc: reflect.ValueOf(New{{.Name}}Scalar),
valueType: reflect.TypeOf({{.Type}}(0)) },
+{{end}}
+}
+
+var (
+{{range .In -}}
+ _ Scalar = (*{{.Name}})(nil)
+{{end}}
+)
diff --git a/go/arrow/scalar/numeric.gen.go.tmpldata
b/go/arrow/scalar/numeric.gen.go.tmpldata
new file mode 100644
index 0000000..415b51b
--- /dev/null
+++ b/go/arrow/scalar/numeric.gen.go.tmpldata
@@ -0,0 +1,52 @@
+[
+ {
+ "Name": "Int8",
+ "Type": "int8",
+ "Size": 8
+ },
+ {
+ "Name": "Int16",
+ "Type": "int16",
+ "Size": 16
+ },
+ {
+ "Name": "Int32",
+ "Type": "int32",
+ "Size": 32
+ },
+ {
+ "Name": "Int64",
+ "Type": "int64",
+ "Size": 64
+ },
+ {
+ "Name": "Uint8",
+ "Type": "uint8",
+ "Size": 8
+ },
+ {
+ "Name": "Uint16",
+ "Type": "uint16",
+ "Size": 16
+ },
+ {
+ "Name": "Uint32",
+ "Type": "uint32",
+ "Size": 32
+ },
+ {
+ "Name": "Uint64",
+ "Type": "uint64",
+ "Size": 64
+ },
+ {
+ "Name": "Float32",
+ "Type": "float32",
+ "Size": 32
+ },
+ {
+ "Name": "Float64",
+ "Type": "float64",
+ "Size": 64
+ }
+]
diff --git a/go/arrow/scalar/numeric.gen_test.go
b/go/arrow/scalar/numeric.gen_test.go
new file mode 100644
index 0000000..458fbb6
--- /dev/null
+++ b/go/arrow/scalar/numeric.gen_test.go
@@ -0,0 +1,377 @@
+// Code generated by scalar/numeric.gen_test.go.tmpl. DO NOT EDIT.
+
+// 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_test
+
+import (
+ "testing"
+
+ "github.com/apache/arrow/go/arrow"
+ "github.com/apache/arrow/go/arrow/scalar"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestBasicInt8Scalars(t *testing.T) {
+ value := int8(1)
+
+ scalarVal := scalar.NewInt8Scalar(value)
+ assert.Equal(t, value, scalarVal.Value)
+ assert.True(t, scalarVal.IsValid())
+ assert.NoError(t, scalarVal.ValidateFull())
+
+ expectedType := arrow.PrimitiveTypes.Int8
+ assert.True(t, arrow.TypeEqual(scalarVal.DataType(), expectedType))
+
+ other := int8(2)
+ scalarOther := scalar.NewInt8Scalar(other)
+ assert.NotEqual(t, scalarVal, scalarOther)
+ assert.False(t, scalar.Equals(scalarVal, scalarOther))
+
+ scalarVal.Value = other
+ assert.Equal(t, other, scalarVal.Value)
+ assert.Equal(t, scalarVal, scalarOther)
+ assert.True(t, scalar.Equals(scalarVal, scalarOther))
+
+ nullVal := scalar.MakeNullScalar(arrow.PrimitiveTypes.Int8)
+ assert.False(t, nullVal.IsValid())
+ assert.NoError(t, nullVal.ValidateFull())
+}
+
+func TestMakeScalarInt8(t *testing.T) {
+ three := scalar.MakeScalar(int8(3))
+ assert.NoError(t, three.ValidateFull())
+ assert.Equal(t, scalar.NewInt8Scalar(3), three)
+
+ assertMakeScalar(t, scalar.NewInt8Scalar(3), int8(3))
+ assertParseScalar(t, arrow.PrimitiveTypes.Int8, "3",
scalar.NewInt8Scalar(3))
+}
+
+func TestBasicInt16Scalars(t *testing.T) {
+ value := int16(1)
+
+ scalarVal := scalar.NewInt16Scalar(value)
+ assert.Equal(t, value, scalarVal.Value)
+ assert.True(t, scalarVal.IsValid())
+ assert.NoError(t, scalarVal.ValidateFull())
+
+ expectedType := arrow.PrimitiveTypes.Int16
+ assert.True(t, arrow.TypeEqual(scalarVal.DataType(), expectedType))
+
+ other := int16(2)
+ scalarOther := scalar.NewInt16Scalar(other)
+ assert.NotEqual(t, scalarVal, scalarOther)
+ assert.False(t, scalar.Equals(scalarVal, scalarOther))
+
+ scalarVal.Value = other
+ assert.Equal(t, other, scalarVal.Value)
+ assert.Equal(t, scalarVal, scalarOther)
+ assert.True(t, scalar.Equals(scalarVal, scalarOther))
+
+ nullVal := scalar.MakeNullScalar(arrow.PrimitiveTypes.Int16)
+ assert.False(t, nullVal.IsValid())
+ assert.NoError(t, nullVal.ValidateFull())
+}
+
+func TestMakeScalarInt16(t *testing.T) {
+ three := scalar.MakeScalar(int16(3))
+ assert.NoError(t, three.ValidateFull())
+ assert.Equal(t, scalar.NewInt16Scalar(3), three)
+
+ assertMakeScalar(t, scalar.NewInt16Scalar(3), int16(3))
+ assertParseScalar(t, arrow.PrimitiveTypes.Int16, "3",
scalar.NewInt16Scalar(3))
+}
+
+func TestBasicInt32Scalars(t *testing.T) {
+ value := int32(1)
+
+ scalarVal := scalar.NewInt32Scalar(value)
+ assert.Equal(t, value, scalarVal.Value)
+ assert.True(t, scalarVal.IsValid())
+ assert.NoError(t, scalarVal.ValidateFull())
+
+ expectedType := arrow.PrimitiveTypes.Int32
+ assert.True(t, arrow.TypeEqual(scalarVal.DataType(), expectedType))
+
+ other := int32(2)
+ scalarOther := scalar.NewInt32Scalar(other)
+ assert.NotEqual(t, scalarVal, scalarOther)
+ assert.False(t, scalar.Equals(scalarVal, scalarOther))
+
+ scalarVal.Value = other
+ assert.Equal(t, other, scalarVal.Value)
+ assert.Equal(t, scalarVal, scalarOther)
+ assert.True(t, scalar.Equals(scalarVal, scalarOther))
+
+ nullVal := scalar.MakeNullScalar(arrow.PrimitiveTypes.Int32)
+ assert.False(t, nullVal.IsValid())
+ assert.NoError(t, nullVal.ValidateFull())
+}
+
+func TestMakeScalarInt32(t *testing.T) {
+ three := scalar.MakeScalar(int32(3))
+ assert.NoError(t, three.ValidateFull())
+ assert.Equal(t, scalar.NewInt32Scalar(3), three)
+
+ assertMakeScalar(t, scalar.NewInt32Scalar(3), int32(3))
+ assertParseScalar(t, arrow.PrimitiveTypes.Int32, "3",
scalar.NewInt32Scalar(3))
+}
+
+func TestBasicInt64Scalars(t *testing.T) {
+ value := int64(1)
+
+ scalarVal := scalar.NewInt64Scalar(value)
+ assert.Equal(t, value, scalarVal.Value)
+ assert.True(t, scalarVal.IsValid())
+ assert.NoError(t, scalarVal.ValidateFull())
+
+ expectedType := arrow.PrimitiveTypes.Int64
+ assert.True(t, arrow.TypeEqual(scalarVal.DataType(), expectedType))
+
+ other := int64(2)
+ scalarOther := scalar.NewInt64Scalar(other)
+ assert.NotEqual(t, scalarVal, scalarOther)
+ assert.False(t, scalar.Equals(scalarVal, scalarOther))
+
+ scalarVal.Value = other
+ assert.Equal(t, other, scalarVal.Value)
+ assert.Equal(t, scalarVal, scalarOther)
+ assert.True(t, scalar.Equals(scalarVal, scalarOther))
+
+ nullVal := scalar.MakeNullScalar(arrow.PrimitiveTypes.Int64)
+ assert.False(t, nullVal.IsValid())
+ assert.NoError(t, nullVal.ValidateFull())
+}
+
+func TestMakeScalarInt64(t *testing.T) {
+ three := scalar.MakeScalar(int64(3))
+ assert.NoError(t, three.ValidateFull())
+ assert.Equal(t, scalar.NewInt64Scalar(3), three)
+
+ assertMakeScalar(t, scalar.NewInt64Scalar(3), int64(3))
+ assertParseScalar(t, arrow.PrimitiveTypes.Int64, "3",
scalar.NewInt64Scalar(3))
+}
+
+func TestBasicUint8Scalars(t *testing.T) {
+ value := uint8(1)
+
+ scalarVal := scalar.NewUint8Scalar(value)
+ assert.Equal(t, value, scalarVal.Value)
+ assert.True(t, scalarVal.IsValid())
+ assert.NoError(t, scalarVal.ValidateFull())
+
+ expectedType := arrow.PrimitiveTypes.Uint8
+ assert.True(t, arrow.TypeEqual(scalarVal.DataType(), expectedType))
+
+ other := uint8(2)
+ scalarOther := scalar.NewUint8Scalar(other)
+ assert.NotEqual(t, scalarVal, scalarOther)
+ assert.False(t, scalar.Equals(scalarVal, scalarOther))
+
+ scalarVal.Value = other
+ assert.Equal(t, other, scalarVal.Value)
+ assert.Equal(t, scalarVal, scalarOther)
+ assert.True(t, scalar.Equals(scalarVal, scalarOther))
+
+ nullVal := scalar.MakeNullScalar(arrow.PrimitiveTypes.Uint8)
+ assert.False(t, nullVal.IsValid())
+ assert.NoError(t, nullVal.ValidateFull())
+}
+
+func TestMakeScalarUint8(t *testing.T) {
+ three := scalar.MakeScalar(uint8(3))
+ assert.NoError(t, three.ValidateFull())
+ assert.Equal(t, scalar.NewUint8Scalar(3), three)
+
+ assertMakeScalar(t, scalar.NewUint8Scalar(3), uint8(3))
+ assertParseScalar(t, arrow.PrimitiveTypes.Uint8, "3",
scalar.NewUint8Scalar(3))
+}
+
+func TestBasicUint16Scalars(t *testing.T) {
+ value := uint16(1)
+
+ scalarVal := scalar.NewUint16Scalar(value)
+ assert.Equal(t, value, scalarVal.Value)
+ assert.True(t, scalarVal.IsValid())
+ assert.NoError(t, scalarVal.ValidateFull())
+
+ expectedType := arrow.PrimitiveTypes.Uint16
+ assert.True(t, arrow.TypeEqual(scalarVal.DataType(), expectedType))
+
+ other := uint16(2)
+ scalarOther := scalar.NewUint16Scalar(other)
+ assert.NotEqual(t, scalarVal, scalarOther)
+ assert.False(t, scalar.Equals(scalarVal, scalarOther))
+
+ scalarVal.Value = other
+ assert.Equal(t, other, scalarVal.Value)
+ assert.Equal(t, scalarVal, scalarOther)
+ assert.True(t, scalar.Equals(scalarVal, scalarOther))
+
+ nullVal := scalar.MakeNullScalar(arrow.PrimitiveTypes.Uint16)
+ assert.False(t, nullVal.IsValid())
+ assert.NoError(t, nullVal.ValidateFull())
+}
+
+func TestMakeScalarUint16(t *testing.T) {
+ three := scalar.MakeScalar(uint16(3))
+ assert.NoError(t, three.ValidateFull())
+ assert.Equal(t, scalar.NewUint16Scalar(3), three)
+
+ assertMakeScalar(t, scalar.NewUint16Scalar(3), uint16(3))
+ assertParseScalar(t, arrow.PrimitiveTypes.Uint16, "3",
scalar.NewUint16Scalar(3))
+}
+
+func TestBasicUint32Scalars(t *testing.T) {
+ value := uint32(1)
+
+ scalarVal := scalar.NewUint32Scalar(value)
+ assert.Equal(t, value, scalarVal.Value)
+ assert.True(t, scalarVal.IsValid())
+ assert.NoError(t, scalarVal.ValidateFull())
+
+ expectedType := arrow.PrimitiveTypes.Uint32
+ assert.True(t, arrow.TypeEqual(scalarVal.DataType(), expectedType))
+
+ other := uint32(2)
+ scalarOther := scalar.NewUint32Scalar(other)
+ assert.NotEqual(t, scalarVal, scalarOther)
+ assert.False(t, scalar.Equals(scalarVal, scalarOther))
+
+ scalarVal.Value = other
+ assert.Equal(t, other, scalarVal.Value)
+ assert.Equal(t, scalarVal, scalarOther)
+ assert.True(t, scalar.Equals(scalarVal, scalarOther))
+
+ nullVal := scalar.MakeNullScalar(arrow.PrimitiveTypes.Uint32)
+ assert.False(t, nullVal.IsValid())
+ assert.NoError(t, nullVal.ValidateFull())
+}
+
+func TestMakeScalarUint32(t *testing.T) {
+ three := scalar.MakeScalar(uint32(3))
+ assert.NoError(t, three.ValidateFull())
+ assert.Equal(t, scalar.NewUint32Scalar(3), three)
+
+ assertMakeScalar(t, scalar.NewUint32Scalar(3), uint32(3))
+ assertParseScalar(t, arrow.PrimitiveTypes.Uint32, "3",
scalar.NewUint32Scalar(3))
+}
+
+func TestBasicUint64Scalars(t *testing.T) {
+ value := uint64(1)
+
+ scalarVal := scalar.NewUint64Scalar(value)
+ assert.Equal(t, value, scalarVal.Value)
+ assert.True(t, scalarVal.IsValid())
+ assert.NoError(t, scalarVal.ValidateFull())
+
+ expectedType := arrow.PrimitiveTypes.Uint64
+ assert.True(t, arrow.TypeEqual(scalarVal.DataType(), expectedType))
+
+ other := uint64(2)
+ scalarOther := scalar.NewUint64Scalar(other)
+ assert.NotEqual(t, scalarVal, scalarOther)
+ assert.False(t, scalar.Equals(scalarVal, scalarOther))
+
+ scalarVal.Value = other
+ assert.Equal(t, other, scalarVal.Value)
+ assert.Equal(t, scalarVal, scalarOther)
+ assert.True(t, scalar.Equals(scalarVal, scalarOther))
+
+ nullVal := scalar.MakeNullScalar(arrow.PrimitiveTypes.Uint64)
+ assert.False(t, nullVal.IsValid())
+ assert.NoError(t, nullVal.ValidateFull())
+}
+
+func TestMakeScalarUint64(t *testing.T) {
+ three := scalar.MakeScalar(uint64(3))
+ assert.NoError(t, three.ValidateFull())
+ assert.Equal(t, scalar.NewUint64Scalar(3), three)
+
+ assertMakeScalar(t, scalar.NewUint64Scalar(3), uint64(3))
+ assertParseScalar(t, arrow.PrimitiveTypes.Uint64, "3",
scalar.NewUint64Scalar(3))
+}
+
+func TestBasicFloat32Scalars(t *testing.T) {
+ value := float32(1)
+
+ scalarVal := scalar.NewFloat32Scalar(value)
+ assert.Equal(t, value, scalarVal.Value)
+ assert.True(t, scalarVal.IsValid())
+ assert.NoError(t, scalarVal.ValidateFull())
+
+ expectedType := arrow.PrimitiveTypes.Float32
+ assert.True(t, arrow.TypeEqual(scalarVal.DataType(), expectedType))
+
+ other := float32(2)
+ scalarOther := scalar.NewFloat32Scalar(other)
+ assert.NotEqual(t, scalarVal, scalarOther)
+ assert.False(t, scalar.Equals(scalarVal, scalarOther))
+
+ scalarVal.Value = other
+ assert.Equal(t, other, scalarVal.Value)
+ assert.Equal(t, scalarVal, scalarOther)
+ assert.True(t, scalar.Equals(scalarVal, scalarOther))
+
+ nullVal := scalar.MakeNullScalar(arrow.PrimitiveTypes.Float32)
+ assert.False(t, nullVal.IsValid())
+ assert.NoError(t, nullVal.ValidateFull())
+}
+
+func TestMakeScalarFloat32(t *testing.T) {
+ three := scalar.MakeScalar(float32(3))
+ assert.NoError(t, three.ValidateFull())
+ assert.Equal(t, scalar.NewFloat32Scalar(3), three)
+
+ assertMakeScalar(t, scalar.NewFloat32Scalar(3), float32(3))
+ assertParseScalar(t, arrow.PrimitiveTypes.Float32, "3",
scalar.NewFloat32Scalar(3))
+}
+
+func TestBasicFloat64Scalars(t *testing.T) {
+ value := float64(1)
+
+ scalarVal := scalar.NewFloat64Scalar(value)
+ assert.Equal(t, value, scalarVal.Value)
+ assert.True(t, scalarVal.IsValid())
+ assert.NoError(t, scalarVal.ValidateFull())
+
+ expectedType := arrow.PrimitiveTypes.Float64
+ assert.True(t, arrow.TypeEqual(scalarVal.DataType(), expectedType))
+
+ other := float64(2)
+ scalarOther := scalar.NewFloat64Scalar(other)
+ assert.NotEqual(t, scalarVal, scalarOther)
+ assert.False(t, scalar.Equals(scalarVal, scalarOther))
+
+ scalarVal.Value = other
+ assert.Equal(t, other, scalarVal.Value)
+ assert.Equal(t, scalarVal, scalarOther)
+ assert.True(t, scalar.Equals(scalarVal, scalarOther))
+
+ nullVal := scalar.MakeNullScalar(arrow.PrimitiveTypes.Float64)
+ assert.False(t, nullVal.IsValid())
+ assert.NoError(t, nullVal.ValidateFull())
+}
+
+func TestMakeScalarFloat64(t *testing.T) {
+ three := scalar.MakeScalar(float64(3))
+ assert.NoError(t, three.ValidateFull())
+ assert.Equal(t, scalar.NewFloat64Scalar(3), three)
+
+ assertMakeScalar(t, scalar.NewFloat64Scalar(3), float64(3))
+ assertParseScalar(t, arrow.PrimitiveTypes.Float64, "3",
scalar.NewFloat64Scalar(3))
+}
diff --git a/go/arrow/scalar/numeric.gen_test.go.tmpl
b/go/arrow/scalar/numeric.gen_test.go.tmpl
new file mode 100644
index 0000000..7ac3a25
--- /dev/null
+++ b/go/arrow/scalar/numeric.gen_test.go.tmpl
@@ -0,0 +1,63 @@
+// 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_test
+
+import (
+ "testing"
+
+ "github.com/apache/arrow/go/arrow"
+ "github.com/apache/arrow/go/arrow/scalar"
+ "github.com/stretchr/testify/assert"
+)
+
+
+{{range .In}}
+func TestBasic{{.Name}}Scalars(t *testing.T) {
+ value := {{.Type}}(1)
+
+ scalarVal := scalar.New{{.Name}}Scalar(value)
+ assert.Equal(t, value, scalarVal.Value)
+ assert.True(t, scalarVal.IsValid())
+ assert.NoError(t, scalarVal.ValidateFull())
+
+ expectedType := arrow.PrimitiveTypes.{{.Name}}
+ assert.True(t, arrow.TypeEqual(scalarVal.DataType(), expectedType))
+
+ other := {{.Type}}(2)
+ scalarOther := scalar.New{{.Name}}Scalar(other)
+ assert.NotEqual(t, scalarVal, scalarOther)
+ assert.False(t, scalar.Equals(scalarVal, scalarOther))
+
+ scalarVal.Value = other
+ assert.Equal(t, other, scalarVal.Value)
+ assert.Equal(t, scalarVal, scalarOther)
+ assert.True(t, scalar.Equals(scalarVal, scalarOther))
+
+ nullVal := scalar.MakeNullScalar(arrow.PrimitiveTypes.{{.Name}})
+ assert.False(t, nullVal.IsValid())
+ assert.NoError(t, nullVal.ValidateFull())
+}
+
+func TestMakeScalar{{.Name}}(t *testing.T) {
+ three := scalar.MakeScalar({{.Type}}(3))
+ assert.NoError(t, three.ValidateFull())
+ assert.Equal(t, scalar.New{{.Name}}Scalar(3), three)
+
+ assertMakeScalar(t, scalar.New{{.Name}}Scalar(3), {{.Type}}(3))
+ assertParseScalar(t, arrow.PrimitiveTypes.{{.Name}}, "3",
scalar.New{{.Name}}Scalar(3))
+}
+{{end}}
diff --git a/go/arrow/scalar/parse.go b/go/arrow/scalar/parse.go
new file mode 100644
index 0000000..e5bb827
--- /dev/null
+++ b/go/arrow/scalar/parse.go
@@ -0,0 +1,336 @@
+// 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 (
+ "math/bits"
+ "strconv"
+ "time"
+
+ "github.com/apache/arrow/go/arrow"
+ "github.com/apache/arrow/go/arrow/array"
+ "github.com/apache/arrow/go/arrow/float16"
+ "github.com/apache/arrow/go/arrow/memory"
+ "golang.org/x/xerrors"
+)
+
+// MakeScalarParam is for converting a value to a scalar when it requires a
+// parameterized data type such as a time type that needs units, or a fixed
+// size list which needs it's size.
+//
+// Will fall back to MakeScalar without the passed in type if not one of the
+// parameterized types.
+func MakeScalarParam(val interface{}, dt arrow.DataType) (Scalar, error) {
+ switch v := val.(type) {
+ case []byte:
+ buf := memory.NewBufferBytes(v)
+ defer buf.Release()
+
+ switch dt.ID() {
+ case arrow.BINARY:
+ return NewBinaryScalar(buf, dt), nil
+ case arrow.STRING:
+ return NewStringScalarFromBuffer(buf), nil
+ case arrow.FIXED_SIZE_BINARY:
+ if buf.Len() ==
dt.(*arrow.FixedSizeBinaryType).ByteWidth {
+ return NewFixedSizeBinaryScalar(buf, dt), nil
+ }
+ return nil, xerrors.Errorf("invalid scalar value of len
%d for type %s", v, dt)
+ }
+ case *memory.Buffer:
+ switch dt.ID() {
+ case arrow.BINARY:
+ return NewBinaryScalar(v, dt), nil
+ case arrow.STRING:
+ return NewStringScalarFromBuffer(v), nil
+ case arrow.FIXED_SIZE_BINARY:
+ if v.Len() == dt.(*arrow.FixedSizeBinaryType).ByteWidth
{
+ return NewFixedSizeBinaryScalar(v, dt), nil
+ }
+ return nil, xerrors.Errorf("invalid scalar value of len
%d for type %s", v.Len(), dt)
+ }
+ case arrow.Time32:
+ return NewTime32Scalar(v, dt), nil
+ case arrow.Time64:
+ return NewTime64Scalar(v, dt), nil
+ case arrow.Timestamp:
+ return NewTimestampScalar(v, dt), nil
+ case array.Interface:
+ switch dt.ID() {
+ case arrow.LIST:
+ if !arrow.TypeEqual(v.DataType(),
dt.(*arrow.ListType).Elem()) {
+ return nil, xerrors.Errorf("inconsistent type
for list scalar array and data type")
+ }
+ return NewListScalar(v), nil
+ case arrow.FIXED_SIZE_LIST:
+ if !arrow.TypeEqual(v.DataType(),
dt.(*arrow.FixedSizeListType).Elem()) {
+ return nil, xerrors.Errorf("inconsistent type
for list scalar array and data type")
+ }
+ return NewFixedSizeListScalarWithType(v, dt), nil
+ case arrow.MAP:
+ if !arrow.TypeEqual(dt.(*arrow.MapType).ValueType(),
v.DataType()) {
+ return nil, xerrors.Errorf("inconsistent type
for map scalar type")
+ }
+ return NewMapScalar(v), nil
+ }
+ }
+ return MakeScalar(val), nil
+}
+
+// MakeScalar creates a scalar of the passed in type via reflection.
+func MakeScalar(val interface{}) Scalar {
+ switch v := val.(type) {
+ case nil:
+ return ScalarNull
+ case bool:
+ return NewBooleanScalar(v)
+ case int8:
+ return NewInt8Scalar(v)
+ case uint8:
+ return NewUint8Scalar(v)
+ case int16:
+ return NewInt16Scalar(v)
+ case uint16:
+ return NewUint16Scalar(v)
+ case int32:
+ return NewInt32Scalar(v)
+ case uint32:
+ return NewUint32Scalar(v)
+ case int64:
+ return NewInt64Scalar(v)
+ case uint64:
+ return NewUint64Scalar(v)
+ case int:
+ // determine size of an int on this system
+ switch bits.UintSize {
+ case 32:
+ return NewInt32Scalar(int32(v))
+ case 64:
+ return NewInt64Scalar(int64(v))
+ }
+ case uint:
+ // determine size of an int on this system
+ switch bits.UintSize {
+ case 32:
+ return NewUint32Scalar(uint32(v))
+ case 64:
+ return NewUint64Scalar(uint64(v))
+ }
+ case []byte:
+ buf := memory.NewBufferBytes(v)
+ defer buf.Release()
+ return NewBinaryScalar(buf, arrow.BinaryTypes.Binary)
+ case string:
+ return NewStringScalar(v)
+ case arrow.Date32:
+ return NewDate32Scalar(v)
+ case arrow.Date64:
+ return NewDate64Scalar(v)
+ case float16.Num:
+ return NewFloat16Scalar(v)
+ case float32:
+ return NewFloat32Scalar(v)
+ case float64:
+ return NewFloat64Scalar(v)
+ case arrow.MonthInterval:
+ return NewMonthIntervalScalar(v)
+ case arrow.DayTimeInterval:
+ return NewDayTimeIntervalScalar(v)
+ }
+
+ panic(xerrors.Errorf("makescalar not implemented for type value %#v",
val))
+}
+
+// MakeIntegerScalar is a helper function for creating an integer scalar of a
+// given bitsize.
+func MakeIntegerScalar(v int64, bitsize int) (Scalar, error) {
+ switch bitsize {
+ case 8:
+ return NewInt8Scalar(int8(v)), nil
+ case 16:
+ return NewInt16Scalar(int16(v)), nil
+ case 32:
+ return NewInt32Scalar(int32(v)), nil
+ case 64:
+ return NewInt64Scalar(int64(v)), nil
+ }
+ return nil, xerrors.Errorf("invalid bitsize for integer scalar: %d",
bitsize)
+}
+
+// MakeUnsignedIntegerScalar is a helper function for creating an unsigned int
+// scalar of the specified bit width.
+func MakeUnsignedIntegerScalar(v uint64, bitsize int) (Scalar, error) {
+ switch bitsize {
+ case 8:
+ return NewUint8Scalar(uint8(v)), nil
+ case 16:
+ return NewUint16Scalar(uint16(v)), nil
+ case 32:
+ return NewUint32Scalar(uint32(v)), nil
+ case 64:
+ return NewUint64Scalar(uint64(v)), nil
+ }
+ return nil, xerrors.Errorf("invalid bitsize for uint scalar: %d",
bitsize)
+}
+
+// ParseScalar parses a string to create a scalar of the passed in type.
Currently
+// does not support any nested types such as Structs or Lists.
+func ParseScalar(dt arrow.DataType, val string) (Scalar, error) {
+ switch dt.ID() {
+ case arrow.STRING:
+ return NewStringScalar(val), nil
+ case arrow.BINARY:
+ buf := memory.NewBufferBytes([]byte(val))
+ defer buf.Release()
+ return NewBinaryScalar(buf, dt), nil
+ case arrow.FIXED_SIZE_BINARY:
+ if len(val) != dt.(*arrow.FixedSizeBinaryType).ByteWidth {
+ return nil, xerrors.Errorf("invalid value %s for scalar
of type %s", val, dt)
+ }
+ buf := memory.NewBufferBytes([]byte(val))
+ defer buf.Release()
+ return NewFixedSizeBinaryScalar(buf, dt), nil
+ case arrow.BOOL:
+ val, err := strconv.ParseBool(val)
+ if err != nil {
+ return nil, err
+ }
+ return NewBooleanScalar(val), nil
+ case arrow.INT8, arrow.INT16, arrow.INT32, arrow.INT64:
+ width := dt.(arrow.FixedWidthDataType).BitWidth()
+ val, err := strconv.ParseInt(val, 0, width)
+ if err != nil {
+ return nil, err
+ }
+ return MakeIntegerScalar(val, width)
+ case arrow.UINT8, arrow.UINT16, arrow.UINT32, arrow.UINT64:
+ width := dt.(arrow.FixedWidthDataType).BitWidth()
+ val, err := strconv.ParseUint(val, 0, width)
+ if err != nil {
+ return nil, err
+ }
+ return MakeUnsignedIntegerScalar(val, width)
+ case arrow.FLOAT16:
+ val, err := strconv.ParseFloat(val, 32)
+ if err != nil {
+ return nil, err
+ }
+ return NewFloat16ScalarFromFloat32(float32(val)), nil
+ case arrow.FLOAT32, arrow.FLOAT64:
+ width := dt.(arrow.FixedWidthDataType).BitWidth()
+ val, err := strconv.ParseFloat(val, width)
+ if err != nil {
+ return nil, err
+ }
+ switch width {
+ case 32:
+ return NewFloat32Scalar(float32(val)), nil
+ case 64:
+ return NewFloat64Scalar(float64(val)), nil
+ }
+ case arrow.TIMESTAMP:
+ format := "2006-01-02"
+ if val[len(val)-1] == 'Z' {
+ val = val[:len(val)-1]
+ }
+
+ switch {
+ case len(val) == 13:
+ format += string(val[10]) + "15"
+ case len(val) == 16:
+ format += string(val[10]) + "15:04"
+ case len(val) >= 19:
+ format += string(val[10]) + "15:04:05.999999999"
+ }
+
+ out, err := time.ParseInLocation(format, val, time.UTC)
+ if err != nil {
+ return nil, err
+ }
+
+ value :=
arrow.Timestamp(ConvertTimestampValue(arrow.Nanosecond,
dt.(*arrow.TimestampType).Unit, out.UnixNano()))
+ return NewTimestampScalar(value, dt), nil
+ case arrow.DURATION:
+ value, err := time.ParseDuration(val)
+ if err != nil {
+ return nil, err
+ }
+ unit := dt.(*arrow.DurationType).Unit
+ var out arrow.Duration
+ switch unit {
+ case arrow.Nanosecond:
+ out = arrow.Duration(value.Nanoseconds())
+ case arrow.Microsecond:
+ out = arrow.Duration(value.Microseconds())
+ case arrow.Millisecond:
+ out = arrow.Duration(value.Milliseconds())
+ case arrow.Second:
+ out = arrow.Duration(value.Seconds())
+ }
+ return NewDurationScalar(out, dt), nil
+ case arrow.DATE32, arrow.DATE64:
+ out, err := time.ParseInLocation("2006-01-02", val, time.UTC)
+ if err != nil {
+ return nil, err
+ }
+ if dt.ID() == arrow.DATE32 {
+ return NewDate32Scalar(arrow.Date32(out.Unix() /
int64((time.Hour * 24).Seconds()))), nil
+ } else {
+ return NewDate64Scalar(arrow.Date64(out.Unix() *
1000)), nil
+ }
+ case arrow.TIME32:
+ var (
+ out time.Time
+ err error
+ )
+ switch {
+ case len(val) == 5:
+ out, err = time.ParseInLocation("15:04", val, time.UTC)
+ default:
+ out, err = time.ParseInLocation("15:04:05.999", val,
time.UTC)
+ }
+ if err != nil {
+ return nil, err
+ }
+ t := out.Sub(time.Date(0, 1, 1, 0, 0, 0, 0, time.UTC))
+ if dt.(*arrow.Time32Type).Unit == arrow.Second {
+ return NewTime32Scalar(arrow.Time32(t.Seconds()), dt),
nil
+ }
+ return NewTime32Scalar(arrow.Time32(t.Milliseconds()), dt), nil
+ case arrow.TIME64:
+ var (
+ out time.Time
+ err error
+ )
+ switch {
+ case len(val) == 5:
+ out, err = time.ParseInLocation("15:04", val, time.UTC)
+ default:
+ out, err = time.ParseInLocation("15:04:05.999999999",
val, time.UTC)
+ }
+ if err != nil {
+ return nil, err
+ }
+ t := out.Sub(time.Date(0, 1, 1, 0, 0, 0, 0, time.UTC))
+ if dt.(*arrow.Time64Type).Unit == arrow.Microsecond {
+ return NewTime64Scalar(arrow.Time64(t.Microseconds()),
dt), nil
+ }
+ return NewTime64Scalar(arrow.Time64(t.Nanoseconds()), dt), nil
+ }
+
+ return nil, xerrors.Errorf("parsing of scalar for type %s not
implemented", dt)
+}
diff --git a/go/arrow/scalar/scalar.go b/go/arrow/scalar/scalar.go
new file mode 100644
index 0000000..49b386d
--- /dev/null
+++ b/go/arrow/scalar/scalar.go
@@ -0,0 +1,612 @@
+// 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"
+ "math"
+ "math/big"
+ "reflect"
+ "strconv"
+ "unsafe"
+
+ "github.com/apache/arrow/go/arrow"
+ "github.com/apache/arrow/go/arrow/array"
+ "github.com/apache/arrow/go/arrow/bitutil"
+ "github.com/apache/arrow/go/arrow/decimal128"
+ "github.com/apache/arrow/go/arrow/float16"
+ "github.com/apache/arrow/go/arrow/internal/debug"
+ "github.com/apache/arrow/go/arrow/memory"
+ "golang.org/x/xerrors"
+)
+
+// Scalar represents a single value of a specific DataType as opposed to
+// an array.
+//
+// Scalars are useful for passing single value inputs to compute functions
+// (not yet implemented) or for representing individual array elements,
+// (with a non-trivial cost though).
+type Scalar interface {
+ fmt.Stringer
+ // IsValid returns true if the value is non-null, otherwise false.
+ IsValid() bool
+ // The datatype of the value in this scalar
+ DataType() arrow.DataType
+ // Performs cheap validation checks, returns nil if successful
+ Validate() error
+ // Perform more expensive validation checks, returns nil if successful
+ ValidateFull() error
+ // Cast the value to the desired DataType (returns an error if unable
to do so)
+ // should take semantics into account and modify the value accordingly.
+ CastTo(arrow.DataType) (Scalar, error)
+
+ // internal only functions for delegation
+ value() interface{}
+ equals(Scalar) bool
+ //TODO(zeroshade): approxEquals
+}
+
+func validateOptional(s *scalar, value interface{}, valueDesc string) error {
+ if s.Valid && value == nil {
+ return xerrors.Errorf("%s scalar is marked valid but doesn't
have a %s", s.Type, valueDesc)
+ }
+ if !s.Valid && value != nil && !reflect.ValueOf(value).IsNil() {
+ return xerrors.Errorf("%s scalar is marked null but has a %s",
s.Type, valueDesc)
+ }
+ return nil
+}
+
+type scalar struct {
+ Type arrow.DataType
+ Valid bool
+}
+
+func (s *scalar) String() string {
+ if !s.Valid {
+ return "null"
+ }
+
+ return "..."
+}
+
+func (s *scalar) IsValid() bool { return s.Valid }
+
+func (s *scalar) Validate() error {
+ if s.Type == nil {
+ return xerrors.New("scalar lacks a type")
+ }
+ return nil
+}
+
+func (s *scalar) ValidateFull() error {
+ return s.Validate()
+}
+
+func (s scalar) DataType() arrow.DataType { return s.Type }
+
+type Null struct {
+ scalar
+}
+
+// by the time we get here we already know that the rhs is the right type
+func (n *Null) equals(s Scalar) bool {
+ debug.Assert(s.DataType().ID() == arrow.NULL, "scalar null equals
should only receive null")
+ return true
+}
+
+func (n *Null) value() interface{} { return nil }
+
+func (n *Null) CastTo(dt arrow.DataType) (Scalar, error) {
+ return MakeNullScalar(dt), nil
+}
+
+func (n *Null) Validate() (err error) {
+ err = n.scalar.Validate()
+ if err != nil {
+ return
+ }
+ if n.Valid {
+ err = xerrors.New("null scalar should have Valid = false")
+ }
+ return
+}
+
+func (n *Null) ValidateFull() error { return n.Validate() }
+
+var (
+ ScalarNull *Null = &Null{scalar{Type: arrow.Null, Valid: false}}
+)
+
+type PrimitiveScalar interface {
+ Scalar
+ Data() []byte
+}
+
+type Boolean struct {
+ scalar
+ Value bool
+}
+
+// by the time we get here we already know that the rhs is the right type
+func (n *Boolean) equals(rhs Scalar) bool {
+ return n.Value == rhs.(*Boolean).Value
+}
+
+func (s *Boolean) value() interface{} { return s.Value }
+
+func (s *Boolean) Data() []byte {
+ return (*[1]byte)(unsafe.Pointer(&s.Value))[:]
+}
+
+func (s *Boolean) 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 *Boolean) CastTo(dt arrow.DataType) (Scalar, error) {
+ if !s.Valid {
+ return MakeNullScalar(dt), nil
+ }
+
+ if dt.ID() == arrow.STRING {
+ return NewStringScalar(strconv.FormatBool(s.Value)), nil
+ }
+
+ val := 0
+ if s.Value {
+ val = 1
+ }
+
+ switch dt.ID() {
+ case arrow.UINT8:
+ return NewUint8Scalar(uint8(val)), nil
+ case arrow.INT8:
+ return NewInt8Scalar(int8(val)), nil
+ case arrow.UINT16:
+ return NewUint16Scalar(uint16(val)), nil
+ case arrow.INT16:
+ return NewInt16Scalar(int16(val)), nil
+ case arrow.UINT32:
+ return NewUint32Scalar(uint32(val)), nil
+ case arrow.INT32:
+ return NewInt32Scalar(int32(val)), nil
+ case arrow.UINT64:
+ return NewUint64Scalar(uint64(val)), nil
+ case arrow.INT64:
+ return NewInt64Scalar(int64(val)), nil
+ case arrow.FLOAT16:
+ return NewFloat16Scalar(float16.New(float32(val))), nil
+ case arrow.FLOAT32:
+ return NewFloat32Scalar(float32(val)), nil
+ case arrow.FLOAT64:
+ return NewFloat64Scalar(float64(val)), nil
+ default:
+ return nil, xerrors.Errorf("invalid scalar cast from type bool
to type %s", dt)
+ }
+}
+
+func NewBooleanScalar(val bool) *Boolean {
+ return &Boolean{scalar{arrow.FixedWidthTypes.Boolean, true}, val}
+}
+
+type Float16 struct {
+ scalar
+ Value float16.Num
+}
+
+func (s *Float16) value() interface{} { return s.Value }
+
+func (f *Float16) Data() []byte {
+ return (*[arrow.Float16SizeBytes]byte)(unsafe.Pointer(&f.Value))[:]
+}
+func (f *Float16) equals(rhs Scalar) bool {
+ return f.Value == rhs.(*Float16).Value
+}
+func (f *Float16) CastTo(to arrow.DataType) (Scalar, error) {
+ if !f.Valid {
+ return MakeNullScalar(to), nil
+ }
+
+ if r, ok := numericMap[to.ID()]; ok {
+ return convertToNumeric(reflect.ValueOf(f.Value.Float32()),
r.valueType, r.scalarFunc), nil
+ }
+
+ if to.ID() == arrow.BOOL {
+ return NewBooleanScalar(f.Value.Uint16() != 0), nil
+ } else if to.ID() == arrow.STRING {
+ return NewStringScalar(f.Value.String()), nil
+ }
+
+ return nil, xerrors.Errorf("cannot cast non-null float16 scalar to type
%s", to)
+}
+
+func (s *Float16) 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 NewFloat16ScalarFromFloat32(val float32) *Float16 {
+ return NewFloat16Scalar(float16.New(val))
+}
+
+func NewFloat16Scalar(val float16.Num) *Float16 {
+ return &Float16{scalar{arrow.FixedWidthTypes.Float16, true}, val}
+}
+
+type Decimal128 struct {
+ scalar
+ Value decimal128.Num
+}
+
+func (s *Decimal128) value() interface{} { return s.Value }
+
+func (s *Decimal128) 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 *Decimal128) equals(rhs Scalar) bool {
+ return s.Value == rhs.(*Decimal128).Value
+}
+
+func (s *Decimal128) CastTo(to arrow.DataType) (Scalar, error) {
+ if !s.Valid {
+ return MakeNullScalar(to), nil
+ }
+
+ switch to.ID() {
+ case arrow.DECIMAL:
+ return NewDecimal128Scalar(s.Value, to), nil
+ case arrow.STRING:
+ dt := s.Type.(*arrow.Decimal128Type)
+ scale := big.NewFloat(math.Pow10(int(dt.Scale)))
+ val := (&big.Float{}).SetInt(s.Value.BigInt())
+ return NewStringScalar(val.Quo(val, scale).Text('g',
int(dt.Precision))), nil
+ }
+
+ return nil, xerrors.Errorf("cannot cast non-nil decimal128 scalar to
type %s", to)
+}
+
+func NewDecimal128Scalar(val decimal128.Num, typ arrow.DataType) *Decimal128 {
+ return &Decimal128{scalar{typ, true}, val}
+}
+
+type Extension struct {
+ scalar
+ Value Scalar
+}
+
+func (s *Extension) value() interface{} { return s.Value }
+func (s *Extension) equals(rhs Scalar) bool {
+ return Equals(s.Value, rhs.(*Extension).Value)
+}
+func (e *Extension) Validate() (err error) {
+ if err = e.scalar.Validate(); err != nil {
+ return err
+ }
+
+ if !e.Valid {
+ if e.Value != nil {
+ err = xerrors.Errorf("null %s scalar has storage
value", e.Type)
+ }
+ return
+ }
+
+ switch {
+ case e.Value == nil:
+ err = xerrors.Errorf("non-null %s scalar doesn't have a storage
value", e.Type)
+ case !e.Value.IsValid():
+ err = xerrors.Errorf("non-null %s scalar has a null storage
value", e.Type)
+ default:
+ if err = e.Value.Validate(); err != nil {
+ err = xerrors.Errorf("%s scalar fails validation for
storage value: %w", e.Type, err)
+ }
+ }
+ return
+}
+
+func (e *Extension) ValidateFull() error {
+ if err := e.Validate(); err != nil {
+ return err
+ }
+
+ if e.Valid {
+ return e.Value.ValidateFull()
+ }
+ return nil
+}
+
+func (s *Extension) CastTo(to arrow.DataType) (Scalar, error) {
+ if !s.Valid {
+ return MakeNullScalar(to), nil
+ }
+
+ if arrow.TypeEqual(s.Type, to) {
+ return s, nil
+ }
+
+ return nil, xerrors.Errorf("cannot cast non-null extension scalar of
type %s to type %s", s.Type, to)
+}
+
+func (s *Extension) 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 NewExtensionScalar(storage Scalar, typ arrow.DataType) *Extension {
+ return &Extension{scalar{typ, true}, storage}
+}
+
+func convertToNumeric(v reflect.Value, to reflect.Type, fn reflect.Value)
Scalar {
+ return fn.Call([]reflect.Value{v.Convert(to)})[0].Interface().(Scalar)
+}
+
+// MakeNullScalar creates a scalar value of the desired type representing a
null value
+func MakeNullScalar(dt arrow.DataType) Scalar {
+ return makeNullFn[byte(dt.ID()&0x1f)](dt)
+}
+
+func unsupportedScalarType(dt arrow.DataType) Scalar {
+ panic("unsupported scalar data type: " + dt.ID().String())
+}
+
+func invalidScalarType(dt arrow.DataType) Scalar {
+ panic("invalid scalar type: " + dt.ID().String())
+}
+
+type scalarMakeNullFn func(arrow.DataType) Scalar
+
+var makeNullFn [32]scalarMakeNullFn
+
+func init() {
+ makeNullFn = [...]scalarMakeNullFn{
+ arrow.NULL: func(dt arrow.DataType) Scalar {
return ScalarNull },
+ arrow.BOOL: func(dt arrow.DataType) Scalar {
return &Boolean{scalar: scalar{dt, false}} },
+ arrow.UINT8: func(dt arrow.DataType) Scalar {
return &Uint8{scalar: scalar{dt, false}} },
+ arrow.INT8: func(dt arrow.DataType) Scalar {
return &Int8{scalar: scalar{dt, false}} },
+ arrow.UINT16: func(dt arrow.DataType) Scalar {
return &Uint16{scalar: scalar{dt, false}} },
+ arrow.INT16: func(dt arrow.DataType) Scalar {
return &Int16{scalar: scalar{dt, false}} },
+ arrow.UINT32: func(dt arrow.DataType) Scalar {
return &Uint32{scalar: scalar{dt, false}} },
+ arrow.INT32: func(dt arrow.DataType) Scalar {
return &Int32{scalar: scalar{dt, false}} },
+ arrow.UINT64: func(dt arrow.DataType) Scalar {
return &Uint64{scalar: scalar{dt, false}} },
+ arrow.INT64: func(dt arrow.DataType) Scalar {
return &Int64{scalar: scalar{dt, false}} },
+ arrow.FLOAT16: func(dt arrow.DataType) Scalar {
return &Float16{scalar: scalar{dt, false}} },
+ arrow.FLOAT32: func(dt arrow.DataType) Scalar {
return &Float32{scalar: scalar{dt, false}} },
+ arrow.FLOAT64: func(dt arrow.DataType) Scalar {
return &Float64{scalar: scalar{dt, false}} },
+ arrow.STRING: func(dt arrow.DataType) Scalar {
return &String{&Binary{scalar: scalar{dt, false}}} },
+ arrow.BINARY: func(dt arrow.DataType) Scalar {
return &Binary{scalar: scalar{dt, false}} },
+ arrow.FIXED_SIZE_BINARY: func(dt arrow.DataType) Scalar {
return &FixedSizeBinary{&Binary{scalar: scalar{dt, false}}} },
+ arrow.DATE32: func(dt arrow.DataType) Scalar {
return &Date32{scalar: scalar{dt, false}} },
+ arrow.DATE64: func(dt arrow.DataType) Scalar {
return &Date64{scalar: scalar{dt, false}} },
+ arrow.TIMESTAMP: func(dt arrow.DataType) Scalar {
return &Timestamp{scalar: scalar{dt, false}} },
+ arrow.TIME32: func(dt arrow.DataType) Scalar {
return &Time32{scalar: scalar{dt, false}} },
+ arrow.TIME64: func(dt arrow.DataType) Scalar {
return &Time64{scalar: scalar{dt, false}} },
+ arrow.INTERVAL: func(dt arrow.DataType) Scalar {
+ if arrow.TypeEqual(dt,
arrow.FixedWidthTypes.MonthInterval) {
+ return &MonthInterval{scalar: scalar{dt, false}}
+ }
+ return &DayTimeInterval{scalar: scalar{dt, false}}
+ },
+ arrow.DECIMAL: func(dt arrow.DataType) Scalar { return
&Decimal128{scalar: scalar{dt, false}} },
+ arrow.LIST: func(dt arrow.DataType) Scalar { return
&List{scalar: scalar{dt, false}} },
+ arrow.STRUCT: func(dt arrow.DataType) Scalar { return
&Struct{scalar: scalar{dt, false}} },
+ arrow.UNION: unsupportedScalarType,
+ arrow.DICTIONARY: unsupportedScalarType,
+ arrow.MAP: func(dt arrow.DataType) Scalar { return
&Map{&List{scalar: scalar{dt, false}}} },
+ arrow.EXTENSION: func(dt arrow.DataType) Scalar { return
&Extension{scalar: scalar{dt, false}} },
+ arrow.FIXED_SIZE_LIST: func(dt arrow.DataType) Scalar { return
&FixedSizeList{&List{scalar: scalar{dt, false}}} },
+ arrow.DURATION: func(dt arrow.DataType) Scalar { return
&Duration{scalar: scalar{dt, false}} },
+
+ // invalid data types to fill out array size 2⁵-1
+ 31: invalidScalarType,
+ }
+
+ f := numericMap[arrow.FLOAT16]
+ f.scalarFunc = reflect.ValueOf(NewFloat16ScalarFromFloat32)
+ f.valueType = reflect.TypeOf(float32(0))
+ numericMap[arrow.FLOAT16] = f
+}
+
+// GetScalar creates a scalar object from the value at a given index in the
+// passed in array, returns an error if unable to do so.
+func GetScalar(arr array.Interface, idx int) (Scalar, error) {
+ switch arr := arr.(type) {
+ case *array.Binary:
+ buf := memory.NewBufferBytes(arr.Value(idx))
+ defer buf.Release()
+ return NewBinaryScalar(buf, arr.DataType()), nil
+ case *array.Boolean:
+ return NewBooleanScalar(arr.Value(idx)), nil
+ case *array.Date32:
+ return NewDate32Scalar(arr.Value(idx)), nil
+ case *array.Date64:
+ return NewDate64Scalar(arr.Value(idx)), nil
+ case *array.DayTimeInterval:
+ return NewDayTimeIntervalScalar(arr.Value(idx)), nil
+ case *array.Decimal128:
+ return NewDecimal128Scalar(arr.Value(idx), arr.DataType()), nil
+ case *array.Duration:
+ return NewDurationScalar(arr.Value(idx), arr.DataType()), nil
+ case array.ExtensionArray:
+ storage, err := GetScalar(arr.Storage(), idx)
+ if err != nil {
+ return nil, err
+ }
+ return NewExtensionScalar(storage, arr.DataType()), nil
+ case *array.FixedSizeBinary:
+ buf := memory.NewBufferBytes(arr.Value(idx))
+ defer buf.Release()
+ return NewFixedSizeBinaryScalar(buf, arr.DataType()), nil
+ case *array.FixedSizeList:
+ size := int(arr.DataType().(*arrow.FixedSizeListType).Len())
+ return
NewFixedSizeListScalarWithType(array.NewSlice(arr.ListValues(),
int64(idx*size), int64((idx+1)*size)), arr.DataType()), nil
+ case *array.Float16:
+ return NewFloat16Scalar(arr.Value(idx)), nil
+ case *array.Float32:
+ return NewFloat32Scalar(arr.Value(idx)), nil
+ case *array.Float64:
+ return NewFloat64Scalar(arr.Value(idx)), nil
+ case *array.Int8:
+ return NewInt8Scalar(arr.Value(idx)), nil
+ case *array.Int16:
+ return NewInt16Scalar(arr.Value(idx)), nil
+ case *array.Int32:
+ return NewInt32Scalar(arr.Value(idx)), nil
+ case *array.Int64:
+ return NewInt64Scalar(arr.Value(idx)), nil
+ case *array.Uint8:
+ return NewUint8Scalar(arr.Value(idx)), nil
+ case *array.Uint16:
+ return NewUint16Scalar(arr.Value(idx)), nil
+ case *array.Uint32:
+ return NewUint32Scalar(arr.Value(idx)), nil
+ case *array.Uint64:
+ return NewUint64Scalar(arr.Value(idx)), nil
+ case *array.List:
+ offsets := arr.Offsets()
+ return NewListScalar(array.NewSlice(arr.ListValues(),
int64(offsets[idx]), int64(offsets[idx+1]))), nil
+ case *array.Map:
+ offsets := arr.Offsets()
+ return NewMapScalar(array.NewSlice(arr.ListValues(),
int64(offsets[idx]), int64(offsets[idx+1]))), nil
+ case *array.MonthInterval:
+ return NewMonthIntervalScalar(arr.Value(idx)), nil
+ case *array.Null:
+ return ScalarNull, nil
+ case *array.String:
+ return NewStringScalar(arr.Value(idx)), nil
+ case *array.Struct:
+ children := make(Vector, arr.NumField())
+ for i := range children {
+ child, err := GetScalar(arr.Field(i), idx)
+ if err != nil {
+ return nil, err
+ }
+ children[i] = child
+ }
+ return NewStructScalar(children, arr.DataType()), nil
+ case *array.Time32:
+ return NewTime32Scalar(arr.Value(idx), arr.DataType()), nil
+ case *array.Time64:
+ return NewTime64Scalar(arr.Value(idx), arr.DataType()), nil
+ case *array.Timestamp:
+ return NewTimestampScalar(arr.Value(idx), arr.DataType()), nil
+ }
+
+ return nil, xerrors.Errorf("cannot create scalar from array of type
%s", arr.DataType())
+}
+
+// MakeArrayOfNull creates an array of size length which is all null of the
given data type.
+func MakeArrayOfNull(dt arrow.DataType, length int, mem memory.Allocator)
array.Interface {
+ nullBuf := memory.NewResizableBuffer(mem)
+ nullBuf.Resize(int(bitutil.BytesForBits(int64(length))))
+ defer nullBuf.Release()
+ memory.Set(nullBuf.Bytes(), 0xFF)
+
+ data := array.NewData(dt, length, []*memory.Buffer{nullBuf, nil}, nil,
length, 0)
+ defer data.Release()
+ return array.MakeFromData(data)
+}
+
+// MakeArrayFromScalar returns an array filled with the scalar value repeated
length times.
+// Not yet implemented for nested types such as Struct, List, extension and so
on.
+func MakeArrayFromScalar(sc Scalar, length int, mem memory.Allocator)
(array.Interface, error) {
+ if !sc.IsValid() {
+ return MakeArrayOfNull(sc.DataType(), length, mem), nil
+ }
+
+ createOffsets := func(valLength int32) *memory.Buffer {
+ buffer := memory.NewResizableBuffer(mem)
+ buffer.Resize(arrow.Int32Traits.BytesRequired(length + 1))
+
+ out := arrow.Int32Traits.CastFromBytes(buffer.Bytes())
+ for i, offset := 0, int32(0); i < length+1; i, offset = i+1,
offset+valLength {
+ out[i] = offset
+ }
+ return buffer
+ }
+
+ createBuffer := func(data []byte) *memory.Buffer {
+ buffer := memory.NewResizableBuffer(mem)
+ buffer.Resize(len(data) * length)
+
+ out := buffer.Bytes()
+ copy(out, data)
+ for j := len(data); j < len(out); j *= 2 {
+ copy(out[j:], out[:j])
+ }
+ return buffer
+ }
+
+ finishFixedWidth := func(data []byte) *array.Data {
+ buffer := createBuffer(data)
+ return array.NewData(sc.DataType(), length,
[]*memory.Buffer{nil, buffer}, nil, 0, 0)
+ }
+
+ switch s := sc.(type) {
+ case *Boolean:
+ data := memory.NewResizableBuffer(mem)
+ data.Resize(int(bitutil.BytesForBits(int64(length))))
+ c := byte(0x00)
+ if s.Value {
+ c = 0xFF
+ }
+ memory.Set(data.Bytes(), c)
+ return array.NewBoolean(length, data, nil, 0), nil
+ case BinaryScalar:
+ if s.DataType().ID() == arrow.FIXED_SIZE_BINARY {
+ data := finishFixedWidth(s.Data())
+ defer data.Release()
+ return array.MakeFromData(data), nil
+ }
+
+ valuesBuf := createBuffer(s.Data())
+ offsetsBuf := createOffsets(int32(len(s.Data())))
+ data := array.NewData(sc.DataType(), length,
[]*memory.Buffer{nil, offsetsBuf, valuesBuf}, nil, 0, 0)
+ defer data.Release()
+ return array.MakeFromData(data), nil
+ case PrimitiveScalar:
+ data := finishFixedWidth(s.Data())
+ defer data.Release()
+ return array.MakeFromData(data), nil
+ default:
+ return nil, xerrors.Errorf("array from scalar not yet
implemented for type %s", sc.DataType())
+ }
+}
diff --git a/go/arrow/scalar/scalar_test.go b/go/arrow/scalar/scalar_test.go
new file mode 100644
index 0000000..f2b1c57
--- /dev/null
+++ b/go/arrow/scalar/scalar_test.go
@@ -0,0 +1,769 @@
+// 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_test
+
+import (
+ "bytes"
+ "math/bits"
+ "testing"
+ "time"
+
+ "github.com/apache/arrow/go/arrow"
+ "github.com/apache/arrow/go/arrow/array"
+ "github.com/apache/arrow/go/arrow/decimal128"
+ "github.com/apache/arrow/go/arrow/memory"
+ "github.com/apache/arrow/go/arrow/scalar"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/suite"
+)
+
+func assertScalarsEqual(t *testing.T, expected, actual scalar.Scalar) {
+ assert.Truef(t, scalar.Equals(expected, actual),
"Expected:\n%s\nActual:\n%s", expected, actual)
+}
+
+func assertMakeScalarParam(t *testing.T, expected scalar.Scalar, dt
arrow.DataType, val interface{}) {
+ out, err := scalar.MakeScalarParam(val, dt)
+ assert.NoError(t, err)
+ assert.NoError(t, out.Validate())
+ assert.NoError(t, out.ValidateFull())
+ assertScalarsEqual(t, expected, out)
+}
+
+func assertMakeScalar(t *testing.T, expected scalar.Scalar, val interface{}) {
+ out := scalar.MakeScalar(val)
+ assert.NoError(t, out.Validate())
+ assert.NoError(t, out.ValidateFull())
+ assertScalarsEqual(t, expected, out)
+}
+
+func assertParseScalar(t *testing.T, dt arrow.DataType, str string, expected
scalar.Scalar) {
+ out, err := scalar.ParseScalar(dt, str)
+ assert.NoError(t, err)
+ assert.NoError(t, out.Validate())
+ assert.NoError(t, out.ValidateFull())
+ assertScalarsEqual(t, expected, out)
+}
+
+func TestMakeScalarInt(t *testing.T) {
+ three := scalar.MakeScalar(int(3))
+ assert.NoError(t, three.ValidateFull())
+
+ var expected scalar.Scalar
+ if bits.UintSize == 32 {
+ expected = scalar.NewInt32Scalar(3)
+ } else {
+ expected = scalar.NewInt64Scalar(3)
+ }
+
+ assert.Equal(t, expected, three)
+ assertMakeScalar(t, expected, int(3))
+ assertParseScalar(t, expected.DataType(), "3", expected)
+}
+
+func checkMakeNullScalar(t *testing.T, dt arrow.DataType) scalar.Scalar {
+ s := scalar.MakeNullScalar(dt)
+ assert.NoError(t, s.Validate())
+ assert.NoError(t, s.ValidateFull())
+ assert.True(t, arrow.TypeEqual(s.DataType(), dt))
+ assert.False(t, s.IsValid())
+ return s
+}
+
+func TestMakeScalarUint(t *testing.T) {
+ three := scalar.MakeScalar(uint(3))
+ assert.NoError(t, three.ValidateFull())
+
+ var expected scalar.Scalar
+ if bits.UintSize == 32 {
+ expected = scalar.NewUint32Scalar(3)
+ } else {
+ expected = scalar.NewUint64Scalar(3)
+ }
+
+ assert.Equal(t, expected, three)
+ assertMakeScalar(t, expected, uint(3))
+ assertParseScalar(t, expected.DataType(), "3", expected)
+}
+
+func TestBasicDecimal128(t *testing.T) {
+ ty := &arrow.Decimal128Type{Precision: 3, Scale: 2}
+ pi := scalar.NewDecimal128Scalar(decimal128.New(0, 314), ty)
+ pi2 := scalar.NewDecimal128Scalar(decimal128.FromI64(628), ty)
+ null := checkMakeNullScalar(t, ty)
+
+ assert.NoError(t, pi.ValidateFull())
+ assert.True(t, pi.IsValid())
+ assert.Equal(t, decimal128.FromI64(314), pi.Value)
+
+ assert.NoError(t, null.ValidateFull())
+ assert.False(t, null.IsValid())
+
+ assert.False(t, scalar.Equals(pi, pi2))
+}
+
+func TestBinaryScalarBasics(t *testing.T) {
+ data := "test data"
+ buf := memory.NewBufferBytes([]byte(data))
+
+ value := scalar.NewBinaryScalar(buf, arrow.BinaryTypes.Binary)
+ assert.NoError(t, value.ValidateFull())
+ assert.True(t, bytes.Equal(value.Value.Bytes(), buf.Bytes()))
+ assert.True(t, value.IsValid())
+ assert.True(t, arrow.TypeEqual(value.DataType(),
arrow.BinaryTypes.Binary))
+
+ nullValue := checkMakeNullScalar(t, arrow.BinaryTypes.Binary)
+ assert.False(t, nullValue.IsValid())
+ assert.Nil(t, nullValue.(*scalar.Binary).Value)
+ assert.NoError(t, nullValue.ValidateFull())
+
+ value2 := scalar.NewStringScalarFromBuffer(buf)
+ assert.NoError(t, value2.ValidateFull())
+ assert.True(t, bytes.Equal(value2.Value.Bytes(), buf.Bytes()))
+ assert.True(t, value2.IsValid())
+ assert.True(t, arrow.TypeEqual(arrow.BinaryTypes.String,
value2.DataType()))
+
+ assert.NotEqual(t, value2, value)
+ assert.False(t, scalar.Equals(value2, value))
+
+ value3 := scalar.NewStringScalar(data)
+ assert.True(t, scalar.Equals(value2, value3))
+}
+
+func TestBinaryScalarValidateErrors(t *testing.T) {
+ sc := scalar.NewBinaryScalar(memory.NewBufferBytes([]byte("xxx")),
arrow.BinaryTypes.Binary)
+ sc.Valid = false
+ assert.Error(t, sc.Validate())
+ assert.Error(t, sc.ValidateFull())
+
+ nullScalar := scalar.MakeNullScalar(arrow.BinaryTypes.Binary)
+ nullScalar.(*scalar.Binary).Valid = true
+ assert.Error(t, sc.Validate())
+ assert.Error(t, sc.ValidateFull())
+}
+
+func TestStringMakeScalar(t *testing.T) {
+ assertMakeScalar(t, scalar.NewStringScalar("three"), "three")
+ assertParseScalar(t, arrow.BinaryTypes.String, "three",
scalar.NewStringScalar("three"))
+}
+
+func TestStringScalarValidateErrors(t *testing.T) {
+ sc := scalar.NewStringScalar("xxx")
+ sc.Valid = false
+ assert.Error(t, sc.Validate())
+ assert.Error(t, sc.ValidateFull())
+
+ nullScalar := scalar.MakeNullScalar(arrow.BinaryTypes.String)
+ nullScalar.(*scalar.String).Valid = true
+ assert.Error(t, sc.Validate())
+ assert.Error(t, sc.ValidateFull())
+
+ // invalid utf8
+ sc =
scalar.NewStringScalarFromBuffer(memory.NewBufferBytes([]byte{0xff}))
+ assert.NoError(t, sc.Validate())
+ assert.Error(t, sc.ValidateFull())
+}
+
+func TestFixedSizeBinaryScalarBasics(t *testing.T) {
+ data := "test data"
+ buf := memory.NewBufferBytes([]byte(data))
+
+ exType := &arrow.FixedSizeBinaryType{ByteWidth: 9}
+
+ value := scalar.NewFixedSizeBinaryScalar(buf, exType)
+ assert.NoError(t, value.ValidateFull())
+ assert.True(t, bytes.Equal(value.Value.Bytes(), buf.Bytes()))
+ assert.True(t, value.Valid)
+ assert.True(t, arrow.TypeEqual(value.DataType(), exType))
+
+ nullValue := scalar.MakeNullScalar(exType)
+ assert.NoError(t, nullValue.ValidateFull())
+ assert.False(t, nullValue.IsValid())
+ assert.Nil(t, nullValue.(*scalar.FixedSizeBinary).Value)
+}
+
+func TestFixedSizeBinaryMakeScalar(t *testing.T) {
+ data := "test data"
+ buf := memory.NewBufferBytes([]byte(data))
+ exType := &arrow.FixedSizeBinaryType{ByteWidth: 9}
+
+ assertMakeScalarParam(t, scalar.NewFixedSizeBinaryScalar(buf, exType),
exType, buf)
+ assertParseScalar(t, exType, data, scalar.NewFixedSizeBinaryScalar(buf,
exType))
+
+ _, err := scalar.MakeScalarParam(buf.Bytes()[:3], exType)
+ assert.Error(t, err)
+ _, err = scalar.ParseScalar(exType, data[:3])
+ assert.Error(t, err)
+}
+
+func TestFixedSizeBinaryScalarValidateErrors(t *testing.T) {
+ data := "test data"
+ buf := memory.NewBufferBytes([]byte(data))
+ exType := &arrow.FixedSizeBinaryType{ByteWidth: 9}
+
+ value := scalar.NewFixedSizeBinaryScalar(buf, exType)
+ assert.NoError(t, value.ValidateFull())
+
+ value.Value.Reset(buf.Bytes()[:1])
+ assert.Error(t, value.ValidateFull())
+}
+
+func TestDateScalarBasics(t *testing.T) {
+ i32Val := arrow.Date32(1)
+ date32Val := scalar.NewDate32Scalar(i32Val)
+ date32Null := scalar.MakeNullScalar(arrow.FixedWidthTypes.Date32)
+ assert.NoError(t, date32Null.ValidateFull())
+ assert.NoError(t, date32Val.ValidateFull())
+
+ assert.True(t, arrow.TypeEqual(arrow.FixedWidthTypes.Date32,
date32Val.DataType()))
+ assert.True(t, date32Val.IsValid())
+ assert.False(t, date32Null.IsValid())
+
+ i64Val := arrow.Date64(2)
+ date64Val := scalar.NewDate64Scalar(i64Val)
+ date64Null := scalar.MakeNullScalar(arrow.FixedWidthTypes.Date64)
+ assert.NoError(t, date64Null.ValidateFull())
+ assert.NoError(t, date64Val.ValidateFull())
+
+ assert.True(t, arrow.TypeEqual(arrow.FixedWidthTypes.Date64,
date64Val.DataType()))
+ assert.True(t, date64Val.IsValid())
+ assert.False(t, date64Null.IsValid())
+}
+
+func TestDateScalarMakeScalar(t *testing.T) {
+ assertMakeScalar(t, scalar.NewDate32Scalar(arrow.Date32(1)),
arrow.Date32(1))
+ assertParseScalar(t, arrow.FixedWidthTypes.Date32, "1454-10-22",
scalar.NewDate32Scalar(arrow.Date32(-188171)))
+ assert.Equal(t, "1454-10-22",
scalar.NewDate32Scalar(arrow.Date32(-188171)).String())
+
+ assertMakeScalar(t, scalar.NewDate64Scalar(arrow.Date64(1)),
arrow.Date64(1))
+ assertParseScalar(t, arrow.FixedWidthTypes.Date64, "1454-10-22",
scalar.NewDate64Scalar(arrow.Date64(-188171*(time.Hour*24).Milliseconds())))
+ assert.Equal(t, "1454-10-22",
scalar.NewDate64Scalar(arrow.Date64(-188171*(time.Hour*24).Milliseconds())).String())
+
+ d32 := scalar.NewDate32Scalar(arrow.Date32(-188171))
+ d64 := scalar.NewDate64Scalar(arrow.Date64(-188171 * (time.Hour *
24).Milliseconds()))
+
+ d32Casted, err := d32.CastTo(arrow.FixedWidthTypes.Date64)
+ assert.NoError(t, err)
+ assert.True(t, scalar.Equals(d64, d32Casted))
+
+ d64Casted, err := d64.CastTo(arrow.FixedWidthTypes.Date32)
+ assert.NoError(t, err)
+ assert.True(t, scalar.Equals(d64Casted, d32))
+}
+
+func TestTimeScalarsBasics(t *testing.T) {
+ typ1 := arrow.FixedWidthTypes.Time32ms
+ typ2 := arrow.FixedWidthTypes.Time32s
+ typ3 := arrow.FixedWidthTypes.Time64us
+ typ4 := arrow.FixedWidthTypes.Time64ns
+
+ t32val := arrow.Time32(1)
+ time32Val := scalar.NewTime32Scalar(t32val, typ1)
+ time32Null := scalar.MakeNullScalar(typ2)
+ assert.NoError(t, time32Val.ValidateFull())
+ assert.NoError(t, time32Null.ValidateFull())
+
+ assert.Equal(t, t32val, time32Val.Value)
+ assert.True(t, arrow.TypeEqual(time32Val.Type, typ1))
+ assert.True(t, time32Val.IsValid())
+ assert.False(t, time32Null.IsValid())
+ assert.True(t, arrow.TypeEqual(time32Null.DataType(), typ2))
+
+ t64val := arrow.Time64(1)
+ time64Val := scalar.NewTime64Scalar(t64val, typ3)
+ time64Null := scalar.MakeNullScalar(typ4)
+ assert.NoError(t, time64Val.ValidateFull())
+ assert.NoError(t, time64Null.ValidateFull())
+
+ assert.Equal(t, t64val, time64Val.Value)
+ assert.True(t, arrow.TypeEqual(time64Val.Type, typ3))
+ assert.True(t, time64Val.IsValid())
+ assert.False(t, time64Null.IsValid())
+ assert.True(t, arrow.TypeEqual(time64Null.DataType(), typ4))
+}
+
+func TestTimeScalarsMakeScalar(t *testing.T) {
+ typ1 := arrow.FixedWidthTypes.Time32s
+ typ2 := arrow.FixedWidthTypes.Time32ms
+ typ3 := arrow.FixedWidthTypes.Time64us
+ typ4 := arrow.FixedWidthTypes.Time64ns
+
+ assertMakeScalarParam(t, scalar.NewTime32Scalar(arrow.Time32(1), typ1),
typ1, arrow.Time32(1))
+ assertMakeScalarParam(t, scalar.NewTime32Scalar(arrow.Time32(1), typ2),
typ2, arrow.Time32(1))
+ assertMakeScalarParam(t, scalar.NewTime64Scalar(arrow.Time64(1), typ3),
typ3, arrow.Time64(1))
+ assertMakeScalarParam(t, scalar.NewTime64Scalar(arrow.Time64(1), typ4),
typ4, arrow.Time64(1))
+
+ tententen := 60*(60*(10)+10) + 10
+ assertParseScalar(t, typ1, "10:10:10",
scalar.NewTime32Scalar(arrow.Time32(tententen), typ1))
+ assert.Equal(t, "10:10:10",
scalar.NewTime32Scalar(arrow.Time32(tententen), typ1).String())
+
+ tententen = 1000*tententen + 123
+ assertParseScalar(t, typ2, "10:10:10.123",
scalar.NewTime32Scalar(arrow.Time32(tententen), typ2))
+ assert.Equal(t, "10:10:10.123",
scalar.NewTime32Scalar(arrow.Time32(tententen), typ2).String())
+
+ tententen = 1000*tententen + 456
+ assertParseScalar(t, typ3, "10:10:10.123456",
scalar.NewTime64Scalar(arrow.Time64(tententen), typ3))
+ assert.Equal(t, "10:10:10.123456",
scalar.NewTime64Scalar(arrow.Time64(tententen), typ3).String())
+
+ tententen = 1000*tententen + 789
+ assertParseScalar(t, typ4, "10:10:10.123456789",
scalar.NewTime64Scalar(arrow.Time64(tententen), typ4))
+ assert.Equal(t, "10:10:10.123456789",
scalar.NewTime64Scalar(arrow.Time64(tententen), typ4).String())
+}
+
+func TestTimestampScalarBasics(t *testing.T) {
+ typ1 := arrow.FixedWidthTypes.Timestamp_ms
+ typ2 := arrow.FixedWidthTypes.Timestamp_s
+
+ val1 := arrow.Timestamp(1)
+ val2 := arrow.Timestamp(2)
+ tsVal1 := scalar.NewTimestampScalar(val1, typ1)
+ tsVal2 := scalar.NewTimestampScalar(val2, typ2)
+ tsNull := scalar.MakeNullScalar(typ1)
+ assert.NoError(t, tsVal1.ValidateFull())
+ assert.NoError(t, tsVal2.ValidateFull())
+ assert.NoError(t, tsNull.ValidateFull())
+
+ assert.Equal(t, val1, tsVal1.Value)
+
+ assert.True(t, arrow.TypeEqual(tsVal1.Type, typ1))
+ assert.True(t, arrow.TypeEqual(tsVal2.DataType(), typ2))
+ assert.True(t, tsVal1.Valid)
+ assert.True(t, tsVal2.IsValid())
+ assert.False(t, tsNull.IsValid())
+ assert.True(t, arrow.TypeEqual(tsNull.DataType(), typ1))
+
+ assert.NotEqual(t, tsVal1, tsVal2)
+ assert.False(t, scalar.Equals(tsVal1, tsVal2))
+ assert.NotEqual(t, tsVal1, tsNull)
+ assert.False(t, scalar.Equals(tsVal1, tsNull))
+ assert.NotEqual(t, tsVal2, tsNull)
+ assert.False(t, scalar.Equals(tsVal2, tsNull))
+}
+
+func TestTimestampScalarsMakeScalar(t *testing.T) {
+ typ1 := arrow.FixedWidthTypes.Timestamp_ms
+ typ2 := arrow.FixedWidthTypes.Timestamp_s
+ typ3 := arrow.FixedWidthTypes.Timestamp_us
+ typ4 := arrow.FixedWidthTypes.Timestamp_ns
+
+ epochPlus1s := "1970-01-01 00:00:01"
+
+ assertMakeScalarParam(t, scalar.NewTimestampScalar(arrow.Timestamp(1),
typ1), typ1, arrow.Timestamp(1))
+ assertParseScalar(t, typ1, epochPlus1s, scalar.NewTimestampScalar(1000,
typ1))
+
+ assertMakeScalarParam(t, scalar.NewTimestampScalar(arrow.Timestamp(1),
typ2), typ2, arrow.Timestamp(1))
+ assertParseScalar(t, typ2, epochPlus1s,
scalar.NewTimestampScalar(arrow.Timestamp(1), typ2))
+
+ assertMakeScalarParam(t, scalar.NewTimestampScalar(arrow.Timestamp(1),
typ3), typ3, arrow.Timestamp(1))
+ assertParseScalar(t, typ3, epochPlus1s,
scalar.NewTimestampScalar(arrow.Timestamp(1000*1000), typ3))
+
+ assertMakeScalarParam(t, scalar.NewTimestampScalar(arrow.Timestamp(1),
typ4), typ4, arrow.Timestamp(1))
+ assertParseScalar(t, typ4, epochPlus1s,
scalar.NewTimestampScalar(arrow.Timestamp(1000*1000*1000), typ4))
+}
+
+func TestTimestampScalarsCasting(t *testing.T) {
+ convert := func(in, out arrow.TimeUnit, val arrow.Timestamp)
arrow.Timestamp {
+ s, err := scalar.NewTimestampScalar(val,
&arrow.TimestampType{Unit: in}).CastTo(&arrow.TimestampType{Unit: out})
+ assert.NoError(t, err)
+ return s.(*scalar.Timestamp).Value
+ }
+
+ assert.EqualValues(t, convert(arrow.Second, arrow.Millisecond,
arrow.Timestamp(1)), 1000)
+ assert.EqualValues(t, convert(arrow.Second, arrow.Nanosecond,
arrow.Timestamp(1)), 1000000000)
+
+ assert.EqualValues(t, convert(arrow.Nanosecond, arrow.Microsecond,
arrow.Timestamp(1234)), 1)
+ assert.EqualValues(t, convert(arrow.Microsecond, arrow.Millisecond,
arrow.Timestamp(4567)), 4)
+
+ str, err := scalar.NewTimestampScalar(arrow.Timestamp(1024),
arrow.FixedWidthTypes.Timestamp_ms).CastTo(arrow.BinaryTypes.String)
+ assert.NoError(t, err)
+ assert.Truef(t, scalar.Equals(scalar.NewStringScalar("1970-01-01
00:00:01.024"), str), "expected: '1970-01-01 00:00:01.024', got: %s", str)
+
+ i64, err := scalar.NewTimestampScalar(arrow.Timestamp(1024),
arrow.FixedWidthTypes.Timestamp_ms).CastTo(arrow.PrimitiveTypes.Int64)
+ assert.NoError(t, err)
+ assert.Truef(t, scalar.Equals(scalar.NewInt64Scalar(1024), i64),
"expected 1024, got %s", i64)
+
+ const millisInDay = 86400000
+ d64, err :=
scalar.NewTimestampScalar(arrow.Timestamp(1024*millisInDay+3),
arrow.FixedWidthTypes.Timestamp_ms).CastTo(arrow.FixedWidthTypes.Date64)
+ assert.NoError(t, err)
+
+ d32, err :=
scalar.NewTimestampScalar(arrow.Timestamp(1024*millisInDay+3),
arrow.FixedWidthTypes.Timestamp_ms).CastTo(arrow.FixedWidthTypes.Date32)
+ assert.NoError(t, err)
+
+ assert.True(t,
scalar.Equals(scalar.NewDate32Scalar(arrow.Date32(1024)), d32))
+ assert.Truef(t,
scalar.Equals(scalar.NewDate64Scalar(arrow.Date64(1024*millisInDay)), d64),
"got %s", d64)
+ tms, err := scalar.NewDate64Scalar(arrow.Date64(1024 *
millisInDay)).CastTo(arrow.FixedWidthTypes.Timestamp_ms)
+ assert.NoError(t, err)
+ assert.True(t, scalar.Equals(tms,
scalar.NewTimestampScalar(arrow.Timestamp(1024*millisInDay),
arrow.FixedWidthTypes.Timestamp_ms)))
+
+ tms, err =
scalar.NewDate32Scalar(arrow.Date32(1024)).CastTo(arrow.FixedWidthTypes.Timestamp_ms)
+ assert.NoError(t, err)
+ assert.True(t, scalar.Equals(tms,
scalar.NewTimestampScalar(arrow.Timestamp(1024*millisInDay),
arrow.FixedWidthTypes.Timestamp_ms)))
+}
+
+func TestDurationScalarBasics(t *testing.T) {
+ typ1 := arrow.FixedWidthTypes.Duration_ms
+ typ2 := arrow.FixedWidthTypes.Duration_s
+
+ val1 := arrow.Duration(1)
+ val2 := arrow.Duration(2)
+ tsVal1 := scalar.NewDurationScalar(val1, typ1)
+ tsVal2 := scalar.NewDurationScalar(val2, typ2)
+ tsNull := scalar.MakeNullScalar(typ1)
+ assert.NoError(t, tsVal1.ValidateFull())
+ assert.NoError(t, tsVal2.ValidateFull())
+ assert.NoError(t, tsNull.ValidateFull())
+
+ assert.Equal(t, val1, tsVal1.Value)
+
+ assert.True(t, arrow.TypeEqual(tsVal1.Type, typ1))
+ assert.True(t, arrow.TypeEqual(tsVal2.DataType(), typ2))
+ assert.True(t, tsVal1.Valid)
+ assert.False(t, tsNull.IsValid())
+ assert.True(t, arrow.TypeEqual(typ1, tsNull.DataType()))
+
+ assert.False(t, scalar.Equals(tsVal1, tsVal2))
+ assert.False(t, scalar.Equals(tsVal1, tsNull))
+ assert.False(t, scalar.Equals(tsNull, tsVal2))
+}
+
+func TestMonthIntervalScalarBasics(t *testing.T) {
+ typ1 := arrow.FixedWidthTypes.MonthInterval
+ typ2 := arrow.FixedWidthTypes.MonthInterval
+
+ val1 := arrow.MonthInterval(1)
+ val2 := arrow.MonthInterval(2)
+ tsVal1 := scalar.NewMonthIntervalScalar(val1)
+ tsVal2 := scalar.NewMonthIntervalScalar(val2)
+ tsNull := scalar.MakeNullScalar(typ1)
+ assert.NoError(t, tsVal1.ValidateFull())
+ assert.NoError(t, tsVal2.ValidateFull())
+ assert.NoError(t, tsNull.ValidateFull())
+
+ assert.Equal(t, val1, tsVal1.Value)
+
+ assert.True(t, arrow.TypeEqual(tsVal1.Type, typ1))
+ assert.True(t, arrow.TypeEqual(tsVal2.DataType(), typ2))
+ assert.True(t, tsVal1.Valid)
+ assert.False(t, tsNull.IsValid())
+ assert.True(t, arrow.TypeEqual(typ1, tsNull.DataType()))
+
+ assert.False(t, scalar.Equals(tsVal1, tsVal2))
+ assert.False(t, scalar.Equals(tsVal1, tsNull))
+ assert.False(t, scalar.Equals(tsNull, tsVal2))
+}
+
+func TestDayTimeIntervalScalarBasics(t *testing.T) {
+ typ := arrow.FixedWidthTypes.DayTimeInterval
+
+ val1 := arrow.DayTimeInterval{Days: 1, Milliseconds: 1}
+ val2 := arrow.DayTimeInterval{Days: 2, Milliseconds: 2}
+ tsVal1 := scalar.NewDayTimeIntervalScalar(val1)
+ tsVal2 := scalar.NewDayTimeIntervalScalar(val2)
+ tsNull := scalar.MakeNullScalar(typ)
+ assert.NoError(t, tsVal1.ValidateFull())
+ assert.NoError(t, tsVal2.ValidateFull())
+ assert.NoError(t, tsNull.ValidateFull())
+
+ assert.Equal(t, val1, tsVal1.Value)
+
+ assert.True(t, arrow.TypeEqual(tsVal1.Type, typ))
+ assert.True(t, arrow.TypeEqual(tsVal2.DataType(), typ))
+ assert.True(t, tsVal1.Valid)
+ assert.False(t, tsNull.IsValid())
+ assert.True(t, arrow.TypeEqual(typ, tsNull.DataType()))
+
+ assert.False(t, scalar.Equals(tsVal1, tsVal2))
+ assert.False(t, scalar.Equals(tsVal1, tsNull))
+ assert.False(t, scalar.Equals(tsNull, tsVal2))
+}
+
+func TestNumericScalarCasts(t *testing.T) {
+ tests := []arrow.DataType{
+ arrow.PrimitiveTypes.Int8,
+ arrow.PrimitiveTypes.Int16,
+ arrow.PrimitiveTypes.Int32,
+ arrow.PrimitiveTypes.Int64,
+ arrow.PrimitiveTypes.Uint8,
+ arrow.PrimitiveTypes.Uint16,
+ arrow.PrimitiveTypes.Uint32,
+ arrow.PrimitiveTypes.Uint64,
+ arrow.PrimitiveTypes.Float32,
+ arrow.PrimitiveTypes.Float64,
+ arrow.FixedWidthTypes.Float16,
+ }
+
+ temporalTypes := []arrow.DataType{
+ arrow.FixedWidthTypes.Date32,
+ arrow.FixedWidthTypes.Date64,
+ arrow.FixedWidthTypes.Date64,
+ arrow.FixedWidthTypes.Time32ms,
+ arrow.FixedWidthTypes.Time64us,
+ arrow.FixedWidthTypes.Timestamp_ms,
+ arrow.FixedWidthTypes.MonthInterval,
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.ID().String(), func(t *testing.T) {
+ for _, repr := range []string{"0", "1", "3"} {
+ nullTest := scalar.MakeNullScalar(tt)
+ assert.Equal(t, "null", nullTest.String())
+
+ s, err := scalar.ParseScalar(tt, repr)
+ assert.NoError(t, err)
+
+ for _, other := range
[]arrow.DataType{arrow.PrimitiveTypes.Float32, arrow.PrimitiveTypes.Int8,
arrow.PrimitiveTypes.Int64, arrow.PrimitiveTypes.Uint32} {
+ otherNull, err := nullTest.CastTo(other)
+ assert.NoError(t, err)
+
+ expectedNull :=
scalar.MakeNullScalar(other)
+ assert.True(t, scalar.Equals(otherNull,
expectedNull))
+
+ otherScalar, err :=
scalar.ParseScalar(other, repr)
+ assert.NoError(t, err)
+
+ castToOther, err := s.CastTo(other)
+ assert.NoError(t, err)
+ assert.True(t,
scalar.Equals(castToOther, otherScalar))
+
+ castFromOther, err :=
otherScalar.CastTo(tt)
+ assert.NoError(t, err)
+ assert.True(t,
scalar.Equals(castFromOther, s))
+ }
+
+ castToBool, err :=
s.CastTo(arrow.FixedWidthTypes.Boolean)
+ assert.NoError(t, err)
+ assert.True(t, castToBool.IsValid())
+ assert.Equal(t, repr != "0",
castToBool.(*scalar.Boolean).Value)
+
+ castFromStr, err :=
scalar.NewStringScalar(repr).CastTo(tt)
+ assert.NoError(t, err)
+
+ assert.True(t, scalar.Equals(castFromStr, s))
+ assert.Equal(t, repr, s.String())
+ if tt == arrow.FixedWidthTypes.Float16 {
+ continue
+ }
+
+ for _, tmtyp := range temporalTypes {
+ castToTemporal, err := s.CastTo(tmtyp)
+ assert.NoError(t, err)
+ assert.NoError(t,
castToTemporal.ValidateFull())
+ assert.True(t, arrow.TypeEqual(tmtyp,
castToTemporal.DataType()))
+ }
+
+ if tt == arrow.PrimitiveTypes.Float32 || tt ==
arrow.PrimitiveTypes.Float64 {
+ continue
+ }
+
+ castToStr, err :=
s.CastTo(arrow.BinaryTypes.String)
+ assert.NoError(t, err)
+ assert.Equal(t, repr,
string(castToStr.(*scalar.String).Value.Bytes()))
+ }
+ })
+ }
+}
+
+type ListScalarSuite struct {
+ suite.Suite
+
+ typ arrow.DataType
+ val array.Interface
+}
+
+func (l *ListScalarSuite) SetupTest() {
+ bld := array.NewInt16Builder(memory.DefaultAllocator)
+ defer bld.Release()
+ bld.AppendValues([]int16{1, 2, 0}, []bool{true, true, false})
+
+ l.val = bld.NewInt16Array()
+}
+
+func (l *ListScalarSuite) TearDownTest() {
+ l.val.Release()
+}
+
+func (l *ListScalarSuite) TestBasics() {
+ s, err := scalar.MakeScalarParam(l.val, l.typ)
+ l.NoError(err)
+
+ l.NoError(s.ValidateFull())
+ l.True(s.IsValid())
+ l.True(arrow.TypeEqual(l.typ, s.DataType()))
+
+ nullScalar := checkMakeNullScalar(l.T(), l.typ)
+ l.NoError(nullScalar.ValidateFull())
+ l.False(nullScalar.IsValid())
+ l.True(arrow.TypeEqual(nullScalar.DataType(), l.typ))
+
+ l.Equal("[1 2 (null)]", s.String())
+}
+
+func (l *ListScalarSuite) TestValidateErrors() {
+ // inconsistent isvalid / value
+ s, _ := scalar.MakeScalarParam(l.val, l.typ)
+ switch s := s.(type) {
+ case *scalar.List:
+ s.Valid = false
+ case *scalar.FixedSizeList:
+ s.Valid = false
+ }
+ l.Error(s.Validate())
+
+ s, _ = scalar.MakeScalarParam(l.val, l.typ)
+ switch s := s.(type) {
+ case *scalar.List:
+ s.Value = nil
+ case *scalar.FixedSizeList:
+ s.Value = nil
+ }
+ l.Error(s.Validate())
+
+ // inconsistent child type
+ bld := array.NewInt32Builder(memory.DefaultAllocator)
+ defer bld.Release()
+ bld.AppendValues([]int32{1, 2, 0}, []bool{true, true, false})
+ arr := bld.NewArray()
+ defer arr.Release()
+
+ s, _ = scalar.MakeScalarParam(l.val, l.typ)
+ switch s := s.(type) {
+ case *scalar.List:
+ s.Value = arr
+ case *scalar.FixedSizeList:
+ s.Value = arr
+ }
+ l.Error(s.Validate())
+}
+
+func TestListScalars(t *testing.T) {
+ ls := new(ListScalarSuite)
+ ls.typ = arrow.ListOf(arrow.PrimitiveTypes.Int16)
+ suite.Run(t, ls)
+ ls.typ = arrow.FixedSizeListOf(3, arrow.PrimitiveTypes.Int16)
+ suite.Run(t, ls)
+}
+
+func TestFixedSizeListScalarWrongNumber(t *testing.T) {
+ typ := arrow.FixedSizeListOf(3, arrow.PrimitiveTypes.Int16)
+ bld := array.NewInt16Builder(memory.DefaultAllocator)
+ defer bld.Release()
+ bld.AppendValues([]int16{1, 2, 5}, nil)
+ arr := bld.NewArray()
+ defer arr.Release()
+
+ sc := scalar.NewFixedSizeListScalarWithType(arr, typ)
+ assert.NoError(t, sc.ValidateFull())
+
+ sc.Type = arrow.FixedSizeListOf(4, arrow.PrimitiveTypes.Int16)
+ assert.Error(t, sc.ValidateFull())
+}
+
+func TestMapScalarBasics(t *testing.T) {
+ bld := array.NewStructBuilder(memory.DefaultAllocator, arrow.StructOf(
+ arrow.Field{Name: "key", Type: arrow.BinaryTypes.String,
Nullable: false},
+ arrow.Field{Name: "value", Type: arrow.PrimitiveTypes.Int8,
Nullable: true}))
+ defer bld.Release()
+ bld.FieldBuilder(0).(*array.StringBuilder).AppendValues([]string{"a",
"b"}, nil)
+ bld.FieldBuilder(1).(*array.Int8Builder).AppendValues([]int8{1, 2}, nil)
+ value := bld.NewArray()
+ defer value.Release()
+
+ s := scalar.NewMapScalar(value)
+ assert.NoError(t, s.ValidateFull())
+
+ expectedScalarType := arrow.MapOf(arrow.BinaryTypes.String,
arrow.PrimitiveTypes.Int8)
+ assert.True(t, arrow.TypeEqual(s.DataType(), expectedScalarType))
+ assert.True(t, array.ArrayEqual(value, s.Value))
+
+ checkMakeNullScalar(t, expectedScalarType)
+}
+
+func TestStructScalar(t *testing.T) {
+ abc := scalar.NewStructScalar([]scalar.Scalar{
+ scalar.MakeScalar(true),
+ scalar.MakeNullScalar(arrow.PrimitiveTypes.Int32),
+ scalar.MakeScalar("hello"),
+ scalar.MakeNullScalar(arrow.PrimitiveTypes.Int64),
+ }, arrow.StructOf(
+ arrow.Field{Name: "a", Type: arrow.FixedWidthTypes.Boolean,
Nullable: true},
+ arrow.Field{Name: "b", Type: arrow.PrimitiveTypes.Int32,
Nullable: true},
+ arrow.Field{Name: "c", Type: arrow.BinaryTypes.String,
Nullable: true},
+ arrow.Field{Name: "d", Type: arrow.PrimitiveTypes.Int64,
Nullable: true}))
+
+ assert.NoError(t, abc.Validate())
+ assert.NoError(t, abc.ValidateFull())
+
+ a, err := abc.Field("a")
+ assert.NoError(t, err)
+ assert.True(t, scalar.Equals(a, abc.Value[0]))
+
+ _, err = abc.Field("f")
+ assert.Error(t, err)
+
+ d, err := abc.Field("d")
+ assert.NoError(t, err)
+ assert.True(t,
scalar.Equals(scalar.MakeNullScalar(arrow.PrimitiveTypes.Int64), d))
+ assert.False(t, scalar.Equals(scalar.MakeScalar(int64(12)), d))
+
+ abc2, err := scalar.NewStructScalarWithNames(abc.Value, []string{"a",
"b", "c", "d"})
+ assert.NoError(t, err)
+ assert.True(t, scalar.Equals(abc, abc2))
+
+ assert.Equal(t, "{a:bool = true, b:int32 = null, c:utf8 = hello,
d:int64 = null}", abc.String())
+}
+
+func TestNullStructScalar(t *testing.T) {
+ ty := arrow.StructOf(
+ arrow.Field{Name: "a", Type: arrow.FixedWidthTypes.Boolean,
Nullable: true},
+ arrow.Field{Name: "b", Type: arrow.PrimitiveTypes.Int32,
Nullable: true},
+ arrow.Field{Name: "c", Type: arrow.BinaryTypes.String,
Nullable: true},
+ arrow.Field{Name: "d", Type: arrow.PrimitiveTypes.Int64,
Nullable: true})
+ nullScalar := scalar.MakeNullScalar(ty)
+ assert.NoError(t, nullScalar.ValidateFull())
+ assert.False(t, nullScalar.IsValid())
+
+ sc := checkMakeNullScalar(t, ty)
+ assert.True(t, scalar.Equals(nullScalar, sc))
+}
+
+func TestStructScalarValidateErrors(t *testing.T) {
+ ty := arrow.StructOf(arrow.Field{Name: "a", Type:
arrow.BinaryTypes.String})
+
+ // inconsistent isvalid value
+ sc :=
scalar.NewStructScalar([]scalar.Scalar{scalar.MakeScalar("hello")}, ty)
+ sc.Valid = false
+ assert.Error(t, sc.ValidateFull())
+
+ sc = scalar.NewStructScalar(nil, ty)
+ sc.Valid = true
+ assert.Error(t, sc.ValidateFull())
+
+ // inconsistent number of fields
+ sc = scalar.NewStructScalar([]scalar.Scalar{}, ty)
+ assert.Error(t, sc.ValidateFull())
+
+ sc = scalar.NewStructScalar([]scalar.Scalar{scalar.MakeScalar("foo"),
scalar.MakeScalar("bar")}, ty)
+ assert.Error(t, sc.ValidateFull())
+
+ // inconsistent child value type
+ sc = scalar.NewStructScalar([]scalar.Scalar{scalar.MakeScalar(42)}, ty)
+ assert.Error(t, sc.ValidateFull())
+
+ // child value has invalid utf8 data
+ sc = scalar.NewStructScalar([]scalar.Scalar{scalar.MakeScalar("\xff")},
ty)
+ assert.NoError(t, sc.Validate())
+ assert.Error(t, sc.ValidateFull())
+}
diff --git a/go/arrow/scalar/temporal.go b/go/arrow/scalar/temporal.go
new file mode 100644
index 0000000..47a4dec4
--- /dev/null
+++ b/go/arrow/scalar/temporal.go
@@ -0,0 +1,469 @@
+// 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/arrow"
+ "golang.org/x/xerrors"
+)
+
+type op int8
+
+const (
+ convDIVIDE = iota
+ convMULTIPLY
+)
+
+var timestampConversion = [...][4]struct {
+ op op
+ factor int64
+}{
+ arrow.Nanosecond: {
+ arrow.Nanosecond: {convMULTIPLY, int64(time.Nanosecond)},
+ arrow.Microsecond: {convDIVIDE, int64(time.Microsecond)},
+ arrow.Millisecond: {convDIVIDE, int64(time.Millisecond)},
+ arrow.Second: {convDIVIDE, int64(time.Second)},
+ },
+ arrow.Microsecond: {
+ arrow.Nanosecond: {convMULTIPLY, int64(time.Microsecond)},
+ arrow.Microsecond: {convMULTIPLY, 1},
+ arrow.Millisecond: {convDIVIDE, int64(time.Millisecond /
time.Microsecond)},
+ arrow.Second: {convDIVIDE, int64(time.Second /
time.Microsecond)},
+ },
+ arrow.Millisecond: {
+ arrow.Nanosecond: {convMULTIPLY, int64(time.Millisecond)},
+ arrow.Microsecond: {convMULTIPLY, int64(time.Millisecond /
time.Microsecond)},
+ arrow.Millisecond: {convMULTIPLY, 1},
+ arrow.Second: {convDIVIDE, int64(time.Second /
time.Millisecond)},
+ },
+ arrow.Second: {
+ arrow.Nanosecond: {convMULTIPLY, int64(time.Second)},
+ arrow.Microsecond: {convMULTIPLY, int64(time.Second /
time.Microsecond)},
+ arrow.Millisecond: {convMULTIPLY, int64(time.Second /
time.Millisecond)},
+ arrow.Second: {convMULTIPLY, 1},
+ },
+}
+
+func ConvertTimestampValue(in, out arrow.TimeUnit, value int64) int64 {
+ conv := timestampConversion[int(in)][int(out)]
+ switch conv.op {
+ case convMULTIPLY:
+ return value * conv.factor
+ case convDIVIDE:
+ return value / conv.factor
+ }
+
+ return 0
+}
+
+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(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(ConvertTimestampValue(s.Unit(), to.Unit,
int64(s.Value))), to), nil
+ case *arrow.Date32Type:
+ millis := ConvertTimestampValue(s.Unit(),
arrow.Millisecond, int64(s.Value))
+ return NewDate32Scalar(arrow.Date32(millis /
int64(millisecondsInDay))), nil
+ case *arrow.Date64Type:
+ millis := 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(ConvertTimestampValue(s.Unit(), to.Unit,
int64(s.value().(arrow.Time64)))), to), nil
+ case *arrow.Time64Type:
+ return
NewTime64Scalar(arrow.Time64(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(ConvertTimestampValue(s.Unit(), to.Unit,
int64(s.Value))), to), nil
+ }
+ }
+
+ return nil, xerrors.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, xerrors.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, xerrors.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}
+}
+
+var (
+ _ Scalar = (*Date32)(nil)
+)