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