| 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 package datastore | 5 package datastore |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "errors" | 8 "errors" |
| 9 "fmt" | 9 "fmt" |
| 10 "math" | 10 "math" |
| 11 "reflect" | 11 "reflect" |
| 12 "time" | 12 "time" |
| 13 | 13 |
| 14 "github.com/luci/gae/service/blobstore" | 14 "github.com/luci/gae/service/blobstore" |
| 15 ) | 15 ) |
| 16 | 16 |
| 17 var ( | 17 var ( |
| 18 minTime = time.Unix(int64(math.MinInt64)/1e6, (int64(math.MinInt64)%1e6)
*1e3) | 18 minTime = time.Unix(int64(math.MinInt64)/1e6, (int64(math.MinInt64)%1e6)
*1e3) |
| 19 maxTime = time.Unix(int64(math.MaxInt64)/1e6, (int64(math.MaxInt64)%1e6)
*1e3) | 19 maxTime = time.Unix(int64(math.MaxInt64)/1e6, (int64(math.MaxInt64)%1e6)
*1e3) |
| 20 |
| 21 utcTestTime = time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC) |
| 20 ) | 22 ) |
| 21 | 23 |
| 22 // IndexSetting indicates whether or not a Property should be indexed by the | 24 // IndexSetting indicates whether or not a Property should be indexed by the |
| 23 // datastore. | 25 // datastore. |
| 24 type IndexSetting bool | 26 type IndexSetting bool |
| 25 | 27 |
| 26 // ShouldIndex is the default, which is why it must assume the zero value, | 28 // ShouldIndex is the default, which is why it must assume the zero value, |
| 27 // even though it's werid :(. | 29 // even though it's werid :(. |
| 28 const ( | 30 const ( |
| 29 ShouldIndex IndexSetting = false | 31 ShouldIndex IndexSetting = false |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 case string: | 201 case string: |
| 200 return PTString, nil | 202 return PTString, nil |
| 201 case Key: | 203 case Key: |
| 202 // TODO(riannucci): Check key for validity in its own namespace? | 204 // TODO(riannucci): Check key for validity in its own namespace? |
| 203 return PTKey, nil | 205 return PTKey, nil |
| 204 case time.Time: | 206 case time.Time: |
| 205 err := error(nil) | 207 err := error(nil) |
| 206 if checkValid && (x.Before(minTime) || x.After(maxTime)) { | 208 if checkValid && (x.Before(minTime) || x.After(maxTime)) { |
| 207 err = errors.New("time value out of range") | 209 err = errors.New("time value out of range") |
| 208 } | 210 } |
| 209 » » if checkValid && x.Location() != time.UTC { | 211 » » if checkValid && !timeLocationIsUTC(x.Location()) { |
| 210 » » » err = fmt.Errorf("time value has wrong Location: %s", x.
Location()) | 212 » » » err = fmt.Errorf("time value has wrong Location: %v %v",
x.Location()) |
| 211 } | 213 } |
| 212 return PTTime, err | 214 return PTTime, err |
| 213 case GeoPoint: | 215 case GeoPoint: |
| 214 err := error(nil) | 216 err := error(nil) |
| 215 if checkValid && !x.Valid() { | 217 if checkValid && !x.Valid() { |
| 216 err = errors.New("invalid GeoPoint value") | 218 err = errors.New("invalid GeoPoint value") |
| 217 } | 219 } |
| 218 return PTGeoPoint, err | 220 return PTGeoPoint, err |
| 219 default: | 221 default: |
| 220 return PTUnknown, fmt.Errorf("gae: Property has bad type %T", v) | 222 return PTUnknown, fmt.Errorf("gae: Property has bad type %T", v) |
| 221 } | 223 } |
| 222 } | 224 } |
| 223 | 225 |
| 226 // timeLocationsEqual tests if two time.Location are equal. |
| 227 // |
| 228 // This is tricky using the standard time API, as time is implicitly normalized |
| 229 // to UTC and all equality checks are performed relative to that normalized |
| 230 // time. To compensate, we instantiate two new time.Time using the respective |
| 231 // Locations. |
| 232 func timeLocationIsUTC(l *time.Location) bool { |
| 233 return time.Date(1970, 1, 1, 0, 0, 0, 0, l).Equal(utcTestTime) |
| 234 } |
| 235 |
| 224 // UpconvertUnderlyingType takes an object o, and attempts to convert it to | 236 // UpconvertUnderlyingType takes an object o, and attempts to convert it to |
| 225 // its native datastore-compatible type. e.g. int16 will convert to int64, and | 237 // its native datastore-compatible type. e.g. int16 will convert to int64, and |
| 226 // `type Foo string` will convert to `string`. | 238 // `type Foo string` will convert to `string`. |
| 227 func UpconvertUnderlyingType(o interface{}) interface{} { | 239 func UpconvertUnderlyingType(o interface{}) interface{} { |
| 228 if o == nil { | 240 if o == nil { |
| 229 return o | 241 return o |
| 230 } | 242 } |
| 231 | 243 |
| 232 v := reflect.ValueOf(o) | 244 v := reflect.ValueOf(o) |
| 233 t := v.Type() | 245 t := v.Type() |
| (...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 486 dflt = UpconvertUnderlyingType(dflt) | 498 dflt = UpconvertUnderlyingType(dflt) |
| 487 cur, err := gm(key) | 499 cur, err := gm(key) |
| 488 if err != nil { | 500 if err != nil { |
| 489 return dflt | 501 return dflt |
| 490 } | 502 } |
| 491 if dflt != nil && reflect.TypeOf(cur) != reflect.TypeOf(dflt) { | 503 if dflt != nil && reflect.TypeOf(cur) != reflect.TypeOf(dflt) { |
| 492 return dflt | 504 return dflt |
| 493 } | 505 } |
| 494 return cur | 506 return cur |
| 495 } | 507 } |
| OLD | NEW |