in sources/csv/data.go [320:498]
func convArray(spannerType ddl.Type, val string) (interface{}, error) {
val = strings.TrimSpace(val)
// Handle empty array. Note that we use an empty NullString array
// for all Spanner array types since this will be converted to the
// appropriate type by the Spanner client.
if val == "{}" || val == "[]" {
return []spanner.NullString{}, nil
}
braces := val[:1] + val[len(val)-1:]
if braces != "{}" && braces != "[]" {
return []interface{}{}, fmt.Errorf("unrecognized data format for array: expected {v1, v2, ...} or [v1, v2, ...]")
}
a := strings.Split(val[1:len(val)-1], ",")
// The Spanner client for go does not accept []interface{} for arrays.
// Instead it only accepts slices of a specific type e.g. []int64, []string.
// Hence we have to do the following case analysis.
switch spannerType.Name {
case ddl.Bool:
var r []spanner.NullBool
for _, s := range a {
if s == "NULL" {
r = append(r, spanner.NullBool{Valid: false})
continue
}
s, err := processQuote(s)
if err != nil {
return []spanner.NullBool{}, err
}
b, err := convBool(s)
if err != nil {
return []spanner.NullBool{}, err
}
r = append(r, spanner.NullBool{Bool: b, Valid: true})
}
return r, nil
case ddl.Bytes:
var r [][]byte
for _, s := range a {
if s == "NULL" {
r = append(r, nil)
continue
}
s, err := processQuote(s)
if err != nil {
return [][]byte{}, err
}
b, err := convBytes(s)
if err != nil {
return [][]byte{}, err
}
r = append(r, b)
}
return r, nil
case ddl.Date:
var r []spanner.NullDate
for _, s := range a {
if s == "NULL" {
r = append(r, spanner.NullDate{Valid: false})
continue
}
s, err := processQuote(s)
if err != nil {
return []spanner.NullDate{}, err
}
date, err := convDate(s)
if err != nil {
return []spanner.NullDate{}, err
}
r = append(r, spanner.NullDate{Date: date, Valid: true})
}
return r, nil
case ddl.Float32:
var r []spanner.NullFloat32
for _, s := range a {
if s == "NULL" {
r = append(r, spanner.NullFloat32{Valid: false})
continue
}
s, err := processQuote(s)
if err != nil {
return []spanner.NullFloat32{}, err
}
f, err := convFloat32(s)
if err != nil {
return []spanner.NullFloat32{}, err
}
r = append(r, spanner.NullFloat32{Float32: f, Valid: true})
}
return r, nil
case ddl.Float64:
var r []spanner.NullFloat64
for _, s := range a {
if s == "NULL" {
r = append(r, spanner.NullFloat64{Valid: false})
continue
}
s, err := processQuote(s)
if err != nil {
return []spanner.NullFloat64{}, err
}
f, err := convFloat64(s)
if err != nil {
return []spanner.NullFloat64{}, err
}
r = append(r, spanner.NullFloat64{Float64: f, Valid: true})
}
return r, nil
case ddl.Numeric:
var r []spanner.NullNumeric
for _, s := range a {
if s == "NULL" {
r = append(r, spanner.NullNumeric{Valid: false})
continue
}
s, err := processQuote(s)
if err != nil {
return []spanner.NullNumeric{}, err
}
n, err := convNumeric(s)
if err != nil {
return []spanner.NullNumeric{}, err
}
r = append(r, spanner.NullNumeric{Numeric: n, Valid: true})
}
return r, nil
case ddl.Int64:
var r []spanner.NullInt64
for _, s := range a {
if s == "NULL" {
r = append(r, spanner.NullInt64{Valid: false})
continue
}
s, err := processQuote(s)
if err != nil {
return []spanner.NullInt64{}, err
}
i, err := convInt64(s)
if err != nil {
return r, err
}
r = append(r, spanner.NullInt64{Int64: i, Valid: true})
}
return r, nil
case ddl.String:
var r []spanner.NullString
for _, s := range a {
if s == "NULL" {
r = append(r, spanner.NullString{Valid: false})
continue
}
s, err := processQuote(s)
if err != nil {
return []spanner.NullString{}, err
}
r = append(r, spanner.NullString{StringVal: s, Valid: true})
}
return r, nil
case ddl.Timestamp:
var r []spanner.NullTime
for _, s := range a {
if s == "NULL" {
r = append(r, spanner.NullTime{Valid: false})
continue
}
s, err := processQuote(s)
if err != nil {
return []spanner.NullTime{}, err
}
t, err := convTimestamp(s)
if err != nil {
return []spanner.NullTime{}, err
}
r = append(r, spanner.NullTime{Time: t, Valid: true})
}
return r, nil
}
return []interface{}{}, fmt.Errorf("array type conversion not implemented for type []%v", spannerType.Name)
}