Пример #1
0
// Run starts a query for log records, which contain request and application
// level log information.
func (params *Query) Run(c appengine.Context) *Result {
	req := &log_proto.LogReadRequest{}
	appId := c.FullyQualifiedAppID()
	req.AppId = &appId
	if params.StartTime != 0 {
		req.StartTime = &params.StartTime
	}
	if params.EndTime != 0 {
		req.EndTime = &params.EndTime
	}
	if params.Incomplete {
		req.IncludeIncomplete = &params.Incomplete
	}
	if params.AppLogs {
		req.IncludeAppLogs = &params.AppLogs
	}
	if params.ApplyMinLevel {
		req.MinimumLogLevel = proto.Int32(int32(params.MinLevel))
	}
	if params.Versions == nil {
		// If no versions were specified, default to the major version
		// used by this app.
		versionID := appengine.VersionID(c)
		if i := strings.Index(versionID, "."); i >= 0 {
			versionID = versionID[:i]
		}
		req.VersionId = []string{versionID}
	} else {
		req.VersionId = params.Versions
	}

	return &Result{context: c, request: req}
}
Пример #2
0
// Run starts a query for log records, which contain request and application
// level log information.
func (params *Query) Run(c appengine.Context) *Result {
	req, err := makeRequest(params, c.FullyQualifiedAppID(), appengine.VersionID(c))
	return &Result{
		context: c,
		request: req,
		err:     err,
	}
}
Пример #3
0
// NewKey creates a new key.
// kind cannot be empty.
// Either one or both of stringID and intID must be zero. If both are zero,
// the key returned is incomplete.
// parent must either be a complete key or nil.
func NewKey(c appengine.Context, kind, stringID string, intID int64, parent *Key) *Key {
	return &Key{
		kind:     kind,
		stringID: stringID,
		intID:    intID,
		parent:   parent,
		appID:    c.FullyQualifiedAppID(),
	}
}
Пример #4
0
// DeleteMulti is a batch version of Delete.
func DeleteMulti(c appengine.Context, key []*Key) error {
	if len(key) == 0 {
		return nil
	}
	if err := multiValid(key); err != nil {
		return err
	}
	req := &pb.DeleteRequest{
		Key: multiKeyToProto(c.FullyQualifiedAppID(), key),
	}
	res := &pb.DeleteResponse{}
	return c.Call("datastore_v3", "Delete", req, res, nil)
}
Пример #5
0
// Run runs the query in the given context.
func (q *Query) Run(c appengine.Context) *Iterator {
	if q.err != nil {
		return &Iterator{err: q.err}
	}
	req, err := q.toProto(c.FullyQualifiedAppID())
	return &Iterator{
		c:        c,
		keysOnly: q.keysOnly,
		offset:   q.offset,
		req:      req,
		err:      err,
	}
}
Пример #6
0
// PutMulti is a batch version of Put.
func PutMulti(c appengine.Context, key []*Key, src []interface{}) ([]*Key, error) {
	if len(key) != len(src) {
		return nil, errors.New("datastore: key and src slices have different length")
	}
	if len(key) == 0 {
		return nil, nil
	}
	appID := c.FullyQualifiedAppID()
	if err := multiValid(key); err != nil {
		return nil, err
	}
	req := &pb.PutRequest{}
	for i, sIface := range src {
		if m, ok := sIface.(Map); ok {
			sProto, err := saveMap(appID, key[i], m)
			if err != nil {
				return nil, err
			}
			req.Entity = append(req.Entity, sProto)
		} else {
			sv, err := asStructValue(sIface)
			if err != nil {
				return nil, err
			}
			sProto, err := saveStruct(appID, key[i], sv)
			if err != nil {
				return nil, err
			}
			req.Entity = append(req.Entity, sProto)
		}
	}
	res := &pb.PutResponse{}
	err := c.Call("datastore_v3", "Put", req, res, nil)
	if err != nil {
		return nil, err
	}
	if len(key) != len(res.Key) {
		return nil, errors.New("datastore: internal error: server returned the wrong number of keys")
	}
	ret := make([]*Key, len(key))
	for i := range ret {
		ret[i], err = protoToKey(res.Key[i])
		if err != nil || ret[i].Incomplete() {
			return nil, errors.New("datastore: internal error: server returned an invalid key")
		}
	}
	return ret, nil
}
Пример #7
0
// GetMulti is a batch version of Get.
//
// dst must be a []S, []*S, []I or []P, for some struct type S, some interface
// type I, or some non-interface non-pointer type P such that P or *P
// implements PropertyLoadSaver. If an []I, each element must be a valid dst
// for Get: it must be a struct pointer or implement PropertyLoadSaver.
//
// As a special case, PropertyList is an invalid type for dst, even though a
// PropertyList is a slice of structs. It is treated as invalid to avoid being
// mistakenly passed when []PropertyList was intended.
func GetMulti(c appengine.Context, key []*Key, dst interface{}) error {
	v := reflect.ValueOf(dst)
	multiArgType, _ := checkMultiArg(v)
	if multiArgType == multiArgTypeInvalid {
		return errors.New("datastore: dst has invalid type")
	}
	if len(key) != v.Len() {
		return errors.New("datastore: key and dst slices have different length")
	}
	if len(key) == 0 {
		return nil
	}
	if err := multiValid(key); err != nil {
		return err
	}
	req := &pb.GetRequest{
		Key: multiKeyToProto(c.FullyQualifiedAppID(), key),
	}
	res := &pb.GetResponse{}
	if err := c.Call("datastore_v3", "Get", req, res, nil); err != nil {
		return err
	}
	if len(key) != len(res.Entity) {
		return errors.New("datastore: internal error: server returned the wrong number of entities")
	}
	multiErr, any := make(appengine.MultiError, len(key)), false
	for i, e := range res.Entity {
		if e.Entity == nil {
			multiErr[i] = ErrNoSuchEntity
		} else {
			elem := v.Index(i)
			if multiArgType == multiArgTypePropertyLoadSaver || multiArgType == multiArgTypeStruct {
				elem = elem.Addr()
			}
			if multiArgType == multiArgTypeStructPtr && elem.IsNil() {
				elem.Set(reflect.New(elem.Type().Elem()))
			}
			multiErr[i] = loadEntity(elem.Interface(), e.Entity)
		}
		if multiErr[i] != nil {
			any = true
		}
	}
	if any {
		return multiErr
	}
	return nil
}
Пример #8
0
// Run starts a query for log records, which contain request and application
// level log information.
func (params *Query) Run(c appengine.Context) *Result {
	req := &pb.LogReadRequest{}
	appId := c.FullyQualifiedAppID()
	req.AppId = &appId
	if !params.StartTime.IsZero() {
		req.StartTime = proto.Int64(params.StartTime.UnixNano() / 1e3)
	}
	if !params.EndTime.IsZero() {
		req.EndTime = proto.Int64(params.EndTime.UnixNano() / 1e3)
	}
	if params.Offset != nil {
		var offset pb.LogOffset
		if err := proto.Unmarshal(params.Offset, &offset); err != nil {
			return &Result{context: c, err: fmt.Errorf("bad Offset: %v", err)}
		}
		req.Offset = &offset
	}
	if params.Incomplete {
		req.IncludeIncomplete = &params.Incomplete
	}
	if params.AppLogs {
		req.IncludeAppLogs = &params.AppLogs
	}
	if params.ApplyMinLevel {
		req.MinimumLogLevel = proto.Int32(int32(params.MinLevel))
	}
	if params.Versions == nil {
		// If no versions were specified, default to the major version
		// used by this app.
		versionID := appengine.VersionID(c)
		if i := strings.Index(versionID, "."); i >= 0 {
			versionID = versionID[:i]
		}
		req.VersionId = []string{versionID}
	} else {
		req.VersionId = params.Versions
	}
	if params.RequestIDs != nil {
		ids := make([][]byte, len(params.RequestIDs))
		for i, v := range params.RequestIDs {
			ids[i] = []byte(v)
		}
		req.RequestId = ids
	}

	return &Result{context: c, request: req}
}
Пример #9
0
func runOnce(c appengine.Context, f func(appengine.Context) error, opts *TransactionOptions) error {
	// Begin the transaction.
	t := &transaction{Context: c}
	req := &pb.BeginTransactionRequest{
		App: proto.String(c.FullyQualifiedAppID()),
	}
	if opts != nil && opts.XG {
		req.AllowMultipleEg = proto.Bool(true)
	}
	if err := t.Context.Call("datastore_v3", "BeginTransaction", req, &t.transaction, nil); err != nil {
		return err
	}

	// Call f, rolling back the transaction if f returns a non-nil error, or panics.
	// The panic is not recovered.
	defer func() {
		if t.finished {
			return
		}
		t.finished = true
		// Ignore the error return value, since we are already returning a non-nil
		// error (or we're panicking).
		c.Call("datastore_v3", "Rollback", &t.transaction, &pb.VoidProto{}, nil)
	}()
	if err := f(t); err != nil {
		return err
	}
	t.finished = true

	// Commit the transaction.
	res := &pb.CommitResponse{}
	err := c.Call("datastore_v3", "Commit", &t.transaction, res, nil)
	if ae, ok := err.(*appengine_internal.APIError); ok {
		if appengine.IsDevAppServer() {
			// The Python Dev AppServer raises an ApplicationError with error code 2 (which is
			// Error.CONCURRENT_TRANSACTION) and message "Concurrency exception.".
			if ae.Code == int32(pb.Error_BAD_REQUEST) && ae.Detail == "ApplicationError: 2 Concurrency exception." {
				return ErrConcurrentTransaction
			}
		}
		if ae.Code == int32(pb.Error_CONCURRENT_TRANSACTION) {
			return ErrConcurrentTransaction
		}
	}
	return err
}
Пример #10
0
// GetMulti is a batch version of Get.
func GetMulti(c appengine.Context, key []*Key, dst []interface{}) error {
	if len(key) != len(dst) {
		return errors.New("datastore: key and dst slices have different length")
	}
	if len(key) == 0 {
		return nil
	}
	if err := multiValid(key); err != nil {
		return err
	}
	req := &pb.GetRequest{
		Key: multiKeyToProto(c.FullyQualifiedAppID(), key),
	}
	res := &pb.GetResponse{}
	err := c.Call("datastore_v3", "Get", req, res, nil)
	if err != nil {
		return err
	}
	if len(key) != len(res.Entity) {
		return errors.New("datastore: internal error: server returned the wrong number of entities")
	}
	errMulti := make(ErrMulti, len(key))
	for i, e := range res.Entity {
		if e.Entity == nil {
			errMulti[i] = ErrNoSuchEntity
			continue
		}
		if m, ok := dst[i].(Map); ok {
			errMulti[i] = loadMap(m, key[i], e.Entity)
			continue
		}
		sv, err := asStructValue(dst[i])
		if err != nil {
			errMulti[i] = err
			continue
		}
		errMulti[i] = loadStruct(sv, key[i], e.Entity)
	}
	for _, e := range errMulti {
		if e != nil {
			return errMulti
		}
	}
	return nil
}
Пример #11
0
// PutMulti is a batch version of Put.
//
// src must satisfy the same conditions as the dst argument to GetMulti.
func PutMulti(c appengine.Context, key []*Key, src interface{}) ([]*Key, error) {
	v := reflect.ValueOf(src)
	multiArgType, _ := checkMultiArg(v)
	if multiArgType == multiArgTypeInvalid {
		return nil, errors.New("datastore: src has invalid type")
	}
	if len(key) != v.Len() {
		return nil, errors.New("datastore: key and src slices have different length")
	}
	if len(key) == 0 {
		return nil, nil
	}
	appID := c.FullyQualifiedAppID()
	if err := multiValid(key); err != nil {
		return nil, err
	}
	req := &pb.PutRequest{}
	for i := range key {
		elem := v.Index(i)
		if multiArgType == multiArgTypePropertyLoadSaver || multiArgType == multiArgTypeStruct {
			elem = elem.Addr()
		}
		sProto, err := saveEntity(appID, key[i], elem.Interface())
		if err != nil {
			return nil, err
		}
		req.Entity = append(req.Entity, sProto)
	}
	res := &pb.PutResponse{}
	if err := c.Call("datastore_v3", "Put", req, res, nil); err != nil {
		return nil, err
	}
	if len(key) != len(res.Key) {
		return nil, errors.New("datastore: internal error: server returned the wrong number of keys")
	}
	ret := make([]*Key, len(key))
	for i := range ret {
		var err error
		ret[i], err = protoToKey(res.Key[i])
		if err != nil || ret[i].Incomplete() {
			return nil, errors.New("datastore: internal error: server returned an invalid key")
		}
	}
	return ret, nil
}
Пример #12
0
// Run runs the query in the given context.
func (q *Query) Run(c appengine.Context) *Iterator {
	if q.err != nil {
		return &Iterator{err: q.err}
	}
	t := &Iterator{
		c:      c,
		offset: q.offset,
		limit:  q.limit,
	}
	var req pb.Query
	if err := q.toProto(&req, c.FullyQualifiedAppID(), zeroLimitMeansUnlimited); err != nil {
		t.err = err
		return t
	}
	if err := c.Call("datastore_v3", "RunQuery", &req, &t.res, nil); err != nil {
		t.err = err
		return t
	}
	return t
}
Пример #13
0
// NewKey creates a new key.
// kind cannot be empty.
// Either one or both of stringID and intID must be zero. If both are zero,
// the key returned is incomplete.
// parent must either be a complete key or nil.
func NewKey(c appengine.Context, kind, stringID string, intID int64, parent *Key) *Key {
	// If there's a parent key, use its namespace.
	// Otherwise, do a fake RPC to try to get a namespace if c is a namespacedContext (or wraps one).
	var namespace string
	if parent != nil {
		namespace = parent.namespace
	} else {
		s := &basepb.StringProto{}
		c.Call("__go__", "GetNamespace", &basepb.VoidProto{}, s, nil)
		namespace = s.GetValue() // "" if the RPC fails
	}

	return &Key{
		kind:      kind,
		stringID:  stringID,
		intID:     intID,
		parent:    parent,
		appID:     c.FullyQualifiedAppID(),
		namespace: namespace,
	}
}
Пример #14
0
// Run runs the query in the given context.
func (q *Query) Run(c appengine.Context) *Iterator {
	if q.err != nil {
		return &Iterator{err: q.err}
	}
	t := &Iterator{
		c:      c,
		limit:  q.limit,
		q:      q,
		prevCC: q.start,
	}
	var req pb.Query
	if err := q.toProto(&req, c.FullyQualifiedAppID()); err != nil {
		t.err = err
		return t
	}
	if err := c.Call("datastore_v3", "RunQuery", &req, &t.res, nil); err != nil {
		t.err = err
		return t
	}
	offset := q.offset - t.res.GetSkippedResults()
	for offset > 0 && t.res.GetMoreResults() {
		t.prevCC = t.res.CompiledCursor
		if err := callNext(t.c, &t.res, offset, t.limit); err != nil {
			t.err = err
			break
		}
		skip := t.res.GetSkippedResults()
		if skip < 0 {
			t.err = errors.New("datastore: internal error: negative number of skipped_results")
			break
		}
		offset -= skip
	}
	if offset < 0 {
		t.err = errors.New("datastore: internal error: query offset was overshot")
	}
	return t
}
Пример #15
0
// Count returns the number of results for the query.
func (q *Query) Count(c appengine.Context) (int, error) {
	// Check that the query is well-formed.
	if q.err != nil {
		return 0, q.err
	}

	// Run a copy of the query, with keysOnly true, and an adjusted offset.
	// We also set the limit to zero, as we don't want any actual entity data,
	// just the number of skipped results.
	newQ := *q
	newQ.keysOnly = true
	newQ.limit = 0
	if q.limit == 0 {
		// If the original query was unlimited, set the new query's offset to maximum.
		newQ.offset = math.MaxInt32
	} else {
		newQ.offset = q.offset + q.limit
		if newQ.offset < 0 {
			// Do the best we can, in the presence of overflow.
			newQ.offset = math.MaxInt32
		}
	}
	req := &pb.Query{}
	if err := newQ.toProto(req, c.FullyQualifiedAppID(), zeroLimitMeansZero); err != nil {
		return 0, err
	}
	res := &pb.QueryResult{}
	if err := c.Call("datastore_v3", "RunQuery", req, res, nil); err != nil {
		return 0, err
	}

	// n is the count we will return. For example, suppose that our original
	// query had an offset of 4 and a limit of 2008: the count will be 2008,
	// provided that there are at least 2012 matching entities. However, the
	// RPCs will only skip 1000 results at a time. The RPC sequence is:
	//   call RunQuery with (offset, limit) = (2012, 0)  // 2012 == newQ.offset
	//   response has (skippedResults, moreResults) = (1000, true)
	//   n += 1000  // n == 1000
	//   call Next     with (offset, limit) = (1012, 0)  // 1012 == newQ.offset - n
	//   response has (skippedResults, moreResults) = (1000, true)
	//   n += 1000  // n == 2000
	//   call Next     with (offset, limit) = (12, 0)    // 12 == newQ.offset - n
	//   response has (skippedResults, moreResults) = (12, false)
	//   n += 12    // n == 2012
	//   // exit the loop
	//   n -= 4     // n == 2008
	var n int32
	for {
		// The QueryResult should have no actual entity data, just skipped results.
		if len(res.Result) != 0 {
			return 0, errors.New("datastore: internal error: Count request returned too much data")
		}
		n += proto.GetInt32(res.SkippedResults)
		if !proto.GetBool(res.MoreResults) {
			break
		}
		if err := callNext(c, res, newQ.offset-n, 0, zeroLimitMeansZero); err != nil {
			return 0, err
		}
	}
	n -= q.offset
	if n < 0 {
		// If the offset was greater than the number of matching entities,
		// return 0 instead of negative.
		n = 0
	}
	return int(n), nil
}