| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // adapted from github.com/golang/appengine/datastore | 5 // adapted from github.com/golang/appengine/datastore |
| 6 | 6 |
| 7 package datastore | 7 package datastore |
| 8 | 8 |
| 9 import ( | 9 import ( |
| 10 "bytes" | 10 "bytes" |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 117 | 117 |
| 118 type G0 struct { | 118 type G0 struct { |
| 119 G GeoPoint | 119 G GeoPoint |
| 120 } | 120 } |
| 121 | 121 |
| 122 type G1 struct { | 122 type G1 struct { |
| 123 G []GeoPoint | 123 G []GeoPoint |
| 124 } | 124 } |
| 125 | 125 |
| 126 type K0 struct { | 126 type K0 struct { |
| 127 » K Key | 127 » K *Key |
| 128 } | 128 } |
| 129 | 129 |
| 130 type K1 struct { | 130 type K1 struct { |
| 131 » K []Key | 131 » K []*Key |
| 132 } | 132 } |
| 133 | 133 |
| 134 type N0 struct { | 134 type N0 struct { |
| 135 X0 | 135 X0 |
| 136 ID int64 `gae:"$id"` | 136 ID int64 `gae:"$id"` |
| 137 _kind string `gae:"$kind,whatnow"` | 137 _kind string `gae:"$kind,whatnow"` |
| 138 Nonymous X0 | 138 Nonymous X0 |
| 139 Ignore string `gae:"-"` | 139 Ignore string `gae:"-"` |
| 140 Other string | 140 Other string |
| 141 } | 141 } |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 324 } | 324 } |
| 325 | 325 |
| 326 type Underspecified struct { | 326 type Underspecified struct { |
| 327 Iface PropertyConverter | 327 Iface PropertyConverter |
| 328 } | 328 } |
| 329 | 329 |
| 330 type MismatchTypes struct { | 330 type MismatchTypes struct { |
| 331 S string | 331 S string |
| 332 B bool | 332 B bool |
| 333 F float32 | 333 F float32 |
| 334 » K Key | 334 » K *Key |
| 335 T time.Time | 335 T time.Time |
| 336 G GeoPoint | 336 G GeoPoint |
| 337 IS []int | 337 IS []int |
| 338 } | 338 } |
| 339 | 339 |
| 340 type BadMeta struct { | 340 type BadMeta struct { |
| 341 ID int64 `gae:"$id"` | 341 ID int64 `gae:"$id"` |
| 342 id string `gae:"$id"` | 342 id string `gae:"$id"` |
| 343 } | 343 } |
| 344 | 344 |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 520 *c = Complex(complex(gval.Lat, gval.Lng)) | 520 *c = Complex(complex(gval.Lat, gval.Lng)) |
| 521 return nil | 521 return nil |
| 522 } | 522 } |
| 523 return fmt.Errorf("nope") | 523 return fmt.Errorf("nope") |
| 524 } | 524 } |
| 525 | 525 |
| 526 type Impossible4 struct { | 526 type Impossible4 struct { |
| 527 Values []Complex | 527 Values []Complex |
| 528 } | 528 } |
| 529 | 529 |
| 530 // TODO(riannucci): see if there's a way to NOT have this be a duplicate of | |
| 531 // key.Generic. I couldn't figure out the package interdependency, and this | |
| 532 // allows things to be in separate packages. | |
| 533 type genericKey struct { | |
| 534 kind string | |
| 535 sid string | |
| 536 iid int64 | |
| 537 | |
| 538 aid string | |
| 539 ns string | |
| 540 | |
| 541 parent *genericKey | |
| 542 } | |
| 543 | |
| 544 func (g *genericKey) Kind() string { return g.kind } | |
| 545 func (g *genericKey) StringID() string { return g.sid } | |
| 546 func (g *genericKey) IntID() int64 { return g.iid } | |
| 547 func (g *genericKey) AppID() string { return g.aid } | |
| 548 func (g *genericKey) Namespace() string { return g.ns } | |
| 549 func (g *genericKey) Parent() Key { return g.parent } | |
| 550 | |
| 551 func marshalDSKey(b *bytes.Buffer, k *genericKey) { | |
| 552 if k.parent != nil { | |
| 553 marshalDSKey(b, k.parent) | |
| 554 } | |
| 555 b.WriteByte('/') | |
| 556 b.WriteString(k.kind) | |
| 557 b.WriteByte(',') | |
| 558 if k.sid != "" { | |
| 559 b.WriteString(k.sid) | |
| 560 } else { | |
| 561 b.WriteString(strconv.FormatInt(k.iid, 10)) | |
| 562 } | |
| 563 } | |
| 564 | |
| 565 func (g *genericKey) String() string { | |
| 566 if g == nil { | |
| 567 return "" | |
| 568 } | |
| 569 b := bytes.NewBuffer(make([]byte, 0, 512)) | |
| 570 marshalDSKey(b, g) | |
| 571 return b.String() | |
| 572 } | |
| 573 | |
| 574 func (g *genericKey) Incomplete() bool { | |
| 575 return g.iid == 0 && g.sid == "" | |
| 576 } | |
| 577 | |
| 578 func (g *genericKey) Valid(allowSpecial bool, aid, ns string) bool { | |
| 579 if g == nil { | |
| 580 return false | |
| 581 } | |
| 582 if aid != g.AppID() || ns != g.Namespace() { | |
| 583 return false | |
| 584 } | |
| 585 for ; g != nil; g = g.parent { | |
| 586 if !allowSpecial && len(g.Kind()) >= 2 && g.Kind()[:2] == "__" { | |
| 587 return false | |
| 588 } | |
| 589 if g.Kind() == "" || g.AppID() == "" { | |
| 590 return false | |
| 591 } | |
| 592 if g.StringID() != "" && g.IntID() != 0 { | |
| 593 return false | |
| 594 } | |
| 595 if g.parent != nil { | |
| 596 if g.parent.Incomplete() { | |
| 597 return false | |
| 598 } | |
| 599 if g.parent.AppID() != g.AppID() || g.parent.Namespace()
!= g.Namespace() { | |
| 600 return false | |
| 601 } | |
| 602 } | |
| 603 } | |
| 604 return true | |
| 605 } | |
| 606 | |
| 607 func (g *genericKey) PartialValid(aid, ns string) bool { | |
| 608 if g.Incomplete() { | |
| 609 g = mkKey(g.AppID(), g.Namespace(), g.Kind(), 1, g.Parent()).(*g
enericKey) | |
| 610 } | |
| 611 return g.Valid(false, aid, ns) | |
| 612 } | |
| 613 | |
| 614 var _ Key = (*genericKey)(nil) | |
| 615 | |
| 616 func mkKey(aid, ns string, pairs ...interface{}) Key { | |
| 617 ret := (*genericKey)(nil) | |
| 618 if len(pairs)%2 != 0 { | |
| 619 ret, _ = pairs[len(pairs)-1].(*genericKey) | |
| 620 pairs = pairs[:len(pairs)-1] | |
| 621 } | |
| 622 for i := 0; i < len(pairs); i += 2 { | |
| 623 kind := pairs[i].(string) | |
| 624 id := pairs[i+1] | |
| 625 ret = &genericKey{ | |
| 626 kind: kind, | |
| 627 aid: aid, | |
| 628 ns: ns, | |
| 629 parent: ret, | |
| 630 } | |
| 631 ret.sid, _ = id.(string) | |
| 632 iid, ok := id.(int) | |
| 633 if ok { | |
| 634 ret.iid = int64(iid) | |
| 635 } else { | |
| 636 ret.iid, _ = id.(int64) | |
| 637 } | |
| 638 } | |
| 639 return ret | |
| 640 } | |
| 641 | |
| 642 type DerivedKey struct { | 530 type DerivedKey struct { |
| 643 » K *genericKey | 531 » K *Key |
| 644 } | 532 } |
| 645 | 533 |
| 646 type IfaceKey struct { | 534 type IfaceKey struct { |
| 647 » K Key | 535 » K *Key |
| 648 } | 536 } |
| 649 | 537 |
| 650 type testCase struct { | 538 type testCase struct { |
| 651 desc string | 539 desc string |
| 652 src interface{} | 540 src interface{} |
| 653 want interface{} | 541 want interface{} |
| 654 plsErr string | 542 plsErr string |
| 655 saveErr string | 543 saveErr string |
| 656 plsLoadErr string | 544 plsLoadErr string |
| 657 loadErr string | 545 loadErr string |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 728 src: &K0{K: testKey2a}, | 616 src: &K0{K: testKey2a}, |
| 729 want: &K0{K: testKey2b}, | 617 want: &K0{K: testKey2b}, |
| 730 }, | 618 }, |
| 731 { | 619 { |
| 732 desc: "nil key", | 620 desc: "nil key", |
| 733 src: &K0{}, | 621 src: &K0{}, |
| 734 want: &K0{}, | 622 want: &K0{}, |
| 735 }, | 623 }, |
| 736 { | 624 { |
| 737 desc: "all nil keys in slice", | 625 desc: "all nil keys in slice", |
| 738 » » src: &K1{[]Key{nil, nil}}, | 626 » » src: &K1{[]*Key{nil, nil}}, |
| 739 » » want: &K1{[]Key{nil, nil}}, | 627 » » want: &K1{[]*Key{nil, nil}}, |
| 740 }, | 628 }, |
| 741 { | 629 { |
| 742 desc: "some nil keys in slice", | 630 desc: "some nil keys in slice", |
| 743 » » src: &K1{[]Key{testKey1a, nil, testKey2a}}, | 631 » » src: &K1{[]*Key{testKey1a, nil, testKey2a}}, |
| 744 » » want: &K1{[]Key{testKey1b, nil, testKey2b}}, | 632 » » want: &K1{[]*Key{testKey1b, nil, testKey2b}}, |
| 745 }, | 633 }, |
| 746 { | 634 { |
| 747 desc: "overflow", | 635 desc: "overflow", |
| 748 src: &O0{I: 1 << 48}, | 636 src: &O0{I: 1 << 48}, |
| 749 want: &O1{}, | 637 want: &O1{}, |
| 750 loadErr: "overflow", | 638 loadErr: "overflow", |
| 751 }, | 639 }, |
| 752 { | 640 { |
| 753 desc: "time", | 641 desc: "time", |
| 754 src: &T{T: time.Unix(1e9, 0).UTC()}, | 642 src: &T{T: time.Unix(1e9, 0).UTC()}, |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 902 mp(GeoPoint{Lat: 1, Lng: 2}), mp(GeoPoint{Lat: 3
, Lng: 4})}, | 790 mp(GeoPoint{Lat: 1, Lng: 2}), mp(GeoPoint{Lat: 3
, Lng: 4})}, |
| 903 }, | 791 }, |
| 904 }, | 792 }, |
| 905 { | 793 { |
| 906 desc: "convertable complex slice (bad load)", | 794 desc: "convertable complex slice (bad load)", |
| 907 src: PropertyMap{"Values": {mp("hello")}}, | 795 src: PropertyMap{"Values": {mp("hello")}}, |
| 908 want: &Impossible4{[]Complex(nil)}, | 796 want: &Impossible4{[]Complex(nil)}, |
| 909 loadErr: "nope", | 797 loadErr: "nope", |
| 910 }, | 798 }, |
| 911 { | 799 { |
| 912 » » desc: "allow concrete Key implementors (save)", | 800 » » desc: "allow concrete *Key implementors (save)", |
| 913 » » src: &DerivedKey{testKey2a.(*genericKey)}, | 801 » » src: &DerivedKey{testKey2a}, |
| 914 want: &IfaceKey{testKey2b}, | 802 want: &IfaceKey{testKey2b}, |
| 915 }, | 803 }, |
| 916 { | 804 { |
| 917 » » desc: "allow concrete Key implementors (load)", | 805 » » desc: "allow concrete *Key implementors (load)", |
| 918 src: &IfaceKey{testKey2b}, | 806 src: &IfaceKey{testKey2b}, |
| 919 » » want: &DerivedKey{testKey2a.(*genericKey)}, | 807 » » want: &DerivedKey{testKey2a}, |
| 920 }, | 808 }, |
| 921 { | 809 { |
| 922 desc: "save []float64 load []int64", | 810 desc: "save []float64 load []int64", |
| 923 src: &Y0{B: true, F: []float64{7, 8, 9}}, | 811 src: &Y0{B: true, F: []float64{7, 8, 9}}, |
| 924 want: &Y2{B: true}, | 812 want: &Y2{B: true}, |
| 925 loadErr: "type mismatch", | 813 loadErr: "type mismatch", |
| 926 }, | 814 }, |
| 927 { | 815 { |
| 928 desc: "single slice is too long", | 816 desc: "single slice is too long", |
| 929 src: &Y0{F: make([]float64, maxIndexedProperties+1)}, | 817 src: &Y0{F: make([]float64, maxIndexedProperties+1)}, |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1096 mp(nil), | 984 mp(nil), |
| 1097 mp(7), | 985 mp(7), |
| 1098 mp(nil), | 986 mp(nil), |
| 1099 }, | 987 }, |
| 1100 }, | 988 }, |
| 1101 want: &struct { | 989 want: &struct { |
| 1102 I int64 | 990 I int64 |
| 1103 B bool | 991 B bool |
| 1104 S string | 992 S string |
| 1105 F float64 | 993 F float64 |
| 1106 » » » K Key | 994 » » » K *Key |
| 1107 T time.Time | 995 T time.Time |
| 1108 J []int64 | 996 J []int64 |
| 1109 }{ | 997 }{ |
| 1110 J: []int64{0, 7, 0}, | 998 J: []int64{0, 7, 0}, |
| 1111 }, | 999 }, |
| 1112 }, | 1000 }, |
| 1113 { | 1001 { |
| 1114 desc: "save outer load props", | 1002 desc: "save outer load props", |
| 1115 src: &Outer{ | 1003 src: &Outer{ |
| 1116 A: 1, | 1004 A: 1, |
| (...skipping 706 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1823 | 1711 |
| 1824 Convey("Bad default meta type", func() { | 1712 Convey("Bad default meta type", func() { |
| 1825 type BadDefault struct { | 1713 type BadDefault struct { |
| 1826 Val time.Time `gae:"$meta,tomorrow"` | 1714 Val time.Time `gae:"$meta,tomorrow"` |
| 1827 } | 1715 } |
| 1828 pls := GetPLS(&BadDefault{}) | 1716 pls := GetPLS(&BadDefault{}) |
| 1829 So(pls.Problem().Error(), ShouldContainSubstring, "bad t
ype") | 1717 So(pls.Problem().Error(), ShouldContainSubstring, "bad t
ype") |
| 1830 }) | 1718 }) |
| 1831 }) | 1719 }) |
| 1832 } | 1720 } |
| OLD | NEW |