github.com/ydb-platform/ydb-go-sdk/v3@v3.57.0/internal/table/scanner/scanner_test.go (about) 1 package scanner 2 3 import ( 4 "encoding/binary" 5 "encoding/json" 6 "math" 7 "strconv" 8 "testing" 9 "time" 10 11 "github.com/stretchr/testify/require" 12 "github.com/ydb-platform/ydb-go-genproto/protos/Ydb" 13 14 "github.com/ydb-platform/ydb-go-sdk/v3/internal/value" 15 "github.com/ydb-platform/ydb-go-sdk/v3/internal/xrand" 16 "github.com/ydb-platform/ydb-go-sdk/v3/table/result/indexed" 17 "github.com/ydb-platform/ydb-go-sdk/v3/table/result/named" 18 "github.com/ydb-platform/ydb-go-sdk/v3/table/types" 19 ) 20 21 //nolint:gocyclo 22 func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{}) { 23 rv := r.Int64(math.MaxInt16) 24 switch c.typeID { 25 case Ydb.Type_BOOL: 26 v := rv%2 == 1 27 ydbval := &Ydb.Value{ 28 Value: &Ydb.Value_BoolValue{ 29 BoolValue: v, 30 }, 31 } 32 if c.optional && !c.testDefault { 33 vp := &v 34 35 return ydbval, &vp 36 } 37 38 return ydbval, &v 39 case Ydb.Type_INT8: 40 v := int8(rv) 41 ydbval := &Ydb.Value{ 42 Value: &Ydb.Value_Int32Value{ 43 Int32Value: int32(v), 44 }, 45 } 46 if c.optional && !c.testDefault { 47 vp := &v 48 49 return ydbval, &vp 50 } 51 52 return ydbval, &v 53 case Ydb.Type_UINT8: 54 if c.nilValue { 55 ydbval := &Ydb.Value{ 56 Value: &Ydb.Value_NullFlagValue{}, 57 } 58 if c.testDefault { 59 var dv uint8 60 61 return ydbval, &dv 62 } 63 var dv *uint8 64 65 return ydbval, &dv 66 } 67 v := uint8(rv) 68 ydbval := &Ydb.Value{ 69 Value: &Ydb.Value_Uint32Value{ 70 Uint32Value: uint32(v), 71 }, 72 } 73 if c.optional && !c.testDefault { 74 vp := &v 75 76 return ydbval, &vp 77 } 78 79 return ydbval, &v 80 case Ydb.Type_INT16: 81 v := int16(rv) 82 ydbval := &Ydb.Value{ 83 Value: &Ydb.Value_Int32Value{ 84 Int32Value: int32(v), 85 }, 86 } 87 if c.optional && !c.testDefault { 88 vp := &v 89 90 return ydbval, &vp 91 } 92 93 return ydbval, &v 94 case Ydb.Type_UINT16: 95 v := uint16(rv) 96 ydbval := &Ydb.Value{ 97 Value: &Ydb.Value_Uint32Value{ 98 Uint32Value: uint32(v), 99 }, 100 } 101 if c.optional && !c.testDefault { 102 vp := &v 103 104 return ydbval, &vp 105 } 106 107 return ydbval, &v 108 case Ydb.Type_INT32: 109 if c.nilValue { 110 ydbval := &Ydb.Value{ 111 Value: &Ydb.Value_NullFlagValue{}, 112 } 113 if c.testDefault { 114 var dv int32 115 116 return ydbval, &dv 117 } 118 var dv *int32 119 120 return ydbval, &dv 121 } 122 v := int32(rv) 123 ydbval := &Ydb.Value{ 124 Value: &Ydb.Value_Int32Value{ 125 Int32Value: v, 126 }, 127 } 128 if c.optional && !c.testDefault { 129 vp := &v 130 131 return ydbval, &vp 132 } 133 134 return ydbval, &v 135 case Ydb.Type_UINT32: 136 v := uint32(rv) 137 ydbval := &Ydb.Value{ 138 Value: &Ydb.Value_Uint32Value{ 139 Uint32Value: v, 140 }, 141 } 142 if c.optional && !c.testDefault { 143 vp := &v 144 145 return ydbval, &vp 146 } 147 148 return ydbval, &v 149 case Ydb.Type_INT64: 150 v := rv 151 ydbval := &Ydb.Value{ 152 Value: &Ydb.Value_Int64Value{ 153 Int64Value: v, 154 }, 155 } 156 if c.ydbvalue { 157 vp := types.Int64Value(v) 158 159 return ydbval, &vp 160 } 161 if c.scanner { 162 s := intIncScanner(v + 10) 163 164 return ydbval, &s 165 } 166 if c.optional && !c.testDefault { 167 vp := &v 168 169 return ydbval, &vp 170 } 171 172 return ydbval, &v 173 case Ydb.Type_UINT64: 174 v := uint64(rv) 175 ydbval := &Ydb.Value{ 176 Value: &Ydb.Value_Uint64Value{ 177 Uint64Value: v, 178 }, 179 } 180 if c.optional && !c.testDefault { 181 vp := &v 182 183 return ydbval, &vp 184 } 185 186 return ydbval, &v 187 case Ydb.Type_FLOAT: 188 v := float32(rv) 189 ydbval := &Ydb.Value{ 190 Value: &Ydb.Value_FloatValue{ 191 FloatValue: v, 192 }, 193 } 194 if c.ydbvalue { 195 vp := types.FloatValue(v) 196 197 return ydbval, &vp 198 } 199 if c.optional && !c.testDefault { 200 vp := &v 201 202 return ydbval, &vp 203 } 204 205 return ydbval, &v 206 case Ydb.Type_DOUBLE: 207 v := float64(rv) 208 ydbval := &Ydb.Value{ 209 Value: &Ydb.Value_DoubleValue{ 210 DoubleValue: v, 211 }, 212 } 213 if c.optional && !c.testDefault { 214 vp := &v 215 216 return ydbval, &vp 217 } 218 219 return ydbval, &v 220 case Ydb.Type_DATE: 221 v := uint32(rv) 222 ydbval := &Ydb.Value{ 223 Value: &Ydb.Value_Uint32Value{ 224 Uint32Value: v, 225 }, 226 } 227 src := value.DateToTime(v) 228 if c.scanner { 229 s := dateScanner(src) 230 231 return ydbval, &s 232 } 233 if c.optional && !c.testDefault { 234 vp := &src 235 236 return ydbval, &vp 237 } 238 239 return ydbval, &src 240 case Ydb.Type_DATETIME: 241 v := uint32(rv) 242 ydbval := &Ydb.Value{ 243 Value: &Ydb.Value_Uint32Value{ 244 Uint32Value: v, 245 }, 246 } 247 src := value.DatetimeToTime(v) 248 if c.optional && !c.testDefault { 249 vp := &src 250 251 return ydbval, &vp 252 } 253 254 return ydbval, &src 255 case Ydb.Type_TIMESTAMP: 256 v := uint64(rv) 257 ydbval := &Ydb.Value{ 258 Value: &Ydb.Value_Uint64Value{ 259 Uint64Value: v, 260 }, 261 } 262 src := value.TimestampToTime(v) 263 if c.optional && !c.testDefault { 264 vp := &src 265 266 return ydbval, &vp 267 } 268 269 return ydbval, &src 270 case Ydb.Type_INTERVAL: 271 if c.nilValue { 272 ydbval := &Ydb.Value{ 273 Value: &Ydb.Value_NullFlagValue{}, 274 } 275 if c.testDefault { 276 var dv time.Duration 277 278 return ydbval, &dv 279 } 280 var dv *time.Duration 281 282 return ydbval, &dv 283 } 284 rv %= time.Now().Unix() 285 v := rv 286 ydbval := &Ydb.Value{ 287 Value: &Ydb.Value_Int64Value{ 288 Int64Value: v, 289 }, 290 } 291 src := value.IntervalToDuration(v) 292 if c.optional && !c.testDefault { 293 vp := &src 294 295 return ydbval, &vp 296 } 297 298 return ydbval, &src 299 case Ydb.Type_TZ_DATE: 300 v := time.Now().Format(value.LayoutDate) + ",Europe/Berlin" 301 ydbval := &Ydb.Value{ 302 Value: &Ydb.Value_TextValue{ 303 TextValue: v, 304 }, 305 } 306 src, _ := value.TzDateToTime(v) 307 if c.optional && !c.testDefault { 308 vp := &src 309 310 return ydbval, &vp 311 } 312 313 return ydbval, &src 314 case Ydb.Type_TZ_DATETIME: 315 if c.nilValue { 316 ydbval := &Ydb.Value{ 317 Value: &Ydb.Value_NullFlagValue{}, 318 } 319 if c.testDefault { 320 var dv time.Time 321 322 return ydbval, &dv 323 } 324 var dv *time.Time 325 326 return ydbval, &dv 327 } 328 rv %= time.Now().Unix() 329 v := value.DatetimeToTime(uint32(rv)).Format(value.LayoutTzDatetime) + ",Europe/Berlin" 330 ydbval := &Ydb.Value{ 331 Value: &Ydb.Value_TextValue{ 332 TextValue: v, 333 }, 334 } 335 src, _ := value.TzDatetimeToTime(v) 336 if c.optional && !c.testDefault { 337 vp := &src 338 339 return ydbval, &vp 340 } 341 342 return ydbval, &src 343 case Ydb.Type_TZ_TIMESTAMP: 344 rv %= time.Now().Unix() 345 v := value.TimestampToTime(uint64(rv)).Format(value.LayoutTzTimestamp) + ",Europe/Berlin" 346 ydbval := &Ydb.Value{ 347 Value: &Ydb.Value_TextValue{ 348 TextValue: v, 349 }, 350 } 351 src, _ := value.TzTimestampToTime(v) 352 if c.optional && !c.testDefault { 353 vp := &src 354 355 return ydbval, &vp 356 } 357 358 return ydbval, &src 359 case Ydb.Type_STRING: 360 if c.nilValue { 361 ydbval := &Ydb.Value{ 362 Value: &Ydb.Value_NullFlagValue{}, 363 } 364 if c.testDefault { 365 var dv []byte 366 367 return ydbval, &dv 368 } 369 var dv *[]byte 370 371 return ydbval, &dv 372 } 373 v := make([]byte, 16) 374 binary.BigEndian.PutUint64(v[0:8], uint64(rv)) 375 binary.BigEndian.PutUint64(v[8:16], uint64(rv)) 376 ydbval := &Ydb.Value{ 377 Value: &Ydb.Value_BytesValue{ 378 BytesValue: v, 379 }, 380 } 381 src := v 382 if c.optional && !c.testDefault { 383 vp := &src 384 385 return ydbval, &vp 386 } 387 388 return ydbval, &src 389 case Ydb.Type_UTF8: 390 v := strconv.FormatUint(uint64(rv), 10) 391 ydbval := &Ydb.Value{ 392 Value: &Ydb.Value_TextValue{ 393 TextValue: v, 394 }, 395 } 396 if c.optional && !c.testDefault { 397 vp := &v 398 399 return ydbval, &vp 400 } 401 402 return ydbval, &v 403 case Ydb.Type_YSON: 404 if c.nilValue { 405 ydbval := &Ydb.Value{ 406 Value: &Ydb.Value_NullFlagValue{}, 407 } 408 if c.testDefault { 409 var dv []byte 410 411 return ydbval, &dv 412 } 413 var dv *[]byte 414 415 return ydbval, &dv 416 } 417 v := strconv.FormatUint(uint64(rv), 10) 418 ydbval := &Ydb.Value{ 419 Value: &Ydb.Value_TextValue{ 420 TextValue: v, 421 }, 422 } 423 src := []byte(v) 424 if c.optional && !c.testDefault { 425 vp := &src 426 427 return ydbval, &vp 428 } 429 430 return ydbval, &src 431 case Ydb.Type_JSON: 432 v := strconv.FormatUint(uint64(rv), 10) 433 ydbval := &Ydb.Value{ 434 Value: &Ydb.Value_TextValue{ 435 TextValue: v, 436 }, 437 } 438 if c.ydbvalue { 439 vp := types.JSONValue(v) 440 441 return ydbval, &vp 442 } 443 src := []byte(v) 444 if c.optional && !c.testDefault { 445 vp := &src 446 447 return ydbval, &vp 448 } 449 450 return ydbval, &src 451 case Ydb.Type_UUID: 452 if c.nilValue { 453 ydbval := &Ydb.Value{ 454 Value: &Ydb.Value_NullFlagValue{}, 455 } 456 if c.testDefault { 457 var dv [16]byte 458 459 return ydbval, &dv 460 } 461 var dv *[16]byte 462 463 return ydbval, &dv 464 } 465 v := [16]byte{} 466 binary.BigEndian.PutUint64(v[0:8], uint64(rv)) 467 binary.BigEndian.PutUint64(v[8:16], uint64(rv)) 468 ydbval := &Ydb.Value{ 469 High_128: binary.BigEndian.Uint64(v[0:8]), 470 Value: &Ydb.Value_Low_128{ 471 Low_128: binary.BigEndian.Uint64(v[8:16]), 472 }, 473 } 474 if c.optional && !c.testDefault { 475 vp := &v 476 477 return ydbval, &vp 478 } 479 480 return ydbval, &v 481 case Ydb.Type_JSON_DOCUMENT: 482 v := strconv.FormatUint(uint64(rv), 10) 483 ydbval := &Ydb.Value{ 484 Value: &Ydb.Value_TextValue{ 485 TextValue: v, 486 }, 487 } 488 src := []byte(v) 489 if c.optional && !c.testDefault { 490 vp := &src 491 492 return ydbval, &vp 493 } 494 495 return ydbval, &src 496 case Ydb.Type_DYNUMBER: 497 v := strconv.FormatUint(uint64(rv), 10) 498 ydbval := &Ydb.Value{ 499 Value: &Ydb.Value_TextValue{ 500 TextValue: v, 501 }, 502 } 503 if c.optional && !c.testDefault { 504 vp := &v 505 506 return ydbval, &vp 507 } 508 509 return ydbval, &v 510 default: 511 panic("ydb: unexpected types") 512 } 513 } 514 515 func getResultSet(count int, col []*column) (result *Ydb.ResultSet, testValues [][]indexed.RequiredOrOptional) { 516 result = &Ydb.ResultSet{} 517 for _, c := range col { 518 t := &Ydb.Type{ 519 Type: &Ydb.Type_TypeId{ 520 TypeId: c.typeID, 521 }, 522 } 523 if c.optional { 524 t = &Ydb.Type{ 525 Type: &Ydb.Type_OptionalType{ 526 OptionalType: &Ydb.OptionalType{ 527 Item: t, 528 }, 529 }, 530 } 531 } 532 result.Columns = append( 533 result.GetColumns(), 534 &Ydb.Column{ 535 Name: c.name, 536 Type: t, 537 }, 538 ) 539 } 540 541 r := xrand.New(xrand.WithLock()) 542 testValues = make([][]indexed.RequiredOrOptional, count) 543 for i := 0; i < count; i++ { 544 var items []*Ydb.Value 545 var vals []indexed.RequiredOrOptional 546 for j := range result.GetColumns() { 547 v, val := valueFromPrimitiveTypeID(col[j], r) 548 vals = append(vals, val) 549 items = append(items, v) 550 } 551 result.Rows = append(result.GetRows(), &Ydb.Value{ 552 Items: items, 553 }) 554 testValues[i] = vals 555 } 556 557 return result, testValues 558 } 559 560 func TestScanSqlTypes(t *testing.T) { 561 s := initScanner() 562 for _, test := range scannerData { 563 t.Run(test.name, func(t *testing.T) { 564 set, expected := getResultSet(test.count, test.columns) 565 s.reset(set, test.setColumns...) 566 for s.NextRow() { 567 if test.columns[0].testDefault { 568 if err := s.ScanWithDefaults(func() (values []indexed.Required) { 569 for _, v := range test.values { 570 values = append(values, v) 571 } 572 573 return values 574 }()...); err != nil { 575 t.Fatalf("test: %s; error: %s", test.name, err) 576 } 577 } else { 578 if err := s.Scan(test.values...); err != nil { 579 t.Fatalf("test: %s; error: %s", test.name, err) 580 } 581 } 582 if test.setColumnIndexes != nil { 583 for i, v := range test.setColumnIndexes { 584 require.Equal(t, expected[0][v], test.values[i]) 585 } 586 } else { 587 require.Equal(t, expected[0], test.values) 588 } 589 expected = expected[1:] 590 } 591 }) 592 } 593 } 594 595 func TestScanNamed(t *testing.T) { 596 s := initScanner() 597 or := func(columns []string, i int, defaultValue string) string { 598 if columns == nil { 599 return defaultValue 600 } 601 602 return columns[i] 603 } 604 for _, test := range scannerData { 605 t.Run(test.name, func(t *testing.T) { 606 set, expected := getResultSet(test.count, test.columns) 607 s.reset(set) 608 for s.NextRow() { 609 values := make([]named.Value, 0, len(test.values)) 610 //nolint:nestif 611 if test.columns[0].testDefault { 612 for i := range test.values { 613 values = append( 614 values, 615 named.OptionalWithDefault( 616 or(test.setColumns, i, test.columns[i].name), 617 test.values[i], 618 ), 619 ) 620 } 621 if err := s.ScanNamed(values...); err != nil { 622 t.Fatalf("test: %s; error: %s", test.name, err) 623 } 624 } else { 625 for i := range test.values { 626 if test.columns[i].optional { 627 if test.columns[i].testDefault { 628 values = append( 629 values, 630 named.OptionalWithDefault( 631 or(test.setColumns, i, test.columns[i].name), 632 test.values[i], 633 ), 634 ) 635 } else { 636 values = append( 637 values, 638 named.Optional( 639 or(test.setColumns, i, test.columns[i].name), 640 test.values[i], 641 ), 642 ) 643 } 644 } else { 645 values = append( 646 values, 647 named.Required( 648 or(test.setColumns, i, test.columns[i].name), 649 test.values[i], 650 ), 651 ) 652 } 653 } 654 if err := s.ScanNamed(values...); err != nil { 655 t.Fatalf("test: %s; error: %s", test.name, err) 656 } 657 } 658 if test.setColumnIndexes != nil { 659 for i, v := range test.setColumnIndexes { 660 require.Equal(t, expected[0][v], test.values[i]) 661 } 662 } else { 663 require.Equal(t, expected[0], test.values) 664 } 665 expected = expected[1:] 666 } 667 }) 668 } 669 } 670 671 type jsonUnmarshaller struct { 672 bytes []byte 673 } 674 675 func (json *jsonUnmarshaller) UnmarshalJSON(bytes []byte) error { 676 json.bytes = bytes 677 678 return nil 679 } 680 681 var _ json.Unmarshaler = &jsonUnmarshaller{} 682 683 func TestScanToJsonUnmarshaller(t *testing.T) { 684 s := initScanner() 685 for _, test := range []struct { 686 name string 687 count int 688 columns []*column 689 values []indexed.RequiredOrOptional 690 }{ 691 { 692 name: "<optional JSONDocument, required JSON> to json.Unmarshaller", 693 count: 2, 694 columns: []*column{{ 695 name: "jsondocument", 696 typeID: Ydb.Type_JSON_DOCUMENT, 697 optional: true, 698 }, { 699 name: "json", 700 typeID: Ydb.Type_JSON, 701 }}, 702 values: []indexed.RequiredOrOptional{ 703 new(jsonUnmarshaller), 704 new(jsonUnmarshaller), 705 }, 706 }, { 707 name: "<required JSONDocument, optional JSON> to json.Unmarshaller", 708 count: 2, 709 columns: []*column{{ 710 name: "jsondocument", 711 typeID: Ydb.Type_JSON_DOCUMENT, 712 }, { 713 name: "json", 714 typeID: Ydb.Type_JSON, 715 optional: true, 716 }}, 717 values: []indexed.RequiredOrOptional{ 718 new(jsonUnmarshaller), 719 new(jsonUnmarshaller), 720 }, 721 }, { 722 name: "<optional JSONDocument, optional JSON> to json.Unmarshaller", 723 count: 2, 724 columns: []*column{{ 725 name: "jsondocument", 726 typeID: Ydb.Type_JSON_DOCUMENT, 727 optional: true, 728 }, { 729 name: "json", 730 typeID: Ydb.Type_JSON, 731 optional: true, 732 }}, 733 values: []indexed.RequiredOrOptional{ 734 new(jsonUnmarshaller), 735 new(jsonUnmarshaller), 736 }, 737 }, { 738 name: "<required JSONDocument, required JSON> to json.Unmarshaller", 739 count: 2, 740 columns: []*column{{ 741 name: "jsondocument", 742 typeID: Ydb.Type_JSON_DOCUMENT, 743 }, { 744 name: "json", 745 typeID: Ydb.Type_JSON, 746 }}, 747 values: []indexed.RequiredOrOptional{ 748 new(jsonUnmarshaller), 749 new(jsonUnmarshaller), 750 }, 751 }, 752 } { 753 set, _ := getResultSet(test.count, test.columns) 754 s.reset(set) 755 for s.NextRow() { 756 values := make([]indexed.RequiredOrOptional, 0, len(test.values)) 757 for i, col := range test.columns { 758 if col.optional { 759 values = append( 760 values, 761 indexed.Optional( 762 test.values[i], 763 ), 764 ) 765 } else { 766 values = append( 767 values, 768 indexed.Required( 769 test.values[i], 770 ), 771 ) 772 } 773 } 774 if err := s.Scan(values...); err != nil { 775 t.Fatalf("test: %s; error: %s", test.name, err) 776 } 777 } 778 } 779 }