// WriteProperty writes a Property to the buffer. `context` behaves the same // way that it does for WriteKey, but only has an effect if `p` contains a // Key as its Value. func WriteProperty(buf Buffer, context KeyContext, p ds.Property) (err error) { defer recoverTo(&err) typb := byte(p.Type()) if p.IndexSetting() != ds.NoIndex { typb |= 0x80 } panicIf(buf.WriteByte(typb)) switch p.Type() { case ds.PTNull: case ds.PTBool: b := p.Value().(bool) if b { err = buf.WriteByte(1) } else { err = buf.WriteByte(0) } case ds.PTInt: _, err = cmpbin.WriteInt(buf, p.Value().(int64)) case ds.PTFloat: _, err = cmpbin.WriteFloat64(buf, p.Value().(float64)) case ds.PTString: _, err = cmpbin.WriteString(buf, p.Value().(string)) case ds.PTBytes: _, err = cmpbin.WriteBytes(buf, p.Value().([]byte)) case ds.PTTime: err = WriteTime(buf, p.Value().(time.Time)) case ds.PTGeoPoint: err = WriteGeoPoint(buf, p.Value().(ds.GeoPoint)) case ds.PTKey: err = WriteKey(buf, context, p.Value().(ds.Key)) case ds.PTBlobKey: _, err = cmpbin.WriteString(buf, string(p.Value().(blobstore.Key))) } return }
// writePropertyImpl is an implementation of WriteProperty and // WriteIndexProperty. func writePropertyImpl(buf Buffer, context KeyContext, p *ds.Property, index bool) (err error) { defer recoverTo(&err) it, v := p.IndexTypeAndValue() if !index { it = p.Type() } typb := byte(it) if p.IndexSetting() != ds.NoIndex { typb |= 0x80 } panicIf(buf.WriteByte(typb)) err = writeIndexValue(buf, context, v) return }
func dsF2RProp(ctx context.Context, in ds.Property) (datastore.Property, error) { err := error(nil) ret := datastore.Property{ NoIndex: in.IndexSetting() == ds.NoIndex, } switch in.Type() { case ds.PTBytes: v := in.Value().([]byte) if in.IndexSetting() == ds.ShouldIndex { ret.Value = datastore.ByteString(v) } else { ret.Value = v } case ds.PTKey: ret.Value, err = dsF2R(ctx, in.Value().(*ds.Key)) case ds.PTBlobKey: ret.Value = appengine.BlobKey(in.Value().(bs.Key)) case ds.PTGeoPoint: ret.Value = appengine.GeoPoint(in.Value().(ds.GeoPoint)) default: ret.Value = in.Value() } return ret, err }
func (q *queryImpl) Filter(fStr string, val interface{}) ds.Query { prop := "" op := qInvalid p := ds.Property{} return q.checkMutateClone( func() error { var err error prop, op, err = parseFilter(fStr) if err != nil { return err } if q.kind == "" && prop != "__key__" { // https://cloud.google.com/appengine/docs/go/datastore/queries#Go_Kindless_queries return fmt.Errorf( "kindless queries can only filter on __key__, got %q", fStr) } err = p.SetValue(val, ds.ShouldIndex) if err != nil { return err } if p.Type() == ds.PTKey { if !p.Value().(ds.Key).Valid(false, globalAppID, q.ns) { return ds.ErrInvalidKey } } if prop == "__key__" { if op == qEqual { return fmt.Errorf( "query equality filter on __key__ is silly: %q", fStr) } if p.Type() != ds.PTKey { return fmt.Errorf("__key__ filter value is not a key: %T", val) } } else if strings.HasPrefix(prop, "__") && strings.HasSuffix(prop, "__") { return fmt.Errorf("filter on reserved property: %q", prop) } if op != qEqual { if q.ineqFilter.prop != "" && q.ineqFilter.prop != prop { return fmt.Errorf( "inequality filters on multiple properties: %q and %q", q.ineqFilter.prop, prop) } if len(q.order) > 0 && q.order[0].Property != prop { return fmt.Errorf( "first sort order must match inequality filter: %q v %q", q.order[0].Property, prop) } } else { for _, p := range q.project { if p == prop { return fmt.Errorf( "cannot project on field which is used in an equality filter: %q", prop) } } } return err }, func(q *queryImpl) { if op == qEqual { // add it to eq filters q.addEqFilt(prop, p) // remove it from sort orders. // https://cloud.google.com/appengine/docs/go/datastore/queries#sort_orders_are_ignored_on_properties_with_equality_filters toRm := -1 for i, o := range q.order { if o.Property == prop { toRm = i break } } if toRm >= 0 { q.order = append(q.order[:toRm], q.order[toRm+1:]...) } } else { q.ineqFilter.prop = prop if q.ineqFilter.constrain(op, serialize.ToBytes(p)) { q.err = errQueryDone } } }) }