github.com/runner-mei/ql@v1.1.0/introspection_test.go (about) 1 // Copyright 2014 The ql Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ql 6 7 import ( 8 "bytes" 9 "fmt" 10 "math/big" 11 //"reflect" 12 "testing" 13 "time" 14 15 "github.com/cznic/mathutil" 16 ) 17 18 type ( 19 testSchema struct { 20 a int8 21 ID int64 22 A int8 23 b int 24 B int `ql:"-"` 25 } 26 27 testSchema2 struct{} 28 29 testSchema3 struct { 30 a int8 31 ID uint64 32 A int8 33 b int 34 B int `ql:"-"` 35 c bool 36 C bool `ql:"name cc"` 37 } 38 39 testSchema4 struct { 40 a int8 41 ID int64 `ql:"name id"` 42 A int8 43 b int 44 B int `ql:"-"` 45 c bool 46 C bool `ql:"name cc"` 47 } 48 49 testSchema5 struct { 50 I int `ql:"index x,uindex u"` 51 } 52 53 testSchema6 struct { 54 A string `ql:"index x"` 55 } 56 57 testSchema7 struct { 58 A int64 59 B string `ql:"uindex x"` 60 C bool 61 } 62 63 testSchema8 struct { 64 A bool 65 //B int 66 C int8 67 D int16 68 E int32 69 F int64 70 //G uint 71 H uint8 72 I uint16 73 J uint32 74 K uint64 75 L float32 76 M float64 77 N complex64 78 O complex128 79 P []byte 80 Q big.Int 81 R big.Rat 82 S string 83 T time.Time 84 U time.Duration 85 PA *bool 86 //PB *int 87 PC *int8 88 PD *int16 89 PE *int32 90 PF *int64 91 //PG *uint 92 PH *uint8 93 PI *uint16 94 PJ *uint32 95 PK *uint64 96 PL *float32 97 PM *float64 98 PN *complex64 99 PO *complex128 100 PP *[]byte 101 PQ *big.Int 102 PR *big.Rat 103 PS *string 104 PT *time.Time 105 PU *time.Duration 106 } 107 108 testSchema9 struct { 109 i int 110 ID int64 `ql:"index xID"` 111 Other string `ql:"-"` 112 DepartmentName string `ql:"uindex xDepartmentName"` 113 } 114 ) 115 116 const ( 117 testSchemaSFFF = "begin transaction; create table if not exists testSchema (A int8); commit;" 118 testSchemaSFFT = "begin transaction; create table if not exists ql_testSchema (A int8); commit;" 119 testSchemaSFTF = "begin transaction; create table testSchema (A int8); commit;" 120 testSchemaSFTT = "begin transaction; create table ql_testSchema (A int8); commit;" 121 testSchemaSTFF = "create table if not exists testSchema (A int8)" 122 testSchemaSTFT = "create table if not exists ql_testSchema (A int8)" 123 testSchemaSTTF = "create table testSchema (A int8)" 124 testSchemaSTTT = "create table ql_testSchema (A int8)" 125 testSchema3S = "begin transaction; create table if not exists testSchema3 (ID uint64, A int8, cc bool); commit;" 126 testSchema4S = "begin transaction; create table if not exists testSchema4 (id int64, A int8, cc bool); commit;" 127 testSchema6S = "create table testSchema6 (A string); create index x on testSchema6 (A);" 128 testSchema7S = "begin transaction; create table testSchema7 (A int64, B string, C bool); create unique index x on testSchema7 (B); commit;" 129 testSchema8S = ` 130 begin transaction; 131 create table if not exists testSchema8 ( 132 A bool, 133 //B int64, 134 C int8, 135 D int16, 136 E int32, 137 F int64, 138 //G uint64, 139 H uint8, 140 I uint16, 141 J uint32, 142 K uint64, 143 L float32, 144 M float64, 145 N complex64, 146 O complex128, 147 P blob, 148 Q bigInt, 149 R bigRat, 150 S string, 151 T time, 152 U duration, 153 PA bool, 154 //PB int64, 155 PC int8, 156 PD int16, 157 PE int32, 158 PF int64, 159 //PG uint64, 160 PH uint8, 161 PI uint16, 162 PJ uint32, 163 PK uint64, 164 PL float32, 165 PM float64, 166 PN complex64, 167 PO complex128, 168 PP blob, 169 PQ bigInt, 170 PR bigRat, 171 PS string, 172 PT time, 173 PU duration, 174 ); 175 commit;` 176 testSchema9S = ` 177 begin transaction; 178 create table if not exists testSchema9 (DepartmentName string); 179 create index if not exists xID on testSchema9 (id()); 180 create unique index if not exists xDepartmentName on testSchema9 (DepartmentName); 181 commit;` 182 ) 183 184 func TestSchema(t *testing.T) { 185 tab := []struct { 186 inst interface{} 187 name string 188 opts *SchemaOptions 189 err bool 190 s string 191 }{ 192 // 0 193 {inst: nil, err: true}, 194 {inst: interface{}(nil), err: true}, 195 {testSchema{}, "", nil, false, testSchemaSFFF}, 196 {testSchema{}, "", &SchemaOptions{}, false, testSchemaSFFF}, 197 {testSchema{}, "", &SchemaOptions{KeepPrefix: true}, false, testSchemaSFFT}, 198 // 5 199 {testSchema{}, "", &SchemaOptions{NoIfNotExists: true}, false, testSchemaSFTF}, 200 {testSchema{}, "", &SchemaOptions{NoIfNotExists: true, KeepPrefix: true}, false, testSchemaSFTT}, 201 {testSchema{}, "", &SchemaOptions{NoTransaction: true}, false, testSchemaSTFF}, 202 {testSchema{}, "", &SchemaOptions{NoTransaction: true, KeepPrefix: true}, false, testSchemaSTFT}, 203 {testSchema{}, "", &SchemaOptions{NoTransaction: true, NoIfNotExists: true}, false, testSchemaSTTF}, 204 // 10 205 {testSchema{}, "", &SchemaOptions{NoTransaction: true, NoIfNotExists: true, KeepPrefix: true}, false, testSchemaSTTT}, 206 {testSchema2{}, "", nil, true, ""}, 207 {testSchema3{}, "", nil, false, testSchema3S}, 208 {testSchema4{}, "", nil, false, testSchema4S}, 209 {testSchema5{}, "", nil, true, ""}, 210 // 15 211 {testSchema6{}, "", &SchemaOptions{NoTransaction: true, NoIfNotExists: true}, false, testSchema6S}, 212 {testSchema7{}, "", &SchemaOptions{NoIfNotExists: true}, false, testSchema7S}, 213 {testSchema8{}, "", nil, false, testSchema8S}, 214 {&testSchema8{}, "", nil, false, testSchema8S}, 215 {&testSchema9{}, "", nil, false, testSchema9S}, 216 } 217 218 for iTest, test := range tab { 219 l, err := Schema(test.inst, test.name, test.opts) 220 if g, e := err != nil, test.err; g != e { 221 t.Fatal(iTest, g, e, err) 222 } 223 224 if err != nil { 225 t.Log(iTest, err) 226 continue 227 } 228 229 s, err := Compile(test.s) 230 if err != nil { 231 panic("internal error 055") 232 } 233 234 if g, e := l.String(), s.String(); g != e { 235 t.Fatalf("%d\n----\n%s\n----\n%s", iTest, g, e) 236 } 237 } 238 } 239 240 func ExampleSchema() { 241 type department struct { 242 a int // unexported -> ignored 243 ID int64 `ql:"index xID"` 244 Other string `xml:"-" ql:"-"` // ignored by QL tag 245 DepartmentName string `ql:"name Name, uindex xName" json:"foo"` 246 m bool 247 HQ int32 248 z string 249 } 250 251 schema := MustSchema((*department)(nil), "", nil) 252 sel := MustCompile(` 253 SELECT * FROM __Table WHERE !hasPrefix(Name, "__") ORDER BY Name; 254 SELECT * FROM __Column WHERE !hasPrefix(TableName, "__") ORDER BY TableName, Ordinal; 255 SELECT * FROM __Index WHERE !hasPrefix(TableName, "__") ORDER BY Name, ColumnName;`, 256 ) 257 fmt.Print(schema) 258 259 db, err := OpenMem() 260 if err != nil { 261 panic(err) 262 } 263 264 if _, _, err = db.Execute(NewRWCtx(), schema); err != nil { 265 panic(err) 266 } 267 268 rs, _, err := db.Execute(nil, sel) 269 if err != nil { 270 panic(err) 271 } 272 273 for _, rs := range rs { 274 fmt.Println("----") 275 if err = rs.Do(true, func(data []interface{}) (bool, error) { 276 fmt.Println(data) 277 return true, nil 278 }); err != nil { 279 panic(err) 280 } 281 } 282 // Output: 283 // BEGIN TRANSACTION; 284 // CREATE TABLE IF NOT EXISTS department (Name string, HQ int32); 285 // CREATE INDEX IF NOT EXISTS xID ON department (id()); 286 // CREATE UNIQUE INDEX IF NOT EXISTS xName ON department (Name); 287 // COMMIT; 288 // ---- 289 // [Name Schema] 290 // [department CREATE TABLE department (Name string, HQ int32);] 291 // ---- 292 // [TableName Ordinal Name Type] 293 // [department 1 Name string] 294 // [department 2 HQ int32] 295 // ---- 296 // [TableName ColumnName Name IsUnique] 297 // [department id() xID false] 298 // [department Name xName true] 299 } 300 301 func TestMarshal(t *testing.T) { 302 now := time.Now() 303 dur := time.Millisecond 304 schema8 := testSchema8{ 305 A: true, 306 //B: 1, 307 C: 2, 308 D: 3, 309 E: 4, 310 F: 5, 311 //G: 6, 312 H: 7, 313 I: 8, 314 J: 9, 315 K: 10, 316 L: 11, 317 M: 12, 318 N: -1, 319 O: -2, 320 P: []byte("abc"), 321 Q: *big.NewInt(1), 322 R: *big.NewRat(3, 2), 323 S: "string", 324 T: now, 325 U: dur, 326 } 327 schema8.PA = &schema8.A 328 //schema8.PB = &schema8.B 329 schema8.PC = &schema8.C 330 schema8.PD = &schema8.D 331 schema8.PE = &schema8.E 332 schema8.PF = &schema8.F 333 //schema8.PG = &schema8.G 334 schema8.PH = &schema8.H 335 schema8.PI = &schema8.I 336 schema8.PJ = &schema8.J 337 schema8.PK = &schema8.K 338 schema8.PL = &schema8.L 339 schema8.PM = &schema8.M 340 schema8.PN = &schema8.N 341 schema8.PO = &schema8.O 342 schema8.PP = &schema8.P 343 schema8.PQ = &schema8.Q 344 schema8.PR = &schema8.R 345 schema8.PS = &schema8.S 346 schema8.PT = &schema8.T 347 schema8.PU = &schema8.U 348 349 type u int 350 tab := []struct { 351 inst interface{} 352 err bool 353 r []interface{} 354 }{ 355 {42, true, nil}, 356 {new(u), true, nil}, 357 {testSchema8{}, false, []interface{}{ 358 false, 359 //int64(0), 360 int8(0), 361 int16(0), 362 int32(0), 363 int64(0), 364 //uint64(0), 365 uint8(0), 366 uint16(0), 367 uint32(0), 368 uint64(0), 369 float32(0), 370 float64(0), 371 complex64(0), 372 complex128(0), 373 []byte(nil), 374 big.Int{}, 375 big.Rat{}, 376 "", 377 time.Time{}, 378 time.Duration(0), 379 nil, 380 //nil, 381 nil, 382 nil, 383 nil, 384 nil, 385 //nil, 386 nil, 387 nil, 388 nil, 389 nil, 390 nil, 391 nil, 392 nil, 393 nil, 394 nil, 395 nil, 396 nil, 397 nil, 398 nil, 399 nil, 400 }}, 401 {&testSchema8{}, false, []interface{}{ 402 false, 403 //int64(0), 404 int8(0), 405 int16(0), 406 int32(0), 407 int64(0), 408 //uint64(0), 409 uint8(0), 410 uint16(0), 411 uint32(0), 412 uint64(0), 413 float32(0), 414 float64(0), 415 complex64(0), 416 complex128(0), 417 []byte(nil), 418 big.Int{}, 419 big.Rat{}, 420 "", 421 time.Time{}, 422 time.Duration(0), 423 nil, 424 //nil, 425 nil, 426 nil, 427 nil, 428 nil, 429 //nil, 430 nil, 431 nil, 432 nil, 433 nil, 434 nil, 435 nil, 436 nil, 437 nil, 438 nil, 439 nil, 440 nil, 441 nil, 442 nil, 443 nil, 444 }}, 445 {schema8, false, []interface{}{ 446 true, 447 //int64(1), 448 int8(2), 449 int16(3), 450 int32(4), 451 int64(5), 452 //uint64(6), 453 uint8(7), 454 uint16(8), 455 uint32(9), 456 uint64(10), 457 float32(11), 458 float64(12), 459 complex64(-1), 460 complex128(-2), 461 []byte("abc"), 462 *big.NewInt(1), 463 *big.NewRat(3, 2), 464 "string", 465 now, 466 dur, 467 true, 468 //int64(1), 469 int8(2), 470 int16(3), 471 int32(4), 472 int64(5), 473 //uint64(6), 474 uint8(7), 475 uint16(8), 476 uint32(9), 477 uint64(10), 478 float32(11), 479 float64(12), 480 complex64(-1), 481 complex128(-2), 482 []byte("abc"), 483 *big.NewInt(1), 484 *big.NewRat(3, 2), 485 "string", 486 now, 487 dur, 488 }}, 489 {&schema8, false, []interface{}{ 490 true, 491 //int64(1), 492 int8(2), 493 int16(3), 494 int32(4), 495 int64(5), 496 //uint64(6), 497 uint8(7), 498 uint16(8), 499 uint32(9), 500 uint64(10), 501 float32(11), 502 float64(12), 503 complex64(-1), 504 complex128(-2), 505 []byte("abc"), 506 *big.NewInt(1), 507 *big.NewRat(3, 2), 508 "string", 509 now, 510 dur, 511 true, 512 //int64(1), 513 int8(2), 514 int16(3), 515 int32(4), 516 int64(5), 517 //uint64(6), 518 uint8(7), 519 uint16(8), 520 uint32(9), 521 uint64(10), 522 float32(11), 523 float64(12), 524 complex64(-1), 525 complex128(-2), 526 []byte("abc"), 527 *big.NewInt(1), 528 *big.NewRat(3, 2), 529 "string", 530 now, 531 dur, 532 }}, 533 } 534 for iTest, test := range tab { 535 r, err := Marshal(test.inst) 536 if g, e := err != nil, test.err; g != e { 537 t.Fatal(iTest, g, e) 538 } 539 540 if err != nil { 541 t.Log(err) 542 continue 543 } 544 545 for i := 0; i < mathutil.Min(len(r), len(test.r)); i++ { 546 g, e := r[i], test.r[i] 547 use(e) 548 switch x := g.(type) { 549 case bool: 550 switch y := e.(type) { 551 case bool: 552 if x != y { 553 t.Fatal(iTest, x, y) 554 } 555 default: 556 t.Fatalf("%d: %T <-> %T", iTest, x, y) 557 } 558 case int: 559 switch y := e.(type) { 560 case int64: 561 if int64(x) != y { 562 t.Fatal(iTest, x, y) 563 } 564 default: 565 t.Fatalf("%d: %T <-> %T", iTest, x, y) 566 } 567 case int8: 568 switch y := e.(type) { 569 case int8: 570 if x != y { 571 t.Fatal(iTest, x, y) 572 } 573 default: 574 t.Fatalf("%d: %T <-> %T", iTest, x, y) 575 } 576 case int16: 577 switch y := e.(type) { 578 case int16: 579 if x != y { 580 t.Fatal(iTest, x, y) 581 } 582 default: 583 t.Fatalf("%d: %T <-> %T", iTest, x, y) 584 } 585 case int32: 586 switch y := e.(type) { 587 case int32: 588 if x != y { 589 t.Fatal(iTest, x, y) 590 } 591 default: 592 t.Fatalf("%d: %T <-> %T", iTest, x, y) 593 } 594 case int64: 595 switch y := e.(type) { 596 case int64: 597 if x != y { 598 t.Fatal(iTest, x, y) 599 } 600 default: 601 t.Fatalf("%d: %T <-> %T", iTest, x, y) 602 } 603 case uint: 604 switch y := e.(type) { 605 case uint64: 606 if uint64(x) != y { 607 t.Fatal(iTest, x, y) 608 } 609 default: 610 t.Fatalf("%d: %T <-> %T", iTest, x, y) 611 } 612 case uint8: 613 switch y := e.(type) { 614 case uint8: 615 if x != y { 616 t.Fatal(iTest, x, y) 617 } 618 default: 619 t.Fatalf("%d: %T <-> %T", iTest, x, y) 620 } 621 case uint16: 622 switch y := e.(type) { 623 case uint16: 624 if x != y { 625 t.Fatal(iTest, x, y) 626 } 627 default: 628 t.Fatalf("%d: %T <-> %T", iTest, x, y) 629 } 630 case uint32: 631 switch y := e.(type) { 632 case uint32: 633 if x != y { 634 t.Fatal(iTest, x, y) 635 } 636 default: 637 t.Fatalf("%d: %T <-> %T", iTest, x, y) 638 } 639 case uint64: 640 switch y := e.(type) { 641 case uint64: 642 if x != y { 643 t.Fatal(iTest, x, y) 644 } 645 default: 646 t.Fatalf("%d: %T <-> %T", iTest, x, y) 647 } 648 case float32: 649 switch y := e.(type) { 650 case float32: 651 if x != y { 652 t.Fatal(iTest, x, y) 653 } 654 default: 655 t.Fatalf("%d: %T <-> %T", iTest, x, y) 656 } 657 case float64: 658 switch y := e.(type) { 659 case float64: 660 if x != y { 661 t.Fatal(iTest, x, y) 662 } 663 default: 664 t.Fatalf("%d: %T <-> %T", iTest, x, y) 665 } 666 case complex64: 667 switch y := e.(type) { 668 case complex64: 669 if x != y { 670 t.Fatal(iTest, x, y) 671 } 672 default: 673 t.Fatalf("%d: %T <-> %T", iTest, x, y) 674 } 675 case complex128: 676 switch y := e.(type) { 677 case complex128: 678 if x != y { 679 t.Fatal(iTest, x, y) 680 } 681 default: 682 t.Fatalf("%d: %T <-> %T", iTest, x, y) 683 } 684 case []byte: 685 switch y := e.(type) { 686 case []byte: 687 if !bytes.Equal(x, y) { 688 t.Fatal(iTest, x, y) 689 } 690 default: 691 t.Fatalf("%d: %T <-> %T", iTest, x, y) 692 } 693 case big.Int: 694 switch y := e.(type) { 695 case big.Int: 696 if x.Cmp(&y) != 0 { 697 t.Fatal(iTest, &x, &y) 698 } 699 default: 700 t.Fatalf("%d: %T <-> %T", iTest, x, y) 701 } 702 case big.Rat: 703 switch y := e.(type) { 704 case big.Rat: 705 if x.Cmp(&y) != 0 { 706 t.Fatal(iTest, &x, &y) 707 } 708 default: 709 t.Fatalf("%d: %T <-> %T", iTest, x, y) 710 } 711 case string: 712 switch y := e.(type) { 713 case string: 714 if x != y { 715 t.Fatal(iTest, x, y) 716 } 717 default: 718 t.Fatalf("%d: %T <-> %T", iTest, x, y) 719 } 720 case time.Time: 721 switch y := e.(type) { 722 case time.Time: 723 if !x.Equal(y) { 724 t.Fatal(iTest, x, y) 725 } 726 default: 727 t.Fatalf("%d: %T <-> %T", iTest, x, y) 728 } 729 case time.Duration: 730 switch y := e.(type) { 731 case time.Duration: 732 if x != y { 733 t.Fatal(iTest, x, y) 734 } 735 default: 736 t.Fatalf("%d: %T <-> %T", iTest, x, y) 737 } 738 case nil: 739 switch y := e.(type) { 740 case nil: 741 // ok 742 default: 743 t.Fatalf("%d: %T <-> %T", iTest, x, y) 744 } 745 default: 746 panic(fmt.Errorf("%T", x)) 747 } 748 } 749 750 if g, e := len(r), len(test.r); g != e { 751 t.Fatal(iTest, g, e) 752 } 753 754 } 755 } 756 757 func ExampleMarshal() { 758 type myInt int16 759 760 type myString string 761 762 type item struct { 763 ID int64 764 Name myString 765 Qty *myInt // pointer enables nil values 766 Bar int8 767 } 768 769 schema := MustSchema((*item)(nil), "", nil) 770 ins := MustCompile(` 771 BEGIN TRANSACTION; 772 INSERT INTO item VALUES($1, $2, $3); 773 COMMIT;`, 774 ) 775 776 db, err := OpenMem() 777 if err != nil { 778 panic(err) 779 } 780 781 ctx := NewRWCtx() 782 if _, _, err := db.Execute(ctx, schema); err != nil { 783 panic(err) 784 } 785 786 if _, _, err := db.Execute(ctx, ins, MustMarshal(&item{Name: "foo", Bar: -1})...); err != nil { 787 panic(err) 788 } 789 790 q := myInt(42) 791 if _, _, err := db.Execute(ctx, ins, MustMarshal(&item{Name: "bar", Qty: &q})...); err != nil { 792 panic(err) 793 } 794 795 rs, _, err := db.Run(nil, "SELECT * FROM item ORDER BY id();") 796 if err != nil { 797 panic(err) 798 } 799 800 if err = rs[0].Do(true, func(data []interface{}) (bool, error) { 801 fmt.Println(data) 802 return true, nil 803 }); err != nil { 804 panic(err) 805 } 806 // Output: 807 // [Name Qty Bar] 808 // [foo <nil> -1] 809 // [bar 42 0] 810 } 811 812 func TestUnmarshal0(t *testing.T) { 813 type t1 struct { 814 I, J int64 815 } 816 817 // ---- value field 818 v1 := &t1{-1, -2} 819 if err := Unmarshal(v1, []interface{}{int64(42), int64(314)}); err != nil { 820 t.Fatal(err) 821 } 822 823 if g, e := v1.I, int64(42); g != e { 824 t.Fatal(g, e) 825 } 826 827 if g, e := v1.J, int64(314); g != e { 828 t.Fatal(g, e) 829 } 830 831 type t2 struct { 832 P *int64 833 } 834 835 // ---- nil into nil ptr field 836 v2 := &t2{P: nil} 837 if err := Unmarshal(v2, []interface{}{nil}); err != nil { 838 t.Fatal(err) 839 } 840 841 if g, e := v2.P, (*int64)(nil); g != e { 842 t.Fatal(g, e) 843 } 844 845 v2 = &t2{P: nil} 846 if err := Unmarshal(v2, []interface{}{interface{}(nil)}); err != nil { 847 t.Fatal(err) 848 } 849 850 if g, e := v2.P, (*int64)(nil); g != e { 851 t.Fatal(g, e) 852 } 853 854 // ---- nil into non nil ptr field 855 i := int64(42) 856 v2 = &t2{P: &i} 857 if err := Unmarshal(v2, []interface{}{nil}); err != nil { 858 t.Fatal(err) 859 } 860 861 if g, e := v2.P, (*int64)(nil); g != e { 862 t.Fatal(g, e) 863 } 864 865 if g, e := i, int64(42); g != e { 866 t.Fatal(g, e) 867 } 868 869 v2 = &t2{P: &i} 870 if err := Unmarshal(v2, []interface{}{interface{}(nil)}); err != nil { 871 t.Fatal(err) 872 } 873 874 if g, e := v2.P, (*int64)(nil); g != e { 875 t.Fatal(g, e) 876 } 877 878 if g, e := i, int64(42); g != e { 879 t.Fatal(g, e) 880 } 881 882 // ---- non nil value into non nil ptr field 883 i = 42 884 v2 = &t2{P: &i} 885 if err := Unmarshal(v2, []interface{}{int64(314)}); err != nil { 886 t.Fatal(err) 887 } 888 889 if g, e := v2.P, &i; g != e { 890 t.Fatal(g, e) 891 } 892 893 if g, e := i, int64(314); g != e { 894 t.Fatal(g, e) 895 } 896 897 // ---- non nil value into nil ptr field 898 v2 = &t2{P: nil} 899 if err := Unmarshal(v2, []interface{}{int64(314)}); err != nil { 900 t.Fatal(err) 901 } 902 903 if g, e := v2.P != nil, true; g != e { 904 t.Fatal(g, e) 905 } 906 907 if g, e := *v2.P, int64(314); g != e { 908 t.Fatal(g, e) 909 } 910 } 911 912 func TestUnmarshal(t *testing.T) { 913 type myString string 914 915 type t1 struct { 916 A bool 917 B myString 918 } 919 920 type t2 struct { 921 A bool 922 ID int64 923 B myString 924 } 925 926 f := func(v interface{}) int64 { 927 if x, ok := v.(*t2); ok { 928 return x.ID 929 } 930 931 return -1 932 } 933 934 tab := []struct { 935 inst interface{} 936 data []interface{} 937 err bool 938 }{ 939 // 0 940 {t1{}, []interface{}{true, "foo"}, true}, // not a ptr 941 {&t1{}, []interface{}{true}, true}, // too few values 942 {&t1{}, []interface{}{"foo"}, true}, // too few values 943 {&t1{}, []interface{}{true, "foo", 42}, true}, // too many values 944 {&t1{}, []interface{}{"foo", true, 42}, true}, // too many values 945 // 5 946 {&t1{}, []interface{}{true, "foo"}, false}, 947 {&t1{}, []interface{}{false, "bar"}, false}, 948 {&t1{}, []interface{}{"bar", "baz"}, true}, 949 {&t1{}, []interface{}{true, 42.7}, true}, 950 {&t2{}, []interface{}{1}, true}, // too few values 951 // 10 952 {&t2{}, []interface{}{1, 2, 3, 4}, true}, // too many values 953 {&t2{}, []interface{}{false, int64(314), "foo"}, false}, 954 {&t2{}, []interface{}{true, int64(42), "foo"}, false}, 955 {&t2{}, []interface{}{false, "foo"}, false}, 956 // 15 957 {&t2{}, []interface{}{true, "foo"}, false}, 958 } 959 960 for iTest, test := range tab { 961 inst := test.inst 962 err := Unmarshal(inst, test.data) 963 if g, e := err != nil, test.err; g != e { 964 t.Fatal(iTest, g, e) 965 } 966 967 if err != nil { 968 t.Log(iTest, err) 969 continue 970 } 971 972 data, err := Marshal(inst) 973 if err != nil { 974 t.Fatal(iTest, err) 975 } 976 977 if g, e := len(data), len(test.data); g > e { 978 t.Fatal(iTest, g, e) 979 } 980 981 j := 0 982 for _, v := range data { 983 v2 := test.data[j] 984 j++ 985 if _, ok := v2.(int64); ok { 986 if g, e := f(inst), v2; g != e { 987 t.Fatal(iTest, g, e) 988 } 989 990 continue 991 } 992 993 if g, e := v, v2; g != e { 994 t.Fatal(iTest, g, e) 995 } 996 } 997 } 998 } 999 1000 func ExampleUnmarshal() { 1001 type myString string 1002 1003 type row struct { 1004 ID int64 1005 S myString 1006 P *int64 1007 } 1008 1009 schema := MustSchema((*row)(nil), "", nil) 1010 ins := MustCompile(` 1011 BEGIN TRANSACTION; 1012 INSERT INTO row VALUES($1, $2); 1013 COMMIT;`, 1014 ) 1015 sel := MustCompile(` 1016 SELECT id(), S, P FROM row ORDER by id(); 1017 SELECT * FROM row ORDER by id();`, 1018 ) 1019 1020 db, err := OpenMem() 1021 if err != nil { 1022 panic(err) 1023 } 1024 1025 ctx := NewRWCtx() 1026 if _, _, err = db.Execute(ctx, schema); err != nil { 1027 panic(err) 1028 } 1029 1030 r := &row{S: "foo"} 1031 if _, _, err = db.Execute(ctx, ins, MustMarshal(r)...); err != nil { 1032 panic(err) 1033 } 1034 1035 i42 := int64(42) 1036 r = &row{S: "bar", P: &i42} 1037 if _, _, err = db.Execute(ctx, ins, MustMarshal(r)...); err != nil { 1038 panic(err) 1039 } 1040 1041 rs, _, err := db.Execute(nil, sel) 1042 if err != nil { 1043 panic(err) 1044 } 1045 1046 for _, rs := range rs { 1047 fmt.Println("----") 1048 if err := rs.Do(false, func(data []interface{}) (bool, error) { 1049 r := &row{} 1050 if err := Unmarshal(r, data); err != nil { 1051 return false, err 1052 } 1053 1054 fmt.Printf("ID %d, S %q, P ", r.ID, r.S) 1055 switch r.P == nil { 1056 case true: 1057 fmt.Println("<nil>") 1058 default: 1059 fmt.Println(*r.P) 1060 } 1061 return true, nil 1062 }); err != nil { 1063 panic(err) 1064 } 1065 } 1066 // Output: 1067 // ---- 1068 // ID 1, S "foo", P <nil> 1069 // ID 2, S "bar", P 42 1070 // ---- 1071 // ID 0, S "foo", P <nil> 1072 // ID 0, S "bar", P 42 1073 }