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 }