| // 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() |
| } |
| } |
| }) |
| } |
| } |
| } |