github.com/ydb-platform/ydb-go-sdk/v3@v3.57.0/internal/query/scanner/indexed_test.go (about) 1 package scanner 2 3 import ( 4 "reflect" 5 "testing" 6 "time" 7 8 "github.com/stretchr/testify/require" 9 "github.com/ydb-platform/ydb-go-genproto/protos/Ydb" 10 11 "github.com/ydb-platform/ydb-go-sdk/v3/internal/value" 12 ) 13 14 func TestIndexed(t *testing.T) { 15 for _, tt := range []struct { 16 name string 17 s IndexedScanner 18 dst [][]interface{} 19 exp [][]interface{} 20 }{ 21 { 22 name: "Ydb.Type_UTF8", 23 s: Indexed(Data( 24 []*Ydb.Column{ 25 { 26 Type: &Ydb.Type{ 27 Type: &Ydb.Type_TypeId{ 28 TypeId: Ydb.Type_UTF8, 29 }, 30 }, 31 }, 32 }, 33 []*Ydb.Value{ 34 { 35 Value: &Ydb.Value_TextValue{ 36 TextValue: "test", 37 }, 38 }, 39 }, 40 )), 41 dst: [][]interface{}{ 42 {func(v string) *string { return &v }("")}, 43 {func(v []byte) *[]byte { return &v }([]byte(""))}, 44 }, 45 exp: [][]interface{}{ 46 {func(v string) *string { return &v }("test")}, 47 {func(v []byte) *[]byte { return &v }([]byte("test"))}, 48 }, 49 }, 50 { 51 name: "Ydb.Type_STRING", 52 s: Indexed(Data( 53 []*Ydb.Column{ 54 { 55 Type: &Ydb.Type{ 56 Type: &Ydb.Type_TypeId{ 57 TypeId: Ydb.Type_STRING, 58 }, 59 }, 60 }, 61 }, 62 []*Ydb.Value{ 63 { 64 Value: &Ydb.Value_BytesValue{ 65 BytesValue: []byte("test"), 66 }, 67 }, 68 }, 69 )), 70 dst: [][]interface{}{ 71 {func(v string) *string { return &v }("")}, 72 {func(v []byte) *[]byte { return &v }([]byte(""))}, 73 }, 74 exp: [][]interface{}{ 75 {func(v string) *string { return &v }("test")}, 76 {func(v []byte) *[]byte { return &v }([]byte("test"))}, 77 }, 78 }, 79 { 80 name: "Ydb.Type_UINT64", 81 s: Indexed(Data( 82 []*Ydb.Column{ 83 { 84 Type: &Ydb.Type{ 85 Type: &Ydb.Type_TypeId{ 86 TypeId: Ydb.Type_UINT64, 87 }, 88 }, 89 }, 90 }, 91 []*Ydb.Value{ 92 { 93 Value: &Ydb.Value_Uint64Value{ 94 Uint64Value: 123, 95 }, 96 }, 97 }, 98 )), 99 dst: [][]interface{}{ 100 {func(v uint64) *uint64 { return &v }(0)}, 101 }, 102 exp: [][]interface{}{ 103 {func(v uint64) *uint64 { return &v }(123)}, 104 }, 105 }, 106 { 107 name: "Ydb.Type_INT64", 108 s: Indexed(Data( 109 []*Ydb.Column{ 110 { 111 Type: &Ydb.Type{ 112 Type: &Ydb.Type_TypeId{ 113 TypeId: Ydb.Type_INT64, 114 }, 115 }, 116 }, 117 }, 118 []*Ydb.Value{ 119 { 120 Value: &Ydb.Value_Int64Value{ 121 Int64Value: 123, 122 }, 123 }, 124 }, 125 )), 126 dst: [][]interface{}{ 127 {func(v int64) *int64 { return &v }(0)}, 128 }, 129 exp: [][]interface{}{ 130 {func(v int64) *int64 { return &v }(123)}, 131 }, 132 }, 133 { 134 name: "Ydb.Type_UINT32", 135 s: Indexed(Data( 136 []*Ydb.Column{ 137 { 138 Type: &Ydb.Type{ 139 Type: &Ydb.Type_TypeId{ 140 TypeId: Ydb.Type_UINT32, 141 }, 142 }, 143 }, 144 }, 145 []*Ydb.Value{ 146 { 147 Value: &Ydb.Value_Uint32Value{ 148 Uint32Value: 123, 149 }, 150 }, 151 }, 152 )), 153 dst: [][]interface{}{ 154 {func(v uint64) *uint64 { return &v }(0)}, 155 {func(v int64) *int64 { return &v }(0)}, 156 {func(v uint32) *uint32 { return &v }(0)}, 157 {func(v float64) *float64 { return &v }(0)}, 158 }, 159 exp: [][]interface{}{ 160 {func(v uint64) *uint64 { return &v }(123)}, 161 {func(v int64) *int64 { return &v }(123)}, 162 {func(v uint32) *uint32 { return &v }(123)}, 163 {func(v float64) *float64 { return &v }(123)}, 164 }, 165 }, 166 { 167 name: "Ydb.Type_INT32", 168 s: Indexed(Data( 169 []*Ydb.Column{ 170 { 171 Type: &Ydb.Type{ 172 Type: &Ydb.Type_TypeId{ 173 TypeId: Ydb.Type_INT32, 174 }, 175 }, 176 }, 177 }, 178 []*Ydb.Value{ 179 { 180 Value: &Ydb.Value_Int32Value{ 181 Int32Value: 123, 182 }, 183 }, 184 }, 185 )), 186 dst: [][]interface{}{ 187 {func(v int64) *int64 { return &v }(0)}, 188 {func(v int32) *int32 { return &v }(0)}, 189 {func(v int) *int { return &v }(0)}, 190 {func(v float32) *float32 { return &v }(0)}, 191 {func(v float64) *float64 { return &v }(0)}, 192 }, 193 exp: [][]interface{}{ 194 {func(v int64) *int64 { return &v }(123)}, 195 {func(v int32) *int32 { return &v }(123)}, 196 {func(v int) *int { return &v }(123)}, 197 {func(v float32) *float32 { return &v }(123)}, 198 {func(v float64) *float64 { return &v }(123)}, 199 }, 200 }, 201 { 202 name: "Ydb.Type_UINT16", 203 s: Indexed(Data( 204 []*Ydb.Column{ 205 { 206 Type: &Ydb.Type{ 207 Type: &Ydb.Type_TypeId{ 208 TypeId: Ydb.Type_UINT16, 209 }, 210 }, 211 }, 212 }, 213 []*Ydb.Value{ 214 { 215 Value: &Ydb.Value_Uint32Value{ 216 Uint32Value: 123, 217 }, 218 }, 219 }, 220 )), 221 dst: [][]interface{}{ 222 {func(v uint64) *uint64 { return &v }(0)}, 223 {func(v int64) *int64 { return &v }(0)}, 224 {func(v uint32) *uint32 { return &v }(0)}, 225 {func(v int32) *int32 { return &v }(0)}, 226 {func(v float32) *float32 { return &v }(0)}, 227 {func(v float64) *float64 { return &v }(0)}, 228 }, 229 exp: [][]interface{}{ 230 {func(v uint64) *uint64 { return &v }(123)}, 231 {func(v int64) *int64 { return &v }(123)}, 232 {func(v uint32) *uint32 { return &v }(123)}, 233 {func(v int32) *int32 { return &v }(123)}, 234 {func(v float32) *float32 { return &v }(123)}, 235 {func(v float64) *float64 { return &v }(123)}, 236 }, 237 }, 238 { 239 name: "Ydb.Type_INT16", 240 s: Indexed(Data( 241 []*Ydb.Column{ 242 { 243 Type: &Ydb.Type{ 244 Type: &Ydb.Type_TypeId{ 245 TypeId: Ydb.Type_INT16, 246 }, 247 }, 248 }, 249 }, 250 []*Ydb.Value{ 251 { 252 Value: &Ydb.Value_Int32Value{ 253 Int32Value: 123, 254 }, 255 }, 256 }, 257 )), 258 dst: [][]interface{}{ 259 {func(v int64) *int64 { return &v }(0)}, 260 {func(v int32) *int32 { return &v }(0)}, 261 {func(v float32) *float32 { return &v }(0)}, 262 {func(v float64) *float64 { return &v }(0)}, 263 }, 264 exp: [][]interface{}{ 265 {func(v int64) *int64 { return &v }(123)}, 266 {func(v int32) *int32 { return &v }(123)}, 267 {func(v float32) *float32 { return &v }(123)}, 268 {func(v float64) *float64 { return &v }(123)}, 269 }, 270 }, 271 { 272 name: "Ydb.Type_UINT8", 273 s: Indexed(Data( 274 []*Ydb.Column{ 275 { 276 Type: &Ydb.Type{ 277 Type: &Ydb.Type_TypeId{ 278 TypeId: Ydb.Type_UINT8, 279 }, 280 }, 281 }, 282 }, 283 []*Ydb.Value{ 284 { 285 Value: &Ydb.Value_Uint32Value{ 286 Uint32Value: 123, 287 }, 288 }, 289 }, 290 )), 291 dst: [][]interface{}{ 292 {func(v uint64) *uint64 { return &v }(0)}, 293 {func(v int64) *int64 { return &v }(0)}, 294 {func(v uint32) *uint32 { return &v }(0)}, 295 {func(v int32) *int32 { return &v }(0)}, 296 {func(v uint8) *uint8 { return &v }(0)}, 297 {func(v float32) *float32 { return &v }(0)}, 298 {func(v float64) *float64 { return &v }(0)}, 299 }, 300 exp: [][]interface{}{ 301 {func(v uint64) *uint64 { return &v }(123)}, 302 {func(v int64) *int64 { return &v }(123)}, 303 {func(v uint32) *uint32 { return &v }(123)}, 304 {func(v int32) *int32 { return &v }(123)}, 305 {func(v uint8) *uint8 { return &v }(123)}, 306 {func(v float32) *float32 { return &v }(123)}, 307 {func(v float64) *float64 { return &v }(123)}, 308 }, 309 }, 310 { 311 name: "Ydb.Type_INT8", 312 s: Indexed(Data( 313 []*Ydb.Column{ 314 { 315 Type: &Ydb.Type{ 316 Type: &Ydb.Type_TypeId{ 317 TypeId: Ydb.Type_INT8, 318 }, 319 }, 320 }, 321 }, 322 []*Ydb.Value{ 323 { 324 Value: &Ydb.Value_Int32Value{ 325 Int32Value: 123, 326 }, 327 }, 328 }, 329 )), 330 dst: [][]interface{}{ 331 {func(v int64) *int64 { return &v }(0)}, 332 {func(v int32) *int32 { return &v }(0)}, 333 {func(v int8) *int8 { return &v }(0)}, 334 {func(v float32) *float32 { return &v }(0)}, 335 {func(v float64) *float64 { return &v }(0)}, 336 }, 337 exp: [][]interface{}{ 338 {func(v int64) *int64 { return &v }(123)}, 339 {func(v int32) *int32 { return &v }(123)}, 340 {func(v int8) *int8 { return &v }(123)}, 341 {func(v float32) *float32 { return &v }(123)}, 342 {func(v float64) *float64 { return &v }(123)}, 343 }, 344 }, 345 { 346 name: "Ydb.Type_BOOL", 347 s: Indexed(Data( 348 []*Ydb.Column{ 349 { 350 Type: &Ydb.Type{ 351 Type: &Ydb.Type_TypeId{ 352 TypeId: Ydb.Type_BOOL, 353 }, 354 }, 355 }, 356 }, 357 []*Ydb.Value{ 358 { 359 Value: &Ydb.Value_BoolValue{ 360 BoolValue: true, 361 }, 362 }, 363 }, 364 )), 365 dst: [][]interface{}{ 366 {func(v bool) *bool { return &v }(false)}, 367 }, 368 exp: [][]interface{}{ 369 {func(v bool) *bool { return &v }(true)}, 370 }, 371 }, 372 { 373 name: "Ydb.Type_DATE", 374 s: Indexed(Data( 375 []*Ydb.Column{ 376 { 377 Type: &Ydb.Type{ 378 Type: &Ydb.Type_TypeId{ 379 TypeId: Ydb.Type_DATE, 380 }, 381 }, 382 }, 383 }, 384 []*Ydb.Value{ 385 { 386 Value: &Ydb.Value_Uint32Value{ 387 Uint32Value: 100500, 388 }, 389 }, 390 }, 391 )), 392 dst: [][]interface{}{ 393 {func(v uint64) *uint64 { return &v }(0)}, 394 {func(v int64) *int64 { return &v }(0)}, 395 {func(v int32) *int32 { return &v }(0)}, 396 {func(v time.Time) *time.Time { return &v }(time.Unix(0, 0))}, 397 }, 398 exp: [][]interface{}{ 399 {func(v uint64) *uint64 { return &v }(100500)}, 400 {func(v int64) *int64 { return &v }(100500)}, 401 {func(v int32) *int32 { return &v }(100500)}, 402 {func(v time.Time) *time.Time { return &v }(time.Unix(8683200000, 0))}, 403 }, 404 }, 405 { 406 name: "Ydb.Type_DATETIME", 407 s: Indexed(Data( 408 []*Ydb.Column{ 409 { 410 Type: &Ydb.Type{ 411 Type: &Ydb.Type_TypeId{ 412 TypeId: Ydb.Type_DATETIME, 413 }, 414 }, 415 }, 416 }, 417 []*Ydb.Value{ 418 { 419 Value: &Ydb.Value_Uint32Value{ 420 Uint32Value: 100500, 421 }, 422 }, 423 }, 424 )), 425 dst: [][]interface{}{ 426 {func(v uint64) *uint64 { return &v }(0)}, 427 {func(v int64) *int64 { return &v }(0)}, 428 {func(v uint32) *uint32 { return &v }(0)}, 429 {func(v time.Time) *time.Time { return &v }(time.Unix(0, 0))}, 430 }, 431 exp: [][]interface{}{ 432 {func(v uint64) *uint64 { return &v }(100500)}, 433 {func(v int64) *int64 { return &v }(100500)}, 434 {func(v uint32) *uint32 { return &v }(100500)}, 435 {func(v time.Time) *time.Time { return &v }(time.Unix(100500, 0))}, 436 }, 437 }, 438 { 439 name: "Ydb.Type_TIMESTAMP", 440 s: Indexed(Data( 441 []*Ydb.Column{ 442 { 443 Type: &Ydb.Type{ 444 Type: &Ydb.Type_TypeId{ 445 TypeId: Ydb.Type_TIMESTAMP, 446 }, 447 }, 448 }, 449 }, 450 []*Ydb.Value{ 451 { 452 Value: &Ydb.Value_Uint64Value{ 453 Uint64Value: 12345678987654321, 454 }, 455 }, 456 }, 457 )), 458 dst: [][]interface{}{ 459 {func(v uint64) *uint64 { return &v }(0)}, 460 {func(v time.Time) *time.Time { return &v }(time.Unix(0, 0))}, 461 }, 462 exp: [][]interface{}{ 463 {func(v uint64) *uint64 { return &v }(12345678987654321)}, 464 {func(v time.Time) *time.Time { return &v }(time.Unix(12345678987, 654321000))}, 465 }, 466 }, 467 { 468 name: "Ydb.Type_INTERVAL", 469 s: Indexed(Data( 470 []*Ydb.Column{ 471 { 472 Type: &Ydb.Type{ 473 Type: &Ydb.Type_TypeId{ 474 TypeId: Ydb.Type_INTERVAL, 475 }, 476 }, 477 }, 478 }, 479 []*Ydb.Value{ 480 { 481 Value: &Ydb.Value_Int64Value{ 482 Int64Value: 100500, 483 }, 484 }, 485 }, 486 )), 487 dst: [][]interface{}{ 488 {func(v int64) *int64 { return &v }(0)}, 489 {func(v time.Duration) *time.Duration { return &v }(time.Duration(0))}, 490 }, 491 exp: [][]interface{}{ 492 {func(v int64) *int64 { return &v }(100500)}, 493 {func(v time.Duration) *time.Duration { return &v }(time.Duration(100500000))}, 494 }, 495 }, 496 } { 497 for i := range tt.dst { 498 t.Run(tt.name+"→"+reflect.TypeOf(tt.dst[i][0]).Elem().String(), func(t *testing.T) { 499 err := tt.s.Scan(tt.dst[i]...) 500 require.NoError(t, err) 501 require.Equal(t, tt.exp[i], tt.dst[i]) 502 }) 503 } 504 } 505 } 506 507 func TestIndexedIncompatibleColumnsAndDestinations(t *testing.T) { 508 scanner := &IndexedScanner{data: Data( 509 []*Ydb.Column{ 510 { 511 Name: "a", 512 Type: &Ydb.Type{ 513 Type: &Ydb.Type_TypeId{ 514 TypeId: Ydb.Type_UTF8, 515 }, 516 }, 517 }, 518 }, 519 []*Ydb.Value{ 520 { 521 Value: &Ydb.Value_TextValue{ 522 TextValue: "test", 523 }, 524 }, 525 }, 526 )} 527 var ( 528 B string 529 C string 530 ) 531 err := scanner.Scan(&B, &C) 532 require.ErrorIs(t, err, errIncompatibleColumnsAndDestinations) 533 } 534 535 func TestIndexedCastFailed(t *testing.T) { 536 scanner := Indexed(Data( 537 []*Ydb.Column{ 538 { 539 Name: "a", 540 Type: &Ydb.Type{ 541 Type: &Ydb.Type_TypeId{ 542 TypeId: Ydb.Type_UTF8, 543 }, 544 }, 545 }, 546 }, 547 []*Ydb.Value{ 548 { 549 Value: &Ydb.Value_TextValue{ 550 TextValue: "test", 551 }, 552 }, 553 }, 554 )) 555 var A uint64 556 err := scanner.Scan(&A) 557 require.ErrorIs(t, err, value.ErrCannotCast) 558 }