Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(663)

Unified Diff: go/src/infra/gae/libs/gae/helper/datastore_impl.go

Issue 1227183003: Change RawDatastore to do less reflection. (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@move_dummy
Patch Set: fix No/ShouldIndex Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « go/src/infra/gae/libs/gae/helper/datastore.go ('k') | go/src/infra/gae/libs/gae/helper/datastore_test.go » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: go/src/infra/gae/libs/gae/helper/datastore_impl.go
diff --git a/go/src/infra/gae/libs/gae/helper/datastore_impl.go b/go/src/infra/gae/libs/gae/helper/datastore_impl.go
index bfe066ea4871b9713e6ade287f3a284fe316d5e7..9e94217c920d39f6944c62087655c63bf664c0de 100644
--- a/go/src/infra/gae/libs/gae/helper/datastore_impl.go
+++ b/go/src/infra/gae/libs/gae/helper/datastore_impl.go
@@ -9,12 +9,14 @@ package helper
import (
"errors"
"fmt"
- "infra/gae/libs/gae"
"reflect"
+ "strconv"
"strings"
"sync"
"time"
"unicode"
+
+ "infra/gae/libs/gae"
)
// Entities with more than this many indexed properties will not be saved.
@@ -25,25 +27,29 @@ var (
typeOfDSPropertyConverter = reflect.TypeOf((*gae.DSPropertyConverter)(nil)).Elem()
typeOfGeoPoint = reflect.TypeOf(gae.DSGeoPoint{})
typeOfTime = reflect.TypeOf(time.Time{})
+ typeOfString = reflect.TypeOf("")
+ typeOfInt64 = reflect.TypeOf(int64(0))
+ typeOfBool = reflect.TypeOf(true)
valueOfnilDSKey = reflect.Zero(typeOfDSKey)
)
type structTag struct {
name string
- noIndex bool
+ idxSetting gae.IndexSetting
isSlice bool
substructCodec *structCodec
convert bool
- specialVal string
+ metaVal interface{}
+ canSet bool
}
type structCodec struct {
- bySpecial map[string]int
- byName map[string]int
- byIndex []structTag
- hasSlice bool
- problem error
+ byMeta map[string]int
+ byName map[string]int
+ byIndex []structTag
+ hasSlice bool
+ problem error
}
type structPLS struct {
@@ -51,7 +57,7 @@ type structPLS struct {
c *structCodec
}
-var _ gae.DSStructPLS = (*structPLS)(nil)
+var _ gae.DSPropertyLoadSaver = (*structPLS)(nil)
// typeMismatchReason returns a string explaining why the property p could not
// be stored in an entity field of type v.Type().
@@ -60,22 +66,35 @@ func typeMismatchReason(val interface{}, v reflect.Value) string {
return fmt.Sprintf("type mismatch: %s versus %v", entityType, v.Type())
}
-func (p *structPLS) Load(propMap gae.DSPropertyMap) (convFailures []string, fatal error) {
- if fatal = p.Problem(); fatal != nil {
- return
+func (p *structPLS) Load(propMap gae.DSPropertyMap) error {
+ if err := p.Problem(); err != nil {
+ return err
}
- t := p.o.Type()
+ convFailures := gae.MultiError(nil)
+
+ t := reflect.Type(nil)
for name, props := range propMap {
multiple := len(props) > 1
for i, prop := range props {
if reason := loadInner(p.c, p.o, i, name, prop, multiple); reason != "" {
- convFailures = append(convFailures, fmt.Sprintf(
- "cannot load field %q into a %q: %s", name, t, reason))
+ if t == nil {
+ t = p.o.Type()
+ }
+ convFailures = append(convFailures, &gae.ErrDSFieldMismatch{
+ StructType: t,
+ FieldName: name,
+ Reason: reason,
+ })
}
}
}
- return
+
+ if len(convFailures) > 0 {
+ return convFailures
+ }
+
+ return nil
}
func loadInner(codec *structCodec, structValue reflect.Value, index int, name string, p gae.DSProperty, requireSlice bool) string {
@@ -222,38 +241,61 @@ func loadInner(codec *structCodec, structValue reflect.Value, index int, name st
return ""
}
-func (p *structPLS) Save() (gae.DSPropertyMap, error) {
- ret := gae.DSPropertyMap{}
- idxCount := 0
- if err := p.save(ret, &idxCount, "", false); err != nil {
+func (p *structPLS) Save(withMeta bool) (gae.DSPropertyMap, error) {
+ size := len(p.c.byName)
+ if withMeta {
+ size += len(p.c.byMeta)
+ }
+ ret := make(gae.DSPropertyMap, size)
+ if _, err := p.save(ret, "", gae.ShouldIndex); err != nil {
return nil, err
}
+ if withMeta {
+ for k := range p.c.byMeta {
+ val, err := p.GetMeta(k)
+ if err != nil {
+ return nil, err // TODO(riannucci): should these be ignored?
+ }
+ p := gae.DSProperty{}
+ if err = p.SetValue(val, gae.NoIndex); err != nil {
+ return nil, err
+ }
+ ret["$"+k] = []gae.DSProperty{p}
+ }
+ }
return ret, nil
}
-func (p *structPLS) save(propMap gae.DSPropertyMap, idxCount *int, prefix string, noIndex bool) (err error) {
+func (p *structPLS) save(propMap gae.DSPropertyMap, prefix string, is gae.IndexSetting) (idxCount int, err error) {
if err = p.Problem(); err != nil {
return
}
- saveProp := func(name string, ni bool, v reflect.Value, st *structTag) (err error) {
+ saveProp := func(name string, si gae.IndexSetting, v reflect.Value, st *structTag) (err error) {
if st.substructCodec != nil {
- return (&structPLS{v, st.substructCodec}).save(propMap, idxCount, name, ni)
+ count, err := (&structPLS{v, st.substructCodec}).save(propMap, name, si)
+ if err == nil {
+ idxCount += count
+ if idxCount > maxIndexedProperties {
+ err = errors.New("gae: too many indexed properties")
+ }
+ }
+ return err
}
prop := gae.DSProperty{}
if st.convert {
prop, err = v.Addr().Interface().(gae.DSPropertyConverter).ToDSProperty()
} else {
- err = prop.SetValue(v.Interface(), ni)
+ err = prop.SetValue(v.Interface(), si)
}
if err != nil {
return err
}
propMap[name] = append(propMap[name], prop)
- if !prop.NoIndex() {
- *idxCount++
- if *idxCount > maxIndexedProperties {
+ if prop.IndexSetting() == gae.ShouldIndex {
+ idxCount++
+ if idxCount > maxIndexedProperties {
return errors.New("gae: too many indexed properties")
}
}
@@ -269,53 +311,55 @@ func (p *structPLS) save(propMap gae.DSPropertyMap, idxCount *int, prefix string
name = prefix + name
}
v := p.o.Field(i)
- noIndex1 := noIndex || st.noIndex
+ is1 := is
+ if st.idxSetting == gae.NoIndex {
+ is1 = gae.NoIndex
+ }
if st.isSlice {
for j := 0; j < v.Len(); j++ {
- if err := saveProp(name, noIndex1, v.Index(j), &st); err != nil {
- return err
+ if err = saveProp(name, is1, v.Index(j), &st); err != nil {
+ return
}
}
} else {
- if err := saveProp(name, noIndex1, v, &st); err != nil {
- return err
+ if err = saveProp(name, is1, v, &st); err != nil {
+ return
}
}
}
- return nil
+ return
}
-func (p *structPLS) GetSpecial(key string) (val string, current interface{}, err error) {
- if err = p.Problem(); err != nil {
- return
+func (p *structPLS) GetMeta(key string) (interface{}, error) {
+ if err := p.Problem(); err != nil {
+ return nil, err
}
- idx, ok := p.c.bySpecial[key]
+ idx, ok := p.c.byMeta[key]
if !ok {
- err = gae.ErrDSSpecialFieldUnset
- return
+ return nil, gae.ErrDSMetaFieldUnset
}
- val = p.c.byIndex[idx].specialVal
+ st := p.c.byIndex[idx]
+ val := st.metaVal
f := p.o.Field(idx)
- if f.CanSet() {
- current = f.Interface()
+ if st.canSet {
+ if !reflect.DeepEqual(reflect.Zero(f.Type()).Interface(), f.Interface()) {
+ val = f.Interface()
+ }
}
- return
+ return val, nil
}
-func (p *structPLS) SetSpecial(key string, val interface{}) (err error) {
+func (p *structPLS) SetMeta(key string, val interface{}) (err error) {
if err = p.Problem(); err != nil {
return
}
- idx, ok := p.c.bySpecial[key]
+ idx, ok := p.c.byMeta[key]
if !ok {
- return gae.ErrDSSpecialFieldUnset
+ return gae.ErrDSMetaFieldUnset
+ }
+ if !p.c.byIndex[idx].canSet {
+ return fmt.Errorf("gae/helper: cannot set meta %q: unexported field", key)
}
- defer func() {
- pv := recover()
- if pv != nil && err == nil {
- err = fmt.Errorf("gae/helper: cannot set special %q: %s", key, pv)
- }
- }()
p.o.Field(idx).Set(reflect.ValueOf(val))
return nil
}
@@ -372,17 +416,17 @@ func getStructCodecLocked(t reflect.Type) (c *structCodec) {
}
c = &structCodec{
- byIndex: make([]structTag, t.NumField()),
- byName: make(map[string]int, t.NumField()),
- bySpecial: make(map[string]int, t.NumField()),
- problem: errRecursiveStruct, // we'll clear this later if it's not recursive
+ byIndex: make([]structTag, t.NumField()),
+ byName: make(map[string]int, t.NumField()),
+ byMeta: make(map[string]int, t.NumField()),
+ problem: errRecursiveStruct, // we'll clear this later if it's not recursive
}
defer func() {
// If the codec has a problem, free up the indexes
if c.problem != nil {
c.byIndex = nil
c.byName = nil
- c.bySpecial = nil
+ c.byMeta = nil
}
}()
structCodecs[t] = c
@@ -395,6 +439,7 @@ func getStructCodecLocked(t reflect.Type) (c *structCodec) {
if i := strings.Index(name, ","); i != -1 {
name, opts = name[:i], name[i+1:]
}
+ st.canSet = f.PkgPath == "" // blank == exported
switch {
case name == "":
if !f.Anonymous {
@@ -402,12 +447,17 @@ func getStructCodecLocked(t reflect.Type) (c *structCodec) {
}
case name[0] == '$':
name = name[1:]
- if _, ok := c.bySpecial[name]; ok {
- c.problem = me("special field %q set multiple times", "$"+name)
+ if _, ok := c.byMeta[name]; ok {
+ c.problem = me("meta field %q set multiple times", "$"+name)
+ return
+ }
+ c.byMeta[name] = i
+ mv, err := convertMeta(opts, f.Type)
+ if err != nil {
+ c.problem = me("meta field %q has bad type: %s", "$"+name, err)
return
}
- c.bySpecial[name] = i
- st.specialVal = opts
+ st.metaVal = mv
fallthrough
case name == "-":
st.name = "-"
@@ -418,7 +468,7 @@ func getStructCodecLocked(t reflect.Type) (c *structCodec) {
return
}
}
- if f.PkgPath != "" { // field is unexported, so don't bother doing more.
+ if !st.canSet {
st.name = "-"
continue
}
@@ -500,10 +550,25 @@ func getStructCodecLocked(t reflect.Type) (c *structCodec) {
c.byName[name] = i
}
st.name = name
- st.noIndex = opts == "noindex"
+ if opts == "noindex" {
+ st.idxSetting = gae.NoIndex
+ }
}
if c.problem == errRecursiveStruct {
c.problem = nil
}
return
}
+
+func convertMeta(val string, t reflect.Type) (interface{}, error) {
+ switch t {
+ case typeOfString:
+ return val, nil
+ case typeOfInt64:
+ if val == "" {
+ return int64(0), nil
+ }
+ return strconv.ParseInt(val, 10, 64)
+ }
+ return nil, fmt.Errorf("helper: meta field with bad type/value %s/%s", t, val)
+}
« no previous file with comments | « go/src/infra/gae/libs/gae/helper/datastore.go ('k') | go/src/infra/gae/libs/gae/helper/datastore_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698