| Index: go/src/infra/gae/libs/gae/upstream_errors.go
|
| diff --git a/go/src/infra/gae/libs/gae/upstream_errors.go b/go/src/infra/gae/libs/gae/upstream_errors.go
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f6ebad5538ae2b3dd14ae34b0f3f6766cb8a9cf5
|
| --- /dev/null
|
| +++ b/go/src/infra/gae/libs/gae/upstream_errors.go
|
| @@ -0,0 +1,109 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +// This file contains types and values which are mirrors/duplicates of the
|
| +// upstream SDK errors. This exists so that users can depend solely on this
|
| +// wrapper library without also needing to import the SDK.
|
| +//
|
| +// Format of the errors is Err<sub>Name, where <sub> is one of the 2/3-letter
|
| +// All Caps subpackage codes (e.g. DS, TQ, MC, etc.). Name is the same as the
|
| +// original SDK error.
|
| +//
|
| +// Note that this only replicates the 'named' errors (which a user might compare
|
| +// for equality or observe by-type in their code like ErrDSNoSuchEntity). The
|
| +// underlying implementations can (and do) return many more sorts of non-named
|
| +// and custom errors.
|
| +
|
| +package gae
|
| +
|
| +import (
|
| + "fmt"
|
| + "reflect"
|
| +
|
| + "google.golang.org/appengine/datastore"
|
| + "google.golang.org/appengine/memcache"
|
| + "google.golang.org/appengine/taskqueue"
|
| +)
|
| +
|
| +// These are pass-through versions from the managed-VM SDK. All implementations
|
| +// must return these (exact) errors (not just an error with the same text).
|
| +var (
|
| + ErrDSInvalidEntityType = datastore.ErrInvalidEntityType
|
| + ErrDSInvalidKey = datastore.ErrInvalidKey
|
| + ErrDSNoSuchEntity = datastore.ErrNoSuchEntity
|
| + ErrDSConcurrentTransaction = datastore.ErrConcurrentTransaction
|
| + ErrDSQueryDone = datastore.Done
|
| +
|
| + ErrMCCacheMiss = memcache.ErrCacheMiss
|
| + ErrMCCASConflict = memcache.ErrCASConflict
|
| + ErrMCNoStats = memcache.ErrNoStats
|
| + ErrMCNotStored = memcache.ErrNotStored
|
| + ErrMCServerError = memcache.ErrServerError
|
| +
|
| + ErrTQTaskAlreadyAdded = taskqueue.ErrTaskAlreadyAdded
|
| +)
|
| +
|
| +/////////////////////////////// Supporting code ////////////////////////////////
|
| +
|
| +// MultiError is returned by batch operations when there are errors with
|
| +// particular elements. Errors will be in a one-to-one correspondence with
|
| +// the input elements; successful elements will have a nil entry.
|
| +type MultiError []error
|
| +
|
| +func (m MultiError) Error() string {
|
| + s, n := "", 0
|
| + for _, e := range m {
|
| + if e != nil {
|
| + if n == 0 {
|
| + s = e.Error()
|
| + }
|
| + n++
|
| + }
|
| + }
|
| + switch n {
|
| + case 0:
|
| + return "(0 errors)"
|
| + case 1:
|
| + return s
|
| + case 2:
|
| + return s + " (and 1 other error)"
|
| + }
|
| + return fmt.Sprintf("%s (and %d other errors)", s, n-1)
|
| +}
|
| +
|
| +// SingleError provides a simple way to uwrap a MultiError if you know that it
|
| +// could only ever contain one element.
|
| +//
|
| +// If err is a MultiError, return its first element. Otherwise, return err.
|
| +func SingleError(err error) error {
|
| + if me, ok := err.(MultiError); ok {
|
| + if len(me) == 0 {
|
| + return nil
|
| + }
|
| + return me[0]
|
| + }
|
| + return err
|
| +}
|
| +
|
| +var (
|
| + multiErrorType = reflect.TypeOf(MultiError(nil))
|
| +)
|
| +
|
| +// FixError will convert a backend-specific non-plain error type to the
|
| +// corresponding gae wrapper type. This is intended to be used solely by
|
| +// implementations (not user code). A correct implementation of the gae wrapper
|
| +// should never return an SDK-specific error type if an alternate type appears
|
| +// in this file.
|
| +func FixError(err error) error {
|
| + if err != nil {
|
| + // we know that err already conforms to the error interface (or the caller's
|
| + // method wouldn't compile), so check to see if the error's underlying type
|
| + // looks like one of the special error types we implement.
|
| + v := reflect.ValueOf(err)
|
| + if v.Type().ConvertibleTo(multiErrorType) {
|
| + err = v.Convert(multiErrorType).Interface().(error)
|
| + }
|
| + }
|
| + return err
|
| +}
|
|
|