func keyToProto(k *Key) *pb.Key { if k == nil { return nil } // TODO(jbd): Eliminate unrequired allocations. path := []*pb.Key_PathElement(nil) for { el := &pb.Key_PathElement{ Kind: proto.String(k.kind), } if k.id != 0 { el.Id = proto.Int64(k.id) } if k.name != "" { el.Name = proto.String(k.name) } path = append([]*pb.Key_PathElement{el}, path...) if k.parent == nil { break } k = k.parent } key := &pb.Key{ PathElement: path, } if k.namespace != "" { key.PartitionId = &pb.PartitionId{ Namespace: proto.String(k.namespace), } } return key }
func propertiesToProto(key *Key, props []Property) (*pb.Entity, error) { e := &pb.Entity{ Key: keyToProto(key), } indexedProps := 0 prevMultiple := make(map[string]*pb.Property) for _, p := range props { val, err := interfaceToProto(p.Value) if err != "" { return nil, fmt.Errorf("datastore: %s for a Property with Name %q", err, p.Name) } if !p.NoIndex { rVal := reflect.ValueOf(p.Value) if rVal.Kind() == reflect.Slice && rVal.Type().Elem().Kind() != reflect.Uint8 { indexedProps += rVal.Len() } else { indexedProps++ } } if indexedProps > maxIndexedProperties { return nil, errors.New("datastore: too many indexed properties") } switch v := p.Value.(type) { case string: case []byte: if len(v) > 500 && !p.NoIndex { return nil, fmt.Errorf("datastore: cannot index a Property with Name %q", p.Name) } } val.Indexed = proto.Bool(!p.NoIndex) if p.Multiple { x, ok := prevMultiple[p.Name] if !ok { x = &pb.Property{ Name: proto.String(p.Name), Value: &pb.Value{}, } prevMultiple[p.Name] = x e.Property = append(e.Property, x) } x.Value.ListValue = append(x.Value.ListValue, val) } else { e.Property = append(e.Property, &pb.Property{ Name: proto.String(p.Name), Value: val, }) } } return e, nil }
func fakeRunQuery(in *pb.RunQueryRequest, out *pb.RunQueryResponse) error { expectedIn := &pb.RunQueryRequest{ Query: &pb.Query{ Kind: []*pb.KindExpression{&pb.KindExpression{Name: proto.String("Gopher")}}, }, } if !proto.Equal(in, expectedIn) { return fmt.Errorf("unsupported argument: got %v want %v", in, expectedIn) } *out = pb.RunQueryResponse{ Batch: &pb.QueryResultBatch{ MoreResults: pb.QueryResultBatch_NO_MORE_RESULTS.Enum(), EntityResultType: pb.EntityResult_FULL.Enum(), EntityResult: []*pb.EntityResult{ &pb.EntityResult{ Entity: &pb.Entity{ Key: key1, Property: []*pb.Property{ { Name: proto.String("Name"), Value: &pb.Value{StringValue: proto.String("George")}, }, { Name: proto.String("Height"), Value: &pb.Value{ IntegerValue: proto.Int64(32), }, }, }, }, }, &pb.EntityResult{ Entity: &pb.Entity{ Key: key2, Property: []*pb.Property{ { Name: proto.String("Name"), Value: &pb.Value{StringValue: proto.String("Rufus")}, }, // No height for Rufus. }, }, }, }, }, } return nil }
func interfaceToProto(iv interface{}) (p *pb.Value, errStr string) { val := new(pb.Value) switch v := iv.(type) { case int: val.IntegerValue = proto.Int64(int64(v)) case int32: val.IntegerValue = proto.Int64(int64(v)) case int64: val.IntegerValue = proto.Int64(v) case bool: val.BooleanValue = proto.Bool(v) case string: val.StringValue = proto.String(v) case float32: val.DoubleValue = proto.Float64(float64(v)) case float64: val.DoubleValue = proto.Float64(v) case *Key: if v != nil { val.KeyValue = keyToProto(v) } case time.Time: if v.Before(minTime) || v.After(maxTime) { return nil, fmt.Sprintf("time value out of range") } val.TimestampMicrosecondsValue = proto.Int64(toUnixMicro(v)) case []byte: val.BlobValue = v default: if iv != nil { return nil, fmt.Sprintf("invalid Value type %t", iv) } } // TODO(jbd): Support ListValue and EntityValue. // TODO(jbd): Support types whose underlying type is one of the types above. return val, "" }
"fmt" "io/ioutil" "net/http" "reflect" "testing" "camlistore.org/third_party/github.com/golang/protobuf/proto" "google.golang.org/cloud" pb "google.golang.org/cloud/internal/datastore" ) var ( key1 = &pb.Key{ PathElement: []*pb.Key_PathElement{ { Kind: proto.String("Gopher"), Id: proto.Int64(6), }, }, } key2 = &pb.Key{ PathElement: []*pb.Key_PathElement{ { Kind: proto.String("Gopher"), Id: proto.Int64(6), }, { Kind: proto.String("Gopher"), Id: proto.Int64(8), }, },
// toProto converts the query to a protocol buffer. func (q *Query) toProto(req *pb.RunQueryRequest) error { dst := pb.Query{} if len(q.projection) != 0 && q.keysOnly { return errors.New("datastore: query cannot both project and be keys-only") } dst.Reset() if q.kind != "" { dst.Kind = []*pb.KindExpression{&pb.KindExpression{Name: proto.String(q.kind)}} } if q.projection != nil { for _, propertyName := range q.projection { dst.Projection = append(dst.Projection, &pb.PropertyExpression{Property: &pb.PropertyReference{Name: proto.String(propertyName)}}) } if q.distinct { for _, propertyName := range q.projection { dst.GroupBy = append(dst.GroupBy, &pb.PropertyReference{Name: proto.String(propertyName)}) } } } if q.keysOnly { dst.Projection = []*pb.PropertyExpression{&pb.PropertyExpression{Property: &pb.PropertyReference{Name: proto.String(keyFieldName)}}} } var filters []*pb.Filter for _, qf := range q.filter { if qf.FieldName == "" { return errors.New("datastore: empty query filter field name") } v, errStr := interfaceToProto(reflect.ValueOf(qf.Value).Interface()) if errStr != "" { return errors.New("datastore: bad query filter value type: " + errStr) } xf := &pb.PropertyFilter{ Operator: operatorToProto[qf.Op], Property: &pb.PropertyReference{Name: proto.String(qf.FieldName)}, Value: v, } if xf.Operator == nil { return errors.New("datastore: unknown query filter operator") } filters = append(filters, &pb.Filter{PropertyFilter: xf}) } if q.ancestor != nil { filters = append(filters, &pb.Filter{ PropertyFilter: &pb.PropertyFilter{ Property: &pb.PropertyReference{Name: proto.String("__key__")}, Operator: pb.PropertyFilter_HAS_ANCESTOR.Enum(), Value: &pb.Value{KeyValue: keyToProto(q.ancestor)}, }}) } if len(filters) == 1 { dst.Filter = filters[0] } else if len(filters) > 1 { dst.Filter = &pb.Filter{CompositeFilter: &pb.CompositeFilter{ Operator: pb.CompositeFilter_AND.Enum(), Filter: filters, }} } for _, qo := range q.order { if qo.FieldName == "" { return errors.New("datastore: empty query order field name") } xo := &pb.PropertyOrder{ Property: &pb.PropertyReference{Name: proto.String(qo.FieldName)}, Direction: sortDirectionToProto[qo.Direction], } if xo.Direction == nil { return errors.New("datastore: unknown query order direction") } dst.Order = append(dst.Order, xo) } if q.limit >= 0 { dst.Limit = proto.Int32(q.limit) } if q.offset != 0 { dst.Offset = proto.Int32(q.offset) } dst.StartCursor = q.start dst.EndCursor = q.end req.Query = &dst return nil }