| 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 datastore | 7 package datastore |
| 8 | 8 |
| 9 import ( | 9 import ( |
| 10 "fmt" | 10 "fmt" |
| 11 "reflect" | 11 "reflect" |
| 12 "strconv" | 12 "strconv" |
| 13 "strings" | 13 "strings" |
| 14 "sync" | 14 "sync" |
| 15 "time" | |
| 16 "unicode" | 15 "unicode" |
| 17 | 16 |
| 18 "github.com/luci/gae/service/blobstore" | |
| 19 "github.com/luci/luci-go/common/errors" | 17 "github.com/luci/luci-go/common/errors" |
| 20 ) | 18 ) |
| 21 | 19 |
| 22 // Entities with more than this many indexed properties will not be saved. | 20 // Entities with more than this many indexed properties will not be saved. |
| 23 const maxIndexedProperties = 20000 | 21 const maxIndexedProperties = 20000 |
| 24 | 22 |
| 25 type structTag struct { | 23 type structTag struct { |
| 26 name string | 24 name string |
| 27 idxSetting IndexSetting | 25 idxSetting IndexSetting |
| 28 isSlice bool | 26 isSlice bool |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 131 } | 129 } |
| 132 | 130 |
| 133 var slice reflect.Value | 131 var slice reflect.Value |
| 134 if v.Kind() == reflect.Slice && v.Type().Elem().Kind() != reflect.Uint8
{ | 132 if v.Kind() == reflect.Slice && v.Type().Elem().Kind() != reflect.Uint8
{ |
| 135 slice = v | 133 slice = v |
| 136 v = reflect.New(v.Type().Elem()).Elem() | 134 v = reflect.New(v.Type().Elem()).Elem() |
| 137 } else if requireSlice { | 135 } else if requireSlice { |
| 138 return "multiple-valued property requires a slice field type" | 136 return "multiple-valued property requires a slice field type" |
| 139 } | 137 } |
| 140 | 138 |
| 141 pVal := p.Value() | |
| 142 | |
| 143 if ret, ok := doConversion(v); ok { | 139 if ret, ok := doConversion(v); ok { |
| 144 if ret != "" { | 140 if ret != "" { |
| 145 return ret | 141 return ret |
| 146 } | 142 } |
| 147 } else { | 143 } else { |
| 148 knd := v.Kind() | 144 knd := v.Kind() |
| 149 if v.Type().Implements(typeOfKey) { | 145 if v.Type().Implements(typeOfKey) { |
| 150 knd = reflect.Interface | 146 knd = reflect.Interface |
| 151 } | 147 } |
| 148 |
| 149 project := PTNull |
| 150 overflow := (func(interface{}) bool)(nil) |
| 151 set := (func(interface{}))(nil) |
| 152 |
| 152 switch knd { | 153 switch knd { |
| 153 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: |
| 154 » » » x, ok := pVal.(int64) | 155 » » » project = PTInt |
| 155 » » » if !ok && pVal != nil { | 156 » » » overflow = func(x interface{}) bool { return v.OverflowI
nt(x.(int64)) } |
| 156 » » » » return typeMismatchReason(pVal, v) | 157 » » » set = func(x interface{}) { v.SetInt(x.(int64)) } |
| 157 » » » } | |
| 158 » » » if v.OverflowInt(x) { | |
| 159 » » » » return fmt.Sprintf("value %v overflows struct fi
eld of type %v", x, v.Type()) | |
| 160 » » » } | |
| 161 » » » v.SetInt(x) | |
| 162 case reflect.Bool: | 158 case reflect.Bool: |
| 163 » » » x, ok := pVal.(bool) | 159 » » » project = PTBool |
| 164 » » » if !ok && pVal != nil { | 160 » » » set = func(x interface{}) { v.SetBool(x.(bool)) } |
| 165 » » » » return typeMismatchReason(pVal, v) | |
| 166 » » » } | |
| 167 » » » v.SetBool(x) | |
| 168 case reflect.String: | 161 case reflect.String: |
| 169 » » » switch x := pVal.(type) { | 162 » » » project = PTString |
| 170 » » » case blobstore.Key: | 163 » » » set = func(x interface{}) { v.SetString(x.(string)) } |
| 171 » » » » v.SetString(string(x)) | 164 » » case reflect.Float32, reflect.Float64: |
| 172 » » » case string: | 165 » » » project = PTFloat |
| 173 » » » » v.SetString(x) | 166 » » » overflow = func(x interface{}) bool { return v.OverflowF
loat(x.(float64)) } |
| 174 » » » default: | 167 » » » set = func(x interface{}) { v.SetFloat(x.(float64)) } |
| 175 » » » » if pVal != nil { | 168 » » case reflect.Interface: |
| 176 » » » » » return typeMismatchReason(pVal, v) | 169 » » » project = PTKey |
| 170 » » » set = func(x interface{}) { |
| 171 » » » » if k, ok := x.(Key); ok { |
| 172 » » » » » v.Set(reflect.ValueOf(k)) |
| 177 } | 173 } |
| 178 } | 174 } |
| 179 case reflect.Float32, reflect.Float64: | |
| 180 x, ok := pVal.(float64) | |
| 181 if !ok && pVal != nil { | |
| 182 return typeMismatchReason(pVal, v) | |
| 183 } | |
| 184 if v.OverflowFloat(x) { | |
| 185 return fmt.Sprintf("value %v overflows struct fi
eld of type %v", x, v.Type()) | |
| 186 } | |
| 187 v.SetFloat(x) | |
| 188 case reflect.Interface: | |
| 189 x, ok := pVal.(Key) | |
| 190 if !ok && pVal != nil { | |
| 191 return typeMismatchReason(pVal, v) | |
| 192 } | |
| 193 if x != nil { | |
| 194 v.Set(reflect.ValueOf(x)) | |
| 195 } | |
| 196 case reflect.Struct: | 175 case reflect.Struct: |
| 197 switch v.Type() { | 176 switch v.Type() { |
| 198 case typeOfTime: | 177 case typeOfTime: |
| 199 » » » » x, ok := pVal.(time.Time) | 178 » » » » project = PTTime |
| 200 » » » » if !ok && pVal != nil { | 179 » » » » set = func(x interface{}) { v.Set(reflect.ValueO
f(x)) } |
| 201 » » » » » return typeMismatchReason(pVal, v) | |
| 202 » » » » } | |
| 203 » » » » v.Set(reflect.ValueOf(x)) | |
| 204 case typeOfGeoPoint: | 180 case typeOfGeoPoint: |
| 205 » » » » x, ok := pVal.(GeoPoint) | 181 » » » » project = PTGeoPoint |
| 206 » » » » if !ok && pVal != nil { | 182 » » » » set = func(x interface{}) { v.Set(reflect.ValueO
f(x)) } |
| 207 » » » » » return typeMismatchReason(pVal, v) | |
| 208 » » » » } | |
| 209 » » » » v.Set(reflect.ValueOf(x)) | |
| 210 default: | 183 default: |
| 211 » » » » panic(fmt.Errorf("helper: impossible: %s", typeM
ismatchReason(pVal, v))) | 184 » » » » panic(fmt.Errorf("helper: impossible: %s", typeM
ismatchReason(p.value, v))) |
| 212 } | 185 } |
| 213 case reflect.Slice: | 186 case reflect.Slice: |
| 214 » » » switch x := pVal.(type) { | 187 » » » project = PTBytes |
| 215 » » » case []byte: | 188 » » » set = func(x interface{}) { |
| 216 » » » » v.SetBytes(x) | 189 » » » » v.SetBytes(reflect.ValueOf(x).Bytes()) |
| 217 » » » case ByteString: | |
| 218 » » » » v.SetBytes([]byte(x)) | |
| 219 » » » default: | |
| 220 » » » » panic(fmt.Errorf("helper: impossible: %s", typeM
ismatchReason(pVal, v))) | |
| 221 } | 190 } |
| 222 default: | 191 default: |
| 223 » » » panic(fmt.Errorf("helper: impossible: %s", typeMismatchR
eason(pVal, v))) | 192 » » » panic(fmt.Errorf("helper: impossible: %s", typeMismatchR
eason(p.value, v))) |
| 224 } | 193 } |
| 194 |
| 195 pVal, err := p.Project(project) |
| 196 if err != nil { |
| 197 return typeMismatchReason(p.value, v) |
| 198 } |
| 199 if overflow != nil && overflow(pVal) { |
| 200 return fmt.Sprintf("value %v overflows struct field of t
ype %v", pVal, v.Type()) |
| 201 } |
| 202 set(pVal) |
| 225 } | 203 } |
| 226 if slice.IsValid() { | 204 if slice.IsValid() { |
| 227 slice.Set(reflect.Append(slice, v)) | 205 slice.Set(reflect.Append(slice, v)) |
| 228 } | 206 } |
| 229 return "" | 207 return "" |
| 230 } | 208 } |
| 231 | 209 |
| 232 func (p *structPLS) Save(withMeta bool) (PropertyMap, error) { | 210 func (p *structPLS) Save(withMeta bool) (PropertyMap, error) { |
| 233 size := len(p.c.byName) | 211 size := len(p.c.byName) |
| 234 if withMeta { | 212 if withMeta { |
| (...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 595 switch val { | 573 switch val { |
| 596 case "on", "On", "true": | 574 case "on", "On", "true": |
| 597 return true, nil | 575 return true, nil |
| 598 case "off", "Off", "false": | 576 case "off", "Off", "false": |
| 599 return false, nil | 577 return false, nil |
| 600 } | 578 } |
| 601 return nil, fmt.Errorf("Toggle field has bad/missing default, go
t %q", val) | 579 return nil, fmt.Errorf("Toggle field has bad/missing default, go
t %q", val) |
| 602 } | 580 } |
| 603 return nil, fmt.Errorf("helper: meta field with bad type/value %s/%q", t
, val) | 581 return nil, fmt.Errorf("helper: meta field with bad type/value %s/%q", t
, val) |
| 604 } | 582 } |
| OLD | NEW |