github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/internal/services/v1/preconditions.go (about) 1 package v1 2 3 import ( 4 "context" 5 "fmt" 6 7 v1 "github.com/authzed/authzed-go/proto/authzed/api/v1" 8 9 "github.com/authzed/spicedb/pkg/datastore" 10 "github.com/authzed/spicedb/pkg/datastore/options" 11 ) 12 13 var limitOne uint64 = 1 14 15 // checkPreconditions checks whether the preconditions are met in the context of a datastore 16 // read-write transaction, and returns an error if they are not met. 17 func checkPreconditions( 18 ctx context.Context, 19 rwt datastore.ReadWriteTransaction, 20 preconditions []*v1.Precondition, 21 ) error { 22 for _, precond := range preconditions { 23 dsFilter, err := datastore.RelationshipsFilterFromPublicFilter(precond.Filter) 24 if err != nil { 25 return fmt.Errorf("error converting filter: %w", err) 26 } 27 28 iter, err := rwt.QueryRelationships(ctx, dsFilter, options.WithLimit(&limitOne)) 29 if err != nil { 30 return fmt.Errorf("error reading relationships: %w", err) 31 } 32 defer iter.Close() 33 34 first := iter.Next() 35 if first == nil && iter.Err() != nil { 36 return fmt.Errorf("error reading relationships from iterator: %w", err) 37 } 38 iter.Close() 39 40 switch precond.Operation { 41 case v1.Precondition_OPERATION_MUST_NOT_MATCH: 42 if first != nil { 43 return NewPreconditionFailedErr(precond) 44 } 45 case v1.Precondition_OPERATION_MUST_MATCH: 46 if first == nil { 47 return NewPreconditionFailedErr(precond) 48 } 49 default: 50 return fmt.Errorf("unspecified precondition operation: %s", precond.Operation) 51 } 52 } 53 54 return nil 55 }