go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/gae/service/datastore/errors.go (about)

     1  // Copyright 2015 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package datastore
    16  
    17  import (
    18  	"fmt"
    19  	"reflect"
    20  
    21  	"google.golang.org/appengine/datastore"
    22  
    23  	"go.chromium.org/luci/common/errors"
    24  )
    25  
    26  type stopErr struct{}
    27  
    28  func (stopErr) Error() string { return "stop iteration" }
    29  
    30  // These errors are returned by various datastore.Interface methods.
    31  var (
    32  	ErrNoSuchEntity          = datastore.ErrNoSuchEntity
    33  	ErrConcurrentTransaction = datastore.ErrConcurrentTransaction
    34  
    35  	// Stop is understood by various services to stop iterative processes. Examples
    36  	// include datastore.Interface.Run's callback.
    37  	Stop = stopErr{}
    38  )
    39  
    40  // MakeErrInvalidKey returns an errors.Annotator instance that wraps an invalid
    41  // key error. Calling IsErrInvalidKey on this Annotator or its derivatives will
    42  // return true.
    43  func MakeErrInvalidKey(reason string, args ...any) *errors.Annotator {
    44  	return errors.Annotate(datastore.ErrInvalidKey, reason, args...)
    45  }
    46  
    47  // IsErrInvalidKey tests if a given error is a wrapped datastore.ErrInvalidKey
    48  // error.
    49  func IsErrInvalidKey(err error) bool { return errors.Unwrap(err) == datastore.ErrInvalidKey }
    50  
    51  // IsErrNoSuchEntity tests if an error is ErrNoSuchEntity,
    52  // or is a MultiError that contains ErrNoSuchEntity and no other errors.
    53  func IsErrNoSuchEntity(err error) (found bool) {
    54  	errors.WalkLeaves(err, func(ierr error) bool {
    55  		found = ierr == ErrNoSuchEntity
    56  		// If we found an ErrNoSuchEntity, continue walking.
    57  		// If we found a different type of error, signal WalkLeaves to stop walking by returning false.
    58  		// WalkLeaves does not walk nil errors nor wrapper errors.
    59  		return found
    60  	})
    61  	return
    62  }
    63  
    64  // ErrFieldMismatch is returned when a field is to be loaded into a different
    65  // type than the one it was stored from, or when a field is missing or
    66  // unexported in the destination struct.
    67  // StructType is the type of the struct pointed to by the destination argument
    68  // passed to Get or to Iterator.Next.
    69  type ErrFieldMismatch struct {
    70  	StructType reflect.Type
    71  	FieldName  string
    72  	Reason     string
    73  }
    74  
    75  func (e *ErrFieldMismatch) Error() string {
    76  	return fmt.Sprintf("gae: cannot load field %q into a %q: %s",
    77  		e.FieldName, e.StructType, e.Reason)
    78  }