This is an automated email from the ASF dual-hosted git repository.
zeroshade pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-adbc.git
The following commit(s) were added to refs/heads/main by this push:
new 3adf236 feat(go/sqldriver): convert Arrow times and dates to Golang
time.Time (#393)
3adf236 is described below
commit 3adf23635040c2f95bdb39814d0ecf723667469f
Author: Jacob Marble <[email protected]>
AuthorDate: Fri Jan 27 10:14:08 2023 -0800
feat(go/sqldriver): convert Arrow times and dates to Golang time.Time (#393)
* feat(go/sqldriver): convert Arrow times and dates to Golang time.Time
* chore: add unit test
* chore: remove TODO comment
---
go/adbc/sqldriver/driver.go | 23 ++---
go/adbc/sqldriver/driver_internals_test.go | 130 +++++++++++++++++++++++++++++
2 files changed, 138 insertions(+), 15 deletions(-)
diff --git a/go/adbc/sqldriver/driver.go b/go/adbc/sqldriver/driver.go
index a9a8ad4..53aa40a 100644
--- a/go/adbc/sqldriver/driver.go
+++ b/go/adbc/sqldriver/driver.go
@@ -40,6 +40,7 @@ import (
"reflect"
"strconv"
"strings"
+ "time"
"unsafe"
"github.com/apache/arrow-adbc/go/adbc"
@@ -635,15 +636,15 @@ func (r *rows) Next(dest []driver.Value) error {
case *array.LargeBinary:
dest[i] = col.Value(int(r.curRow))
case *array.Date32:
- dest[i] = col.Value(int(r.curRow))
+ dest[i] = col.Value(int(r.curRow)).ToTime()
case *array.Date64:
- dest[i] = col.Value(int(r.curRow))
+ dest[i] = col.Value(int(r.curRow)).ToTime()
case *array.Time32:
- dest[i] = col.Value(int(r.curRow))
+ dest[i] =
col.Value(int(r.curRow)).ToTime(col.DataType().(*arrow.Time32Type).Unit)
case *array.Time64:
- dest[i] = col.Value(int(r.curRow))
+ dest[i] =
col.Value(int(r.curRow)).ToTime(col.DataType().(*arrow.Time64Type).Unit)
case *array.Timestamp:
- dest[i] = col.Value(int(r.curRow))
+ dest[i] =
col.Value(int(r.curRow)).ToTime(col.DataType().(*arrow.TimestampType).Unit)
default:
return &adbc.Error{
Code: adbc.StatusNotImplemented,
@@ -703,16 +704,8 @@ func (r *rows) ColumnTypeScanType(index int) reflect.Type {
return reflect.TypeOf([]byte{})
case arrow.STRING:
return reflect.TypeOf(string(""))
- case arrow.TIME32:
- return reflect.TypeOf(arrow.Time32(0))
- case arrow.TIME64:
- return reflect.TypeOf(arrow.Time64(0))
- case arrow.DATE32:
- return reflect.TypeOf(arrow.Date32(0))
- case arrow.DATE64:
- return reflect.TypeOf(arrow.Date64(0))
- case arrow.TIMESTAMP:
- return reflect.TypeOf(arrow.Timestamp(0))
+ case arrow.TIME32, arrow.TIME64, arrow.DATE32, arrow.DATE64,
arrow.TIMESTAMP:
+ return reflect.TypeOf(time.Time{})
}
return nil
}
diff --git a/go/adbc/sqldriver/driver_internals_test.go
b/go/adbc/sqldriver/driver_internals_test.go
index 97ef4e8..74f86e4 100644
--- a/go/adbc/sqldriver/driver_internals_test.go
+++ b/go/adbc/sqldriver/driver_internals_test.go
@@ -18,12 +18,18 @@
package sqldriver
import (
+ "database/sql/driver"
"fmt"
"strings"
"testing"
+ "time"
"github.com/apache/arrow-adbc/go/adbc"
+ "github.com/apache/arrow/go/v11/arrow"
+ "github.com/apache/arrow/go/v11/arrow/array"
+ "github.com/apache/arrow/go/v11/arrow/memory"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
func TestParseConnectStr(t *testing.T) {
@@ -59,3 +65,127 @@ func TestParseConnectStr(t *testing.T) {
assert.Equal(t, expectOpts, gotOpts)
}
}
+
+var (
+ tz = time.FixedZone("North Idaho", -int((8 *
time.Hour).Seconds()))
+ testTime = time.Date(2023, time.January, 26, 15, 40, 39, 123456789, tz)
+)
+
+func TestNextRowTypes(t *testing.T) {
+ tests := []struct {
+ arrowType arrow.DataType
+ arrowValueFunc func(*testing.T, array.Builder)
+ golangValue any
+ }{
+ {
+ arrowType: &arrow.StringType{},
+ arrowValueFunc: func(t *testing.T, b array.Builder) {
+ t.Helper()
+ b.(*array.StringBuilder).Append("my-string")
+ },
+ golangValue: "my-string",
+ },
+ {
+ arrowType: &arrow.Date32Type{},
+ arrowValueFunc: func(t *testing.T, b array.Builder) {
+ t.Helper()
+
b.(*array.Date32Builder).Append(arrow.Date32FromTime(testTime))
+ },
+ golangValue: testTime.UTC().Truncate(24 * time.Hour),
+ },
+ {
+ arrowType: &arrow.Date64Type{},
+ arrowValueFunc: func(t *testing.T, b array.Builder) {
+ t.Helper()
+
b.(*array.Date64Builder).Append(arrow.Date64FromTime(testTime))
+ },
+ golangValue: testTime.UTC().Truncate(24 * time.Hour),
+ },
+ {
+ arrowType: &arrow.TimestampType{Unit: arrow.Second,
TimeZone: "North Idaho"},
+ arrowValueFunc: func(t *testing.T, b array.Builder) {
+ t.Helper()
+ s := testTime.Format("2006-01-02
15:04:05-07:00")
+ timestamp, _, err :=
arrow.TimestampFromStringInLocation(s, arrow.Second, tz)
+ require.NoError(t, err)
+ b.(*array.TimestampBuilder).Append(timestamp)
+ },
+ golangValue: testTime.UTC().Truncate(time.Second),
+ },
+ {
+ arrowType: &arrow.TimestampType{Unit:
arrow.Millisecond},
+ arrowValueFunc: func(t *testing.T, b array.Builder) {
+ t.Helper()
+ s := testTime.Format("2006-01-02
15:04:05.999-07:00")
+ timestamp, _, err :=
arrow.TimestampFromStringInLocation(s, arrow.Millisecond, tz)
+ require.NoError(t, err)
+ b.(*array.TimestampBuilder).Append(timestamp)
+ },
+ golangValue: testTime.UTC().Truncate(time.Millisecond),
+ },
+ {
+ arrowType: &arrow.Time32Type{Unit: arrow.Second},
+ arrowValueFunc: func(t *testing.T, b array.Builder) {
+ t.Helper()
+ s := testTime.Format("15:04:05")
+ t.Log(s)
+ time32, err := arrow.Time32FromString(s,
arrow.Second)
+ require.NoError(t, err)
+ b.(*array.Time32Builder).Append(time32)
+ t.Log("end of avf")
+ },
+ golangValue: time.Date(1970, time.January, 1,
testTime.Hour(), testTime.Minute(), testTime.Second(), 0, time.UTC),
+ },
+ {
+ arrowType: &arrow.Time32Type{Unit: arrow.Millisecond},
+ arrowValueFunc: func(t *testing.T, b array.Builder) {
+ t.Helper()
+ s := testTime.Format("15:04:05.999")
+ time32, err := arrow.Time32FromString(s,
arrow.Millisecond)
+ require.NoError(t, err)
+ b.(*array.Time32Builder).Append(time32)
+ },
+ golangValue: time.Date(1970, time.January, 1,
testTime.Hour(), testTime.Minute(), testTime.Second(),
testTime.Nanosecond()-testTime.Nanosecond()%int(time.Millisecond), time.UTC),
+ },
+ {
+ arrowType: &arrow.Time64Type{Unit: arrow.Microsecond},
+ arrowValueFunc: func(t *testing.T, b array.Builder) {
+ t.Helper()
+ s := testTime.Format("15:04:05.999999")
+ time64, err := arrow.Time64FromString(s,
arrow.Microsecond)
+ require.NoError(t, err)
+ b.(*array.Time64Builder).Append(time64)
+ },
+ golangValue: time.Date(1970, time.January, 1,
testTime.Hour(), testTime.Minute(), testTime.Second(),
testTime.Nanosecond()-testTime.Nanosecond()%int(time.Microsecond), time.UTC),
+ },
+ {
+ arrowType: &arrow.Time64Type{Unit: arrow.Nanosecond},
+ arrowValueFunc: func(t *testing.T, b array.Builder) {
+ t.Helper()
+ s := testTime.Format("15:04:05.999999999")
+ time64, err := arrow.Time64FromString(s,
arrow.Nanosecond)
+ require.NoError(t, err)
+ b.(*array.Time64Builder).Append(time64)
+ },
+ golangValue: time.Date(1970, time.January, 1,
testTime.Hour(), testTime.Minute(), testTime.Second(), testTime.Nanosecond(),
time.UTC),
+ },
+ }
+
+ for i, test := range tests {
+ t.Run(fmt.Sprintf("%d-%s", i, test.arrowType.String()), func(t
*testing.T) {
+ schema := arrow.NewSchema([]arrow.Field{{Type:
test.arrowType}}, nil)
+ recordBuilder :=
array.NewRecordBuilder(memory.DefaultAllocator, schema)
+ t.Cleanup(recordBuilder.Release)
+ test.arrowValueFunc(t, recordBuilder.Field(0))
+ record := recordBuilder.NewRecord()
+ t.Cleanup(record.Release)
+
+ r := &rows{curRecord: record}
+ dest := make([]driver.Value, 1)
+ err := r.Next(dest)
+ assert.NoError(t, err)
+ assert.IsType(t, test.golangValue, dest[0])
+ assert.Equal(t, test.golangValue, dest[0])
+ })
+ }
+}