github.com/ydb-platform/ydb-go-sdk/v3@v3.89.2/internal/value/value_test.go (about) 1 package value 2 3 import ( 4 "fmt" 5 "math" 6 "math/big" 7 "reflect" 8 "strconv" 9 "testing" 10 "time" 11 12 "github.com/stretchr/testify/require" 13 "google.golang.org/protobuf/proto" 14 15 "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator" 16 "github.com/ydb-platform/ydb-go-sdk/v3/internal/pg" 17 "github.com/ydb-platform/ydb-go-sdk/v3/internal/types" 18 "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest" 19 ) 20 21 func BenchmarkMemory(b *testing.B) { 22 b.ReportAllocs() 23 v := TupleValue( 24 VoidValue(), 25 BoolValue(true), 26 Int8Value(1), 27 Int16Value(1), 28 Int32Value(1), 29 Int64Value(1), 30 Uint8Value(1), 31 Uint16Value(1), 32 Uint32Value(1), 33 Uint64Value(1), 34 DateValue(1), 35 DatetimeValue(1), 36 TimestampValue(1), 37 IntervalValue(1), 38 VoidValue(), 39 FloatValue(1), 40 DoubleValue(1), 41 BytesValue([]byte("test")), 42 DecimalValue([...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}, 22, 9), 43 DyNumberValue("123"), 44 JSONValue("{}"), 45 JSONDocumentValue("{}"), 46 TzDateValue("1"), 47 TzDatetimeValue("1"), 48 TzTimestampValue("1"), 49 TextValue("1"), 50 UUIDWithIssue1501Value([...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}), 51 YSONValue([]byte("{}")), 52 ListValue( 53 Int64Value(1), 54 Int64Value(2), 55 Int64Value(3), 56 ), 57 SetValue( 58 Int64Value(1), 59 Int64Value(2), 60 Int64Value(3), 61 ), 62 OptionalValue(IntervalValue(1)), 63 OptionalValue(OptionalValue(IntervalValue(1))), 64 StructValue( 65 StructValueField{"series_id", Uint64Value(1)}, 66 StructValueField{"title", TextValue("test")}, 67 StructValueField{"air_date", DateValue(1)}, 68 StructValueField{"remove_date", OptionalValue(TzDatetimeValue("1234"))}, 69 ), 70 DictValue( 71 DictValueField{TextValue("series_id"), Uint64Value(1)}, 72 DictValueField{TextValue("title"), Uint64Value(2)}, 73 DictValueField{TextValue("air_date"), Uint64Value(3)}, 74 DictValueField{TextValue("remove_date"), Uint64Value(4)}, 75 ), 76 NullValue(types.NewOptional(types.NewOptional(types.NewOptional(types.Bool)))), 77 VariantValueTuple(Int32Value(42), 1, types.NewTuple( 78 types.Bytes, 79 types.Int32, 80 )), 81 VariantValueStruct(Int32Value(42), "bar", types.NewStruct( 82 types.StructField{ 83 Name: "foo", 84 T: types.Bytes, 85 }, 86 types.StructField{ 87 Name: "bar", 88 T: types.Int32, 89 }, 90 )), 91 ZeroValue(types.Text), 92 ZeroValue(types.NewStruct()), 93 ZeroValue(types.NewTuple()), 94 ) 95 for i := 0; i < b.N; i++ { 96 a := allocator.New() 97 _ = ToYDB(v, a) 98 a.Free() 99 } 100 } 101 102 func TestToYDBFromYDB(t *testing.T) { 103 for i, v := range []Value{ 104 BoolValue(true), 105 Int8Value(1), 106 Int16Value(1), 107 Int32Value(1), 108 Int64Value(1), 109 Uint8Value(1), 110 Uint16Value(1), 111 Uint32Value(1), 112 Uint64Value(1), 113 DateValue(1), 114 DatetimeValue(1), 115 TimestampValue(1), 116 IntervalValue(1), 117 VoidValue(), 118 FloatValue(1), 119 DoubleValue(1), 120 BytesValue([]byte("test")), 121 DecimalValue([...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}, 22, 9), 122 DyNumberValue("123"), 123 JSONValue("{}"), 124 JSONDocumentValue("{}"), 125 TzDateValue("1"), 126 TzDatetimeValue("1"), 127 TzTimestampValue("1"), 128 TextValue("1"), 129 UUIDWithIssue1501Value([...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}), 130 YSONValue([]byte("{}")), 131 TupleValue( 132 Int64Value(1), 133 Int32Value(2), 134 Int16Value(3), 135 Int8Value(4), 136 ), 137 ListValue( 138 Int64Value(1), 139 Int64Value(2), 140 Int64Value(3), 141 ), 142 SetValue( 143 Int64Value(1), 144 Int64Value(2), 145 Int64Value(3), 146 ), 147 OptionalValue(IntervalValue(1)), 148 OptionalValue(OptionalValue(IntervalValue(1))), 149 StructValue( 150 StructValueField{"series_id", Uint64Value(1)}, 151 StructValueField{"title", TextValue("test")}, 152 StructValueField{"air_date", DateValue(1)}, 153 StructValueField{"remove_date", OptionalValue(TzDatetimeValue("1234"))}, 154 ), 155 DictValue( 156 DictValueField{TextValue("series_id"), Uint64Value(1)}, 157 DictValueField{TextValue("title"), Uint64Value(2)}, 158 DictValueField{TextValue("air_date"), Uint64Value(3)}, 159 DictValueField{TextValue("remove_date"), Uint64Value(4)}, 160 ), 161 NullValue(types.Bool), 162 NullValue(types.NewOptional(types.Bool)), 163 VariantValueTuple(Int32Value(42), 1, types.NewTuple( 164 types.Bytes, 165 types.Int32, 166 )), 167 VariantValueStruct(Int32Value(42), "bar", types.NewStruct( 168 types.StructField{ 169 Name: "foo", 170 T: types.Bytes, 171 }, 172 types.StructField{ 173 Name: "bar", 174 T: types.Int32, 175 }, 176 )), 177 ZeroValue(types.Text), 178 ZeroValue(types.NewStruct()), 179 ZeroValue(types.NewTuple()), 180 PgValue(pg.OIDInt4, "123"), 181 } { 182 t.Run(strconv.Itoa(i)+"."+v.Yql(), func(t *testing.T) { 183 a := allocator.New() 184 defer a.Free() 185 value := ToYDB(v, a) 186 dualConversedValue, err := fromYDB(value.GetType(), value.GetValue()) 187 require.NoError(t, err) 188 if !proto.Equal(value, ToYDB(dualConversedValue, a)) { 189 t.Errorf("dual conversion failed:\n\n - got: %v\n\n - want: %v", ToYDB(dualConversedValue, a), value) 190 } 191 }) 192 } 193 } 194 195 func TestValueYql(t *testing.T) { 196 for i, tt := range []struct { 197 value Value 198 literal string 199 }{ 200 { 201 value: VoidValue(), 202 literal: `Void()`, 203 }, 204 { 205 value: TextValue("some\"text\"with brackets"), 206 literal: `"some\"text\"with brackets"u`, 207 }, 208 { 209 value: TextValue(`some text with slashes \ \\ \\\`), 210 literal: `"some text with slashes \\ \\\\ \\\\\\"u`, 211 }, 212 { 213 value: BytesValue([]byte("foo")), 214 literal: `"foo"`, 215 }, 216 { 217 value: BytesValue([]byte("\xFE\xFF")), 218 literal: `"\xfe\xff"`, 219 }, 220 { 221 value: OptionalValue(BytesValue([]byte{0, 1, 2, 3, 4, 5, 6})), 222 literal: `Just("\x00\x01\x02\x03\x04\x05\x06")`, 223 }, 224 { 225 value: BoolValue(true), 226 literal: `true`, 227 }, 228 { 229 value: Int8Value(42), 230 literal: `42t`, 231 }, 232 { 233 value: Uint8Value(42), 234 literal: `42ut`, 235 }, 236 { 237 value: Int16Value(42), 238 literal: `42s`, 239 }, 240 { 241 value: Uint16Value(42), 242 literal: `42us`, 243 }, 244 { 245 value: Int32Value(42), 246 literal: `42`, 247 }, 248 { 249 value: Uint32Value(42), 250 literal: `42u`, 251 }, 252 { 253 value: Int64Value(42), 254 literal: `42l`, 255 }, 256 { 257 value: Uint64Value(42), 258 literal: `42ul`, 259 }, 260 { 261 value: Uint64Value(200000000000), 262 literal: `200000000000ul`, 263 }, 264 { 265 value: FloatValue(42.2121236), 266 literal: `Float("42.212124")`, 267 }, 268 { 269 value: FloatValue(float32(math.Inf(+1))), 270 literal: `Float("+Inf")`, 271 }, 272 { 273 value: FloatValue(float32(math.Inf(-1))), 274 literal: `Float("-Inf")`, 275 }, 276 { 277 value: FloatValue(float32(math.NaN())), 278 literal: `Float("NaN")`, 279 }, 280 { 281 value: DoubleValue(42.2121236192), 282 literal: `Double("42.2121236192")`, 283 }, 284 { 285 value: DoubleValue(math.Inf(+1)), 286 literal: `Double("+Inf")`, 287 }, 288 { 289 value: DoubleValue(math.Inf(-1)), 290 literal: `Double("-Inf")`, 291 }, 292 { 293 value: DoubleValue(math.NaN()), 294 literal: `Double("NaN")`, 295 }, 296 { 297 value: DateValue(func() uint32 { 298 v, _ := time.Parse("2006-01-02", "2022-06-17") 299 300 return uint32(v.Sub(time.Unix(0, 0)) / time.Hour / 24) 301 }()), 302 literal: `Date("2022-06-17")`, 303 }, 304 { 305 value: DatetimeValue(func() uint32 { 306 v, _ := time.Parse("2006-01-02 15:04:05", "2022-06-17 05:19:20") 307 308 return uint32(v.UTC().Sub(time.Unix(0, 0)).Seconds()) 309 }()), 310 literal: `Datetime("2022-06-17T05:19:20Z")`, 311 }, 312 { 313 value: TzDateValue("2022-06-17,Europe/Berlin"), 314 literal: `TzDate("2022-06-17,Europe/Berlin")`, 315 }, 316 { 317 value: TzDatetimeValue("2022-06-17T05:19:20,Europe/Berlin"), 318 literal: `TzDatetime("2022-06-17T05:19:20,Europe/Berlin")`, 319 }, 320 { 321 value: IntervalValueFromDuration(time.Duration(42) * time.Millisecond), 322 literal: `Interval("PT0.042000S")`, 323 }, 324 { 325 value: TimestampValueFromTime(func() time.Time { 326 tt, err := time.Parse(LayoutTimestamp, "1997-12-14T03:09:42.123456Z") 327 require.NoError(t, err) 328 329 return tt.UTC() 330 }()), 331 literal: `Timestamp("1997-12-14T03:09:42.123456Z")`, 332 }, 333 { 334 value: TzTimestampValue("1997-12-14T03:09:42.123456,Europe/Berlin"), 335 literal: `TzTimestamp("1997-12-14T03:09:42.123456,Europe/Berlin")`, 336 }, 337 { 338 value: NullValue(types.Int32), 339 literal: `Nothing(Optional<Int32>)`, 340 }, 341 { 342 value: NullValue(types.NewOptional(types.Bool)), 343 literal: `Nothing(Optional<Optional<Bool>>)`, 344 }, 345 { 346 value: Int32Value(42), 347 literal: `42`, 348 }, 349 { 350 value: OptionalValue(Int32Value(42)), 351 literal: `Just(42)`, 352 }, 353 { 354 value: OptionalValue(OptionalValue(Int32Value(42))), 355 literal: `Just(Just(42))`, 356 }, 357 { 358 value: OptionalValue(OptionalValue(OptionalValue(Int32Value(42)))), 359 literal: `Just(Just(Just(42)))`, 360 }, 361 { 362 value: ListValue( 363 Int32Value(-1), 364 Int32Value(0), 365 Int32Value(1), 366 Int32Value(2), 367 Int32Value(3), 368 ), 369 literal: `[-1,0,1,2,3]`, 370 }, 371 { 372 value: ListValue( 373 Int64Value(0), 374 Int64Value(1), 375 Int64Value(2), 376 Int64Value(3), 377 ), 378 literal: `[0l,1l,2l,3l]`, 379 }, 380 { 381 value: SetValue( 382 Int64Value(0), 383 Int64Value(1), 384 Int64Value(2), 385 Int64Value(3), 386 ), 387 literal: `{0l,1l,2l,3l}`, 388 }, 389 { 390 value: TupleValue( 391 Int32Value(0), 392 Int64Value(1), 393 FloatValue(2), 394 TextValue("3"), 395 ), 396 literal: `(0,1l,Float("2"),"3"u)`, 397 }, 398 { 399 value: VariantValueTuple(Int32Value(42), 1, types.NewTuple( 400 types.Bytes, 401 types.Int32, 402 )), 403 literal: `Variant(42,"1",Variant<String,Int32>)`, 404 }, 405 { 406 value: VariantValueTuple(TextValue("foo"), 1, types.NewTuple( 407 types.Bytes, 408 types.Text, 409 )), 410 literal: `Variant("foo"u,"1",Variant<String,Utf8>)`, 411 }, 412 { 413 value: VariantValueTuple(BoolValue(true), 0, types.NewTuple( 414 types.Bytes, 415 types.Int32, 416 )), 417 literal: `Variant(true,"0",Variant<String,Int32>)`, 418 }, 419 { 420 value: VariantValueStruct(Int32Value(42), "bar", types.NewStruct( 421 types.StructField{ 422 Name: "foo", 423 T: types.Bytes, 424 }, 425 types.StructField{ 426 Name: "bar", 427 T: types.Int32, 428 }, 429 )), 430 literal: `Variant(42,"bar",Variant<'bar':Int32,'foo':String>)`, 431 }, 432 { 433 value: StructValue( 434 StructValueField{"series_id", Uint64Value(1)}, 435 StructValueField{"title", TextValue("test")}, 436 StructValueField{"air_date", DateValue(1)}, 437 ), 438 literal: "<|`air_date`:Date(\"1970-01-02\"),`series_id`:1ul,`title`:\"test\"u|>", 439 }, 440 { 441 value: DictValue( 442 DictValueField{TextValue("foo"), Int32Value(42)}, 443 DictValueField{TextValue("bar"), Int32Value(43)}, 444 ), 445 literal: `{"bar"u:43,"foo"u:42}`, 446 }, 447 { 448 value: DictValue( 449 DictValueField{TextValue("foo"), VoidValue()}, 450 DictValueField{TextValue("bar"), VoidValue()}, 451 ), 452 literal: `{"bar"u:Void(),"foo"u:Void()}`, 453 }, 454 { 455 value: ZeroValue(types.Bool), 456 literal: `false`, 457 }, 458 { 459 value: ZeroValue(types.NewOptional(types.Bool)), 460 literal: `Nothing(Optional<Bool>)`, 461 }, 462 { 463 value: ZeroValue(types.NewTuple(types.Bool, types.Double)), 464 literal: `(false,Double("0"))`, 465 }, 466 { 467 value: ZeroValue(types.NewStruct( 468 types.StructField{ 469 Name: "foo", 470 T: types.Bool, 471 }, 472 types.StructField{ 473 Name: "bar", 474 T: types.Text, 475 }, 476 )), 477 literal: "<|`bar`:\"\"u,`foo`:false|>", 478 }, 479 { 480 value: ZeroValue(types.UUID), 481 literal: `Uuid("00000000-0000-0000-0000-000000000000")`, 482 }, 483 { 484 value: DecimalValueFromBigInt(big.NewInt(-1234567890123456), 22, 9), 485 literal: `Decimal("-1234567.890123456",22,9)`, 486 }, 487 { 488 value: DyNumberValue("-1234567890123456"), 489 literal: `DyNumber("-1234567890123456")`, 490 }, 491 { 492 value: JSONValue("{\"a\":-1234567890123456}"), 493 literal: `Json(@@{"a":-1234567890123456}@@)`, 494 }, 495 { 496 value: JSONDocumentValue("{\"a\":-1234567890123456}"), 497 literal: `JsonDocument(@@{"a":-1234567890123456}@@)`, 498 }, 499 { 500 value: YSONValue([]byte("<a=1>[3;%false]")), 501 literal: `Yson("<a=1>[3;%false]")`, 502 }, 503 { 504 value: PgValue(pg.OIDUnknown, "123"), 505 literal: `PgConst("123", PgType(705))`, 506 }, 507 } { 508 t.Run(strconv.Itoa(i)+"."+tt.literal, func(t *testing.T) { 509 require.Equal(t, tt.literal, tt.value.Yql()) 510 }) 511 } 512 } 513 514 func TestOptionalValueCastTo(t *testing.T) { 515 for _, tt := range []struct { 516 name string 517 v *optionalValue 518 dst **string 519 exp interface{} 520 err error 521 }{ 522 { 523 name: xtest.CurrentFileLine(), 524 v: OptionalValue(TextValue("test")), 525 dst: func(v *string) **string { return &v }(func(s string) *string { return &s }("")), 526 exp: func(v *string) **string { return &v }(func(s string) *string { return &s }("test")), 527 err: nil, 528 }, 529 { 530 name: xtest.CurrentFileLine(), 531 v: OptionalValue(TextValue("test")), 532 dst: func(v *string) **string { return &v }(func() *string { return nil }()), 533 exp: func(v *string) **string { return &v }(func(s string) *string { return &s }("test")), 534 err: nil, 535 }, 536 { 537 name: xtest.CurrentFileLine(), 538 v: NullValue(types.Text), 539 dst: func(v *string) **string { return &v }(func(s string) *string { return &s }("")), 540 exp: func(v *string) **string { return &v }(func() *string { return nil }()), 541 err: nil, 542 }, 543 { 544 name: xtest.CurrentFileLine(), 545 v: NullValue(types.Text), 546 dst: func(v *string) **string { return &v }(func() *string { return nil }()), 547 exp: func(v *string) **string { return &v }(func() *string { return nil }()), 548 err: nil, 549 }, 550 } { 551 t.Run(tt.name, func(t *testing.T) { 552 err := tt.v.castTo(tt.dst) 553 if tt.err != nil { 554 require.ErrorIs(t, err, tt.err) 555 } else { 556 require.NoError(t, err) 557 require.Equal(t, tt.exp, tt.dst) 558 } 559 }) 560 } 561 } 562 563 func TestNullable(t *testing.T) { 564 for _, test := range []struct { 565 name string 566 t types.Type 567 v interface{} 568 exp Value 569 }{ 570 { 571 name: "bool", 572 t: types.Bool, 573 v: func(v bool) *bool { return &v }(true), 574 exp: OptionalValue(BoolValue(true)), 575 }, 576 { 577 name: "nil bool", 578 t: types.Bool, 579 v: func() *bool { return nil }(), 580 exp: NullValue(types.Bool), 581 }, 582 { 583 name: "int8", 584 t: types.Int8, 585 v: func(v int8) *int8 { return &v }(123), 586 exp: OptionalValue(Int8Value(123)), 587 }, 588 { 589 name: "nil int8", 590 t: types.Int8, 591 v: func() *int8 { return nil }(), 592 exp: NullValue(types.Int8), 593 }, 594 { 595 name: "uint8", 596 t: types.Uint8, 597 v: func(v uint8) *uint8 { return &v }(123), 598 exp: OptionalValue(Uint8Value(123)), 599 }, 600 { 601 name: "nil uint8", 602 t: types.Uint8, 603 v: func() *uint8 { return nil }(), 604 exp: NullValue(types.Uint8), 605 }, 606 { 607 name: "int16", 608 t: types.Int16, 609 v: func(v int16) *int16 { return &v }(123), 610 exp: OptionalValue(Int16Value(123)), 611 }, 612 { 613 name: "nil int16", 614 t: types.Int16, 615 v: func() *int16 { return nil }(), 616 exp: NullValue(types.Int16), 617 }, 618 { 619 name: "uint16", 620 t: types.Uint16, 621 v: func(v uint16) *uint16 { return &v }(123), 622 exp: OptionalValue(Uint16Value(123)), 623 }, 624 { 625 name: "nil uint16", 626 t: types.Uint16, 627 v: func() *uint16 { return nil }(), 628 exp: NullValue(types.Uint16), 629 }, 630 { 631 name: "int32", 632 t: types.Int32, 633 v: func(v int32) *int32 { return &v }(123), 634 exp: OptionalValue(Int32Value(123)), 635 }, 636 { 637 name: "nil int32", 638 t: types.Int32, 639 v: func() *int32 { return nil }(), 640 exp: NullValue(types.Int32), 641 }, 642 { 643 name: "uint32", 644 t: types.Uint32, 645 v: func(v uint32) *uint32 { return &v }(123), 646 exp: OptionalValue(Uint32Value(123)), 647 }, 648 { 649 name: "nil uint32", 650 t: types.Uint32, 651 v: func() *uint32 { return nil }(), 652 exp: NullValue(types.Uint32), 653 }, 654 { 655 name: "int64", 656 t: types.Int64, 657 v: func(v int64) *int64 { return &v }(123), 658 exp: OptionalValue(Int64Value(123)), 659 }, 660 { 661 name: "nil int64", 662 t: types.Int64, 663 v: func() *int64 { return nil }(), 664 exp: NullValue(types.Int64), 665 }, 666 { 667 name: "uint64", 668 t: types.Uint64, 669 v: func(v uint64) *uint64 { return &v }(123), 670 exp: OptionalValue(Uint64Value(123)), 671 }, 672 { 673 name: "nil uint64", 674 t: types.Uint64, 675 v: func() *uint64 { return nil }(), 676 exp: NullValue(types.Uint64), 677 }, 678 { 679 name: "float", 680 t: types.Float, 681 v: func(v float32) *float32 { return &v }(123), 682 exp: OptionalValue(FloatValue(123)), 683 }, 684 { 685 name: "nil float", 686 t: types.Float, 687 v: func() *float32 { return nil }(), 688 exp: NullValue(types.Float), 689 }, 690 { 691 name: "double", 692 t: types.Double, 693 v: func(v float64) *float64 { return &v }(123), 694 exp: OptionalValue(DoubleValue(123)), 695 }, 696 { 697 name: "nil float", 698 t: types.Double, 699 v: func() *float64 { return nil }(), 700 exp: NullValue(types.Double), 701 }, 702 { 703 name: "date from int32", 704 t: types.Date, 705 v: func(v uint32) *uint32 { return &v }(123), 706 exp: OptionalValue(DateValue(123)), 707 }, 708 { 709 name: "date from time.Time", 710 t: types.Date, 711 v: func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)), 712 exp: OptionalValue(DateValueFromTime(time.Unix(123, 456))), 713 }, 714 { 715 name: "nil date", 716 t: types.Date, 717 v: func() *uint32 { return nil }(), 718 exp: NullValue(types.Date), 719 }, 720 { 721 name: "datetime from int32", 722 t: types.Datetime, 723 v: func(v uint32) *uint32 { return &v }(123), 724 exp: OptionalValue(DatetimeValue(123)), 725 }, 726 { 727 name: "datetime from time.Time", 728 t: types.Datetime, 729 v: func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)), 730 exp: OptionalValue(DatetimeValueFromTime(time.Unix(123, 456))), 731 }, 732 { 733 name: "nil datetime", 734 t: types.Datetime, 735 v: func() *uint32 { return nil }(), 736 exp: NullValue(types.Datetime), 737 }, 738 { 739 name: "timestamp from int32", 740 t: types.Timestamp, 741 v: func(v uint64) *uint64 { return &v }(123), 742 exp: OptionalValue(TimestampValue(123)), 743 }, 744 { 745 name: "timestamp from time.Time", 746 t: types.Timestamp, 747 v: func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)), 748 exp: OptionalValue(TimestampValueFromTime(time.Unix(123, 456))), 749 }, 750 { 751 name: "nil timestamp", 752 t: types.Timestamp, 753 v: func() *uint64 { return nil }(), 754 exp: NullValue(types.Timestamp), 755 }, 756 { 757 name: "tzDate from int32", 758 t: types.TzDate, 759 v: func(v string) *string { return &v }(""), 760 exp: OptionalValue(TzDateValue("")), 761 }, 762 { 763 name: "tzDate from time.Time", 764 t: types.TzDate, 765 v: func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)), 766 exp: OptionalValue(TzDateValueFromTime(time.Unix(123, 456))), 767 }, 768 { 769 name: "nil tzDate", 770 t: types.TzDate, 771 v: func() *string { return nil }(), 772 exp: NullValue(types.TzDate), 773 }, 774 { 775 name: "interval from int64", 776 t: types.Interval, 777 v: func(v int64) *int64 { return &v }(123), 778 exp: OptionalValue(IntervalValue(123)), 779 }, 780 { 781 name: "interval from time.Time", 782 t: types.Interval, 783 v: func(v time.Duration) *time.Duration { return &v }(time.Second), 784 exp: OptionalValue(IntervalValueFromDuration(time.Second)), 785 }, 786 { 787 name: "nil interval", 788 t: types.Interval, 789 v: func() *int64 { return nil }(), 790 exp: NullValue(types.Interval), 791 }, 792 { 793 name: "tzDatetime from int32", 794 t: types.TzDatetime, 795 v: func(v string) *string { return &v }(""), 796 exp: OptionalValue(TzDatetimeValue("")), 797 }, 798 { 799 name: "tzTzDatetime from time.Time", 800 t: types.TzDatetime, 801 v: func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)), 802 exp: OptionalValue(TzDatetimeValueFromTime(time.Unix(123, 456))), 803 }, 804 { 805 name: "nil tzTzDatetime", 806 t: types.TzDatetime, 807 v: func() *string { return nil }(), 808 exp: NullValue(types.TzDatetime), 809 }, 810 { 811 name: "tzTimestamp from int32", 812 t: types.TzTimestamp, 813 v: func(v string) *string { return &v }(""), 814 exp: OptionalValue(TzTimestampValue("")), 815 }, 816 { 817 name: "TzTimestamp from time.Time", 818 t: types.TzTimestamp, 819 v: func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)), 820 exp: OptionalValue(TzTimestampValueFromTime(time.Unix(123, 456))), 821 }, 822 { 823 name: "nil TzTimestamp", 824 t: types.TzTimestamp, 825 v: func() *string { return nil }(), 826 exp: NullValue(types.TzTimestamp), 827 }, 828 { 829 name: "string", 830 t: types.Bytes, 831 v: func(v string) *string { return &v }("test"), 832 exp: OptionalValue(BytesValue([]byte("test"))), 833 }, 834 { 835 name: "string", 836 t: types.Bytes, 837 v: func(v []byte) *[]byte { return &v }([]byte("test")), 838 exp: OptionalValue(BytesValue([]byte("test"))), 839 }, 840 { 841 name: "nil string", 842 t: types.Bytes, 843 v: func() *string { return nil }(), 844 exp: NullValue(types.Bytes), 845 }, 846 { 847 name: "utf8", 848 t: types.Text, 849 v: func(v string) *string { return &v }("test"), 850 exp: OptionalValue(TextValue("test")), 851 }, 852 { 853 name: "nil utf8", 854 t: types.Text, 855 v: func() *string { return nil }(), 856 exp: NullValue(types.Text), 857 }, 858 { 859 name: "yson", 860 t: types.YSON, 861 v: func(v string) *string { return &v }("test"), 862 exp: OptionalValue(YSONValue([]byte("test"))), 863 }, 864 { 865 name: "yson", 866 t: types.YSON, 867 v: func(v []byte) *[]byte { return &v }([]byte("test")), 868 exp: OptionalValue(YSONValue([]byte("test"))), 869 }, 870 { 871 name: "nil yson", 872 t: types.YSON, 873 v: func() *string { return nil }(), 874 exp: NullValue(types.YSON), 875 }, 876 { 877 name: "json", 878 t: types.JSON, 879 v: func(v string) *string { return &v }("test"), 880 exp: OptionalValue(JSONValue("test")), 881 }, 882 { 883 name: "json", 884 t: types.JSON, 885 v: func(v []byte) *[]byte { return &v }([]byte("test")), 886 exp: OptionalValue(JSONValue("test")), 887 }, 888 { 889 name: "nil json", 890 t: types.JSON, 891 v: func() *string { return nil }(), 892 exp: NullValue(types.JSON), 893 }, 894 { 895 name: "uuid", 896 t: types.UUID, 897 v: func(v [16]byte) *[16]byte { return &v }([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}), 898 exp: OptionalValue(UUIDWithIssue1501Value([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16})), 899 }, 900 { 901 name: "jsonDocument", 902 t: types.JSONDocument, 903 v: func(v string) *string { return &v }("test"), 904 exp: OptionalValue(JSONDocumentValue("test")), 905 }, 906 { 907 name: "jsonDocument", 908 t: types.JSONDocument, 909 v: func(v []byte) *[]byte { return &v }([]byte("test")), 910 exp: OptionalValue(JSONDocumentValue("test")), 911 }, 912 { 913 name: "nil jsonDocument", 914 t: types.JSONDocument, 915 v: func() *string { return nil }(), 916 exp: NullValue(types.JSONDocument), 917 }, 918 { 919 name: "dyNumber", 920 t: types.DyNumber, 921 v: func(v string) *string { return &v }("test"), 922 exp: OptionalValue(DyNumberValue("test")), 923 }, 924 { 925 name: "nil dyNumber", 926 t: types.DyNumber, 927 v: func() *string { return nil }(), 928 exp: NullValue(types.DyNumber), 929 }, 930 } { 931 t.Run(test.name, func(t *testing.T) { 932 a := allocator.New() 933 defer a.Free() 934 v := Nullable(test.t, test.v) 935 if !proto.Equal(ToYDB(v, a), ToYDB(test.exp, a)) { 936 t.Fatalf("unexpected value: %v, exp: %v", v, test.exp) 937 } 938 }) 939 } 940 } 941 942 func TestCastNumbers(t *testing.T) { 943 numberValues := []struct { 944 value Value 945 signed bool 946 len int 947 }{ 948 { 949 value: Uint64Value(1), 950 signed: false, 951 len: 8, 952 }, 953 { 954 value: Int64Value(-2), 955 signed: true, 956 len: 8, 957 }, 958 { 959 value: Uint32Value(3), 960 signed: false, 961 len: 4, 962 }, 963 { 964 value: Int32Value(-4), 965 signed: true, 966 len: 4, 967 }, 968 { 969 value: Uint16Value(5), 970 signed: false, 971 len: 2, 972 }, 973 { 974 value: Int16Value(-6), 975 signed: true, 976 len: 2, 977 }, 978 { 979 value: Uint8Value(7), 980 signed: false, 981 len: 1, 982 }, 983 { 984 value: Int8Value(-8), 985 signed: true, 986 len: 1, 987 }, 988 } 989 numberDestinations := []struct { 990 destination interface{} 991 signed bool 992 len int 993 }{ 994 { 995 destination: func(v uint64) *uint64 { return &v }(1), 996 signed: false, 997 len: 8, 998 }, 999 { 1000 destination: func(v int64) *int64 { return &v }(2), 1001 signed: true, 1002 len: 8, 1003 }, 1004 { 1005 destination: func(v uint32) *uint32 { return &v }(3), 1006 signed: false, 1007 len: 4, 1008 }, 1009 { 1010 destination: func(v int32) *int32 { return &v }(4), 1011 signed: true, 1012 len: 4, 1013 }, 1014 { 1015 destination: func(v uint16) *uint16 { return &v }(5), 1016 signed: false, 1017 len: 2, 1018 }, 1019 { 1020 destination: func(v int16) *int16 { return &v }(6), 1021 signed: true, 1022 len: 2, 1023 }, 1024 { 1025 destination: func(v uint8) *uint8 { return &v }(7), 1026 signed: false, 1027 len: 1, 1028 }, 1029 { 1030 destination: func(v int8) *int8 { return &v }(8), 1031 signed: true, 1032 len: 1, 1033 }, 1034 { 1035 destination: func(v float32) *float32 { return &v }(7), 1036 signed: true, 1037 len: 4, 1038 }, 1039 { 1040 destination: func(v float64) *float64 { return &v }(8), 1041 signed: true, 1042 len: 8, 1043 }, 1044 } 1045 for _, dst := range numberDestinations { 1046 for _, src := range numberValues { 1047 t.Run(fmt.Sprintf("%s(%s)ā%s", 1048 src.value.Type().Yql(), src.value.Yql(), reflect.ValueOf(dst.destination).Type().Elem().String(), 1049 ), func(t *testing.T) { 1050 mustErr := false 1051 switch { 1052 case src.len == dst.len && src.signed != dst.signed, 1053 src.len > dst.len, 1054 src.signed && !dst.signed: 1055 mustErr = true 1056 } 1057 err := CastTo(src.value, dst.destination) 1058 if mustErr { 1059 require.Error(t, err) 1060 } else { 1061 require.NoError(t, err) 1062 } 1063 }) 1064 t.Run(fmt.Sprintf("Optional(%s(%s))ā%s", 1065 src.value.Type().Yql(), src.value.Yql(), reflect.ValueOf(dst.destination).Type().Elem().String(), 1066 ), func(t *testing.T) { 1067 mustErr := false 1068 switch { 1069 case src.len == dst.len && src.signed != dst.signed, 1070 src.len > dst.len, 1071 src.signed && !dst.signed: 1072 mustErr = true 1073 } 1074 err := CastTo(OptionalValue(src.value), dst.destination) 1075 if mustErr { 1076 require.Error(t, err) 1077 } else { 1078 require.NoError(t, err) 1079 } 1080 }) 1081 } 1082 } 1083 } 1084 1085 func TestCastOtherTypes(t *testing.T) { 1086 for _, tt := range []struct { 1087 v Value 1088 dst interface{} 1089 result interface{} 1090 error bool 1091 }{ 1092 { 1093 v: BytesValue([]byte("test")), 1094 dst: func(v []byte) *[]byte { return &v }(make([]byte, 0, 10)), 1095 result: func(v []byte) *[]byte { return &v }([]byte("test")), 1096 error: false, 1097 }, 1098 { 1099 v: TextValue("test"), 1100 dst: func(v []byte) *[]byte { return &v }(make([]byte, 0, 10)), 1101 result: func(v []byte) *[]byte { return &v }([]byte("test")), 1102 error: false, 1103 }, 1104 { 1105 v: BytesValue([]byte("test")), 1106 dst: func(v string) *string { return &v }(""), 1107 result: func(v string) *string { return &v }("test"), 1108 error: false, 1109 }, 1110 { 1111 v: DoubleValue(123), 1112 dst: func(v float64) *float64 { return &v }(9), 1113 result: func(v float64) *float64 { return &v }(123), 1114 error: false, 1115 }, 1116 { 1117 v: DoubleValue(123), 1118 dst: func(v float32) *float32 { return &v }(9), 1119 result: func(v float32) *float32 { return &v }(9), 1120 error: true, 1121 }, 1122 { 1123 v: FloatValue(123), 1124 dst: func(v float64) *float64 { return &v }(9), 1125 result: func(v float64) *float64 { return &v }(123), 1126 error: false, 1127 }, 1128 { 1129 v: FloatValue(123), 1130 dst: func(v float32) *float32 { return &v }(9), 1131 result: func(v float32) *float32 { return &v }(123), 1132 error: false, 1133 }, 1134 { 1135 v: Uint64Value(123), 1136 dst: func(v float32) *float32 { return &v }(9), 1137 result: func(v float32) *float32 { return &v }(9), 1138 error: true, 1139 }, 1140 { 1141 v: Uint64Value(123), 1142 dst: func(v float64) *float64 { return &v }(9), 1143 result: func(v float64) *float64 { return &v }(9), 1144 error: true, 1145 }, 1146 { 1147 v: OptionalValue(DoubleValue(123)), 1148 dst: func(v float64) *float64 { return &v }(9), 1149 result: func(v float64) *float64 { return &v }(123), 1150 error: false, 1151 }, 1152 } { 1153 t.Run(fmt.Sprintf("%sā%v", tt.v.Type().Yql(), reflect.ValueOf(tt.dst).Type().Elem()), 1154 func(t *testing.T) { 1155 if err := CastTo(tt.v, tt.dst); (err != nil) != tt.error { 1156 t.Errorf("castTo() error = %v, want %v", err, tt.error) 1157 } else if !reflect.DeepEqual(tt.dst, tt.result) { 1158 t.Errorf("castTo() result = %+v, want %+v", 1159 reflect.ValueOf(tt.dst).Elem(), 1160 reflect.ValueOf(tt.result).Elem(), 1161 ) 1162 } 1163 }, 1164 ) 1165 } 1166 }