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 13 matching lines...) Expand all Loading... |
358 if err != nil { | 358 if err != nil { |
359 return nil, err | 359 return nil, err |
360 } | 360 } |
361 | 361 |
362 // Edit that map and send it on. | 362 // Edit that map and send it on. |
363 for _, props := range propMap { | 363 for _, props := range propMap { |
364 for i := range props { | 364 for i := range props { |
365 switch v := props[i].Value().(type) { | 365 switch v := props[i].Value().(type) { |
366 case string: | 366 case string: |
367 // + means string concatenation. | 367 // + means string concatenation. |
368 » » » » props[i].SetValue(v+v, props[i].IndexSetting()) | 368 » » » » So(props[i].SetValue(v+v, props[i].IndexSetting(
)), ShouldBeNil) |
369 case int64: | 369 case int64: |
370 // + means integer addition. | 370 // + means integer addition. |
371 » » » » props[i].SetValue(v+v, props[i].IndexSetting()) | 371 » » » » So(props[i].SetValue(v+v, props[i].IndexSetting(
)), ShouldBeNil) |
372 } | 372 } |
373 } | 373 } |
374 } | 374 } |
375 return propMap, nil | 375 return propMap, nil |
376 } | 376 } |
377 | 377 |
378 func (d *Doubler) GetMeta(string) (interface{}, error) { retur
n nil, ErrMetaFieldUnset } | 378 func (d *Doubler) GetMeta(string) (interface{}, error) { retur
n nil, ErrMetaFieldUnset } |
379 func (d *Doubler) GetMetaDefault(_ string, dflt interface{}) interface{} { retur
n dflt } | 379 func (d *Doubler) GetMetaDefault(_ string, dflt interface{}) interface{} { retur
n dflt } |
380 func (d *Doubler) SetMeta(string, interface{}) error { retur
n ErrMetaFieldUnset } | 380 func (d *Doubler) SetMeta(string, interface{}) error { retur
n ErrMetaFieldUnset } |
381 func (d *Doubler) Problem() error { retur
n nil } | 381 func (d *Doubler) Problem() error { retur
n nil } |
(...skipping 138 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 |