Skip to content

Commit

Permalink
feat: Implement parsing all supported datatypes
Browse files Browse the repository at this point in the history
  • Loading branch information
yuryfirebolt committed Jul 6, 2022
1 parent d9057e5 commit 71d9288
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 15 deletions.
64 changes: 50 additions & 14 deletions rows.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ package fireboltgosdk

import (
"database/sql/driver"
"fmt"
"io"
"reflect"
"strings"
"time"
)

type fireboltRows struct {
Expand Down Expand Up @@ -32,23 +36,55 @@ func (f *fireboltRows) Next(dest []driver.Value) error {
}

for i, column := range f.response.Meta {
val := f.response.Data[f.cursorPosition][i]
switch column.Type {
case "UInt32":
dest[i] = uint32(val.(float64))
case "Int32":
dest[i] = int32(val.(float64))
case "Int64":
dest[i] = int64(val.(float64))
case "Float32":
dest[i] = float32(val.(float64))
case "Float64":
dest[i] = val.(float64)
default:
dest[i] = val
var err error
if dest[i], err = parseValue(column.Type, f.response.Data[f.cursorPosition][i]); err != nil {
return fmt.Errorf("error during fetching Next result: %s", err)
}
}

f.cursorPosition++
return nil
}

func parseValue(columnType string, val interface{}) (driver.Value, error) {
switch columnType {
case "UInt8":
return uint8(val.(float64)), nil
case "UInt32":
return uint32(val.(float64)), nil
case "Int32":
return int32(val.(float64)), nil
case "UInt64":
return uint64(val.(float64)), nil
case "Int64":
return int64(val.(float64)), nil
case "Float32":
return float32(val.(float64)), nil
case "Float64":
return val.(float64), nil
case "String":
return val.(string), nil
case "DateTime":
// Go doesn't use yyyy-mm-dd layout. Instead, it uses the value: Mon Jan 2 15:04:05 MST 2006
return time.Parse("2006-01-02 15:04:05", val.(string))
case "Date":
return time.Parse("2006-01-02", val.(string))
}

const (
arrayPrefix = "Array("
arraySuffix = ")"
)

if strings.HasPrefix(columnType, arrayPrefix) && strings.HasSuffix(columnType, arraySuffix) {
s := reflect.ValueOf(val)
res := make([]driver.Value, s.Len())

for i := 0; i < s.Len(); i++ {
res[i], _ = parseValue(columnType[len(arrayPrefix):len(columnType)-len(arraySuffix)], s.Index(i).Interface())
}
return res, nil
}

return nil, fmt.Errorf("type not known: %s", columnType)
}
6 changes: 5 additions & 1 deletion rows_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"io"
"reflect"
"testing"
"time"
)

func assert(val bool, t *testing.T, err string) {
Expand All @@ -15,7 +16,7 @@ func assert(val bool, t *testing.T, err string) {
}

func mockRows() driver.Rows {
resultJson := "{\"query\":{\"query_id\":\"16FF2A0300ECA753\"},\"meta\":[{\"name\":\"int_col\",\"type\":\"Int32\"},{\"name\":\"bigint_col\",\"type\":\"Int64\"},{\"name\":\"float_col\",\"type\":\"Float32\"},{\"name\":\"double_col\",\"type\":\"Float64\"},{\"name\":\"text_col\",\"type\":\"String\"},{\"name\":\"date_col\",\"type\":\"Date\"},{\"name\":\"timestamp_col\",\"type\":\"DateTime\"},{\"name\":\"bool_col\",\"type\":\"UInt8\"},{\"name\":\"array_col\",\"type\":\"Array(Int32)\"},{\"name\":\"nested_array_col\",\"type\":\"Array(Array(String))\"}],\"data\":[[2,1,0.312321,123213.321321,\"text\",\"1970-01-01\",\"1970-01-01 00:00:00\",1,[1,2,3],[[]]],[2,1,0.312321,123213.321321,\"text\",\"1970-01-01\",\"1970-01-01 00:00:00\",1,[1,2,3],[[]]],[3,5,0.312321,123213.321321,\"text\",\"1970-01-01\",\"1970-01-01 00:00:00\",1,[5,2,3,2],[[\"TEST\",\"TEST1\"],[\"TEST3\"]]]],\"rows\":3,\"statistics\":{\"elapsed\":0.001797702,\"rows_read\":3,\"bytes_read\":293,\"time_before_execution\":0.001251613,\"time_to_execute\":0.000544098,\"scanned_bytes_cache\":2003,\"scanned_bytes_storage\":0}}"
resultJson := "{\"query\":{\"query_id\":\"16FF2A0300ECA753\"},\"meta\":[{\"name\":\"int_col\",\"type\":\"Int32\"},{\"name\":\"bigint_col\",\"type\":\"Int64\"},{\"name\":\"float_col\",\"type\":\"Float32\"},{\"name\":\"double_col\",\"type\":\"Float64\"},{\"name\":\"text_col\",\"type\":\"String\"},{\"name\":\"date_col\",\"type\":\"Date\"},{\"name\":\"timestamp_col\",\"type\":\"DateTime\"},{\"name\":\"bool_col\",\"type\":\"UInt8\"},{\"name\":\"array_col\",\"type\":\"Array(Int32)\"},{\"name\":\"nested_array_col\",\"type\":\"Array(Array(String))\"}],\"data\":[[2,1,0.312321,123213.321321,\"text\",\"2080-12-31\",\"1989-04-15 01:02:03\",1,[1,2,3],[[]]],[2,1,0.312321,123213.321321,\"text\",\"1970-01-01\",\"1970-01-01 00:00:00\",1,[1,2,3],[[]]],[3,5,0.312321,123213.321321,\"text\",\"1970-01-01\",\"1970-01-01 00:00:00\",1,[5,2,3,2],[[\"TEST\",\"TEST1\"],[\"TEST3\"]]]],\"rows\":3,\"statistics\":{\"elapsed\":0.001797702,\"rows_read\":3,\"bytes_read\":293,\"time_before_execution\":0.001251613,\"time_to_execute\":0.000544098,\"scanned_bytes_cache\":2003,\"scanned_bytes_storage\":0}}"
var response QueryResponse
err := json.Unmarshal([]byte(resultJson), &response)
if err != nil {
Expand Down Expand Up @@ -49,13 +50,16 @@ func TestRowsNext(t *testing.T) {
rows := mockRows()
var dest = make([]driver.Value, 10)
err := rows.Next(dest)
loc, _ := time.LoadLocation("UTC")

assert(err == nil, t, "Next shouldn't return an error")
assert(dest[0] == int32(2), t, "results not equal for int32")
assert(dest[1] == int64(1), t, "results not equal for int64")
assert(dest[2] == float32(0.312321), t, "results not equal for float32")
assert(dest[3] == float64(123213.321321), t, "results not equal for float64")
assert(dest[4] == "text", t, "results not equal for string")
assert(dest[5] == time.Date(2080, 12, 31, 0, 0, 0, 0, loc), t, "results not equal for date")
assert(dest[6] == time.Date(1989, 04, 15, 1, 2, 3, 0, loc), t, "results not equal for datetime")

err = rows.Next(dest)
assert(err == nil, t, "Next shouldn't return an error")
Expand Down

0 comments on commit 71d9288

Please sign in to comment.