예제 #1
0
// 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.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 {
				return nil, nilKeyErrStr
			}
			pv.Referencevalue = keyToReferenceValue(defaultAppID, k)
		} else {
			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),
	}
	switch v.Interface().(type) {
	case []byte:
		p.Meaning = pb.NewProperty_Meaning(pb.Property_BLOB)
	case appengine.BlobKey:
		p.Meaning = pb.NewProperty_Meaning(pb.Property_BLOBKEY)
	case Time:
		p.Meaning = pb.NewProperty_Meaning(pb.Property_GD_WHEN)
	}
	return p, ""
}
예제 #2
0
파일: save.go 프로젝트: Bobberino/musings
// valueToProto converts a named value to a newly allocated Property.
// The returned error string is empty on success.
func valueToProto(name string, value interface{}, multiple bool) (p *pb.Property, err error) {
	var (
		pv          pb.PropertyValue
		unsupported bool
	)
	v := reflect.ValueOf(value)
	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(k)
			}
		} else {
			unsupported = true
		}
	case reflect.Struct:
		if t, ok := v.Interface().(time.Time); ok {
			if t.Before(minTime) || t.After(maxTime) {
				return nil, errors.New("time value out of range")
			}
			pv.Int64Value = proto.Int64(t.UnixNano() / 1e3)
		} else {
			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, fmt.Errorf("unsupported datastore value type: %v",
			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.NewProperty_Meaning(pb.Property_BLOB)
		case appengine.BlobKey:
			p.Meaning = pb.NewProperty_Meaning(pb.Property_BLOBKEY)
		case time.Time:
			p.Meaning = pb.NewProperty_Meaning(pb.Property_GD_WHEN)
		}
	}
	return p, nil
}
예제 #3
0
파일: save.go 프로젝트: Bobberino/musings
func propertiesToProto(key *Key, src <-chan Property) (*pb.EntityProto, error) {
	defer func() {
		for _ = range src {
			// Drain the src channel, if we exit early.
		}
	}()
	e := &pb.EntityProto{
		Key: keyToProto(key),
	}
	if key.parent == nil {
		e.EntityGroup = &pb.Path{}
	} else {
		e.EntityGroup = keyToProto(key.root()).Path
	}
	prevMultiple := make(map[string]bool)

	for p := range src {
		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)
		case float64:
			x.Value.DoubleValue = proto.Float64(v)
		case *Key:
			if v != nil {
				x.Value.Referencevalue = keyToReferenceValue(v)
			}
		case time.Time:
			if v.Before(minTime) || v.After(maxTime) {
				return nil, errors.New("datastore: time value out of range")
			}
			x.Value.Int64Value = proto.Int64(v.UnixNano() / 1e3)
			x.Meaning = pb.NewProperty_Meaning(pb.Property_GD_WHEN)
		case appengine.BlobKey:
			x.Value.StringValue = proto.String(string(v))
			x.Meaning = pb.NewProperty_Meaning(pb.Property_BLOBKEY)
		case []byte:
			x.Value.StringValue = proto.String(string(v))
			x.Meaning = pb.NewProperty_Meaning(pb.Property_BLOB)
			if !p.NoIndex {
				return nil, fmt.Errorf("datastore: cannot index a []byte valued Property with Name %q", p.Name)
			}
		default:
			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
}