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 |