| 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 // HEAVILY adapted from github.com/golang/appengine/datastore | 5 // HEAVILY adapted from github.com/golang/appengine/datastore | 
| 6 | 6 | 
| 7 package helper | 7 package rawdatastore | 
| 8 | 8 | 
| 9 import ( | 9 import ( | 
| 10         "errors" | 10         "errors" | 
| 11         "fmt" | 11         "fmt" | 
| 12         "reflect" | 12         "reflect" | 
| 13         "strconv" | 13         "strconv" | 
| 14         "strings" | 14         "strings" | 
| 15         "sync" | 15         "sync" | 
| 16         "time" | 16         "time" | 
| 17         "unicode" | 17         "unicode" | 
| 18 | 18 | 
| 19         "github.com/luci/gae" | 19         "github.com/luci/gae" | 
|  | 20         "github.com/luci/gae/service/blobstore" | 
| 20 ) | 21 ) | 
| 21 | 22 | 
| 22 // Entities with more than this many indexed properties will not be saved. | 23 // Entities with more than this many indexed properties will not be saved. | 
| 23 const maxIndexedProperties = 20000 | 24 const maxIndexedProperties = 20000 | 
| 24 | 25 | 
| 25 var ( |  | 
| 26         typeOfDSKey               = reflect.TypeOf((*gae.DSKey)(nil)).Elem() |  | 
| 27         typeOfDSPropertyConverter = reflect.TypeOf((*gae.DSPropertyConverter)(ni
     l)).Elem() |  | 
| 28         typeOfGeoPoint            = reflect.TypeOf(gae.DSGeoPoint{}) |  | 
| 29         typeOfTime                = reflect.TypeOf(time.Time{}) |  | 
| 30         typeOfString              = reflect.TypeOf("") |  | 
| 31         typeOfInt64               = reflect.TypeOf(int64(0)) |  | 
| 32         typeOfBool                = reflect.TypeOf(true) |  | 
| 33 |  | 
| 34         valueOfnilDSKey = reflect.Zero(typeOfDSKey) |  | 
| 35 ) |  | 
| 36 |  | 
| 37 type structTag struct { | 26 type structTag struct { | 
| 38         name           string | 27         name           string | 
| 39 »       idxSetting     gae.IndexSetting | 28 »       idxSetting     IndexSetting | 
| 40         isSlice        bool | 29         isSlice        bool | 
| 41         substructCodec *structCodec | 30         substructCodec *structCodec | 
| 42         convert        bool | 31         convert        bool | 
| 43         metaVal        interface{} | 32         metaVal        interface{} | 
| 44         canSet         bool | 33         canSet         bool | 
| 45 } | 34 } | 
| 46 | 35 | 
| 47 type structCodec struct { | 36 type structCodec struct { | 
| 48         byMeta   map[string]int | 37         byMeta   map[string]int | 
| 49         byName   map[string]int | 38         byName   map[string]int | 
| 50         byIndex  []structTag | 39         byIndex  []structTag | 
| 51         hasSlice bool | 40         hasSlice bool | 
| 52         problem  error | 41         problem  error | 
| 53 } | 42 } | 
| 54 | 43 | 
| 55 type structPLS struct { | 44 type structPLS struct { | 
| 56         o reflect.Value | 45         o reflect.Value | 
| 57         c *structCodec | 46         c *structCodec | 
| 58 } | 47 } | 
| 59 | 48 | 
| 60 var _ gae.DSPropertyLoadSaver = (*structPLS)(nil) | 49 var _ PropertyLoadSaver = (*structPLS)(nil) | 
| 61 | 50 | 
| 62 // typeMismatchReason returns a string explaining why the property p could not | 51 // typeMismatchReason returns a string explaining why the property p could not | 
| 63 // be stored in an entity field of type v.Type(). | 52 // be stored in an entity field of type v.Type(). | 
| 64 func typeMismatchReason(val interface{}, v reflect.Value) string { | 53 func typeMismatchReason(val interface{}, v reflect.Value) string { | 
| 65         entityType := reflect.TypeOf(val) | 54         entityType := reflect.TypeOf(val) | 
| 66         return fmt.Sprintf("type mismatch: %s versus %v", entityType, v.Type()) | 55         return fmt.Sprintf("type mismatch: %s versus %v", entityType, v.Type()) | 
| 67 } | 56 } | 
| 68 | 57 | 
| 69 func (p *structPLS) Load(propMap gae.DSPropertyMap) error { | 58 func (p *structPLS) Load(propMap PropertyMap) error { | 
| 70         if err := p.Problem(); err != nil { | 59         if err := p.Problem(); err != nil { | 
| 71                 return err | 60                 return err | 
| 72         } | 61         } | 
| 73 | 62 | 
| 74         convFailures := gae.MultiError(nil) | 63         convFailures := gae.MultiError(nil) | 
| 75 | 64 | 
| 76         t := reflect.Type(nil) | 65         t := reflect.Type(nil) | 
| 77         for name, props := range propMap { | 66         for name, props := range propMap { | 
| 78                 multiple := len(props) > 1 | 67                 multiple := len(props) > 1 | 
| 79                 for i, prop := range props { | 68                 for i, prop := range props { | 
| 80                         if reason := loadInner(p.c, p.o, i, name, prop, multiple
     ); reason != "" { | 69                         if reason := loadInner(p.c, p.o, i, name, prop, multiple
     ); reason != "" { | 
| 81                                 if t == nil { | 70                                 if t == nil { | 
| 82                                         t = p.o.Type() | 71                                         t = p.o.Type() | 
| 83                                 } | 72                                 } | 
| 84 »       »       »       »       convFailures = append(convFailures, &gae.ErrDSFi
     eldMismatch{ | 73 »       »       »       »       convFailures = append(convFailures, &ErrFieldMis
     match{ | 
| 85                                         StructType: t, | 74                                         StructType: t, | 
| 86                                         FieldName:  name, | 75                                         FieldName:  name, | 
| 87                                         Reason:     reason, | 76                                         Reason:     reason, | 
| 88                                 }) | 77                                 }) | 
| 89                         } | 78                         } | 
| 90                 } | 79                 } | 
| 91         } | 80         } | 
| 92 | 81 | 
| 93         if len(convFailures) > 0 { | 82         if len(convFailures) > 0 { | 
| 94                 return convFailures | 83                 return convFailures | 
| 95         } | 84         } | 
| 96 | 85 | 
| 97         return nil | 86         return nil | 
| 98 } | 87 } | 
| 99 | 88 | 
| 100 func loadInner(codec *structCodec, structValue reflect.Value, index int, name st
     ring, p gae.DSProperty, requireSlice bool) string { | 89 func loadInner(codec *structCodec, structValue reflect.Value, index int, name st
     ring, p Property, requireSlice bool) string { | 
| 101         var v reflect.Value | 90         var v reflect.Value | 
| 102         // Traverse a struct's struct-typed fields. | 91         // Traverse a struct's struct-typed fields. | 
| 103         for { | 92         for { | 
| 104                 fieldIndex, ok := codec.byName[name] | 93                 fieldIndex, ok := codec.byName[name] | 
| 105                 if !ok { | 94                 if !ok { | 
| 106                         return "no such struct field" | 95                         return "no such struct field" | 
| 107                 } | 96                 } | 
| 108                 v = structValue.Field(fieldIndex) | 97                 v = structValue.Field(fieldIndex) | 
| 109 | 98 | 
| 110                 st := codec.byIndex[fieldIndex] | 99                 st := codec.byIndex[fieldIndex] | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
| 121                 } else { | 110                 } else { | 
| 122                         structValue = v | 111                         structValue = v | 
| 123                 } | 112                 } | 
| 124                 // Strip the "I." from "I.X". | 113                 // Strip the "I." from "I.X". | 
| 125                 name = name[len(st.name):] | 114                 name = name[len(st.name):] | 
| 126                 codec = st.substructCodec | 115                 codec = st.substructCodec | 
| 127         } | 116         } | 
| 128 | 117 | 
| 129         doConversion := func(v reflect.Value) (string, bool) { | 118         doConversion := func(v reflect.Value) (string, bool) { | 
| 130                 a := v.Addr() | 119                 a := v.Addr() | 
| 131 »       »       if conv, ok := a.Interface().(gae.DSPropertyConverter); ok { | 120 »       »       if conv, ok := a.Interface().(PropertyConverter); ok { | 
| 132 »       »       »       err := conv.FromDSProperty(p) | 121 »       »       »       err := conv.FromProperty(p) | 
| 133                         if err != nil { | 122                         if err != nil { | 
| 134                                 return err.Error(), true | 123                                 return err.Error(), true | 
| 135                         } | 124                         } | 
| 136                         return "", true | 125                         return "", true | 
| 137                 } | 126                 } | 
| 138                 return "", false | 127                 return "", false | 
| 139         } | 128         } | 
| 140 | 129 | 
| 141         if ret, ok := doConversion(v); ok { | 130         if ret, ok := doConversion(v); ok { | 
| 142                 return ret | 131                 return ret | 
| 143         } | 132         } | 
| 144 | 133 | 
| 145         var slice reflect.Value | 134         var slice reflect.Value | 
| 146         if v.Kind() == reflect.Slice && v.Type().Elem().Kind() != reflect.Uint8 
     { | 135         if v.Kind() == reflect.Slice && v.Type().Elem().Kind() != reflect.Uint8 
     { | 
| 147                 slice = v | 136                 slice = v | 
| 148                 v = reflect.New(v.Type().Elem()).Elem() | 137                 v = reflect.New(v.Type().Elem()).Elem() | 
| 149         } else if requireSlice { | 138         } else if requireSlice { | 
| 150                 return "multiple-valued property requires a slice field type" | 139                 return "multiple-valued property requires a slice field type" | 
| 151         } | 140         } | 
| 152 | 141 | 
| 153         pVal := p.Value() | 142         pVal := p.Value() | 
| 154 | 143 | 
| 155         if ret, ok := doConversion(v); ok { | 144         if ret, ok := doConversion(v); ok { | 
| 156                 if ret != "" { | 145                 if ret != "" { | 
| 157                         return ret | 146                         return ret | 
| 158                 } | 147                 } | 
| 159         } else { | 148         } else { | 
| 160                 knd := v.Kind() | 149                 knd := v.Kind() | 
| 161 »       »       if v.Type().Implements(typeOfDSKey) { | 150 »       »       if v.Type().Implements(typeOfKey) { | 
| 162                         knd = reflect.Interface | 151                         knd = reflect.Interface | 
| 163                 } | 152                 } | 
| 164                 switch knd { | 153                 switch knd { | 
| 165                 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, re
     flect.Int64: | 154                 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, re
     flect.Int64: | 
| 166                         x, ok := pVal.(int64) | 155                         x, ok := pVal.(int64) | 
| 167                         if !ok && pVal != nil { | 156                         if !ok && pVal != nil { | 
| 168                                 return typeMismatchReason(pVal, v) | 157                                 return typeMismatchReason(pVal, v) | 
| 169                         } | 158                         } | 
| 170                         if v.OverflowInt(x) { | 159                         if v.OverflowInt(x) { | 
| 171                                 return fmt.Sprintf("value %v overflows struct fi
     eld of type %v", x, v.Type()) | 160                                 return fmt.Sprintf("value %v overflows struct fi
     eld of type %v", x, v.Type()) | 
| 172                         } | 161                         } | 
| 173                         v.SetInt(x) | 162                         v.SetInt(x) | 
| 174                 case reflect.Bool: | 163                 case reflect.Bool: | 
| 175                         x, ok := pVal.(bool) | 164                         x, ok := pVal.(bool) | 
| 176                         if !ok && pVal != nil { | 165                         if !ok && pVal != nil { | 
| 177                                 return typeMismatchReason(pVal, v) | 166                                 return typeMismatchReason(pVal, v) | 
| 178                         } | 167                         } | 
| 179                         v.SetBool(x) | 168                         v.SetBool(x) | 
| 180                 case reflect.String: | 169                 case reflect.String: | 
| 181                         switch x := pVal.(type) { | 170                         switch x := pVal.(type) { | 
| 182 »       »       »       case gae.BSKey: | 171 »       »       »       case blobstore.Key: | 
| 183                                 v.SetString(string(x)) | 172                                 v.SetString(string(x)) | 
| 184                         case string: | 173                         case string: | 
| 185                                 v.SetString(x) | 174                                 v.SetString(x) | 
| 186                         default: | 175                         default: | 
| 187                                 if pVal != nil { | 176                                 if pVal != nil { | 
| 188                                         return typeMismatchReason(pVal, v) | 177                                         return typeMismatchReason(pVal, v) | 
| 189                                 } | 178                                 } | 
| 190                         } | 179                         } | 
| 191                 case reflect.Float32, reflect.Float64: | 180                 case reflect.Float32, reflect.Float64: | 
| 192                         x, ok := pVal.(float64) | 181                         x, ok := pVal.(float64) | 
| 193                         if !ok && pVal != nil { | 182                         if !ok && pVal != nil { | 
| 194                                 return typeMismatchReason(pVal, v) | 183                                 return typeMismatchReason(pVal, v) | 
| 195                         } | 184                         } | 
| 196                         if v.OverflowFloat(x) { | 185                         if v.OverflowFloat(x) { | 
| 197                                 return fmt.Sprintf("value %v overflows struct fi
     eld of type %v", x, v.Type()) | 186                                 return fmt.Sprintf("value %v overflows struct fi
     eld of type %v", x, v.Type()) | 
| 198                         } | 187                         } | 
| 199                         v.SetFloat(x) | 188                         v.SetFloat(x) | 
| 200                 case reflect.Interface: | 189                 case reflect.Interface: | 
| 201 »       »       »       x, ok := pVal.(gae.DSKey) | 190 »       »       »       x, ok := pVal.(Key) | 
| 202                         if !ok && pVal != nil { | 191                         if !ok && pVal != nil { | 
| 203                                 return typeMismatchReason(pVal, v) | 192                                 return typeMismatchReason(pVal, v) | 
| 204                         } | 193                         } | 
| 205                         if x != nil { | 194                         if x != nil { | 
| 206                                 v.Set(reflect.ValueOf(x)) | 195                                 v.Set(reflect.ValueOf(x)) | 
| 207                         } | 196                         } | 
| 208                 case reflect.Struct: | 197                 case reflect.Struct: | 
| 209                         switch v.Type() { | 198                         switch v.Type() { | 
| 210                         case typeOfTime: | 199                         case typeOfTime: | 
| 211                                 x, ok := pVal.(time.Time) | 200                                 x, ok := pVal.(time.Time) | 
| 212                                 if !ok && pVal != nil { | 201                                 if !ok && pVal != nil { | 
| 213                                         return typeMismatchReason(pVal, v) | 202                                         return typeMismatchReason(pVal, v) | 
| 214                                 } | 203                                 } | 
| 215                                 v.Set(reflect.ValueOf(x)) | 204                                 v.Set(reflect.ValueOf(x)) | 
| 216                         case typeOfGeoPoint: | 205                         case typeOfGeoPoint: | 
| 217 »       »       »       »       x, ok := pVal.(gae.DSGeoPoint) | 206 »       »       »       »       x, ok := pVal.(GeoPoint) | 
| 218                                 if !ok && pVal != nil { | 207                                 if !ok && pVal != nil { | 
| 219                                         return typeMismatchReason(pVal, v) | 208                                         return typeMismatchReason(pVal, v) | 
| 220                                 } | 209                                 } | 
| 221                                 v.Set(reflect.ValueOf(x)) | 210                                 v.Set(reflect.ValueOf(x)) | 
| 222                         default: | 211                         default: | 
| 223                                 panic(fmt.Errorf("helper: impossible: %s", typeM
     ismatchReason(pVal, v))) | 212                                 panic(fmt.Errorf("helper: impossible: %s", typeM
     ismatchReason(pVal, v))) | 
| 224                         } | 213                         } | 
| 225                 case reflect.Slice: | 214                 case reflect.Slice: | 
| 226                         switch x := pVal.(type) { | 215                         switch x := pVal.(type) { | 
| 227                         case []byte: | 216                         case []byte: | 
| 228                                 v.SetBytes(x) | 217                                 v.SetBytes(x) | 
| 229 »       »       »       case gae.DSByteString: | 218 »       »       »       case ByteString: | 
| 230                                 v.SetBytes([]byte(x)) | 219                                 v.SetBytes([]byte(x)) | 
| 231                         default: | 220                         default: | 
| 232                                 panic(fmt.Errorf("helper: impossible: %s", typeM
     ismatchReason(pVal, v))) | 221                                 panic(fmt.Errorf("helper: impossible: %s", typeM
     ismatchReason(pVal, v))) | 
| 233                         } | 222                         } | 
| 234                 default: | 223                 default: | 
| 235                         panic(fmt.Errorf("helper: impossible: %s", typeMismatchR
     eason(pVal, v))) | 224                         panic(fmt.Errorf("helper: impossible: %s", typeMismatchR
     eason(pVal, v))) | 
| 236                 } | 225                 } | 
| 237         } | 226         } | 
| 238         if slice.IsValid() { | 227         if slice.IsValid() { | 
| 239                 slice.Set(reflect.Append(slice, v)) | 228                 slice.Set(reflect.Append(slice, v)) | 
| 240         } | 229         } | 
| 241         return "" | 230         return "" | 
| 242 } | 231 } | 
| 243 | 232 | 
| 244 func (p *structPLS) Save(withMeta bool) (gae.DSPropertyMap, error) { | 233 func (p *structPLS) Save(withMeta bool) (PropertyMap, error) { | 
| 245         size := len(p.c.byName) | 234         size := len(p.c.byName) | 
| 246         if withMeta { | 235         if withMeta { | 
| 247                 size += len(p.c.byMeta) | 236                 size += len(p.c.byMeta) | 
| 248         } | 237         } | 
| 249 »       ret := make(gae.DSPropertyMap, size) | 238 »       ret := make(PropertyMap, size) | 
| 250 »       if _, err := p.save(ret, "", gae.ShouldIndex); err != nil { | 239 »       if _, err := p.save(ret, "", ShouldIndex); err != nil { | 
| 251                 return nil, err | 240                 return nil, err | 
| 252         } | 241         } | 
| 253         if withMeta { | 242         if withMeta { | 
| 254                 for k := range p.c.byMeta { | 243                 for k := range p.c.byMeta { | 
| 255                         val, err := p.GetMeta(k) | 244                         val, err := p.GetMeta(k) | 
| 256                         if err != nil { | 245                         if err != nil { | 
| 257                                 return nil, err // TODO(riannucci): should these
      be ignored? | 246                                 return nil, err // TODO(riannucci): should these
      be ignored? | 
| 258                         } | 247                         } | 
| 259 »       »       »       p := gae.DSProperty{} | 248 »       »       »       p := Property{} | 
| 260 »       »       »       if err = p.SetValue(val, gae.NoIndex); err != nil { | 249 »       »       »       if err = p.SetValue(val, NoIndex); err != nil { | 
| 261                                 return nil, err | 250                                 return nil, err | 
| 262                         } | 251                         } | 
| 263 »       »       »       ret["$"+k] = []gae.DSProperty{p} | 252 »       »       »       ret["$"+k] = []Property{p} | 
| 264                 } | 253                 } | 
| 265         } | 254         } | 
| 266         return ret, nil | 255         return ret, nil | 
| 267 } | 256 } | 
| 268 | 257 | 
| 269 func (p *structPLS) save(propMap gae.DSPropertyMap, prefix string, is gae.IndexS
     etting) (idxCount int, err error) { | 258 func (p *structPLS) save(propMap PropertyMap, prefix string, is IndexSetting) (i
     dxCount int, err error) { | 
| 270         if err = p.Problem(); err != nil { | 259         if err = p.Problem(); err != nil { | 
| 271                 return | 260                 return | 
| 272         } | 261         } | 
| 273 | 262 | 
| 274 »       saveProp := func(name string, si gae.IndexSetting, v reflect.Value, st *
     structTag) (err error) { | 263 »       saveProp := func(name string, si IndexSetting, v reflect.Value, st *stru
     ctTag) (err error) { | 
| 275                 if st.substructCodec != nil { | 264                 if st.substructCodec != nil { | 
| 276                         count, err := (&structPLS{v, st.substructCodec}).save(pr
     opMap, name, si) | 265                         count, err := (&structPLS{v, st.substructCodec}).save(pr
     opMap, name, si) | 
| 277                         if err == nil { | 266                         if err == nil { | 
| 278                                 idxCount += count | 267                                 idxCount += count | 
| 279                                 if idxCount > maxIndexedProperties { | 268                                 if idxCount > maxIndexedProperties { | 
| 280                                         err = errors.New("gae: too many indexed 
     properties") | 269                                         err = errors.New("gae: too many indexed 
     properties") | 
| 281                                 } | 270                                 } | 
| 282                         } | 271                         } | 
| 283                         return err | 272                         return err | 
| 284                 } | 273                 } | 
| 285 | 274 | 
| 286 »       »       prop := gae.DSProperty{} | 275 »       »       prop := Property{} | 
| 287                 if st.convert { | 276                 if st.convert { | 
| 288 »       »       »       prop, err = v.Addr().Interface().(gae.DSPropertyConverte
     r).ToDSProperty() | 277 »       »       »       prop, err = v.Addr().Interface().(PropertyConverter).ToP
     roperty() | 
| 289                 } else { | 278                 } else { | 
| 290                         err = prop.SetValue(v.Interface(), si) | 279                         err = prop.SetValue(v.Interface(), si) | 
| 291                 } | 280                 } | 
| 292                 if err != nil { | 281                 if err != nil { | 
| 293                         return err | 282                         return err | 
| 294                 } | 283                 } | 
| 295                 propMap[name] = append(propMap[name], prop) | 284                 propMap[name] = append(propMap[name], prop) | 
| 296 »       »       if prop.IndexSetting() == gae.ShouldIndex { | 285 »       »       if prop.IndexSetting() == ShouldIndex { | 
| 297                         idxCount++ | 286                         idxCount++ | 
| 298                         if idxCount > maxIndexedProperties { | 287                         if idxCount > maxIndexedProperties { | 
| 299                                 return errors.New("gae: too many indexed propert
     ies") | 288                                 return errors.New("gae: too many indexed propert
     ies") | 
| 300                         } | 289                         } | 
| 301                 } | 290                 } | 
| 302                 return nil | 291                 return nil | 
| 303         } | 292         } | 
| 304 | 293 | 
| 305         for i, st := range p.c.byIndex { | 294         for i, st := range p.c.byIndex { | 
| 306                 if st.name == "-" { | 295                 if st.name == "-" { | 
| 307                         continue | 296                         continue | 
| 308                 } | 297                 } | 
| 309                 name := st.name | 298                 name := st.name | 
| 310                 if prefix != "" { | 299                 if prefix != "" { | 
| 311                         name = prefix + name | 300                         name = prefix + name | 
| 312                 } | 301                 } | 
| 313                 v := p.o.Field(i) | 302                 v := p.o.Field(i) | 
| 314                 is1 := is | 303                 is1 := is | 
| 315 »       »       if st.idxSetting == gae.NoIndex { | 304 »       »       if st.idxSetting == NoIndex { | 
| 316 »       »       »       is1 = gae.NoIndex | 305 »       »       »       is1 = NoIndex | 
| 317                 } | 306                 } | 
| 318                 if st.isSlice { | 307                 if st.isSlice { | 
| 319                         for j := 0; j < v.Len(); j++ { | 308                         for j := 0; j < v.Len(); j++ { | 
| 320                                 if err = saveProp(name, is1, v.Index(j), &st); e
     rr != nil { | 309                                 if err = saveProp(name, is1, v.Index(j), &st); e
     rr != nil { | 
| 321                                         return | 310                                         return | 
| 322                                 } | 311                                 } | 
| 323                         } | 312                         } | 
| 324                 } else { | 313                 } else { | 
| 325                         if err = saveProp(name, is1, v, &st); err != nil { | 314                         if err = saveProp(name, is1, v, &st); err != nil { | 
| 326                                 return | 315                                 return | 
| 327                         } | 316                         } | 
| 328                 } | 317                 } | 
| 329         } | 318         } | 
| 330         return | 319         return | 
| 331 } | 320 } | 
| 332 | 321 | 
| 333 func (p *structPLS) GetMeta(key string) (interface{}, error) { | 322 func (p *structPLS) GetMeta(key string) (interface{}, error) { | 
| 334         if err := p.Problem(); err != nil { | 323         if err := p.Problem(); err != nil { | 
| 335                 return nil, err | 324                 return nil, err | 
| 336         } | 325         } | 
| 337         idx, ok := p.c.byMeta[key] | 326         idx, ok := p.c.byMeta[key] | 
| 338         if !ok { | 327         if !ok { | 
| 339 »       »       return nil, gae.ErrDSMetaFieldUnset | 328 »       »       return nil, ErrMetaFieldUnset | 
| 340         } | 329         } | 
| 341         st := p.c.byIndex[idx] | 330         st := p.c.byIndex[idx] | 
| 342         val := st.metaVal | 331         val := st.metaVal | 
| 343         f := p.o.Field(idx) | 332         f := p.o.Field(idx) | 
| 344         if st.canSet { | 333         if st.canSet { | 
| 345                 if !reflect.DeepEqual(reflect.Zero(f.Type()).Interface(), f.Inte
     rface()) { | 334                 if !reflect.DeepEqual(reflect.Zero(f.Type()).Interface(), f.Inte
     rface()) { | 
| 346                         val = f.Interface() | 335                         val = f.Interface() | 
| 347                 } | 336                 } | 
| 348         } | 337         } | 
| 349         return val, nil | 338         return val, nil | 
| 350 } | 339 } | 
| 351 | 340 | 
| 352 func (p *structPLS) SetMeta(key string, val interface{}) (err error) { | 341 func (p *structPLS) SetMeta(key string, val interface{}) (err error) { | 
| 353         if err = p.Problem(); err != nil { | 342         if err = p.Problem(); err != nil { | 
| 354                 return | 343                 return | 
| 355         } | 344         } | 
| 356         idx, ok := p.c.byMeta[key] | 345         idx, ok := p.c.byMeta[key] | 
| 357         if !ok { | 346         if !ok { | 
| 358 »       »       return gae.ErrDSMetaFieldUnset | 347 »       »       return ErrMetaFieldUnset | 
| 359         } | 348         } | 
| 360         if !p.c.byIndex[idx].canSet { | 349         if !p.c.byIndex[idx].canSet { | 
| 361                 return fmt.Errorf("gae/helper: cannot set meta %q: unexported fi
     eld", key) | 350                 return fmt.Errorf("gae/helper: cannot set meta %q: unexported fi
     eld", key) | 
| 362         } | 351         } | 
| 363         p.o.Field(idx).Set(reflect.ValueOf(val)) | 352         p.o.Field(idx).Set(reflect.ValueOf(val)) | 
| 364         return nil | 353         return nil | 
| 365 } | 354 } | 
| 366 | 355 | 
| 367 func (p *structPLS) Problem() error { return p.c.problem } | 356 func (p *structPLS) Problem() error { return p.c.problem } | 
| 368 | 357 | 
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 468                                 return | 457                                 return | 
| 469                         } | 458                         } | 
| 470                 } | 459                 } | 
| 471                 if !st.canSet { | 460                 if !st.canSet { | 
| 472                         st.name = "-" | 461                         st.name = "-" | 
| 473                         continue | 462                         continue | 
| 474                 } | 463                 } | 
| 475 | 464 | 
| 476                 substructType := reflect.Type(nil) | 465                 substructType := reflect.Type(nil) | 
| 477                 ft := f.Type | 466                 ft := f.Type | 
| 478 »       »       if reflect.PtrTo(ft).Implements(typeOfDSPropertyConverter) { | 467 »       »       if reflect.PtrTo(ft).Implements(typeOfPropertyConverter) { | 
| 479                         st.convert = true | 468                         st.convert = true | 
| 480                 } else { | 469                 } else { | 
| 481                         switch f.Type.Kind() { | 470                         switch f.Type.Kind() { | 
| 482                         case reflect.Struct: | 471                         case reflect.Struct: | 
| 483                                 if ft != typeOfTime && ft != typeOfGeoPoint { | 472                                 if ft != typeOfTime && ft != typeOfGeoPoint { | 
| 484                                         substructType = ft | 473                                         substructType = ft | 
| 485                                 } | 474                                 } | 
| 486                         case reflect.Slice: | 475                         case reflect.Slice: | 
| 487 »       »       »       »       if reflect.PtrTo(ft.Elem()).Implements(typeOfDSP
     ropertyConverter) { | 476 »       »       »       »       if reflect.PtrTo(ft.Elem()).Implements(typeOfPro
     pertyConverter) { | 
| 488                                         st.convert = true | 477                                         st.convert = true | 
| 489                                 } else if ft.Elem().Kind() == reflect.Struct { | 478                                 } else if ft.Elem().Kind() == reflect.Struct { | 
| 490                                         substructType = ft.Elem() | 479                                         substructType = ft.Elem() | 
| 491                                 } | 480                                 } | 
| 492                                 st.isSlice = ft.Elem().Kind() != reflect.Uint8 | 481                                 st.isSlice = ft.Elem().Kind() != reflect.Uint8 | 
| 493                                 c.hasSlice = c.hasSlice || st.isSlice | 482                                 c.hasSlice = c.hasSlice || st.isSlice | 
| 494                         case reflect.Interface: | 483                         case reflect.Interface: | 
| 495 »       »       »       »       if ft != typeOfDSKey { | 484 »       »       »       »       if ft != typeOfKey { | 
| 496                                         c.problem = me("field %q has non-concret
     e interface type %s", | 485                                         c.problem = me("field %q has non-concret
     e interface type %s", | 
| 497                                                 f.Name, f.Type) | 486                                                 f.Name, f.Type) | 
| 498                                         return | 487                                         return | 
| 499                                 } | 488                                 } | 
| 500                         } | 489                         } | 
| 501                 } | 490                 } | 
| 502 | 491 | 
| 503                 if substructType != nil { | 492                 if substructType != nil { | 
| 504                         sub := getStructCodecLocked(substructType) | 493                         sub := getStructCodecLocked(substructType) | 
| 505                         if sub.problem != nil { | 494                         if sub.problem != nil { | 
| (...skipping 23 matching lines...) Expand all  Loading... | 
| 529                                 } | 518                                 } | 
| 530                                 c.byName[absName] = i | 519                                 c.byName[absName] = i | 
| 531                         } | 520                         } | 
| 532                 } else { | 521                 } else { | 
| 533                         if !st.convert { // check the underlying static type of 
     the field | 522                         if !st.convert { // check the underlying static type of 
     the field | 
| 534                                 t := ft | 523                                 t := ft | 
| 535                                 if st.isSlice { | 524                                 if st.isSlice { | 
| 536                                         t = t.Elem() | 525                                         t = t.Elem() | 
| 537                                 } | 526                                 } | 
| 538                                 v := reflect.New(t).Elem().Interface() | 527                                 v := reflect.New(t).Elem().Interface() | 
| 539 »       »       »       »       v, _ = gae.DSUpconvertUnderlyingType(v, t) | 528 »       »       »       »       v, _ = UpconvertUnderlyingType(v, t) | 
| 540 »       »       »       »       if _, err := gae.DSPropertyTypeOf(v, false); err
      != nil { | 529 »       »       »       »       if _, err := PropertyTypeOf(v, false); err != ni
     l { | 
| 541                                         c.problem = me("field %q has invalid typ
     e: %s", name, ft) | 530                                         c.problem = me("field %q has invalid typ
     e: %s", name, ft) | 
| 542                                         return | 531                                         return | 
| 543                                 } | 532                                 } | 
| 544                         } | 533                         } | 
| 545 | 534 | 
| 546                         if _, ok := c.byName[name]; ok { | 535                         if _, ok := c.byName[name]; ok { | 
| 547                                 c.problem = me("struct tag has repeated property
      name: %q", name) | 536                                 c.problem = me("struct tag has repeated property
      name: %q", name) | 
| 548                                 return | 537                                 return | 
| 549                         } | 538                         } | 
| 550                         c.byName[name] = i | 539                         c.byName[name] = i | 
| 551                 } | 540                 } | 
| 552                 st.name = name | 541                 st.name = name | 
| 553                 if opts == "noindex" { | 542                 if opts == "noindex" { | 
| 554 »       »       »       st.idxSetting = gae.NoIndex | 543 »       »       »       st.idxSetting = NoIndex | 
| 555                 } | 544                 } | 
| 556         } | 545         } | 
| 557         if c.problem == errRecursiveStruct { | 546         if c.problem == errRecursiveStruct { | 
| 558                 c.problem = nil | 547                 c.problem = nil | 
| 559         } | 548         } | 
| 560         return | 549         return | 
| 561 } | 550 } | 
| 562 | 551 | 
| 563 func convertMeta(val string, t reflect.Type) (interface{}, error) { | 552 func convertMeta(val string, t reflect.Type) (interface{}, error) { | 
| 564         switch t { | 553         switch t { | 
| 565         case typeOfString: | 554         case typeOfString: | 
| 566                 return val, nil | 555                 return val, nil | 
| 567         case typeOfInt64: | 556         case typeOfInt64: | 
| 568                 if val == "" { | 557                 if val == "" { | 
| 569                         return int64(0), nil | 558                         return int64(0), nil | 
| 570                 } | 559                 } | 
| 571                 return strconv.ParseInt(val, 10, 64) | 560                 return strconv.ParseInt(val, 10, 64) | 
| 572         } | 561         } | 
| 573         return nil, fmt.Errorf("helper: meta field with bad type/value %s/%s", t
     , val) | 562         return nil, fmt.Errorf("helper: meta field with bad type/value %s/%s", t
     , val) | 
| 574 } | 563 } | 
| OLD | NEW | 
|---|