in sources/postgres/data.go [256:415]
func convArray(spannerType ddl.Type, srcTypeName string, location *time.Location, v string) (interface{}, error) {
v = strings.TrimSpace(v)
// 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 v == "{}" {
return []spanner.NullString{}, nil
}
if v[0] != '{' || v[len(v)-1] != '}' {
return []interface{}{}, fmt.Errorf("unrecognized data format for array: expected {v1, v2, ...}")
}
a := strings.Split(v[1:len(v)-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.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(srcTypeName, location, 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", reflect.TypeOf(spannerType))
}