aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/google.golang.org/appengine/datastore/save.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/google.golang.org/appengine/datastore/save.go')
-rw-r--r--vendor/google.golang.org/appengine/datastore/save.go333
1 files changed, 0 insertions, 333 deletions
diff --git a/vendor/google.golang.org/appengine/datastore/save.go b/vendor/google.golang.org/appengine/datastore/save.go
deleted file mode 100644
index 7b045a5..0000000
--- a/vendor/google.golang.org/appengine/datastore/save.go
+++ /dev/null
@@ -1,333 +0,0 @@
-// Copyright 2011 Google Inc. All rights reserved.
-// Use of this source code is governed by the Apache 2.0
-// license that can be found in the LICENSE file.
-
-package datastore
-
-import (
- "errors"
- "fmt"
- "math"
- "reflect"
- "time"
-
- "github.com/golang/protobuf/proto"
-
- "google.golang.org/appengine"
- pb "google.golang.org/appengine/internal/datastore"
-)
-
-func toUnixMicro(t time.Time) int64 {
- // We cannot use t.UnixNano() / 1e3 because we want to handle times more than
- // 2^63 nanoseconds (which is about 292 years) away from 1970, and those cannot
- // be represented in the numerator of a single int64 divide.
- return t.Unix()*1e6 + int64(t.Nanosecond()/1e3)
-}
-
-func fromUnixMicro(t int64) time.Time {
- return time.Unix(t/1e6, (t%1e6)*1e3).UTC()
-}
-
-var (
- minTime = time.Unix(int64(math.MinInt64)/1e6, (int64(math.MinInt64)%1e6)*1e3)
- maxTime = time.Unix(int64(math.MaxInt64)/1e6, (int64(math.MaxInt64)%1e6)*1e3)
-)
-
-// valueToProto converts a named value to a newly allocated Property.
-// The returned error string is empty on success.
-func valueToProto(defaultAppID, name string, v reflect.Value, multiple bool) (p *pb.Property, errStr string) {
- var (
- pv pb.PropertyValue
- unsupported bool
- )
- switch v.Kind() {
- case reflect.Invalid:
- // No-op.
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- pv.Int64Value = proto.Int64(v.Int())
- case reflect.Bool:
- pv.BooleanValue = proto.Bool(v.Bool())
- case reflect.String:
- pv.StringValue = proto.String(v.String())
- case reflect.Float32, reflect.Float64:
- pv.DoubleValue = proto.Float64(v.Float())
- case reflect.Ptr:
- if k, ok := v.Interface().(*Key); ok {
- if k != nil {
- pv.Referencevalue = keyToReferenceValue(defaultAppID, k)
- }
- } else {
- unsupported = true
- }
- case reflect.Struct:
- switch t := v.Interface().(type) {
- case time.Time:
- if t.Before(minTime) || t.After(maxTime) {
- return nil, "time value out of range"
- }
- pv.Int64Value = proto.Int64(toUnixMicro(t))
- case appengine.GeoPoint:
- if !t.Valid() {
- return nil, "invalid GeoPoint value"
- }
- // NOTE: Strangely, latitude maps to X, longitude to Y.
- pv.Pointvalue = &pb.PropertyValue_PointValue{X: &t.Lat, Y: &t.Lng}
- default:
- unsupported = true
- }
- case reflect.Slice:
- if b, ok := v.Interface().([]byte); ok {
- pv.StringValue = proto.String(string(b))
- } else {
- // nvToProto should already catch slice values.
- // If we get here, we have a slice of slice values.
- unsupported = true
- }
- default:
- unsupported = true
- }
- if unsupported {
- return nil, "unsupported datastore value type: " + v.Type().String()
- }
- p = &pb.Property{
- Name: proto.String(name),
- Value: &pv,
- Multiple: proto.Bool(multiple),
- }
- if v.IsValid() {
- switch v.Interface().(type) {
- case []byte:
- p.Meaning = pb.Property_BLOB.Enum()
- case ByteString:
- p.Meaning = pb.Property_BYTESTRING.Enum()
- case appengine.BlobKey:
- p.Meaning = pb.Property_BLOBKEY.Enum()
- case time.Time:
- p.Meaning = pb.Property_GD_WHEN.Enum()
- case appengine.GeoPoint:
- p.Meaning = pb.Property_GEORSS_POINT.Enum()
- }
- }
- return p, ""
-}
-
-type saveOpts struct {
- noIndex bool
- multiple bool
- omitEmpty bool
-}
-
-// saveEntity saves an EntityProto into a PropertyLoadSaver or struct pointer.
-func saveEntity(defaultAppID string, key *Key, src interface{}) (*pb.EntityProto, error) {
- var err error
- var props []Property
- if e, ok := src.(PropertyLoadSaver); ok {
- props, err = e.Save()
- } else {
- props, err = SaveStruct(src)
- }
- if err != nil {
- return nil, err
- }
- return propertiesToProto(defaultAppID, key, props)
-}
-
-func saveStructProperty(props *[]Property, name string, opts saveOpts, v reflect.Value) error {
- if opts.omitEmpty && isEmptyValue(v) {
- return nil
- }
- p := Property{
- Name: name,
- NoIndex: opts.noIndex,
- Multiple: opts.multiple,
- }
- switch x := v.Interface().(type) {
- case *Key:
- p.Value = x
- case time.Time:
- p.Value = x
- case appengine.BlobKey:
- p.Value = x
- case appengine.GeoPoint:
- p.Value = x
- case ByteString:
- p.Value = x
- default:
- switch v.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- p.Value = v.Int()
- case reflect.Bool:
- p.Value = v.Bool()
- case reflect.String:
- p.Value = v.String()
- case reflect.Float32, reflect.Float64:
- p.Value = v.Float()
- case reflect.Slice:
- if v.Type().Elem().Kind() == reflect.Uint8 {
- p.NoIndex = true
- p.Value = v.Bytes()
- }
- case reflect.Struct:
- if !v.CanAddr() {
- return fmt.Errorf("datastore: unsupported struct field: value is unaddressable")
- }
- sub, err := newStructPLS(v.Addr().Interface())
- if err != nil {
- return fmt.Errorf("datastore: unsupported struct field: %v", err)
- }
- return sub.save(props, name+".", opts)
- }
- }
- if p.Value == nil {
- return fmt.Errorf("datastore: unsupported struct field type: %v", v.Type())
- }
- *props = append(*props, p)
- return nil
-}
-
-func (s structPLS) Save() ([]Property, error) {
- var props []Property
- if err := s.save(&props, "", saveOpts{}); err != nil {
- return nil, err
- }
- return props, nil
-}
-
-func (s structPLS) save(props *[]Property, prefix string, opts saveOpts) error {
- for name, f := range s.codec.fields {
- name = prefix + name
- v := s.v.FieldByIndex(f.path)
- if !v.IsValid() || !v.CanSet() {
- continue
- }
- var opts1 saveOpts
- opts1.noIndex = opts.noIndex || f.noIndex
- opts1.multiple = opts.multiple
- opts1.omitEmpty = f.omitEmpty // don't propagate
- // For slice fields that aren't []byte, save each element.
- if v.Kind() == reflect.Slice && v.Type().Elem().Kind() != reflect.Uint8 {
- opts1.multiple = true
- for j := 0; j < v.Len(); j++ {
- if err := saveStructProperty(props, name, opts1, v.Index(j)); err != nil {
- return err
- }
- }
- continue
- }
- // Otherwise, save the field itself.
- if err := saveStructProperty(props, name, opts1, v); err != nil {
- return err
- }
- }
- return nil
-}
-
-func propertiesToProto(defaultAppID string, key *Key, props []Property) (*pb.EntityProto, error) {
- e := &pb.EntityProto{
- Key: keyToProto(defaultAppID, key),
- }
- if key.parent == nil {
- e.EntityGroup = &pb.Path{}
- } else {
- e.EntityGroup = keyToProto(defaultAppID, key.root()).Path
- }
- prevMultiple := make(map[string]bool)
-
- for _, p := range props {
- if pm, ok := prevMultiple[p.Name]; ok {
- if !pm || !p.Multiple {
- return nil, fmt.Errorf("datastore: multiple Properties with Name %q, but Multiple is false", p.Name)
- }
- } else {
- prevMultiple[p.Name] = p.Multiple
- }
-
- x := &pb.Property{
- Name: proto.String(p.Name),
- Value: new(pb.PropertyValue),
- Multiple: proto.Bool(p.Multiple),
- }
- switch v := p.Value.(type) {
- case int64:
- x.Value.Int64Value = proto.Int64(v)
- case bool:
- x.Value.BooleanValue = proto.Bool(v)
- case string:
- x.Value.StringValue = proto.String(v)
- if p.NoIndex {
- x.Meaning = pb.Property_TEXT.Enum()
- }
- case float64:
- x.Value.DoubleValue = proto.Float64(v)
- case *Key:
- if v != nil {
- x.Value.Referencevalue = keyToReferenceValue(defaultAppID, v)
- }
- case time.Time:
- if v.Before(minTime) || v.After(maxTime) {
- return nil, fmt.Errorf("datastore: time value out of range")
- }
- x.Value.Int64Value = proto.Int64(toUnixMicro(v))
- x.Meaning = pb.Property_GD_WHEN.Enum()
- case appengine.BlobKey:
- x.Value.StringValue = proto.String(string(v))
- x.Meaning = pb.Property_BLOBKEY.Enum()
- case appengine.GeoPoint:
- if !v.Valid() {
- return nil, fmt.Errorf("datastore: invalid GeoPoint value")
- }
- // NOTE: Strangely, latitude maps to X, longitude to Y.
- x.Value.Pointvalue = &pb.PropertyValue_PointValue{X: &v.Lat, Y: &v.Lng}
- x.Meaning = pb.Property_GEORSS_POINT.Enum()
- case []byte:
- x.Value.StringValue = proto.String(string(v))
- x.Meaning = pb.Property_BLOB.Enum()
- if !p.NoIndex {
- return nil, fmt.Errorf("datastore: cannot index a []byte valued Property with Name %q", p.Name)
- }
- case ByteString:
- x.Value.StringValue = proto.String(string(v))
- x.Meaning = pb.Property_BYTESTRING.Enum()
- default:
- if p.Value != nil {
- return nil, fmt.Errorf("datastore: invalid Value type for a Property with Name %q", p.Name)
- }
- }
-
- if p.NoIndex {
- e.RawProperty = append(e.RawProperty, x)
- } else {
- e.Property = append(e.Property, x)
- if len(e.Property) > maxIndexedProperties {
- return nil, errors.New("datastore: too many indexed properties")
- }
- }
- }
- return e, nil
-}
-
-// isEmptyValue is taken from the encoding/json package in the standard library.
-func isEmptyValue(v reflect.Value) bool {
- switch v.Kind() {
- case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
- // TODO(perfomance): Only reflect.String needed, other property types are not supported (copy/paste from json package)
- return v.Len() == 0
- case reflect.Bool:
- return !v.Bool()
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return v.Int() == 0
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- // TODO(perfomance): Uint* are unsupported property types - should be removed (copy/paste from json package)
- return v.Uint() == 0
- case reflect.Float32, reflect.Float64:
- return v.Float() == 0
- case reflect.Interface, reflect.Ptr:
- return v.IsNil()
- case reflect.Struct:
- switch x := v.Interface().(type) {
- case time.Time:
- return x.IsZero()
- }
- }
- return false
-}