func dsR2FProp(in datastore.Property) (ds.Property, error) {
	val := in.Value
	switch x := val.(type) {
	case datastore.ByteString:
		val = []byte(x)
	case *datastore.Key:
		val = dsR2F(x)
	case appengine.BlobKey:
		val = bs.Key(x)
	case appengine.GeoPoint:
		val = ds.GeoPoint(x)
	case time.Time:
		// "appengine" layer instantiates with Local timezone.
		if x.IsZero() {
			val = time.Time{}
		} else {
			val = x.UTC()
		}
	default:
		val = maybeIndexValue(val)
	}
	ret := ds.Property{}
	is := ds.ShouldIndex
	if in.NoIndex {
		is = ds.NoIndex
	}
	err := ret.SetValue(val, is)
	return ret, err
}
func (tf *typeFilter) Load(props []datastore.Property) error {
	tf.pm = make(ds.PropertyMap, len(props))
	for _, p := range props {
		val := p.Value
		switch x := val.(type) {
		case datastore.ByteString:
			val = []byte(x)
		case *datastore.Key:
			val = dsR2F(x)
		case appengine.BlobKey:
			val = bs.Key(x)
		case appengine.GeoPoint:
			val = ds.GeoPoint(x)
		case time.Time:
			// "appengine" layer instantiates with Local timezone.
			val = x.UTC()
		default:
			val = maybeIndexValue(val)
		}
		prop := ds.Property{}
		is := ds.ShouldIndex
		if p.NoIndex {
			is = ds.NoIndex
		}
		if err := prop.SetValue(val, is); err != nil {
			return err
		}
		tf.pm[p.Name] = append(tf.pm[p.Name], prop)
	}
	return nil
}
Example #3
0
// 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
}
Example #5
0
// 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
}
Example #6
0
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
				}
			}
		})
}