blob: a057f91eb26b31fbb26c9ba60b2efc438ae86f70 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package scalar_test
import (
"bytes"
"hash/maphash"
"math/bits"
"testing"
"time"
"github.com/apache/arrow/go/v6/arrow"
"github.com/apache/arrow/go/v6/arrow/array"
"github.com/apache/arrow/go/v6/arrow/decimal128"
"github.com/apache/arrow/go/v6/arrow/memory"
"github.com/apache/arrow/go/v6/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)
seed := maphash.MakeSeed()
assert.Equal(t, scalar.Hash(seed, expected), scalar.Hash(seed, 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 TestMonthDayNanoIntervalScalarBasics(t *testing.T) {
typ := arrow.FixedWidthTypes.MonthDayNanoInterval
val1 := arrow.MonthDayNanoInterval{Months: 1, Days: 2, Nanoseconds: 3000}
val2 := arrow.MonthDayNanoInterval{Months: 2, Days: 3, Nanoseconds: 4000}
tsVal1 := scalar.NewMonthDayNanoIntervalScalar(val1)
tsVal2 := scalar.NewMonthDayNanoIntervalScalar(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,
}
falseScalar := scalar.NewBooleanScalar(false)
trueScalar := scalar.NewBooleanScalar(true)
nullBool := scalar.MakeNullScalar(arrow.FixedWidthTypes.Boolean)
for _, tt := range tests {
t.Run(tt.ID().String()+"from bool", func(t *testing.T) {
zero, _ := scalar.ParseScalar(tt, "0")
zeroFromBool, err := falseScalar.CastTo(tt)
assert.NoError(t, err)
assert.True(t, scalar.Equals(zero, zeroFromBool))
one, _ := scalar.ParseScalar(tt, "1")
oneFromBool, err := trueScalar.CastTo(tt)
assert.NoError(t, err)
assert.True(t, scalar.Equals(one, oneFromBool))
})
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())
castedNull, err := nullBool.CastTo(tt)
assert.NoError(t, err)
assert.True(t, scalar.Equals(castedNull, nullTest))
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.GetList()))
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())
}
func getScalars(mem memory.Allocator) []scalar.Scalar {
hello := memory.NewBufferBytes([]byte("hello"))
daytime := arrow.DayTimeInterval{Days: 1, Milliseconds: 100}
monthdaynano := arrow.MonthDayNanoInterval{Months: 5, Days: 4, Nanoseconds: 100}
int8Bldr := array.NewInt8Builder(mem)
defer int8Bldr.Release()
int8Bldr.AppendValues([]int8{1, 2, 3, 4}, nil)
int8Arr := int8Bldr.NewInt8Array()
defer int8Arr.Release()
mapBldr := array.NewMapBuilder(mem, arrow.PrimitiveTypes.Int8, arrow.BinaryTypes.String, false)
defer mapBldr.Release()
kb := mapBldr.KeyBuilder().(*array.Int8Builder)
ib := mapBldr.ItemBuilder().(*array.StringBuilder)
mapBldr.Append(true)
kb.AppendValues([]int8{1, 2, 3}, nil)
ib.AppendValues([]string{"foo", "bar", "baz"}, nil)
mapArr := mapBldr.NewMapArray()
defer mapArr.Release()
return []scalar.Scalar{
scalar.NewBooleanScalar(false),
scalar.NewInt8Scalar(3),
scalar.NewUint16Scalar(3),
scalar.NewInt32Scalar(3),
scalar.NewUint64Scalar(3),
scalar.NewFloat64Scalar(3.0),
scalar.NewDate32Scalar(10),
scalar.NewDate64Scalar(11),
scalar.NewTime32Scalar(1000, arrow.FixedWidthTypes.Time32s),
scalar.NewTime64Scalar(1111, arrow.FixedWidthTypes.Time64us),
scalar.NewTimestampScalar(111, arrow.FixedWidthTypes.Timestamp_ms),
scalar.NewMonthIntervalScalar(1),
scalar.NewDayTimeIntervalScalar(daytime),
scalar.NewMonthDayNanoIntervalScalar(monthdaynano),
scalar.NewDurationScalar(60, arrow.FixedWidthTypes.Duration_s),
scalar.NewBinaryScalar(hello, arrow.BinaryTypes.Binary),
scalar.NewFixedSizeBinaryScalar(hello, &arrow.FixedSizeBinaryType{ByteWidth: hello.Len()}),
scalar.NewDecimal128Scalar(decimal128.FromI64(10), &arrow.Decimal128Type{Precision: 16, Scale: 4}),
scalar.NewStringScalarFromBuffer(hello),
scalar.NewListScalar(int8Arr),
scalar.NewMapScalar(mapArr.List.ListValues()),
scalar.NewFixedSizeListScalar(int8Arr),
scalar.NewStructScalar([]scalar.Scalar{scalar.NewInt32Scalar(2), scalar.NewInt32Scalar(6)},
arrow.StructOf([]arrow.Field{{Name: "min", Type: arrow.PrimitiveTypes.Int32}, {Name: "max", Type: arrow.PrimitiveTypes.Int32}}...)),
}
}
func TestMakeArrayFromScalar(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
defer mem.AssertSize(t, 0)
nullArray, err := scalar.MakeArrayFromScalar(scalar.ScalarNull, 5, mem)
assert.NoError(t, err)
defer nullArray.Release()
assert.Equal(t, 5, nullArray.Len())
assert.Equal(t, 5, nullArray.NullN())
scalars := getScalars(mem)
for _, length := range []int{16} {
for _, s := range scalars {
t.Run(s.DataType().Name(), func(t *testing.T) {
if ls, ok := s.(scalar.Releasable); ok {
defer ls.Release()
}
arr, err := scalar.MakeArrayFromScalar(s, length, mem)
assert.NoError(t, err)
defer arr.Release()
assert.Equal(t, length, arr.Len())
assert.Zero(t, arr.NullN())
for _, i := range []int{0, length / 2, length - 1} {
scalarCompare, err := scalar.GetScalar(arr, i)
assert.NoError(t, err)
assert.True(t, scalar.Equals(s, scalarCompare))
if ls, ok := scalarCompare.(scalar.Releasable); ok {
ls.Release()
}
}
})
}
}
}