1/* 2Copyright 2017 Google LLC 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package spanner 18 19import ( 20 "encoding/json" 21 "fmt" 22 "math" 23 "math/big" 24 "reflect" 25 "testing" 26 "time" 27 28 "cloud.google.com/go/civil" 29 "cloud.google.com/go/internal/testutil" 30 "github.com/golang/protobuf/proto" 31 proto3 "github.com/golang/protobuf/ptypes/struct" 32 "github.com/google/go-cmp/cmp" 33 sppb "google.golang.org/genproto/googleapis/spanner/v1" 34) 35 36var ( 37 t1 = mustParseTime("2016-11-15T15:04:05.999999999Z") 38 // Boundaries 39 t2 = mustParseTime("0001-01-01T00:00:00.000000000Z") 40 t3 = mustParseTime("9999-12-31T23:59:59.999999999Z") 41 // Local timezone 42 t4 = time.Now() 43 d1 = mustParseDate("2016-11-15") 44 d2 = mustParseDate("1678-01-01") 45) 46 47func mustParseTime(s string) time.Time { 48 t, err := time.Parse(time.RFC3339Nano, s) 49 if err != nil { 50 panic(err) 51 } 52 return t 53} 54 55func mustParseDate(s string) civil.Date { 56 d, err := civil.ParseDate(s) 57 if err != nil { 58 panic(err) 59 } 60 return d 61} 62 63type customStructToString struct { 64 A string 65 B string 66} 67 68// Convert the customStructToString 69func (c customStructToString) EncodeSpanner() (interface{}, error) { 70 return "A-B", nil 71} 72 73// Convert to customStructToString 74func (c *customStructToString) DecodeSpanner(val interface{}) (err error) { 75 c.A = "A" 76 c.B = "B" 77 return nil 78} 79 80type customStructToInt struct { 81 A int64 82 B int64 83} 84 85// Convert the customStructToInt 86func (c customStructToInt) EncodeSpanner() (interface{}, error) { 87 return 123, nil 88} 89 90// Convert to customStructToInt 91func (c *customStructToInt) DecodeSpanner(val interface{}) (err error) { 92 c.A = 1 93 c.B = 23 94 return nil 95} 96 97type customStructToFloat struct { 98 A float64 99 B float64 100} 101 102// Convert the customStructToFloat 103func (c customStructToFloat) EncodeSpanner() (interface{}, error) { 104 return 123.123, nil 105} 106 107// Convert to customStructToFloat 108func (c *customStructToFloat) DecodeSpanner(val interface{}) (err error) { 109 c.A = 1.23 110 c.B = 12.3 111 return nil 112} 113 114type customStructToBool struct { 115 A bool 116 B bool 117} 118 119// Convert the customStructToBool 120func (c customStructToBool) EncodeSpanner() (interface{}, error) { 121 return true, nil 122} 123 124// Convert to customStructToBool 125func (c *customStructToBool) DecodeSpanner(val interface{}) (err error) { 126 c.A = true 127 c.B = false 128 return nil 129} 130 131type customStructToBytes struct { 132 A []byte 133 B []byte 134} 135 136// Convert the customStructToBytes 137func (c customStructToBytes) EncodeSpanner() (interface{}, error) { 138 return []byte("AB"), nil 139} 140 141// Convert to customStructToBytes 142func (c *customStructToBytes) DecodeSpanner(val interface{}) (err error) { 143 c.A = []byte("A") 144 c.B = []byte("B") 145 return nil 146} 147 148type customStructToTime struct { 149 A string 150 B string 151} 152 153// Convert the customStructToTime 154func (c customStructToTime) EncodeSpanner() (interface{}, error) { 155 return t1, nil 156} 157 158// Convert to customStructToTime 159func (c *customStructToTime) DecodeSpanner(val interface{}) (err error) { 160 c.A = "A" 161 c.B = "B" 162 return nil 163} 164 165type customStructToDate struct { 166 A string 167 B string 168} 169 170// Convert the customStructToDate 171func (c customStructToDate) EncodeSpanner() (interface{}, error) { 172 return d1, nil 173} 174 175// Convert to customStructToDate 176func (c *customStructToDate) DecodeSpanner(val interface{}) (err error) { 177 c.A = "A" 178 c.B = "B" 179 return nil 180} 181 182// Test encoding Values. 183func TestEncodeValue(t *testing.T) { 184 type CustomString string 185 type CustomBytes []byte 186 type CustomInt64 int64 187 type CustomBool bool 188 type CustomFloat64 float64 189 type CustomTime time.Time 190 type CustomDate civil.Date 191 type CustomNumeric big.Rat 192 193 type CustomNullString NullString 194 type CustomNullInt64 NullInt64 195 type CustomNullBool NullBool 196 type CustomNullFloat64 NullFloat64 197 type CustomNullTime NullTime 198 type CustomNullDate NullDate 199 type CustomNullNumeric NullNumeric 200 201 sValue := "abc" 202 var sNilPtr *string 203 iValue := int64(7) 204 var iNilPtr *int64 205 bValue := true 206 var bNilPtr *bool 207 fValue := 3.14 208 var fNilPtr *float64 209 tValue := t1 210 var tNilPtr *time.Time 211 dValue := d1 212 var dNilPtr *civil.Date 213 numValuePtr := big.NewRat(12345, 1e3) 214 var numNilPtr *big.Rat 215 num2ValuePtr := big.NewRat(12345, 1e4) 216 217 var ( 218 tString = stringType() 219 tInt = intType() 220 tBool = boolType() 221 tFloat = floatType() 222 tBytes = bytesType() 223 tTime = timeType() 224 tDate = dateType() 225 tNumeric = numericType() 226 ) 227 for i, test := range []struct { 228 in interface{} 229 want *proto3.Value 230 wantType *sppb.Type 231 name string 232 }{ 233 // STRING / STRING ARRAY: 234 {"abc", stringProto("abc"), tString, "string"}, 235 {NullString{"abc", true}, stringProto("abc"), tString, "NullString with value"}, 236 {NullString{"abc", false}, nullProto(), tString, "NullString with null"}, 237 {&sValue, stringProto("abc"), tString, "*string with value"}, 238 {sNilPtr, nullProto(), tString, "*string with null"}, 239 {[]string(nil), nullProto(), listType(tString), "null []string"}, 240 {[]string{"abc", "bcd"}, listProto(stringProto("abc"), stringProto("bcd")), listType(tString), "[]string"}, 241 {[]NullString{{"abcd", true}, {"xyz", false}}, listProto(stringProto("abcd"), nullProto()), listType(tString), "[]NullString"}, 242 {[]*string{&sValue, sNilPtr}, listProto(stringProto("abc"), nullProto()), listType(tString), "[]*string"}, 243 // BYTES / BYTES ARRAY 244 {[]byte("foo"), bytesProto([]byte("foo")), tBytes, "[]byte with value"}, 245 {[]byte(nil), nullProto(), tBytes, "null []byte"}, 246 {[][]byte{nil, []byte("ab")}, listProto(nullProto(), bytesProto([]byte("ab"))), listType(tBytes), "[][]byte"}, 247 {[][]byte(nil), nullProto(), listType(tBytes), "null [][]byte"}, 248 // INT64 / INT64 ARRAY 249 {7, intProto(7), tInt, "int"}, 250 {[]int(nil), nullProto(), listType(tInt), "null []int"}, 251 {[]int{31, 127}, listProto(intProto(31), intProto(127)), listType(tInt), "[]int"}, 252 {int64(81), intProto(81), tInt, "int64"}, 253 {[]int64(nil), nullProto(), listType(tInt), "null []int64"}, 254 {[]int64{33, 129}, listProto(intProto(33), intProto(129)), listType(tInt), "[]int64"}, 255 {NullInt64{11, true}, intProto(11), tInt, "NullInt64 with value"}, 256 {NullInt64{11, false}, nullProto(), tInt, "NullInt64 with null"}, 257 {&iValue, intProto(7), tInt, "*int64 with value"}, 258 {iNilPtr, nullProto(), tInt, "*int64 with null"}, 259 {[]NullInt64{{35, true}, {131, false}}, listProto(intProto(35), nullProto()), listType(tInt), "[]NullInt64"}, 260 {[]*int64{&iValue, iNilPtr}, listProto(intProto(7), nullProto()), listType(tInt), "[]*int64"}, 261 // BOOL / BOOL ARRAY 262 {true, boolProto(true), tBool, "bool"}, 263 {NullBool{true, true}, boolProto(true), tBool, "NullBool with value"}, 264 {NullBool{true, false}, nullProto(), tBool, "NullBool with null"}, 265 {&bValue, boolProto(true), tBool, "*bool with value"}, 266 {bNilPtr, nullProto(), tBool, "*bool with null"}, 267 {[]bool{true, false}, listProto(boolProto(true), boolProto(false)), listType(tBool), "[]bool"}, 268 {[]NullBool{{true, true}, {true, false}}, listProto(boolProto(true), nullProto()), listType(tBool), "[]NullBool"}, 269 {[]*bool{&bValue, bNilPtr}, listProto(boolProto(true), nullProto()), listType(tBool), "[]*bool"}, 270 // FLOAT64 / FLOAT64 ARRAY 271 {3.14, floatProto(3.14), tFloat, "float"}, 272 {NullFloat64{3.1415, true}, floatProto(3.1415), tFloat, "NullFloat64 with value"}, 273 {NullFloat64{math.Inf(1), true}, floatProto(math.Inf(1)), tFloat, "NullFloat64 with infinity"}, 274 {NullFloat64{3.14159, false}, nullProto(), tFloat, "NullFloat64 with null"}, 275 {&fValue, floatProto(3.14), tFloat, "*float64 with value"}, 276 {fNilPtr, nullProto(), tFloat, "*float64 with null"}, 277 {[]float64(nil), nullProto(), listType(tFloat), "null []float64"}, 278 {[]float64{3.141, 0.618, math.Inf(-1)}, listProto(floatProto(3.141), floatProto(0.618), floatProto(math.Inf(-1))), listType(tFloat), "[]float64"}, 279 {[]NullFloat64{{3.141, true}, {0.618, false}}, listProto(floatProto(3.141), nullProto()), listType(tFloat), "[]NullFloat64"}, 280 {[]*float64{&fValue, fNilPtr}, listProto(floatProto(3.14), nullProto()), listType(tFloat), "[]NullFloat64"}, 281 // NUMERIC / NUMERIC ARRAY 282 {*numValuePtr, numericProto(numValuePtr), tNumeric, "big.Rat"}, 283 {numValuePtr, numericProto(numValuePtr), tNumeric, "*big.Rat"}, 284 {numNilPtr, nullProto(), tNumeric, "*big.Rat with null"}, 285 {NullNumeric{*numValuePtr, true}, numericProto(numValuePtr), tNumeric, "NullNumeric with value"}, 286 {NullNumeric{*numValuePtr, false}, nullProto(), tNumeric, "NullNumeric with null"}, 287 {[]big.Rat(nil), nullProto(), listType(tNumeric), "null []big.Rat"}, 288 {[]big.Rat{*numValuePtr, *num2ValuePtr}, listProto(numericProto(numValuePtr), numericProto(num2ValuePtr)), listType(tNumeric), "[]big.Rat"}, 289 {[]NullNumeric{{*numValuePtr, true}, {*numValuePtr, false}}, listProto(numericProto(numValuePtr), nullProto()), listType(tNumeric), "[]NullNumeric"}, 290 {[]*big.Rat{nil, numValuePtr}, listProto(nullProto(), numericProto(numValuePtr)), listType(tNumeric), "[]*big.Rat"}, 291 {[]*big.Rat(nil), nullProto(), listType(tNumeric), "null []*big.Rat"}, 292 // TIMESTAMP / TIMESTAMP ARRAY 293 {t1, timeProto(t1), tTime, "time"}, 294 {NullTime{t1, true}, timeProto(t1), tTime, "NullTime with value"}, 295 {NullTime{t1, false}, nullProto(), tTime, "NullTime with null"}, 296 {&tValue, timeProto(t1), tTime, "*time.Time with value"}, 297 {tNilPtr, nullProto(), tTime, "*time.Time with null"}, 298 {[]time.Time(nil), nullProto(), listType(tTime), "null []time"}, 299 {[]time.Time{t1, t2, t3, t4}, listProto(timeProto(t1), timeProto(t2), timeProto(t3), timeProto(t4)), listType(tTime), "[]time"}, 300 {[]NullTime{{t1, true}, {t1, false}}, listProto(timeProto(t1), nullProto()), listType(tTime), "[]NullTime"}, 301 {[]*time.Time{&tValue, tNilPtr}, listProto(timeProto(t1), nullProto()), listType(tTime), "[]*time.Time"}, 302 // DATE / DATE ARRAY 303 {d1, dateProto(d1), tDate, "date"}, 304 {NullDate{d1, true}, dateProto(d1), tDate, "NullDate with value"}, 305 {NullDate{civil.Date{}, false}, nullProto(), tDate, "NullDate with null"}, 306 {&dValue, dateProto(d1), tDate, "*civil.Date with value"}, 307 {dNilPtr, nullProto(), tDate, "*civil.Date with null"}, 308 {[]civil.Date(nil), nullProto(), listType(tDate), "null []date"}, 309 {[]civil.Date{d1, d2}, listProto(dateProto(d1), dateProto(d2)), listType(tDate), "[]date"}, 310 {[]NullDate{{d1, true}, {civil.Date{}, false}}, listProto(dateProto(d1), nullProto()), listType(tDate), "[]NullDate"}, 311 {[]*civil.Date{&dValue, dNilPtr}, listProto(dateProto(d1), nullProto()), listType(tDate), "[]*civil.Date"}, 312 // GenericColumnValue 313 {GenericColumnValue{tString, stringProto("abc")}, stringProto("abc"), tString, "GenericColumnValue with value"}, 314 {GenericColumnValue{tString, nullProto()}, nullProto(), tString, "GenericColumnValue with null"}, 315 // not actually valid (stringProto inside int list), but demonstrates pass-through. 316 { 317 GenericColumnValue{ 318 Type: listType(tInt), 319 Value: listProto(intProto(5), nullProto(), stringProto("bcd")), 320 }, 321 listProto(intProto(5), nullProto(), stringProto("bcd")), 322 listType(tInt), 323 "pass-through", 324 }, 325 // placeholder 326 {CommitTimestamp, stringProto(commitTimestampPlaceholderString), tTime, "CommitTimestampPlaceholder"}, 327 // CUSTOM STRING / CUSTOM STRING ARRAY 328 {CustomString("abc"), stringProto("abc"), tString, "CustomString"}, 329 {CustomNullString{"abc", true}, stringProto("abc"), tString, "CustomNullString with value"}, 330 {CustomNullString{"abc", false}, nullProto(), tString, "CustomNullString with null"}, 331 {[]CustomString(nil), nullProto(), listType(tString), "null []CustomString"}, 332 {[]CustomString{"abc", "bcd"}, listProto(stringProto("abc"), stringProto("bcd")), listType(tString), "[]CustomString"}, 333 {[]CustomNullString(nil), nullProto(), listType(tString), "null []NullCustomString"}, 334 {[]CustomNullString{{"abcd", true}, {"xyz", false}}, listProto(stringProto("abcd"), nullProto()), listType(tString), "[]NullCustomString"}, 335 // CUSTOM BYTES / CUSTOM BYTES ARRAY 336 {CustomBytes("foo"), bytesProto([]byte("foo")), tBytes, "CustomBytes with value"}, 337 {CustomBytes(nil), nullProto(), tBytes, "null CustomBytes"}, 338 {[]CustomBytes{nil, CustomBytes("ab")}, listProto(nullProto(), bytesProto([]byte("ab"))), listType(tBytes), "[]CustomBytes"}, 339 {[]CustomBytes(nil), nullProto(), listType(tBytes), "null []CustomBytes"}, 340 // CUSTOM INT64 / CUSTOM INT64 ARRAY 341 {CustomInt64(81), intProto(81), tInt, "CustomInt64"}, 342 {[]CustomInt64(nil), nullProto(), listType(tInt), "null []CustomInt64"}, 343 {[]CustomInt64{33, 129}, listProto(intProto(33), intProto(129)), listType(tInt), "[]CustomInt64"}, 344 {CustomNullInt64{11, true}, intProto(11), tInt, "CustomNullInt64 with value"}, 345 {CustomNullInt64{11, false}, nullProto(), tInt, "CustomNullInt64 with null"}, 346 {[]CustomNullInt64(nil), nullProto(), listType(tInt), "null []CustomNullInt64"}, 347 {[]CustomNullInt64{{35, true}, {131, false}}, listProto(intProto(35), nullProto()), listType(tInt), "[]CustomNullInt64"}, 348 // CUSTOM BOOL / CUSTOM BOOL ARRAY 349 {CustomBool(true), boolProto(true), tBool, "CustomBool"}, 350 {CustomNullBool{true, true}, boolProto(true), tBool, "CustomNullBool with value"}, 351 {CustomNullBool{true, false}, nullProto(), tBool, "CustomNullBool with null"}, 352 {[]CustomBool{true, false}, listProto(boolProto(true), boolProto(false)), listType(tBool), "[]CustomBool"}, 353 {[]CustomNullBool{{true, true}, {true, false}}, listProto(boolProto(true), nullProto()), listType(tBool), "[]CustomNullBool"}, 354 // FLOAT64 / FLOAT64 ARRAY 355 {CustomFloat64(3.14), floatProto(3.14), tFloat, "CustomFloat64"}, 356 {CustomNullFloat64{3.1415, true}, floatProto(3.1415), tFloat, "CustomNullFloat64 with value"}, 357 {CustomNullFloat64{math.Inf(1), true}, floatProto(math.Inf(1)), tFloat, "CustomNullFloat64 with infinity"}, 358 {CustomNullFloat64{3.14159, false}, nullProto(), tFloat, "CustomNullFloat64 with null"}, 359 {[]CustomFloat64(nil), nullProto(), listType(tFloat), "null []CustomFloat64"}, 360 {[]CustomFloat64{3.141, 0.618, CustomFloat64(math.Inf(-1))}, listProto(floatProto(3.141), floatProto(0.618), floatProto(math.Inf(-1))), listType(tFloat), "[]CustomFloat64"}, 361 {[]CustomNullFloat64(nil), nullProto(), listType(tFloat), "null []CustomNullFloat64"}, 362 {[]CustomNullFloat64{{3.141, true}, {0.618, false}}, listProto(floatProto(3.141), nullProto()), listType(tFloat), "[]CustomNullFloat64"}, 363 // CUSTOM TIMESTAMP / CUSTOM TIMESTAMP ARRAY 364 {CustomTime(t1), timeProto(t1), tTime, "CustomTime"}, 365 {CustomNullTime{t1, true}, timeProto(t1), tTime, "CustomNullTime with value"}, 366 {CustomNullTime{t1, false}, nullProto(), tTime, "CustomNullTime with null"}, 367 {[]CustomTime(nil), nullProto(), listType(tTime), "null []CustomTime"}, 368 {[]CustomTime{CustomTime(t1), CustomTime(t2), CustomTime(t3), CustomTime(t4)}, listProto(timeProto(t1), timeProto(t2), timeProto(t3), timeProto(t4)), listType(tTime), "[]CustomTime"}, 369 {[]CustomNullTime(nil), nullProto(), listType(tTime), "null []CustomNullTime"}, 370 {[]CustomNullTime{{t1, true}, {t1, false}}, listProto(timeProto(t1), nullProto()), listType(tTime), "[]CustomNullTime"}, 371 // CUSTOM DATE / CUSTOM DATE ARRAY 372 {CustomDate(d1), dateProto(d1), tDate, "CustomDate"}, 373 {CustomNullDate{d1, true}, dateProto(d1), tDate, "CustomNullDate with value"}, 374 {CustomNullDate{civil.Date{}, false}, nullProto(), tDate, "CustomNullDate with null"}, 375 {[]CustomDate(nil), nullProto(), listType(tDate), "null []CustomDate"}, 376 {[]CustomDate{CustomDate(d1), CustomDate(d2)}, listProto(dateProto(d1), dateProto(d2)), listType(tDate), "[]CustomDate"}, 377 {[]CustomNullDate(nil), nullProto(), listType(tDate), "null []CustomNullDate"}, 378 {[]CustomNullDate{{d1, true}, {civil.Date{}, false}}, listProto(dateProto(d1), nullProto()), listType(tDate), "[]NullDate"}, 379 // CUSTOM STRUCT 380 {customStructToString{"A", "B"}, stringProto("A-B"), tString, "a struct to string"}, 381 {customStructToInt{1, 23}, intProto(123), tInt, "a struct to int"}, 382 {customStructToFloat{1.23, 12.3}, floatProto(123.123), tFloat, "a struct to float"}, 383 {customStructToBool{true, false}, boolProto(true), tBool, "a struct to bool"}, 384 {customStructToBytes{[]byte("A"), []byte("B")}, bytesProto([]byte("AB")), tBytes, "a struct to bytes"}, 385 {customStructToTime{"A", "B"}, timeProto(tValue), tTime, "a struct to time"}, 386 {customStructToDate{"A", "B"}, dateProto(dValue), tDate, "a struct to date"}, 387 // CUSTOM NUMERIC / CUSTOM NUMERIC ARRAY 388 {CustomNumeric(*numValuePtr), numericProto(numValuePtr), tNumeric, "CustomNumeric"}, 389 {CustomNullNumeric{*numValuePtr, true}, numericProto(numValuePtr), tNumeric, "CustomNullNumeric with value"}, 390 {CustomNullNumeric{*numValuePtr, false}, nullProto(), tNumeric, "CustomNullNumeric with null"}, 391 {[]CustomNumeric(nil), nullProto(), listType(tNumeric), "null []CustomNumeric"}, 392 {[]CustomNumeric{CustomNumeric(*numValuePtr), CustomNumeric(*num2ValuePtr)}, listProto(numericProto(numValuePtr), numericProto(num2ValuePtr)), listType(tNumeric), "[]CustomNumeric"}, 393 {[]CustomNullNumeric(nil), nullProto(), listType(tNumeric), "null []CustomNullNumeric"}, 394 {[]CustomNullNumeric{{*numValuePtr, true}, {*num2ValuePtr, false}}, listProto(numericProto(numValuePtr), nullProto()), listType(tNumeric), "[]CustomNullNumeric"}, 395 } { 396 got, gotType, err := encodeValue(test.in) 397 if err != nil { 398 t.Fatalf("#%d (%s): got error during encoding: %v, want nil", i, test.name, err) 399 } 400 if !testEqual(got, test.want) { 401 t.Errorf("#%d (%s): got encode result: %v, want %v", i, test.name, got, test.want) 402 } 403 if !testEqual(gotType, test.wantType) { 404 t.Errorf("#%d (%s): got encode type: %v, want %v", i, test.name, gotType, test.wantType) 405 } 406 } 407} 408 409type encodeTest struct { 410 desc string 411 in interface{} 412 want *proto3.Value 413 wantType *sppb.Type 414} 415 416func checkStructEncoding(desc string, got *proto3.Value, gotType *sppb.Type, 417 want *proto3.Value, wantType *sppb.Type, t *testing.T) { 418 if !testEqual(got, want) { 419 t.Errorf("Test %s: got encode result: %v, want %v", desc, got, want) 420 } 421 if !testEqual(gotType, wantType) { 422 t.Errorf("Test %s: got encode type: %v, want %v", desc, gotType, wantType) 423 } 424} 425 426// Testcase code 427func encodeStructValue(test encodeTest, t *testing.T) { 428 got, gotType, err := encodeValue(test.in) 429 if err != nil { 430 t.Fatalf("Test %s: got error during encoding: %v, want nil", test.desc, err) 431 } 432 checkStructEncoding(test.desc, got, gotType, test.want, test.wantType, t) 433} 434 435func TestEncodeStructValuePointers(t *testing.T) { 436 type structf struct { 437 F int `spanner:"ff2"` 438 } 439 nestedStructProto := structType(mkField("ff2", intType())) 440 441 type testType struct { 442 Stringf string 443 Structf *structf 444 ArrStructf []*structf 445 } 446 testTypeProto := structType( 447 mkField("Stringf", stringType()), 448 mkField("Structf", nestedStructProto), 449 mkField("ArrStructf", listType(nestedStructProto))) 450 451 for _, test := range []encodeTest{ 452 { 453 "Pointer to Go struct with pointers-to-(array)-struct fields.", 454 &testType{"hello", &structf{50}, []*structf{{30}, {40}}}, 455 listProto( 456 stringProto("hello"), 457 listProto(intProto(50)), 458 listProto( 459 listProto(intProto(30)), 460 listProto(intProto(40)))), 461 testTypeProto, 462 }, 463 { 464 "Nil pointer to Go struct representing a NULL struct value.", 465 (*testType)(nil), 466 nullProto(), 467 testTypeProto, 468 }, 469 { 470 "Slice of pointers to Go structs with NULL and non-NULL elements.", 471 []*testType{ 472 (*testType)(nil), 473 {"hello", nil, []*structf{nil, {40}}}, 474 {"world", &structf{70}, nil}, 475 }, 476 listProto( 477 nullProto(), 478 listProto( 479 stringProto("hello"), 480 nullProto(), 481 listProto(nullProto(), listProto(intProto(40)))), 482 listProto( 483 stringProto("world"), 484 listProto(intProto(70)), 485 nullProto())), 486 listType(testTypeProto), 487 }, 488 { 489 "Nil slice of pointers to structs representing a NULL array of structs.", 490 []*testType(nil), 491 nullProto(), 492 listType(testTypeProto), 493 }, 494 { 495 "Empty slice of pointers to structs representing an empty array of structs.", 496 []*testType{}, 497 listProto(), 498 listType(testTypeProto), 499 }, 500 } { 501 encodeStructValue(test, t) 502 } 503} 504 505func TestEncodeStructValueErrors(t *testing.T) { 506 type Embedded struct { 507 A int 508 } 509 type embedded struct { 510 B bool 511 } 512 x := 0 513 514 for _, test := range []struct { 515 desc string 516 in interface{} 517 wantErr error 518 }{ 519 { 520 "Unsupported embedded fields.", 521 struct{ Embedded }{Embedded{10}}, 522 errUnsupportedEmbeddedStructFields("Embedded"), 523 }, 524 { 525 "Unsupported pointer to embedded fields.", 526 struct{ *Embedded }{&Embedded{10}}, 527 errUnsupportedEmbeddedStructFields("Embedded"), 528 }, 529 { 530 "Unsupported embedded + unexported fields.", 531 struct { 532 int 533 *bool 534 embedded 535 }{10, nil, embedded{false}}, 536 errUnsupportedEmbeddedStructFields("int"), 537 }, 538 { 539 "Unsupported type.", 540 (**struct{})(nil), 541 errEncoderUnsupportedType((**struct{})(nil)), 542 }, 543 { 544 "Unsupported type.", 545 3, 546 errEncoderUnsupportedType(3), 547 }, 548 { 549 "Unsupported type.", 550 &x, 551 errEncoderUnsupportedType(&x), 552 }, 553 } { 554 _, _, got := encodeStruct(test.in) 555 if got == nil || !testEqual(test.wantErr, got) { 556 t.Errorf("Test: %s, expected error %v during decoding, got %v", test.desc, test.wantErr, got) 557 } 558 } 559} 560 561func TestEncodeStructValueArrayStructFields(t *testing.T) { 562 type structf struct { 563 Intff int 564 } 565 566 structfType := structType(mkField("Intff", intType())) 567 for _, test := range []encodeTest{ 568 { 569 "Unnamed array-of-struct-typed field.", 570 struct { 571 Intf int 572 ArrStructf []structf `spanner:""` 573 }{10, []structf{{1}, {2}}}, 574 listProto( 575 intProto(10), 576 listProto( 577 listProto(intProto(1)), 578 listProto(intProto(2)))), 579 structType( 580 mkField("Intf", intType()), 581 mkField("", listType(structfType))), 582 }, 583 { 584 "Null array-of-struct-typed field.", 585 struct { 586 Intf int 587 ArrStructf []structf 588 }{10, []structf(nil)}, 589 listProto(intProto(10), nullProto()), 590 structType( 591 mkField("Intf", intType()), 592 mkField("ArrStructf", listType(structfType))), 593 }, 594 { 595 "Array-of-struct-typed field representing empty array.", 596 struct { 597 Intf int 598 ArrStructf []structf 599 }{10, []structf{}}, 600 listProto(intProto(10), listProto([]*proto3.Value{}...)), 601 structType( 602 mkField("Intf", intType()), 603 mkField("ArrStructf", listType(structfType))), 604 }, 605 { 606 "Array-of-struct-typed field with nullable struct elements.", 607 struct { 608 Intf int 609 ArrStructf []*structf 610 }{ 611 10, 612 []*structf{(*structf)(nil), {1}}, 613 }, 614 listProto( 615 intProto(10), 616 listProto( 617 nullProto(), 618 listProto(intProto(1)))), 619 structType( 620 mkField("Intf", intType()), 621 mkField("ArrStructf", listType(structfType))), 622 }, 623 } { 624 encodeStructValue(test, t) 625 } 626} 627 628func TestEncodeStructValueStructFields(t *testing.T) { 629 type structf struct { 630 Intff int 631 } 632 structfType := structType(mkField("Intff", intType())) 633 for _, test := range []encodeTest{ 634 { 635 "Named struct-type field.", 636 struct { 637 Intf int 638 Structf structf 639 }{10, structf{10}}, 640 listProto(intProto(10), listProto(intProto(10))), 641 structType( 642 mkField("Intf", intType()), 643 mkField("Structf", structfType)), 644 }, 645 { 646 "Unnamed struct-type field.", 647 struct { 648 Intf int 649 Structf structf `spanner:""` 650 }{10, structf{10}}, 651 listProto(intProto(10), listProto(intProto(10))), 652 structType( 653 mkField("Intf", intType()), 654 mkField("", structfType)), 655 }, 656 { 657 "Duplicate struct-typed field.", 658 struct { 659 Structf1 structf `spanner:""` 660 Structf2 structf `spanner:""` 661 }{structf{10}, structf{20}}, 662 listProto(listProto(intProto(10)), listProto(intProto(20))), 663 structType( 664 mkField("", structfType), 665 mkField("", structfType)), 666 }, 667 { 668 "Null struct-typed field.", 669 struct { 670 Intf int 671 Structf *structf 672 }{10, nil}, 673 listProto(intProto(10), nullProto()), 674 structType( 675 mkField("Intf", intType()), 676 mkField("Structf", structfType)), 677 }, 678 { 679 "Empty struct-typed field.", 680 struct { 681 Intf int 682 Structf struct{} 683 }{10, struct{}{}}, 684 listProto(intProto(10), listProto([]*proto3.Value{}...)), 685 structType( 686 mkField("Intf", intType()), 687 mkField("Structf", structType([]*sppb.StructType_Field{}...))), 688 }, 689 } { 690 encodeStructValue(test, t) 691 } 692} 693 694func TestEncodeStructValueFieldNames(t *testing.T) { 695 type embedded struct { 696 B bool 697 } 698 699 for _, test := range []encodeTest{ 700 { 701 "Duplicate fields.", 702 struct { 703 Field1 int `spanner:"field"` 704 DupField1 int `spanner:"field"` 705 }{10, 20}, 706 listProto(intProto(10), intProto(20)), 707 structType( 708 mkField("field", intType()), 709 mkField("field", intType())), 710 }, 711 { 712 "Duplicate Fields (different types).", 713 struct { 714 IntField int `spanner:"field"` 715 StringField string `spanner:"field"` 716 }{10, "abc"}, 717 listProto(intProto(10), stringProto("abc")), 718 structType( 719 mkField("field", intType()), 720 mkField("field", stringType())), 721 }, 722 { 723 "Duplicate unnamed fields.", 724 struct { 725 Dup int `spanner:""` 726 Dup1 int `spanner:""` 727 }{10, 20}, 728 listProto(intProto(10), intProto(20)), 729 structType( 730 mkField("", intType()), 731 mkField("", intType())), 732 }, 733 { 734 "Named and unnamed fields.", 735 struct { 736 Field string 737 Field1 int `spanner:""` 738 Field2 string `spanner:"field"` 739 }{"abc", 10, "def"}, 740 listProto(stringProto("abc"), intProto(10), stringProto("def")), 741 structType( 742 mkField("Field", stringType()), 743 mkField("", intType()), 744 mkField("field", stringType())), 745 }, 746 { 747 "Ignored unexported fields.", 748 struct { 749 Field int 750 field bool 751 Field1 string `spanner:"field"` 752 }{10, false, "abc"}, 753 listProto(intProto(10), stringProto("abc")), 754 structType( 755 mkField("Field", intType()), 756 mkField("field", stringType())), 757 }, 758 { 759 "Ignored unexported struct/slice fields.", 760 struct { 761 a []*embedded 762 b []embedded 763 c embedded 764 d *embedded 765 Field1 string `spanner:"field"` 766 }{nil, nil, embedded{}, nil, "def"}, 767 listProto(stringProto("def")), 768 structType( 769 mkField("field", stringType())), 770 }, 771 } { 772 encodeStructValue(test, t) 773 } 774} 775 776func TestEncodeStructValueBasicFields(t *testing.T) { 777 type CustomString string 778 type CustomBytes []byte 779 type CustomInt64 int64 780 type CustomBool bool 781 type CustomFloat64 float64 782 type CustomTime time.Time 783 type CustomDate civil.Date 784 785 type CustomNullString NullString 786 type CustomNullInt64 NullInt64 787 type CustomNullBool NullBool 788 type CustomNullFloat64 NullFloat64 789 type CustomNullTime NullTime 790 type CustomNullDate NullDate 791 792 sValue := "abc" 793 iValue := int64(300) 794 bValue := false 795 fValue := 3.45 796 tValue := t1 797 dValue := d1 798 799 StructTypeProto := structType( 800 mkField("Stringf", stringType()), 801 mkField("Intf", intType()), 802 mkField("Boolf", boolType()), 803 mkField("Floatf", floatType()), 804 mkField("Bytef", bytesType()), 805 mkField("Timef", timeType()), 806 mkField("Datef", dateType())) 807 808 for _, test := range []encodeTest{ 809 { 810 "Basic types.", 811 struct { 812 Stringf string 813 Intf int 814 Boolf bool 815 Floatf float64 816 Bytef []byte 817 Timef time.Time 818 Datef civil.Date 819 }{"abc", 300, false, 3.45, []byte("foo"), t1, d1}, 820 listProto( 821 stringProto("abc"), 822 intProto(300), 823 boolProto(false), 824 floatProto(3.45), 825 bytesProto([]byte("foo")), 826 timeProto(t1), 827 dateProto(d1)), 828 StructTypeProto, 829 }, 830 { 831 "Pointers to basic types.", 832 struct { 833 Stringf *string 834 Intf *int64 835 Boolf *bool 836 Floatf *float64 837 Bytef []byte 838 Timef *time.Time 839 Datef *civil.Date 840 }{&sValue, &iValue, &bValue, &fValue, []byte("foo"), &tValue, &dValue}, 841 listProto( 842 stringProto("abc"), 843 intProto(300), 844 boolProto(false), 845 floatProto(3.45), 846 bytesProto([]byte("foo")), 847 timeProto(t1), 848 dateProto(d1)), 849 StructTypeProto, 850 }, 851 { 852 "Pointers to basic types with null values.", 853 struct { 854 Stringf *string 855 Intf *int64 856 Boolf *bool 857 Floatf *float64 858 Bytef []byte 859 Timef *time.Time 860 Datef *civil.Date 861 }{nil, nil, nil, nil, nil, nil, nil}, 862 listProto( 863 nullProto(), 864 nullProto(), 865 nullProto(), 866 nullProto(), 867 nullProto(), 868 nullProto(), 869 nullProto()), 870 StructTypeProto, 871 }, 872 { 873 "Basic custom types.", 874 struct { 875 Stringf CustomString 876 Intf CustomInt64 877 Boolf CustomBool 878 Floatf CustomFloat64 879 Bytef CustomBytes 880 Timef CustomTime 881 Datef CustomDate 882 }{"abc", 300, false, 3.45, []byte("foo"), CustomTime(t1), CustomDate(d1)}, 883 listProto( 884 stringProto("abc"), 885 intProto(300), 886 boolProto(false), 887 floatProto(3.45), 888 bytesProto([]byte("foo")), 889 timeProto(t1), 890 dateProto(d1)), 891 StructTypeProto, 892 }, 893 { 894 "Basic types null values.", 895 struct { 896 Stringf NullString 897 Intf NullInt64 898 Boolf NullBool 899 Floatf NullFloat64 900 Bytef []byte 901 Timef NullTime 902 Datef NullDate 903 }{ 904 NullString{"abc", false}, 905 NullInt64{4, false}, 906 NullBool{false, false}, 907 NullFloat64{5.6, false}, 908 nil, 909 NullTime{t1, false}, 910 NullDate{d1, false}, 911 }, 912 listProto( 913 nullProto(), 914 nullProto(), 915 nullProto(), 916 nullProto(), 917 nullProto(), 918 nullProto(), 919 nullProto()), 920 StructTypeProto, 921 }, 922 { 923 "Basic custom types null values.", 924 struct { 925 Stringf CustomNullString 926 Intf CustomNullInt64 927 Boolf CustomNullBool 928 Floatf CustomNullFloat64 929 Bytef CustomBytes 930 Timef CustomNullTime 931 Datef CustomNullDate 932 }{ 933 CustomNullString{"abc", false}, 934 CustomNullInt64{4, false}, 935 CustomNullBool{false, false}, 936 CustomNullFloat64{5.6, false}, 937 nil, 938 CustomNullTime{t1, false}, 939 CustomNullDate{d1, false}, 940 }, 941 listProto( 942 nullProto(), 943 nullProto(), 944 nullProto(), 945 nullProto(), 946 nullProto(), 947 nullProto(), 948 nullProto()), 949 StructTypeProto, 950 }, 951 } { 952 encodeStructValue(test, t) 953 } 954} 955 956func TestEncodeStructValueArrayFields(t *testing.T) { 957 type CustomString string 958 type CustomBytes []byte 959 type CustomInt64 int64 960 type CustomBool bool 961 type CustomFloat64 float64 962 type CustomTime time.Time 963 type CustomDate civil.Date 964 965 type CustomNullString NullString 966 type CustomNullInt64 NullInt64 967 type CustomNullBool NullBool 968 type CustomNullFloat64 NullFloat64 969 type CustomNullTime NullTime 970 type CustomNullDate NullDate 971 972 sValue := "def" 973 var sNilPtr *string 974 iValue := int64(68) 975 var iNilPtr *int64 976 bValue := true 977 var bNilPtr *bool 978 fValue := 3.14 979 var fNilPtr *float64 980 tValue := t1 981 var tNilPtr *time.Time 982 dValue := d1 983 var dNilPtr *civil.Date 984 985 StructTypeProto := structType( 986 mkField("Stringf", listType(stringType())), 987 mkField("Intf", listType(intType())), 988 mkField("Int64f", listType(intType())), 989 mkField("Boolf", listType(boolType())), 990 mkField("Floatf", listType(floatType())), 991 mkField("Bytef", listType(bytesType())), 992 mkField("Timef", listType(timeType())), 993 mkField("Datef", listType(dateType()))) 994 995 for _, test := range []encodeTest{ 996 { 997 "Arrays of basic types with non-nullable elements", 998 struct { 999 Stringf []string 1000 Intf []int 1001 Int64f []int64 1002 Boolf []bool 1003 Floatf []float64 1004 Bytef [][]byte 1005 Timef []time.Time 1006 Datef []civil.Date 1007 }{ 1008 []string{"abc", "def"}, 1009 []int{4, 67}, 1010 []int64{5, 68}, 1011 []bool{false, true}, 1012 []float64{3.45, 0.93}, 1013 [][]byte{[]byte("foo"), nil}, 1014 []time.Time{t1, t2}, 1015 []civil.Date{d1, d2}, 1016 }, 1017 listProto( 1018 listProto(stringProto("abc"), stringProto("def")), 1019 listProto(intProto(4), intProto(67)), 1020 listProto(intProto(5), intProto(68)), 1021 listProto(boolProto(false), boolProto(true)), 1022 listProto(floatProto(3.45), floatProto(0.93)), 1023 listProto(bytesProto([]byte("foo")), nullProto()), 1024 listProto(timeProto(t1), timeProto(t2)), 1025 listProto(dateProto(d1), dateProto(d2))), 1026 StructTypeProto, 1027 }, 1028 { 1029 "Arrays of basic custom types with non-nullable elements", 1030 struct { 1031 Stringf []CustomString 1032 Intf []CustomInt64 1033 Int64f []CustomInt64 1034 Boolf []CustomBool 1035 Floatf []CustomFloat64 1036 Bytef []CustomBytes 1037 Timef []CustomTime 1038 Datef []CustomDate 1039 }{ 1040 []CustomString{"abc", "def"}, 1041 []CustomInt64{4, 67}, 1042 []CustomInt64{5, 68}, 1043 []CustomBool{false, true}, 1044 []CustomFloat64{3.45, 0.93}, 1045 []CustomBytes{[]byte("foo"), nil}, 1046 []CustomTime{CustomTime(t1), CustomTime(t2)}, 1047 []CustomDate{CustomDate(d1), CustomDate(d2)}, 1048 }, 1049 listProto( 1050 listProto(stringProto("abc"), stringProto("def")), 1051 listProto(intProto(4), intProto(67)), 1052 listProto(intProto(5), intProto(68)), 1053 listProto(boolProto(false), boolProto(true)), 1054 listProto(floatProto(3.45), floatProto(0.93)), 1055 listProto(bytesProto([]byte("foo")), nullProto()), 1056 listProto(timeProto(t1), timeProto(t2)), 1057 listProto(dateProto(d1), dateProto(d2))), 1058 StructTypeProto, 1059 }, 1060 { 1061 "Arrays of basic types with nullable elements.", 1062 struct { 1063 Stringf []NullString 1064 Intf []NullInt64 1065 Int64f []NullInt64 1066 Boolf []NullBool 1067 Floatf []NullFloat64 1068 Bytef [][]byte 1069 Timef []NullTime 1070 Datef []NullDate 1071 }{ 1072 []NullString{{"abc", false}, {"def", true}}, 1073 []NullInt64{{4, false}, {67, true}}, 1074 []NullInt64{{5, false}, {68, true}}, 1075 []NullBool{{true, false}, {false, true}}, 1076 []NullFloat64{{3.45, false}, {0.93, true}}, 1077 [][]byte{[]byte("foo"), nil}, 1078 []NullTime{{t1, false}, {t2, true}}, 1079 []NullDate{{d1, false}, {d2, true}}, 1080 }, 1081 listProto( 1082 listProto(nullProto(), stringProto("def")), 1083 listProto(nullProto(), intProto(67)), 1084 listProto(nullProto(), intProto(68)), 1085 listProto(nullProto(), boolProto(false)), 1086 listProto(nullProto(), floatProto(0.93)), 1087 listProto(bytesProto([]byte("foo")), nullProto()), 1088 listProto(nullProto(), timeProto(t2)), 1089 listProto(nullProto(), dateProto(d2))), 1090 StructTypeProto, 1091 }, 1092 { 1093 "Arrays of pointers to basic types with nullable elements.", 1094 struct { 1095 Stringf []*string 1096 Intf []*int64 1097 Int64f []*int64 1098 Boolf []*bool 1099 Floatf []*float64 1100 Bytef [][]byte 1101 Timef []*time.Time 1102 Datef []*civil.Date 1103 }{ 1104 []*string{sNilPtr, &sValue}, 1105 []*int64{iNilPtr, &iValue}, 1106 []*int64{iNilPtr, &iValue}, 1107 []*bool{bNilPtr, &bValue}, 1108 []*float64{fNilPtr, &fValue}, 1109 [][]byte{[]byte("foo"), nil}, 1110 []*time.Time{tNilPtr, &tValue}, 1111 []*civil.Date{dNilPtr, &dValue}, 1112 }, 1113 listProto( 1114 listProto(nullProto(), stringProto("def")), 1115 listProto(nullProto(), intProto(68)), 1116 listProto(nullProto(), intProto(68)), 1117 listProto(nullProto(), boolProto(true)), 1118 listProto(nullProto(), floatProto(3.14)), 1119 listProto(bytesProto([]byte("foo")), nullProto()), 1120 listProto(nullProto(), timeProto(t1)), 1121 listProto(nullProto(), dateProto(d1))), 1122 StructTypeProto, 1123 }, 1124 { 1125 "Arrays of basic custom types with nullable elements.", 1126 struct { 1127 Stringf []CustomNullString 1128 Intf []CustomNullInt64 1129 Int64f []CustomNullInt64 1130 Boolf []CustomNullBool 1131 Floatf []CustomNullFloat64 1132 Bytef []CustomBytes 1133 Timef []CustomNullTime 1134 Datef []CustomNullDate 1135 }{ 1136 []CustomNullString{{"abc", false}, {"def", true}}, 1137 []CustomNullInt64{{4, false}, {67, true}}, 1138 []CustomNullInt64{{5, false}, {68, true}}, 1139 []CustomNullBool{{true, false}, {false, true}}, 1140 []CustomNullFloat64{{3.45, false}, {0.93, true}}, 1141 []CustomBytes{[]byte("foo"), nil}, 1142 []CustomNullTime{{t1, false}, {t2, true}}, 1143 []CustomNullDate{{d1, false}, {d2, true}}, 1144 }, 1145 listProto( 1146 listProto(nullProto(), stringProto("def")), 1147 listProto(nullProto(), intProto(67)), 1148 listProto(nullProto(), intProto(68)), 1149 listProto(nullProto(), boolProto(false)), 1150 listProto(nullProto(), floatProto(0.93)), 1151 listProto(bytesProto([]byte("foo")), nullProto()), 1152 listProto(nullProto(), timeProto(t2)), 1153 listProto(nullProto(), dateProto(d2))), 1154 StructTypeProto, 1155 }, 1156 { 1157 "Null arrays of basic types.", 1158 struct { 1159 Stringf []NullString 1160 Intf []NullInt64 1161 Int64f []NullInt64 1162 Boolf []NullBool 1163 Floatf []NullFloat64 1164 Bytef [][]byte 1165 Timef []NullTime 1166 Datef []NullDate 1167 }{ 1168 nil, 1169 nil, 1170 nil, 1171 nil, 1172 nil, 1173 nil, 1174 nil, 1175 nil, 1176 }, 1177 listProto( 1178 nullProto(), 1179 nullProto(), 1180 nullProto(), 1181 nullProto(), 1182 nullProto(), 1183 nullProto(), 1184 nullProto(), 1185 nullProto()), 1186 StructTypeProto, 1187 }, 1188 { 1189 "Null arrays of basic custom types.", 1190 struct { 1191 Stringf []CustomNullString 1192 Intf []CustomNullInt64 1193 Int64f []CustomNullInt64 1194 Boolf []CustomNullBool 1195 Floatf []CustomNullFloat64 1196 Bytef []CustomBytes 1197 Timef []CustomNullTime 1198 Datef []CustomNullDate 1199 }{ 1200 nil, 1201 nil, 1202 nil, 1203 nil, 1204 nil, 1205 nil, 1206 nil, 1207 nil, 1208 }, 1209 listProto( 1210 nullProto(), 1211 nullProto(), 1212 nullProto(), 1213 nullProto(), 1214 nullProto(), 1215 nullProto(), 1216 nullProto(), 1217 nullProto()), 1218 StructTypeProto, 1219 }, 1220 } { 1221 encodeStructValue(test, t) 1222 } 1223} 1224 1225// Test decoding Values. 1226func TestDecodeValue(t *testing.T) { 1227 type CustomString string 1228 type CustomBytes []byte 1229 type CustomInt64 int64 1230 type CustomBool bool 1231 type CustomFloat64 float64 1232 type CustomTime time.Time 1233 type CustomDate civil.Date 1234 type CustomNumeric big.Rat 1235 1236 type CustomNullString NullString 1237 type CustomNullInt64 NullInt64 1238 type CustomNullBool NullBool 1239 type CustomNullFloat64 NullFloat64 1240 type CustomNullTime NullTime 1241 type CustomNullDate NullDate 1242 type CustomNullNumeric NullNumeric 1243 1244 // Pointer values. 1245 sValue := "abc" 1246 var sNilPtr *string 1247 s2Value := "bcd" 1248 1249 iValue := int64(15) 1250 var iNilPtr *int64 1251 i1Value := int64(91) 1252 i2Value := int64(87) 1253 1254 bValue := true 1255 var bNilPtr *bool 1256 b2Value := false 1257 1258 fValue := 3.14 1259 var fNilPtr *float64 1260 f2Value := 6.626 1261 1262 numValuePtr := big.NewRat(12345, 1e3) 1263 var numNilPtr *big.Rat 1264 num2ValuePtr := big.NewRat(12345, 1e4) 1265 1266 tValue := t1 1267 var tNilPtr *time.Time 1268 t2Value := t2 1269 1270 dValue := d1 1271 var dNilPtr *civil.Date 1272 d2Value := d2 1273 1274 for _, test := range []struct { 1275 desc string 1276 proto *proto3.Value 1277 protoType *sppb.Type 1278 want interface{} 1279 wantErr bool 1280 }{ 1281 // STRING 1282 {desc: "decode STRING to string", proto: stringProto("abc"), protoType: stringType(), want: "abc"}, 1283 {desc: "decode NULL to string", proto: nullProto(), protoType: stringType(), want: "abc", wantErr: true}, 1284 {desc: "decode STRING to *string", proto: stringProto("abc"), protoType: stringType(), want: &sValue}, 1285 {desc: "decode NULL to *string", proto: nullProto(), protoType: stringType(), want: sNilPtr}, 1286 {desc: "decode STRING to NullString", proto: stringProto("abc"), protoType: stringType(), want: NullString{"abc", true}}, 1287 {desc: "decode NULL to NullString", proto: nullProto(), protoType: stringType(), want: NullString{}}, 1288 // STRING ARRAY with []NullString 1289 {desc: "decode ARRAY<STRING> to []NullString", proto: listProto(stringProto("abc"), nullProto(), stringProto("bcd")), protoType: listType(stringType()), want: []NullString{{"abc", true}, {}, {"bcd", true}}}, 1290 {desc: "decode NULL to []NullString", proto: nullProto(), protoType: listType(stringType()), want: []NullString(nil)}, 1291 // STRING ARRAY with []string 1292 {desc: "decode ARRAY<STRING> to []string", proto: listProto(stringProto("abc"), stringProto("bcd")), protoType: listType(stringType()), want: []string{"abc", "bcd"}}, 1293 // STRING ARRAY with []*string 1294 {desc: "decode ARRAY<STRING> to []*string", proto: listProto(stringProto("abc"), nullProto(), stringProto("bcd")), protoType: listType(stringType()), want: []*string{&sValue, sNilPtr, &s2Value}}, 1295 {desc: "decode NULL to []*string", proto: nullProto(), protoType: listType(stringType()), want: []*string(nil)}, 1296 // BYTES 1297 {desc: "decode BYTES to []byte", proto: bytesProto([]byte("ab")), protoType: bytesType(), want: []byte("ab")}, 1298 {desc: "decode NULL to []byte", proto: nullProto(), protoType: bytesType(), want: []byte(nil)}, 1299 // BYTES ARRAY 1300 {desc: "decode ARRAY<BYTES> to [][]byte", proto: listProto(bytesProto([]byte("ab")), nullProto()), protoType: listType(bytesType()), want: [][]byte{[]byte("ab"), nil}}, 1301 {desc: "decode NULL to [][]byte", proto: nullProto(), protoType: listType(bytesType()), want: [][]byte(nil)}, 1302 //INT64 1303 {desc: "decode INT64 to int64", proto: intProto(15), protoType: intType(), want: int64(15)}, 1304 {desc: "decode NULL to int64", proto: nullProto(), protoType: intType(), want: int64(0), wantErr: true}, 1305 {desc: "decode INT64 to *int64", proto: intProto(15), protoType: intType(), want: &iValue}, 1306 {desc: "decode NULL to *int64", proto: nullProto(), protoType: intType(), want: iNilPtr}, 1307 {desc: "decode INT64 to NullInt64", proto: intProto(15), protoType: intType(), want: NullInt64{15, true}}, 1308 {desc: "decode NULL to NullInt64", proto: nullProto(), protoType: intType(), want: NullInt64{}}, 1309 // INT64 ARRAY with []NullInt64 1310 {desc: "decode ARRAY<INT64> to []NullInt64", proto: listProto(intProto(91), nullProto(), intProto(87)), protoType: listType(intType()), want: []NullInt64{{91, true}, {}, {87, true}}}, 1311 {desc: "decode NULL to []NullInt64", proto: nullProto(), protoType: listType(intType()), want: []NullInt64(nil)}, 1312 // INT64 ARRAY with []int64 1313 {desc: "decode ARRAY<INT64> to []int64", proto: listProto(intProto(91), intProto(87)), protoType: listType(intType()), want: []int64{91, 87}}, 1314 // INT64 ARRAY with []*int64 1315 {desc: "decode ARRAY<INT64> to []*int64", proto: listProto(intProto(91), nullProto(), intProto(87)), protoType: listType(intType()), want: []*int64{&i1Value, nil, &i2Value}}, 1316 {desc: "decode NULL to []*int64", proto: nullProto(), protoType: listType(intType()), want: []*int64(nil)}, 1317 // BOOL 1318 {desc: "decode BOOL to bool", proto: boolProto(true), protoType: boolType(), want: true}, 1319 {desc: "decode NULL to bool", proto: nullProto(), protoType: boolType(), want: true, wantErr: true}, 1320 {desc: "decode BOOL to *bool", proto: boolProto(true), protoType: boolType(), want: &bValue}, 1321 {desc: "decode NULL to *bool", proto: nullProto(), protoType: boolType(), want: bNilPtr}, 1322 {desc: "decode BOOL to NullBool", proto: boolProto(true), protoType: boolType(), want: NullBool{true, true}}, 1323 {desc: "decode BOOL to NullBool", proto: nullProto(), protoType: boolType(), want: NullBool{}}, 1324 // BOOL ARRAY with []NullBool 1325 {desc: "decode ARRAY<BOOL> to []NullBool", proto: listProto(boolProto(true), boolProto(false), nullProto()), protoType: listType(boolType()), want: []NullBool{{true, true}, {false, true}, {}}}, 1326 {desc: "decode NULL to []NullBool", proto: nullProto(), protoType: listType(boolType()), want: []NullBool(nil)}, 1327 // BOOL ARRAY with []bool 1328 {desc: "decode ARRAY<BOOL> to []bool", proto: listProto(boolProto(true), boolProto(false)), protoType: listType(boolType()), want: []bool{true, false}}, 1329 // BOOL ARRAY with []*bool 1330 {desc: "decode ARRAY<BOOL> to []*bool", proto: listProto(boolProto(true), nullProto(), boolProto(false)), protoType: listType(boolType()), want: []*bool{&bValue, bNilPtr, &b2Value}}, 1331 {desc: "decode NULL to []*bool", proto: nullProto(), protoType: listType(boolType()), want: []*bool(nil)}, 1332 // FLOAT64 1333 {desc: "decode FLOAT64 to float64", proto: floatProto(3.14), protoType: floatType(), want: 3.14}, 1334 {desc: "decode NULL to float64", proto: nullProto(), protoType: floatType(), want: 0.00, wantErr: true}, 1335 {desc: "decode FLOAT64 to *float64", proto: floatProto(3.14), protoType: floatType(), want: &fValue}, 1336 {desc: "decode NULL to *float64", proto: nullProto(), protoType: floatType(), want: fNilPtr}, 1337 {desc: "decode FLOAT64 to NullFloat64", proto: floatProto(3.14), protoType: floatType(), want: NullFloat64{3.14, true}}, 1338 {desc: "decode NULL to NullFloat64", proto: nullProto(), protoType: floatType(), want: NullFloat64{}}, 1339 // FLOAT64 ARRAY with []NullFloat64 1340 {desc: "decode ARRAY<FLOAT64> to []NullFloat64", proto: listProto(floatProto(math.Inf(1)), floatProto(math.Inf(-1)), nullProto(), floatProto(3.1)), protoType: listType(floatType()), want: []NullFloat64{{math.Inf(1), true}, {math.Inf(-1), true}, {}, {3.1, true}}}, 1341 {desc: "decode NULL to []NullFloat64", proto: nullProto(), protoType: listType(floatType()), want: []NullFloat64(nil)}, 1342 // FLOAT64 ARRAY with []float64 1343 {desc: "decode ARRAY<FLOAT64> to []float64", proto: listProto(floatProto(math.Inf(1)), floatProto(math.Inf(-1)), floatProto(3.1)), protoType: listType(floatType()), want: []float64{math.Inf(1), math.Inf(-1), 3.1}}, 1344 // FLOAT64 ARRAY with []*float64 1345 {desc: "decode ARRAY<FLOAT64> to []*float64", proto: listProto(floatProto(fValue), nullProto(), floatProto(f2Value)), protoType: listType(floatType()), want: []*float64{&fValue, nil, &f2Value}}, 1346 {desc: "decode NULL to []*float64", proto: nullProto(), protoType: listType(floatType()), want: []*float64(nil)}, 1347 // NUMERIC 1348 {desc: "decode NUMERIC to big.Rat", proto: numericProto(numValuePtr), protoType: numericType(), want: *numValuePtr}, 1349 {desc: "decode NUMERIC to NullNumeric", proto: numericProto(numValuePtr), protoType: numericType(), want: NullNumeric{*numValuePtr, true}}, 1350 {desc: "decode NULL to NullNumeric", proto: nullProto(), protoType: numericType(), want: NullNumeric{}}, 1351 {desc: "decode NUMERIC to *big.Rat", proto: numericProto(numValuePtr), protoType: numericType(), want: numValuePtr}, 1352 {desc: "decode NULL to *big.Rat", proto: nullProto(), protoType: numericType(), want: numNilPtr}, 1353 // NUMERIC ARRAY with []NullNumeric 1354 {desc: "decode ARRAY<Numeric> to []NullNumeric", proto: listProto(numericProto(numValuePtr), numericProto(num2ValuePtr), nullProto()), protoType: listType(numericType()), want: []NullNumeric{{*numValuePtr, true}, {*num2ValuePtr, true}, {}}}, 1355 {desc: "decode NULL to []NullNumeric", proto: nullProto(), protoType: listType(numericType()), want: []NullNumeric(nil)}, 1356 // NUMERIC ARRAY with []big.Rat 1357 {desc: "decode ARRAY<NUMERIC> to []big.Rat", proto: listProto(numericProto(numValuePtr), numericProto(num2ValuePtr)), protoType: listType(numericType()), want: []big.Rat{*numValuePtr, *num2ValuePtr}}, 1358 // NUMERIC ARRAY with []*big.Rat 1359 {desc: "decode ARRAY<NUMERIC> to []*big.Rat", proto: listProto(numericProto(numValuePtr), nullProto(), numericProto(num2ValuePtr)), protoType: listType(numericType()), want: []*big.Rat{numValuePtr, nil, num2ValuePtr}}, 1360 {desc: "decode NULL to []*big.Rat", proto: nullProto(), protoType: listType(numericType()), want: []*big.Rat(nil)}, 1361 // TIMESTAMP 1362 {desc: "decode TIMESTAMP to time.Time", proto: timeProto(t1), protoType: timeType(), want: t1}, 1363 {desc: "decode TIMESTAMP to NullTime", proto: timeProto(t1), protoType: timeType(), want: NullTime{t1, true}}, 1364 {desc: "decode NULL to NullTime", proto: nullProto(), protoType: timeType(), want: NullTime{}}, 1365 {desc: "decode TIMESTAMP to *time.Time", proto: timeProto(t1), protoType: timeType(), want: &tValue}, 1366 {desc: "decode NULL to *time.Time", proto: nullProto(), protoType: timeType(), want: tNilPtr}, 1367 {desc: "decode INT64 to time.Time", proto: intProto(7), protoType: timeType(), want: time.Time{}, wantErr: true}, 1368 // TIMESTAMP ARRAY with []NullTime 1369 {desc: "decode ARRAY<TIMESTAMP> to []NullTime", proto: listProto(timeProto(t1), timeProto(t2), timeProto(t3), nullProto()), protoType: listType(timeType()), want: []NullTime{{t1, true}, {t2, true}, {t3, true}, {}}}, 1370 {desc: "decode NULL to []NullTime", proto: nullProto(), protoType: listType(timeType()), want: []NullTime(nil)}, 1371 // TIMESTAMP ARRAY with []time.Time 1372 {desc: "decode ARRAY<TIMESTAMP> to []time.Time", proto: listProto(timeProto(t1), timeProto(t2), timeProto(t3)), protoType: listType(timeType()), want: []time.Time{t1, t2, t3}}, 1373 // TIMESTAMP ARRAY with []*time.Time 1374 {desc: "decode ARRAY<TIMESTAMP> to []*time.Time", proto: listProto(timeProto(t1), nullProto(), timeProto(t2)), protoType: listType(timeType()), want: []*time.Time{&tValue, nil, &t2Value}}, 1375 {desc: "decode NULL to []*time.Time", proto: nullProto(), protoType: listType(timeType()), want: []*time.Time(nil)}, 1376 // DATE 1377 {desc: "decode DATE to civil.Date", proto: dateProto(d1), protoType: dateType(), want: d1}, 1378 {desc: "decode DATE to NullDate", proto: dateProto(d1), protoType: dateType(), want: NullDate{d1, true}}, 1379 {desc: "decode NULL to NullDate", proto: nullProto(), protoType: dateType(), want: NullDate{}}, 1380 {desc: "decode DATE to *civil.Date", proto: dateProto(d1), protoType: dateType(), want: &dValue}, 1381 {desc: "decode NULL to *civil.Date", proto: nullProto(), protoType: dateType(), want: dNilPtr}, 1382 // DATE ARRAY with []NullDate 1383 {desc: "decode ARRAY<DATE> to []NullDate", proto: listProto(dateProto(d1), dateProto(d2), nullProto()), protoType: listType(dateType()), want: []NullDate{{d1, true}, {d2, true}, {}}}, 1384 {desc: "decode NULL to []NullDate", proto: nullProto(), protoType: listType(dateType()), want: []NullDate(nil)}, 1385 // DATE ARRAY with []civil.Date 1386 {desc: "decode ARRAY<DATE> to []civil.Date", proto: listProto(dateProto(d1), dateProto(d2)), protoType: listType(dateType()), want: []civil.Date{d1, d2}}, 1387 // DATE ARRAY with []NullDate 1388 {desc: "decode ARRAY<DATE> to []*civil.Date", proto: listProto(dateProto(d1), nullProto(), dateProto(d2)), protoType: listType(dateType()), want: []*civil.Date{&dValue, nil, &d2Value}}, 1389 {desc: "decode NULL to []*civil.Date", proto: nullProto(), protoType: listType(dateType()), want: []*civil.Date(nil)}, 1390 // STRUCT ARRAY 1391 // STRUCT schema is equal to the following Go struct: 1392 // type s struct { 1393 // Col1 NullInt64 1394 // Col2 []struct { 1395 // SubCol1 float64 1396 // SubCol2 string 1397 // } 1398 // } 1399 { 1400 desc: "decode ARRAY<STRUCT> to []NullRow", 1401 proto: listProto( 1402 listProto( 1403 intProto(3), 1404 listProto( 1405 listProto(floatProto(3.14), stringProto("this")), 1406 listProto(floatProto(0.57), stringProto("siht")), 1407 ), 1408 ), 1409 listProto( 1410 nullProto(), 1411 nullProto(), 1412 ), 1413 nullProto(), 1414 ), 1415 protoType: listType( 1416 structType( 1417 mkField("Col1", intType()), 1418 mkField( 1419 "Col2", 1420 listType( 1421 structType( 1422 mkField("SubCol1", floatType()), 1423 mkField("SubCol2", stringType()), 1424 ), 1425 ), 1426 ), 1427 ), 1428 ), 1429 want: []NullRow{ 1430 { 1431 Row: Row{ 1432 fields: []*sppb.StructType_Field{ 1433 mkField("Col1", intType()), 1434 mkField( 1435 "Col2", 1436 listType( 1437 structType( 1438 mkField("SubCol1", floatType()), 1439 mkField("SubCol2", stringType()), 1440 ), 1441 ), 1442 ), 1443 }, 1444 vals: []*proto3.Value{ 1445 intProto(3), 1446 listProto( 1447 listProto(floatProto(3.14), stringProto("this")), 1448 listProto(floatProto(0.57), stringProto("siht")), 1449 ), 1450 }, 1451 }, 1452 Valid: true, 1453 }, 1454 { 1455 Row: Row{ 1456 fields: []*sppb.StructType_Field{ 1457 mkField("Col1", intType()), 1458 mkField( 1459 "Col2", 1460 listType( 1461 structType( 1462 mkField("SubCol1", floatType()), 1463 mkField("SubCol2", stringType()), 1464 ), 1465 ), 1466 ), 1467 }, 1468 vals: []*proto3.Value{ 1469 nullProto(), 1470 nullProto(), 1471 }, 1472 }, 1473 Valid: true, 1474 }, 1475 {}, 1476 }, 1477 }, 1478 { 1479 desc: "decode ARRAY<STRUCT> to []*struct", 1480 proto: listProto( 1481 listProto( 1482 intProto(3), 1483 listProto( 1484 listProto(floatProto(3.14), stringProto("this")), 1485 listProto(floatProto(0.57), stringProto("siht")), 1486 ), 1487 ), 1488 listProto( 1489 nullProto(), 1490 nullProto(), 1491 ), 1492 nullProto(), 1493 ), 1494 protoType: listType( 1495 structType( 1496 mkField("Col1", intType()), 1497 mkField( 1498 "Col2", 1499 listType( 1500 structType( 1501 mkField("SubCol1", floatType()), 1502 mkField("SubCol2", stringType()), 1503 ), 1504 ), 1505 ), 1506 ), 1507 ), 1508 want: []*struct { 1509 Col1 NullInt64 1510 StructCol []*struct { 1511 SubCol1 NullFloat64 1512 SubCol2 string 1513 } `spanner:"Col2"` 1514 }{ 1515 { 1516 Col1: NullInt64{3, true}, 1517 StructCol: []*struct { 1518 SubCol1 NullFloat64 1519 SubCol2 string 1520 }{ 1521 { 1522 SubCol1: NullFloat64{3.14, true}, 1523 SubCol2: "this", 1524 }, 1525 { 1526 SubCol1: NullFloat64{0.57, true}, 1527 SubCol2: "siht", 1528 }, 1529 }, 1530 }, 1531 { 1532 Col1: NullInt64{}, 1533 StructCol: []*struct { 1534 SubCol1 NullFloat64 1535 SubCol2 string 1536 }(nil), 1537 }, 1538 nil, 1539 }, 1540 }, 1541 // GenericColumnValue 1542 {desc: "decode STRING to GenericColumnValue", proto: stringProto("abc"), protoType: stringType(), want: GenericColumnValue{stringType(), stringProto("abc")}}, 1543 {desc: "decode NULL to GenericColumnValue", proto: nullProto(), protoType: stringType(), want: GenericColumnValue{stringType(), nullProto()}}, 1544 // not actually valid (stringProto inside int list), but demonstrates pass-through. 1545 {desc: "decode ARRAY<INT64> to GenericColumnValue", proto: listProto(intProto(5), nullProto(), stringProto("bcd")), protoType: listType(intType()), want: GenericColumnValue{Type: listType(intType()), Value: listProto(intProto(5), nullProto(), stringProto("bcd"))}}, 1546 1547 // Custom base types. 1548 {desc: "decode STRING to CustomString", proto: stringProto("bar"), protoType: stringType(), want: CustomString("bar")}, 1549 {desc: "decode BYTES to CustomBytes", proto: bytesProto([]byte("ab")), protoType: bytesType(), want: CustomBytes("ab")}, 1550 {desc: "decode INT64 to CustomInt64", proto: intProto(-100), protoType: intType(), want: CustomInt64(-100)}, 1551 {desc: "decode BOOL to CustomBool", proto: boolProto(true), protoType: boolType(), want: CustomBool(true)}, 1552 {desc: "decode FLOAT64 to CustomFloat64", proto: floatProto(6.626), protoType: floatType(), want: CustomFloat64(6.626)}, 1553 {desc: "decode NUMERIC to CustomNumeric", proto: numericProto(numValuePtr), protoType: numericType(), want: CustomNumeric(*numValuePtr)}, 1554 {desc: "decode TIMESTAMP to CustomTimestamp", proto: timeProto(t1), protoType: timeType(), want: CustomTime(t1)}, 1555 {desc: "decode DATE to CustomDate", proto: dateProto(d1), protoType: dateType(), want: CustomDate(d1)}, 1556 1557 {desc: "decode NULL to CustomString", proto: nullProto(), protoType: stringType(), want: CustomString(""), wantErr: true}, 1558 {desc: "decode NULL to CustomBytes", proto: nullProto(), protoType: bytesType(), want: CustomBytes(nil)}, 1559 {desc: "decode NULL to CustomInt64", proto: nullProto(), protoType: intType(), want: CustomInt64(0), wantErr: true}, 1560 {desc: "decode NULL to CustomBool", proto: nullProto(), protoType: boolType(), want: CustomBool(false), wantErr: true}, 1561 {desc: "decode NULL to CustomFloat64", proto: nullProto(), protoType: floatType(), want: CustomFloat64(0), wantErr: true}, 1562 {desc: "decode NULL to CustomNumeric", proto: nullProto(), protoType: numericType(), want: CustomNumeric{}, wantErr: true}, 1563 {desc: "decode NULL to CustomTime", proto: nullProto(), protoType: timeType(), want: CustomTime{}, wantErr: true}, 1564 {desc: "decode NULL to CustomDate", proto: nullProto(), protoType: dateType(), want: CustomDate{}, wantErr: true}, 1565 1566 {desc: "decode STRING to CustomNullString", proto: stringProto("bar"), protoType: stringType(), want: CustomNullString{"bar", true}}, 1567 {desc: "decode INT64 to CustomNullInt64", proto: intProto(-100), protoType: intType(), want: CustomNullInt64{-100, true}}, 1568 {desc: "decode BOOL to CustomNullBool", proto: boolProto(true), protoType: boolType(), want: CustomNullBool{true, true}}, 1569 {desc: "decode FLOAT64 to CustomNullFloat64", proto: floatProto(6.626), protoType: floatType(), want: CustomNullFloat64{6.626, true}}, 1570 {desc: "decode NUMERIC to CustomNullNumeric", proto: numericProto(numValuePtr), protoType: numericType(), want: CustomNullNumeric{*numValuePtr, true}}, 1571 {desc: "decode TIMESTAMP to CustomNullTime", proto: timeProto(t1), protoType: timeType(), want: CustomNullTime{t1, true}}, 1572 {desc: "decode DATE to CustomNullDate", proto: dateProto(d1), protoType: dateType(), want: CustomNullDate{d1, true}}, 1573 1574 {desc: "decode NULL to CustomNullString", proto: nullProto(), protoType: stringType(), want: CustomNullString{}}, 1575 {desc: "decode NULL to CustomNullInt64", proto: nullProto(), protoType: intType(), want: CustomNullInt64{}}, 1576 {desc: "decode NULL to CustomNullBool", proto: nullProto(), protoType: boolType(), want: CustomNullBool{}}, 1577 {desc: "decode NULL to CustomNullFloat64", proto: nullProto(), protoType: floatType(), want: CustomNullFloat64{}}, 1578 {desc: "decode NULL to CustomNullNumeric", proto: nullProto(), protoType: numericType(), want: CustomNullNumeric{}}, 1579 {desc: "decode NULL to CustomNullTime", proto: nullProto(), protoType: timeType(), want: CustomNullTime{}}, 1580 {desc: "decode NULL to CustomNullDate", proto: nullProto(), protoType: dateType(), want: CustomNullDate{}}, 1581 1582 // STRING ARRAY 1583 {desc: "decode NULL to []CustomString", proto: nullProto(), protoType: listType(stringType()), want: []CustomString(nil)}, 1584 {desc: "decode ARRAY<STRING> to []CustomString", proto: listProto(stringProto("abc"), stringProto("bcd")), protoType: listType(stringType()), want: []CustomString{"abc", "bcd"}}, 1585 {desc: "decode ARRAY<STRING> with NULL values to []CustomString", proto: listProto(stringProto("abc"), nullProto(), stringProto("bcd")), protoType: listType(stringType()), want: []CustomString{}, wantErr: true}, 1586 {desc: "decode NULL to []CustomNullString", proto: nullProto(), protoType: listType(stringType()), want: []CustomNullString(nil)}, 1587 {desc: "decode ARRAY<STRING> to []CustomNullString", proto: listProto(stringProto("abc"), nullProto(), stringProto("bcd")), protoType: listType(stringType()), want: []CustomNullString{{"abc", true}, {}, {"bcd", true}}}, 1588 // BYTES ARRAY 1589 {desc: "decode NULL to []CustomBytes", proto: nullProto(), protoType: listType(bytesType()), want: []CustomBytes(nil)}, 1590 {desc: "decode ARRAY<BYTES> to []CustomBytes", proto: listProto(bytesProto([]byte("abc")), nullProto(), bytesProto([]byte("bcd"))), protoType: listType(bytesType()), want: []CustomBytes{CustomBytes("abc"), CustomBytes(nil), CustomBytes("bcd")}}, 1591 // INT64 ARRAY 1592 {desc: "decode NULL to []CustomInt64", proto: nullProto(), protoType: listType(intType()), want: []CustomInt64(nil)}, 1593 {desc: "decode ARRAY<INT64> with NULL values to []CustomInt64", proto: listProto(intProto(-100), nullProto(), intProto(100)), protoType: listType(intType()), want: []CustomInt64{}, wantErr: true}, 1594 {desc: "decode ARRAY<INT64> to []CustomInt64", proto: listProto(intProto(-100), intProto(100)), protoType: listType(intType()), want: []CustomInt64{-100, 100}}, 1595 {desc: "decode NULL to []CustomNullInt64", proto: nullProto(), protoType: listType(intType()), want: []CustomNullInt64(nil)}, 1596 {desc: "decode ARRAY<INT64> to []CustomNullInt64", proto: listProto(intProto(-100), nullProto(), intProto(100)), protoType: listType(intType()), want: []CustomNullInt64{{-100, true}, {}, {100, true}}}, 1597 // BOOL ARRAY 1598 {desc: "decode NULL to []CustomBool", proto: nullProto(), protoType: listType(boolType()), want: []CustomBool(nil)}, 1599 {desc: "decode ARRAY<BOOL> with NULL values to []CustomBool", proto: listProto(boolProto(false), nullProto(), boolProto(true)), protoType: listType(boolType()), want: []CustomBool{}, wantErr: true}, 1600 {desc: "decode ARRAY<BOOL> to []CustomBool", proto: listProto(boolProto(false), boolProto(true)), protoType: listType(boolType()), want: []CustomBool{false, true}}, 1601 {desc: "decode NULL to []CustomNullBool", proto: nullProto(), protoType: listType(boolType()), want: []CustomNullBool(nil)}, 1602 {desc: "decode ARRAY<BOOL> to []CustomNullBool", proto: listProto(boolProto(false), nullProto(), boolProto(true)), protoType: listType(boolType()), want: []CustomNullBool{{false, true}, {}, {true, true}}}, 1603 // FLOAT64 ARRAY 1604 {desc: "decode NULL to []CustomFloat64", proto: nullProto(), protoType: listType(floatType()), want: []CustomFloat64(nil)}, 1605 {desc: "decode ARRAY<FLOAT64> with NULL values to []CustomFloat64", proto: listProto(floatProto(3.14), nullProto(), floatProto(6.626)), protoType: listType(floatType()), want: []CustomFloat64{}, wantErr: true}, 1606 {desc: "decode ARRAY<FLOAT64> to []CustomFloat64", proto: listProto(floatProto(3.14), floatProto(6.626)), protoType: listType(floatType()), want: []CustomFloat64{3.14, 6.626}}, 1607 {desc: "decode NULL to []CustomNullFloat64", proto: nullProto(), protoType: listType(floatType()), want: []CustomNullFloat64(nil)}, 1608 {desc: "decode ARRAY<FLOAT64> to []CustomNullFloat64", proto: listProto(floatProto(3.14), nullProto(), floatProto(6.626)), protoType: listType(floatType()), want: []CustomNullFloat64{{3.14, true}, {}, {6.626, true}}}, 1609 // NUMERIC ARRAY 1610 {desc: "decode NULL to []CustomNumeric", proto: nullProto(), protoType: listType(numericType()), want: []CustomNumeric(nil)}, 1611 {desc: "decode ARRAY<NUMERIC> with NULL values to []CustomNumeric", proto: listProto(numericProto(numValuePtr), nullProto(), numericProto(num2ValuePtr)), protoType: listType(numericType()), want: []CustomNumeric{}, wantErr: true}, 1612 {desc: "decode ARRAY<NUMERIC> to []CustomNumeric", proto: listProto(numericProto(numValuePtr), numericProto(num2ValuePtr)), protoType: listType(numericType()), want: []CustomNumeric{CustomNumeric(*numValuePtr), CustomNumeric(*num2ValuePtr)}}, 1613 {desc: "decode NULL to []CustomNullNumeric", proto: nullProto(), protoType: listType(numericType()), want: []CustomNullNumeric(nil)}, 1614 {desc: "decode ARRAY<NUMERIC> to []CustomNullNumeric", proto: listProto(numericProto(numValuePtr), nullProto(), numericProto(num2ValuePtr)), protoType: listType(numericType()), want: []CustomNullNumeric{{*numValuePtr, true}, {}, {*num2ValuePtr, true}}}, 1615 // TIME ARRAY 1616 {desc: "decode NULL to []CustomTime", proto: nullProto(), protoType: listType(timeType()), want: []CustomTime(nil)}, 1617 {desc: "decode ARRAY<TIMESTAMP> with NULL values to []CustomTime", proto: listProto(timeProto(t1), nullProto(), timeProto(t2)), protoType: listType(timeType()), want: []CustomTime{}, wantErr: true}, 1618 {desc: "decode ARRAY<TIMESTAMP> to []CustomTime", proto: listProto(timeProto(t1), timeProto(t2)), protoType: listType(timeType()), want: []CustomTime{CustomTime(t1), CustomTime(t2)}}, 1619 {desc: "decode NULL to []CustomNullTime", proto: nullProto(), protoType: listType(timeType()), want: []CustomNullTime(nil)}, 1620 {desc: "decode ARRAY<TIMESTAMP> to []CustomNullTime", proto: listProto(timeProto(t1), nullProto(), timeProto(t2)), protoType: listType(timeType()), want: []CustomNullTime{{t1, true}, {}, {t2, true}}}, 1621 // DATE ARRAY 1622 {desc: "decode NULL to []CustomDate", proto: nullProto(), protoType: listType(dateType()), want: []CustomDate(nil)}, 1623 {desc: "decode ARRAY<DATE> with NULL values to []CustomDate", proto: listProto(dateProto(d1), nullProto(), dateProto(d2)), protoType: listType(dateType()), want: []CustomDate{}, wantErr: true}, 1624 {desc: "decode ARRAY<DATE> to []CustomDate", proto: listProto(dateProto(d1), dateProto(d2)), protoType: listType(dateType()), want: []CustomDate{CustomDate(d1), CustomDate(d2)}}, 1625 {desc: "decode NULL to []CustomNullDate", proto: nullProto(), protoType: listType(dateType()), want: []CustomNullDate(nil)}, 1626 {desc: "decode ARRAY<DATE> to []CustomNullDate", proto: listProto(dateProto(d1), nullProto(), dateProto(d2)), protoType: listType(dateType()), want: []CustomNullDate{{d1, true}, {}, {d2, true}}}, 1627 // CUSTOM STRUCT 1628 {desc: "decode STRING to CustomStructToString", proto: stringProto("A-B"), protoType: stringType(), want: customStructToString{"A", "B"}}, 1629 {desc: "decode INT64 to CustomStructToInt", proto: intProto(123), protoType: intType(), want: customStructToInt{1, 23}}, 1630 {desc: "decode FLOAT64 to CustomStructToFloat", proto: floatProto(123.123), protoType: floatType(), want: customStructToFloat{1.23, 12.3}}, 1631 {desc: "decode BOOL to CustomStructToBool", proto: boolProto(true), protoType: boolType(), want: customStructToBool{true, false}}, 1632 {desc: "decode BYTES to CustomStructToBytes", proto: bytesProto([]byte("AB")), protoType: bytesType(), want: customStructToBytes{[]byte("A"), []byte("B")}}, 1633 {desc: "decode TIMESTAMP to CustomStructToTime", proto: timeProto(t1), protoType: timeType(), want: customStructToTime{"A", "B"}}, 1634 {desc: "decode DATE to CustomStructToDate", proto: dateProto(d1), protoType: dateType(), want: customStructToDate{"A", "B"}}, 1635 } { 1636 gotp := reflect.New(reflect.TypeOf(test.want)) 1637 v := gotp.Interface() 1638 // Initialize the input to a non-zero value to ensure that the decode 1639 // method will override this with the actual value, or a zero value in 1640 // case of a NULL. 1641 switch nullValue := v.(type) { 1642 case *NullString: 1643 nullValue.StringVal = "foo" 1644 case *NullInt64: 1645 nullValue.Int64 = -100 1646 case *NullFloat64: 1647 nullValue.Float64 = 3.14 1648 case *NullBool: 1649 nullValue.Bool = true 1650 case *NullTime: 1651 nullValue.Time = time.Unix(100, 100) 1652 case *NullDate: 1653 nullValue.Date = civil.DateOf(time.Unix(100, 200)) 1654 default: 1655 } 1656 err := decodeValue(test.proto, test.protoType, v) 1657 if test.wantErr { 1658 if err == nil { 1659 t.Errorf("%s: missing expected decode failure for %v(%v)", test.desc, test.proto, test.protoType) 1660 } 1661 continue 1662 } 1663 if err != nil { 1664 t.Errorf("%s: cannot decode %v(%v): %v", test.desc, test.proto, test.protoType, err) 1665 continue 1666 } 1667 got := reflect.Indirect(gotp).Interface() 1668 if !testutil.Equal(got, test.want, cmp.AllowUnexported(CustomNumeric{}, CustomTime{}, CustomDate{}, Row{}, big.Rat{}, big.Int{})) { 1669 t.Errorf("%s: unexpected decoding result - got %v (%T), want %v (%T)", test.desc, got, got, test.want, test.want) 1670 } 1671 } 1672} 1673 1674// Test error cases for decodeValue. 1675func TestDecodeValueErrors(t *testing.T) { 1676 var s string 1677 for i, test := range []struct { 1678 in *proto3.Value 1679 t *sppb.Type 1680 v interface{} 1681 }{ 1682 {nullProto(), stringType(), nil}, 1683 {nullProto(), stringType(), 1}, 1684 {timeProto(t1), timeType(), &s}, 1685 } { 1686 err := decodeValue(test.in, test.t, test.v) 1687 if err == nil { 1688 t.Errorf("#%d: want error, got nil", i) 1689 } 1690 } 1691} 1692 1693func TestGetDecodableSpannerType(t *testing.T) { 1694 type CustomString string 1695 type CustomInt64 int64 1696 type CustomBool bool 1697 type CustomFloat64 float64 1698 type CustomTime time.Time 1699 type CustomDate civil.Date 1700 type CustomNumeric big.Rat 1701 1702 type CustomNullString NullString 1703 type CustomNullInt64 NullInt64 1704 type CustomNullBool NullBool 1705 type CustomNullFloat64 NullFloat64 1706 type CustomNullTime NullTime 1707 type CustomNullDate NullDate 1708 type CustomNullNumeric NullNumeric 1709 1710 type StringEmbedded struct { 1711 string 1712 } 1713 type NullStringEmbedded struct { 1714 NullString 1715 } 1716 1717 for i, test := range []struct { 1718 in interface{} 1719 want decodableSpannerType 1720 }{ 1721 {"foo", spannerTypeNonNullString}, 1722 {[]byte("ab"), spannerTypeByteArray}, 1723 {[]byte(nil), spannerTypeByteArray}, 1724 {int64(123), spannerTypeNonNullInt64}, 1725 {true, spannerTypeNonNullBool}, 1726 {3.14, spannerTypeNonNullFloat64}, 1727 {time.Now(), spannerTypeNonNullTime}, 1728 {civil.DateOf(time.Now()), spannerTypeNonNullDate}, 1729 {NullString{}, spannerTypeNullString}, 1730 {NullInt64{}, spannerTypeNullInt64}, 1731 {NullBool{}, spannerTypeNullBool}, 1732 {NullFloat64{}, spannerTypeNullFloat64}, 1733 {NullTime{}, spannerTypeNullTime}, 1734 {NullDate{}, spannerTypeNullDate}, 1735 {*big.NewRat(1234, 1000), spannerTypeNonNullNumeric}, 1736 {big.Rat{}, spannerTypeNonNullNumeric}, 1737 {NullNumeric{}, spannerTypeNullNumeric}, 1738 1739 {[]string{"foo", "bar"}, spannerTypeArrayOfNonNullString}, 1740 {[][]byte{{1, 2, 3}, {3, 2, 1}}, spannerTypeArrayOfByteArray}, 1741 {[][]byte{}, spannerTypeArrayOfByteArray}, 1742 {[]int64{int64(123)}, spannerTypeArrayOfNonNullInt64}, 1743 {[]bool{true}, spannerTypeArrayOfNonNullBool}, 1744 {[]float64{3.14}, spannerTypeArrayOfNonNullFloat64}, 1745 {[]time.Time{time.Now()}, spannerTypeArrayOfNonNullTime}, 1746 {[]civil.Date{civil.DateOf(time.Now())}, spannerTypeArrayOfNonNullDate}, 1747 {[]NullString{}, spannerTypeArrayOfNullString}, 1748 {[]NullInt64{}, spannerTypeArrayOfNullInt64}, 1749 {[]NullBool{}, spannerTypeArrayOfNullBool}, 1750 {[]NullFloat64{}, spannerTypeArrayOfNullFloat64}, 1751 {[]NullTime{}, spannerTypeArrayOfNullTime}, 1752 {[]NullDate{}, spannerTypeArrayOfNullDate}, 1753 {[]big.Rat{}, spannerTypeArrayOfNonNullNumeric}, 1754 {[]big.Rat{*big.NewRat(1234, 1000), *big.NewRat(1234, 100)}, spannerTypeArrayOfNonNullNumeric}, 1755 {[]NullNumeric{}, spannerTypeArrayOfNullNumeric}, 1756 1757 {CustomString("foo"), spannerTypeNonNullString}, 1758 {CustomInt64(-100), spannerTypeNonNullInt64}, 1759 {CustomBool(true), spannerTypeNonNullBool}, 1760 {CustomFloat64(3.141592), spannerTypeNonNullFloat64}, 1761 {CustomTime(time.Now()), spannerTypeNonNullTime}, 1762 {CustomDate(civil.DateOf(time.Now())), spannerTypeNonNullDate}, 1763 {CustomNumeric(*big.NewRat(1234, 1000)), spannerTypeNonNullNumeric}, 1764 1765 {[]CustomString{}, spannerTypeArrayOfNonNullString}, 1766 {[]CustomInt64{}, spannerTypeArrayOfNonNullInt64}, 1767 {[]CustomBool{}, spannerTypeArrayOfNonNullBool}, 1768 {[]CustomFloat64{}, spannerTypeArrayOfNonNullFloat64}, 1769 {[]CustomTime{}, spannerTypeArrayOfNonNullTime}, 1770 {[]CustomDate{}, spannerTypeArrayOfNonNullDate}, 1771 {[]CustomNumeric{}, spannerTypeArrayOfNonNullNumeric}, 1772 1773 {CustomNullString{}, spannerTypeNullString}, 1774 {CustomNullInt64{}, spannerTypeNullInt64}, 1775 {CustomNullBool{}, spannerTypeNullBool}, 1776 {CustomNullFloat64{}, spannerTypeNullFloat64}, 1777 {CustomNullTime{}, spannerTypeNullTime}, 1778 {CustomNullDate{}, spannerTypeNullDate}, 1779 {CustomNullNumeric{}, spannerTypeNullNumeric}, 1780 1781 {[]CustomNullString{}, spannerTypeArrayOfNullString}, 1782 {[]CustomNullInt64{}, spannerTypeArrayOfNullInt64}, 1783 {[]CustomNullBool{}, spannerTypeArrayOfNullBool}, 1784 {[]CustomNullFloat64{}, spannerTypeArrayOfNullFloat64}, 1785 {[]CustomNullTime{}, spannerTypeArrayOfNullTime}, 1786 {[]CustomNullDate{}, spannerTypeArrayOfNullDate}, 1787 {[]CustomNullNumeric{}, spannerTypeArrayOfNullNumeric}, 1788 1789 {StringEmbedded{}, spannerTypeUnknown}, 1790 {NullStringEmbedded{}, spannerTypeUnknown}, 1791 } { 1792 // Pass a pointer to the original value. 1793 gotp := reflect.New(reflect.TypeOf(test.in)) 1794 got := getDecodableSpannerType(gotp.Interface(), true) 1795 if got != test.want { 1796 t.Errorf("%d: unexpected decodable type from a pointer - got %v, want %v", i, got, test.want) 1797 } 1798 1799 // Pass the original value. 1800 got = getDecodableSpannerType(test.in, false) 1801 if got != test.want { 1802 t.Errorf("%d: unexpected decodable type from a value - got %v, want %v", i, got, test.want) 1803 } 1804 } 1805} 1806 1807// Test NaN encoding/decoding. 1808func TestNaN(t *testing.T) { 1809 // Decode NaN value. 1810 f := 0.0 1811 nf := NullFloat64{} 1812 // To float64 1813 if err := decodeValue(floatProto(math.NaN()), floatType(), &f); err != nil { 1814 t.Errorf("decodeValue returns %q for %v, want nil", err, floatProto(math.NaN())) 1815 } 1816 if !math.IsNaN(f) { 1817 t.Errorf("f = %v, want %v", f, math.NaN()) 1818 } 1819 // To NullFloat64 1820 if err := decodeValue(floatProto(math.NaN()), floatType(), &nf); err != nil { 1821 t.Errorf("decodeValue returns %q for %v, want nil", err, floatProto(math.NaN())) 1822 } 1823 if !math.IsNaN(nf.Float64) || !nf.Valid { 1824 t.Errorf("f = %v, want %v", f, NullFloat64{math.NaN(), true}) 1825 } 1826 // Encode NaN value 1827 // From float64 1828 v, _, err := encodeValue(math.NaN()) 1829 if err != nil { 1830 t.Errorf("encodeValue returns %q for NaN, want nil", err) 1831 } 1832 x, ok := v.GetKind().(*proto3.Value_NumberValue) 1833 if !ok { 1834 t.Errorf("incorrect type for v.GetKind(): %T, want *proto3.Value_NumberValue", v.GetKind()) 1835 } 1836 if !math.IsNaN(x.NumberValue) { 1837 t.Errorf("x.NumberValue = %v, want %v", x.NumberValue, math.NaN()) 1838 } 1839 // From NullFloat64 1840 v, _, err = encodeValue(NullFloat64{math.NaN(), true}) 1841 if err != nil { 1842 t.Errorf("encodeValue returns %q for NaN, want nil", err) 1843 } 1844 x, ok = v.GetKind().(*proto3.Value_NumberValue) 1845 if !ok { 1846 t.Errorf("incorrect type for v.GetKind(): %T, want *proto3.Value_NumberValue", v.GetKind()) 1847 } 1848 if !math.IsNaN(x.NumberValue) { 1849 t.Errorf("x.NumberValue = %v, want %v", x.NumberValue, math.NaN()) 1850 } 1851} 1852 1853func TestGenericColumnValue(t *testing.T) { 1854 for _, test := range []struct { 1855 in GenericColumnValue 1856 want interface{} 1857 fail bool 1858 }{ 1859 {GenericColumnValue{stringType(), stringProto("abc")}, "abc", false}, 1860 {GenericColumnValue{stringType(), stringProto("abc")}, 5, true}, 1861 {GenericColumnValue{listType(intType()), listProto(intProto(91), nullProto(), intProto(87))}, []NullInt64{{91, true}, {}, {87, true}}, false}, 1862 {GenericColumnValue{intType(), intProto(42)}, GenericColumnValue{intType(), intProto(42)}, false}, // trippy! :-) 1863 } { 1864 gotp := reflect.New(reflect.TypeOf(test.want)) 1865 if err := test.in.Decode(gotp.Interface()); err != nil { 1866 if !test.fail { 1867 t.Errorf("cannot decode %v to %v: %v", test.in, test.want, err) 1868 } 1869 continue 1870 } 1871 if test.fail { 1872 t.Errorf("decoding %v to %v succeeds unexpectedly", test.in, test.want) 1873 } 1874 1875 // Test we can go backwards as well. 1876 v, err := newGenericColumnValue(test.want) 1877 if err != nil { 1878 t.Errorf("NewGenericColumnValue failed: %v", err) 1879 continue 1880 } 1881 if !testEqual(*v, test.in) { 1882 t.Errorf("unexpected encode result - got %v, want %v", v, test.in) 1883 } 1884 } 1885} 1886 1887func TestDecodeStruct(t *testing.T) { 1888 type CustomString string 1889 type CustomTime time.Time 1890 stype := &sppb.StructType{Fields: []*sppb.StructType_Field{ 1891 {Name: "Id", Type: stringType()}, 1892 {Name: "Time", Type: timeType()}, 1893 }} 1894 lv := listValueProto(stringProto("id"), timeProto(t1)) 1895 1896 type ( 1897 S1 struct { 1898 ID string 1899 Time time.Time 1900 } 1901 S2 struct { 1902 ID string 1903 Time string 1904 } 1905 S3 struct { 1906 ID CustomString 1907 Time CustomTime 1908 } 1909 S4 struct { 1910 ID CustomString 1911 Time CustomString 1912 } 1913 S5 struct { 1914 NullString 1915 Time CustomTime 1916 } 1917 ) 1918 var ( 1919 s1 S1 1920 s2 S2 1921 s3 S3 1922 s4 S4 1923 s5 S5 1924 ) 1925 1926 for _, test := range []struct { 1927 desc string 1928 ptr interface{} 1929 want interface{} 1930 fail bool 1931 }{ 1932 { 1933 desc: "decode to S1", 1934 ptr: &s1, 1935 want: &S1{ID: "id", Time: t1}, 1936 }, 1937 { 1938 desc: "decode to S2", 1939 ptr: &s2, 1940 fail: true, 1941 }, 1942 { 1943 desc: "decode to S3", 1944 ptr: &s3, 1945 want: &S3{ID: CustomString("id"), Time: CustomTime(t1)}, 1946 }, 1947 { 1948 desc: "decode to S4", 1949 ptr: &s4, 1950 fail: true, 1951 }, 1952 { 1953 desc: "decode to S5", 1954 ptr: &s5, 1955 fail: true, 1956 }, 1957 } { 1958 err := decodeStruct(stype, lv, test.ptr) 1959 if (err != nil) != test.fail { 1960 t.Errorf("%s: got error %v, wanted fail: %v", test.desc, err, test.fail) 1961 } 1962 if err == nil { 1963 if !testutil.Equal(test.ptr, test.want, cmp.AllowUnexported(CustomTime{})) { 1964 t.Errorf("%s: got %+v, want %+v", test.desc, test.ptr, test.want) 1965 } 1966 } 1967 } 1968} 1969 1970func TestDecodeStructWithPointers(t *testing.T) { 1971 stype := &sppb.StructType{Fields: []*sppb.StructType_Field{ 1972 {Name: "Str", Type: stringType()}, 1973 {Name: "Int", Type: intType()}, 1974 {Name: "Bool", Type: boolType()}, 1975 {Name: "Float", Type: floatType()}, 1976 {Name: "Time", Type: timeType()}, 1977 {Name: "Date", Type: dateType()}, 1978 {Name: "StrArray", Type: listType(stringType())}, 1979 {Name: "IntArray", Type: listType(intType())}, 1980 {Name: "BoolArray", Type: listType(boolType())}, 1981 {Name: "FloatArray", Type: listType(floatType())}, 1982 {Name: "TimeArray", Type: listType(timeType())}, 1983 {Name: "DateArray", Type: listType(dateType())}, 1984 }} 1985 lv := []*proto3.ListValue{ 1986 listValueProto( 1987 stringProto("id"), 1988 intProto(15), 1989 boolProto(true), 1990 floatProto(3.14), 1991 timeProto(t1), 1992 dateProto(d1), 1993 listProto(stringProto("id1"), nullProto(), stringProto("id2")), 1994 listProto(intProto(16), nullProto(), intProto(17)), 1995 listProto(boolProto(true), nullProto(), boolProto(false)), 1996 listProto(floatProto(3.14), nullProto(), floatProto(6.626)), 1997 listProto(timeProto(t1), nullProto(), timeProto(t2)), 1998 listProto(dateProto(d1), nullProto(), dateProto(d2)), 1999 ), 2000 listValueProto( 2001 nullProto(), 2002 nullProto(), 2003 nullProto(), 2004 nullProto(), 2005 nullProto(), 2006 nullProto(), 2007 nullProto(), 2008 nullProto(), 2009 nullProto(), 2010 nullProto(), 2011 nullProto(), 2012 nullProto(), 2013 ), 2014 } 2015 2016 type S1 struct { 2017 Str *string 2018 Int *int64 2019 Bool *bool 2020 Float *float64 2021 Time *time.Time 2022 Date *civil.Date 2023 StrArray []*string 2024 IntArray []*int64 2025 BoolArray []*bool 2026 FloatArray []*float64 2027 TimeArray []*time.Time 2028 DateArray []*civil.Date 2029 } 2030 var s1 S1 2031 sValue := "id" 2032 iValue := int64(15) 2033 bValue := true 2034 fValue := 3.14 2035 tValue := t1 2036 dValue := d1 2037 sArrayValue1 := "id1" 2038 sArrayValue2 := "id2" 2039 sArrayValue := []*string{&sArrayValue1, nil, &sArrayValue2} 2040 iArrayValue1 := int64(16) 2041 iArrayValue2 := int64(17) 2042 iArrayValue := []*int64{&iArrayValue1, nil, &iArrayValue2} 2043 bArrayValue1 := true 2044 bArrayValue2 := false 2045 bArrayValue := []*bool{&bArrayValue1, nil, &bArrayValue2} 2046 f1Value := 3.14 2047 f2Value := 6.626 2048 fArrayValue := []*float64{&f1Value, nil, &f2Value} 2049 t1Value := t1 2050 t2Value := t2 2051 tArrayValue := []*time.Time{&t1Value, nil, &t2Value} 2052 d1Value := d1 2053 d2Value := d2 2054 dArrayValue := []*civil.Date{&d1Value, nil, &d2Value} 2055 2056 for i, test := range []struct { 2057 desc string 2058 ptr *S1 2059 want *S1 2060 fail bool 2061 }{ 2062 { 2063 desc: "decode values to S1", 2064 ptr: &s1, 2065 want: &S1{Str: &sValue, Int: &iValue, Bool: &bValue, Float: &fValue, Time: &tValue, Date: &dValue, StrArray: sArrayValue, IntArray: iArrayValue, BoolArray: bArrayValue, FloatArray: fArrayValue, TimeArray: tArrayValue, DateArray: dArrayValue}, 2066 }, 2067 { 2068 desc: "decode nulls to S1", 2069 ptr: &s1, 2070 want: &S1{Str: nil, Int: nil, Bool: nil, Float: nil, Time: nil, Date: nil, StrArray: nil, IntArray: nil, BoolArray: nil, FloatArray: nil, TimeArray: nil, DateArray: nil}, 2071 }, 2072 } { 2073 err := decodeStruct(stype, lv[i], test.ptr) 2074 if (err != nil) != test.fail { 2075 t.Errorf("%s: got error %v, wanted fail: %v", test.desc, err, test.fail) 2076 } 2077 if err == nil { 2078 if !testutil.Equal(test.ptr, test.want) { 2079 t.Errorf("%s: got %+v, want %+v", test.desc, test.ptr, test.want) 2080 } 2081 } 2082 } 2083} 2084 2085func TestEncodeStructValueDynamicStructs(t *testing.T) { 2086 dynStructType := reflect.StructOf([]reflect.StructField{ 2087 {Name: "A", Type: reflect.TypeOf(0), Tag: `spanner:"a"`}, 2088 {Name: "B", Type: reflect.TypeOf(""), Tag: `spanner:"b"`}, 2089 }) 2090 dynNullableStructType := reflect.PtrTo(dynStructType) 2091 dynStructArrType := reflect.SliceOf(dynStructType) 2092 dynNullableStructArrType := reflect.SliceOf(dynNullableStructType) 2093 2094 dynStructValue := reflect.New(dynStructType) 2095 dynStructValue.Elem().Field(0).SetInt(10) 2096 dynStructValue.Elem().Field(1).SetString("abc") 2097 2098 dynStructArrValue := reflect.MakeSlice(dynNullableStructArrType, 2, 2) 2099 dynStructArrValue.Index(0).Set(reflect.Zero(dynNullableStructType)) 2100 dynStructArrValue.Index(1).Set(dynStructValue) 2101 2102 structProtoType := structType( 2103 mkField("a", intType()), 2104 mkField("b", stringType())) 2105 2106 arrProtoType := listType(structProtoType) 2107 2108 for _, test := range []encodeTest{ 2109 { 2110 "Dynanic non-NULL struct value.", 2111 dynStructValue.Elem().Interface(), 2112 listProto(intProto(10), stringProto("abc")), 2113 structProtoType, 2114 }, 2115 { 2116 "Dynanic NULL struct value.", 2117 reflect.Zero(dynNullableStructType).Interface(), 2118 nullProto(), 2119 structProtoType, 2120 }, 2121 { 2122 "Empty array of dynamic structs.", 2123 reflect.MakeSlice(dynStructArrType, 0, 0).Interface(), 2124 listProto([]*proto3.Value{}...), 2125 arrProtoType, 2126 }, 2127 { 2128 "NULL array of non-NULL-able dynamic structs.", 2129 reflect.Zero(dynStructArrType).Interface(), 2130 nullProto(), 2131 arrProtoType, 2132 }, 2133 { 2134 "NULL array of NULL-able(nil) dynamic structs.", 2135 reflect.Zero(dynNullableStructArrType).Interface(), 2136 nullProto(), 2137 arrProtoType, 2138 }, 2139 { 2140 "Array containing NULL(nil) dynamic-typed struct elements.", 2141 dynStructArrValue.Interface(), 2142 listProto( 2143 nullProto(), 2144 listProto(intProto(10), stringProto("abc"))), 2145 arrProtoType, 2146 }, 2147 } { 2148 encodeStructValue(test, t) 2149 } 2150} 2151 2152func TestEncodeStructValueEmptyStruct(t *testing.T) { 2153 emptyListValue := listProto([]*proto3.Value{}...) 2154 emptyStructType := structType([]*sppb.StructType_Field{}...) 2155 emptyStruct := struct{}{} 2156 nullEmptyStruct := (*struct{})(nil) 2157 2158 dynamicEmptyStructType := reflect.StructOf(make([]reflect.StructField, 0, 0)) 2159 dynamicStructArrType := reflect.SliceOf(reflect.PtrTo((dynamicEmptyStructType))) 2160 2161 dynamicEmptyStruct := reflect.New(dynamicEmptyStructType) 2162 dynamicNullEmptyStruct := reflect.Zero(reflect.PtrTo(dynamicEmptyStructType)) 2163 2164 dynamicStructArrValue := reflect.MakeSlice(dynamicStructArrType, 2, 2) 2165 dynamicStructArrValue.Index(0).Set(dynamicNullEmptyStruct) 2166 dynamicStructArrValue.Index(1).Set(dynamicEmptyStruct) 2167 2168 for _, test := range []encodeTest{ 2169 { 2170 "Go empty struct.", 2171 emptyStruct, 2172 emptyListValue, 2173 emptyStructType, 2174 }, 2175 { 2176 "Dynamic empty struct.", 2177 dynamicEmptyStruct.Interface(), 2178 emptyListValue, 2179 emptyStructType, 2180 }, 2181 { 2182 "Go NULL empty struct.", 2183 nullEmptyStruct, 2184 nullProto(), 2185 emptyStructType, 2186 }, 2187 { 2188 "Dynamic NULL empty struct.", 2189 dynamicNullEmptyStruct.Interface(), 2190 nullProto(), 2191 emptyStructType, 2192 }, 2193 { 2194 "Non-empty array of dynamic NULL and non-NULL empty structs.", 2195 dynamicStructArrValue.Interface(), 2196 listProto(nullProto(), emptyListValue), 2197 listType(emptyStructType), 2198 }, 2199 { 2200 "Non-empty array of nullable empty structs.", 2201 []*struct{}{nullEmptyStruct, &emptyStruct}, 2202 listProto(nullProto(), emptyListValue), 2203 listType(emptyStructType), 2204 }, 2205 { 2206 "Empty array of empty struct.", 2207 []struct{}{}, 2208 emptyListValue, 2209 listType(emptyStructType), 2210 }, 2211 { 2212 "Null array of empty structs.", 2213 []struct{}(nil), 2214 nullProto(), 2215 listType(emptyStructType), 2216 }, 2217 } { 2218 encodeStructValue(test, t) 2219 } 2220} 2221 2222func TestEncodeStructValueMixedStructTypes(t *testing.T) { 2223 type staticStruct struct { 2224 F int `spanner:"fStatic"` 2225 } 2226 s1 := staticStruct{10} 2227 s2 := (*staticStruct)(nil) 2228 2229 var f float64 2230 dynStructType := reflect.StructOf([]reflect.StructField{ 2231 {Name: "A", Type: reflect.TypeOf(f), Tag: `spanner:"fDynamic"`}, 2232 }) 2233 s3 := reflect.New(dynStructType) 2234 s3.Elem().Field(0).SetFloat(3.14) 2235 2236 for _, test := range []encodeTest{ 2237 { 2238 "'struct' with static and dynamic *struct, []*struct, []struct fields", 2239 struct { 2240 A []staticStruct 2241 B []*staticStruct 2242 C interface{} 2243 }{ 2244 []staticStruct{s1, s1}, 2245 []*staticStruct{&s1, s2}, 2246 s3.Interface(), 2247 }, 2248 listProto( 2249 listProto(listProto(intProto(10)), listProto(intProto(10))), 2250 listProto(listProto(intProto(10)), nullProto()), 2251 listProto(floatProto(3.14))), 2252 structType( 2253 mkField("A", listType(structType(mkField("fStatic", intType())))), 2254 mkField("B", listType(structType(mkField("fStatic", intType())))), 2255 mkField("C", structType(mkField("fDynamic", floatType())))), 2256 }, 2257 } { 2258 encodeStructValue(test, t) 2259 } 2260} 2261 2262func TestBindParamsDynamic(t *testing.T) { 2263 // Verify Statement.bindParams generates correct values and types. 2264 st := Statement{ 2265 SQL: "SELECT id from t_foo WHERE col = @var", 2266 Params: map[string]interface{}{"var": nil}, 2267 } 2268 want := &sppb.ExecuteSqlRequest{ 2269 Params: &proto3.Struct{ 2270 Fields: map[string]*proto3.Value{"var": nil}, 2271 }, 2272 ParamTypes: map[string]*sppb.Type{"var": nil}, 2273 } 2274 var ( 2275 t1, _ = time.Parse(time.RFC3339Nano, "2016-11-15T15:04:05.999999999Z") 2276 // Boundaries 2277 t2, _ = time.Parse(time.RFC3339Nano, "0001-01-01T00:00:00.000000000Z") 2278 ) 2279 dynamicStructType := reflect.StructOf([]reflect.StructField{ 2280 {Name: "A", Type: reflect.TypeOf(t1), Tag: `spanner:"field"`}, 2281 {Name: "B", Type: reflect.TypeOf(3.14), Tag: `spanner:""`}, 2282 }) 2283 dynamicStructArrType := reflect.SliceOf(reflect.PtrTo(dynamicStructType)) 2284 dynamicEmptyStructType := reflect.StructOf(make([]reflect.StructField, 0, 0)) 2285 2286 dynamicStructTypeProto := structType( 2287 mkField("field", timeType()), 2288 mkField("", floatType())) 2289 2290 s3 := reflect.New(dynamicStructType) 2291 s3.Elem().Field(0).Set(reflect.ValueOf(t1)) 2292 s3.Elem().Field(1).SetFloat(1.4) 2293 2294 s4 := reflect.New(dynamicStructType) 2295 s4.Elem().Field(0).Set(reflect.ValueOf(t2)) 2296 s4.Elem().Field(1).SetFloat(-13.3) 2297 2298 dynamicStructArrayVal := reflect.MakeSlice(dynamicStructArrType, 2, 2) 2299 dynamicStructArrayVal.Index(0).Set(s3) 2300 dynamicStructArrayVal.Index(1).Set(s4) 2301 2302 for _, test := range []struct { 2303 val interface{} 2304 wantField *proto3.Value 2305 wantType *sppb.Type 2306 }{ 2307 { 2308 s3.Interface(), 2309 listProto(timeProto(t1), floatProto(1.4)), 2310 structType( 2311 mkField("field", timeType()), 2312 mkField("", floatType())), 2313 }, 2314 { 2315 reflect.Zero(reflect.PtrTo(dynamicEmptyStructType)).Interface(), 2316 nullProto(), 2317 structType([]*sppb.StructType_Field{}...), 2318 }, 2319 { 2320 dynamicStructArrayVal.Interface(), 2321 listProto( 2322 listProto(timeProto(t1), floatProto(1.4)), 2323 listProto(timeProto(t2), floatProto(-13.3))), 2324 listType(dynamicStructTypeProto), 2325 }, 2326 { 2327 []*struct { 2328 F1 time.Time `spanner:"field"` 2329 F2 float64 `spanner:""` 2330 }{ 2331 nil, 2332 {t1, 1.4}, 2333 }, 2334 listProto( 2335 nullProto(), 2336 listProto(timeProto(t1), floatProto(1.4))), 2337 listType(dynamicStructTypeProto), 2338 }, 2339 } { 2340 st.Params["var"] = test.val 2341 want.Params.Fields["var"] = test.wantField 2342 want.ParamTypes["var"] = test.wantType 2343 gotParams, gotParamTypes, gotErr := st.convertParams() 2344 if gotErr != nil { 2345 t.Error(gotErr) 2346 continue 2347 } 2348 gotParamField := gotParams.Fields["var"] 2349 if !proto.Equal(gotParamField, test.wantField) { 2350 // handle NaN 2351 if test.wantType.Code == floatType().Code && proto.MarshalTextString(gotParamField) == proto.MarshalTextString(test.wantField) { 2352 continue 2353 } 2354 t.Errorf("%#v: got %v, want %v\n", test.val, gotParamField, test.wantField) 2355 } 2356 gotParamType := gotParamTypes["var"] 2357 if !proto.Equal(gotParamType, test.wantType) { 2358 t.Errorf("%#v: got %v, want %v\n", test.val, gotParamType, test.wantField) 2359 } 2360 } 2361} 2362 2363// Test converting nullable types to json strings. 2364func TestJSONMarshal_NullTypes(t *testing.T) { 2365 type testcase struct { 2366 input interface{} 2367 expect string 2368 } 2369 2370 for _, test := range []struct { 2371 name string 2372 cases []testcase 2373 }{ 2374 { 2375 "NullString", 2376 []testcase{ 2377 {input: NullString{"this is a test string", true}, expect: `"this is a test string"`}, 2378 {input: &NullString{"this is a test string", true}, expect: `"this is a test string"`}, 2379 {input: &NullString{"this is a test string", false}, expect: "null"}, 2380 {input: NullString{}, expect: "null"}, 2381 }, 2382 }, 2383 { 2384 "NullInt64", 2385 []testcase{ 2386 {input: NullInt64{int64(123), true}, expect: "123"}, 2387 {input: &NullInt64{int64(123), true}, expect: "123"}, 2388 {input: &NullInt64{int64(123), false}, expect: "null"}, 2389 {input: NullInt64{}, expect: "null"}, 2390 }, 2391 }, 2392 { 2393 "NullFloat64", 2394 []testcase{ 2395 {input: NullFloat64{float64(123.123), true}, expect: "123.123"}, 2396 {input: &NullFloat64{float64(123.123), true}, expect: "123.123"}, 2397 {input: &NullFloat64{float64(123.123), false}, expect: "null"}, 2398 {input: NullFloat64{}, expect: "null"}, 2399 }, 2400 }, 2401 { 2402 "NullBool", 2403 []testcase{ 2404 {input: NullBool{true, true}, expect: "true"}, 2405 {input: &NullBool{true, true}, expect: "true"}, 2406 {input: &NullBool{true, false}, expect: "null"}, 2407 {input: NullBool{}, expect: "null"}, 2408 }, 2409 }, 2410 { 2411 "NullTime", 2412 []testcase{ 2413 {input: NullTime{time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC), true}, expect: `"2009-11-17T20:34:58.651387237Z"`}, 2414 {input: &NullTime{time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC), true}, expect: `"2009-11-17T20:34:58.651387237Z"`}, 2415 {input: &NullTime{time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC), false}, expect: "null"}, 2416 {input: NullTime{}, expect: "null"}, 2417 }, 2418 }, 2419 { 2420 "NullDate", 2421 []testcase{ 2422 {input: NullDate{civil.Date{Year: 2009, Month: time.November, Day: 17}, true}, expect: `"2009-11-17"`}, 2423 {input: &NullDate{civil.Date{Year: 2009, Month: time.November, Day: 17}, true}, expect: `"2009-11-17"`}, 2424 {input: &NullDate{civil.Date{Year: 2009, Month: time.November, Day: 17}, false}, expect: "null"}, 2425 {input: NullDate{}, expect: "null"}, 2426 }, 2427 }, 2428 { 2429 "NullNumeric", 2430 []testcase{ 2431 {input: NullNumeric{*big.NewRat(1234123456789, 1e9), true}, expect: `"1234.123456789"`}, 2432 {input: &NullNumeric{*big.NewRat(1234123456789, 1e9), true}, expect: `"1234.123456789"`}, 2433 {input: &NullNumeric{*big.NewRat(1234123456789, 1e9), false}, expect: "null"}, 2434 {input: NullNumeric{}, expect: "null"}, 2435 }, 2436 }, 2437 } { 2438 t.Run(test.name, func(t *testing.T) { 2439 for _, tc := range test.cases { 2440 bytes, _ := json.Marshal(tc.input) 2441 got := string(bytes) 2442 if got != tc.expect { 2443 t.Fatalf("Incorrect marshalling to json strings: got %v, want %v", got, tc.expect) 2444 } 2445 } 2446 }) 2447 } 2448} 2449 2450// Test converting json strings to nullable types. 2451func TestJSONUnmarshal_NullTypes(t *testing.T) { 2452 type testcase struct { 2453 input []byte 2454 got interface{} 2455 isNull bool 2456 expect string 2457 expectError bool 2458 } 2459 2460 for _, test := range []struct { 2461 name string 2462 cases []testcase 2463 }{ 2464 { 2465 "NullString", 2466 []testcase{ 2467 {input: []byte(`"this is a test string"`), got: NullString{}, isNull: false, expect: "this is a test string", expectError: false}, 2468 {input: []byte(`""`), got: NullString{}, isNull: false, expect: "", expectError: false}, 2469 {input: []byte("null"), got: NullString{}, isNull: true, expect: nullString, expectError: false}, 2470 {input: nil, got: NullString{}, isNull: true, expect: nullString, expectError: true}, 2471 {input: []byte(""), got: NullString{}, isNull: true, expect: nullString, expectError: true}, 2472 {input: []byte(`"hello`), got: NullString{}, isNull: true, expect: nullString, expectError: true}, 2473 }, 2474 }, 2475 { 2476 "NullInt64", 2477 []testcase{ 2478 {input: []byte("123"), got: NullInt64{}, isNull: false, expect: "123", expectError: false}, 2479 {input: []byte("null"), got: NullInt64{}, isNull: true, expect: nullString, expectError: false}, 2480 {input: nil, got: NullInt64{}, isNull: true, expect: nullString, expectError: true}, 2481 {input: []byte(""), got: NullInt64{}, isNull: true, expect: nullString, expectError: true}, 2482 {input: []byte(`"hello`), got: NullInt64{}, isNull: true, expect: nullString, expectError: true}, 2483 }, 2484 }, 2485 { 2486 "NullFloat64", 2487 []testcase{ 2488 {input: []byte("123.123"), got: NullFloat64{}, isNull: false, expect: "123.123", expectError: false}, 2489 {input: []byte("null"), got: NullFloat64{}, isNull: true, expect: nullString, expectError: false}, 2490 {input: nil, got: NullFloat64{}, isNull: true, expect: nullString, expectError: true}, 2491 {input: []byte(""), got: NullFloat64{}, isNull: true, expect: nullString, expectError: true}, 2492 {input: []byte(`"hello`), got: NullFloat64{}, isNull: true, expect: nullString, expectError: true}, 2493 }, 2494 }, 2495 { 2496 "NullBool", 2497 []testcase{ 2498 {input: []byte("true"), got: NullBool{}, isNull: false, expect: "true", expectError: false}, 2499 {input: []byte("null"), got: NullBool{}, isNull: true, expect: nullString, expectError: false}, 2500 {input: nil, got: NullBool{}, isNull: true, expect: nullString, expectError: true}, 2501 {input: []byte(""), got: NullBool{}, isNull: true, expect: nullString, expectError: true}, 2502 {input: []byte(`"hello`), got: NullBool{}, isNull: true, expect: nullString, expectError: true}, 2503 }, 2504 }, 2505 { 2506 "NullTime", 2507 []testcase{ 2508 {input: []byte(`"2009-11-17T20:34:58.651387237Z"`), got: NullTime{}, isNull: false, expect: "2009-11-17T20:34:58.651387237Z", expectError: false}, 2509 {input: []byte("null"), got: NullTime{}, isNull: true, expect: nullString, expectError: false}, 2510 {input: nil, got: NullTime{}, isNull: true, expect: nullString, expectError: true}, 2511 {input: []byte(""), got: NullTime{}, isNull: true, expect: nullString, expectError: true}, 2512 {input: []byte(`"hello`), got: NullTime{}, isNull: true, expect: nullString, expectError: true}, 2513 }, 2514 }, 2515 { 2516 "NullDate", 2517 []testcase{ 2518 {input: []byte(`"2009-11-17"`), got: NullDate{}, isNull: false, expect: "2009-11-17", expectError: false}, 2519 {input: []byte("null"), got: NullDate{}, isNull: true, expect: nullString, expectError: false}, 2520 {input: nil, got: NullDate{}, isNull: true, expect: nullString, expectError: true}, 2521 {input: []byte(""), got: NullDate{}, isNull: true, expect: nullString, expectError: true}, 2522 {input: []byte(`"hello`), got: NullDate{}, isNull: true, expect: nullString, expectError: true}, 2523 }, 2524 }, 2525 { 2526 "NullNumeric", 2527 []testcase{ 2528 {input: []byte(`"1234.123456789"`), got: NullNumeric{}, isNull: false, expect: "1234.123456789", expectError: false}, 2529 {input: []byte("null"), got: NullNumeric{}, isNull: true, expect: nullString, expectError: false}, 2530 {input: nil, got: NullNumeric{}, isNull: true, expect: nullString, expectError: true}, 2531 {input: []byte(""), got: NullNumeric{}, isNull: true, expect: nullString, expectError: true}, 2532 {input: []byte(`"1234.123456789`), got: NullNumeric{}, isNull: true, expect: nullString, expectError: true}, 2533 }, 2534 }, 2535 } { 2536 t.Run(test.name, func(t *testing.T) { 2537 for _, tc := range test.cases { 2538 switch v := tc.got.(type) { 2539 case NullString: 2540 err := json.Unmarshal(tc.input, &v) 2541 expectUnmarshalNullableTypes(t, err, v, tc.isNull, tc.expect, tc.expectError) 2542 case NullInt64: 2543 err := json.Unmarshal(tc.input, &v) 2544 expectUnmarshalNullableTypes(t, err, v, tc.isNull, tc.expect, tc.expectError) 2545 case NullFloat64: 2546 err := json.Unmarshal(tc.input, &v) 2547 expectUnmarshalNullableTypes(t, err, v, tc.isNull, tc.expect, tc.expectError) 2548 case NullBool: 2549 err := json.Unmarshal(tc.input, &v) 2550 expectUnmarshalNullableTypes(t, err, v, tc.isNull, tc.expect, tc.expectError) 2551 case NullTime: 2552 err := json.Unmarshal(tc.input, &v) 2553 expectUnmarshalNullableTypes(t, err, v, tc.isNull, tc.expect, tc.expectError) 2554 case NullDate: 2555 err := json.Unmarshal(tc.input, &v) 2556 expectUnmarshalNullableTypes(t, err, v, tc.isNull, tc.expect, tc.expectError) 2557 case NullNumeric: 2558 err := json.Unmarshal(tc.input, &v) 2559 expectUnmarshalNullableTypes(t, err, v, tc.isNull, tc.expect, tc.expectError) 2560 default: 2561 t.Fatalf("Unknown type: %T", v) 2562 } 2563 } 2564 }) 2565 } 2566} 2567 2568func expectUnmarshalNullableTypes(t *testing.T, err error, v interface{}, isNull bool, expect string, expectError bool) { 2569 if expectError { 2570 if err == nil { 2571 t.Fatalf("Expect to get an error, but got a nil") 2572 } 2573 return 2574 } 2575 2576 if err != nil { 2577 t.Fatalf("Got an error when unmarshalling a valid json string: %q", err) 2578 } 2579 if s, ok := v.(NullableValue); !ok || s.IsNull() != isNull { 2580 t.Fatalf("Incorrect unmarshalling a json string to nullable types: got %q, want %q", v, expect) 2581 } 2582 if s, ok := v.(fmt.Stringer); !ok || s.String() != expect { 2583 t.Fatalf("Incorrect unmarshalling a json string to nullable types: got %q, want %q", v, expect) 2584 } 2585} 2586