github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/pkg/graph/walker.go (about) 1 package graph 2 3 import ( 4 core "github.com/authzed/spicedb/pkg/proto/core/v1" 5 "github.com/authzed/spicedb/pkg/spiceerrors" 6 ) 7 8 // WalkHandler is a function invoked for each node in the rewrite tree. If it returns non-nil, 9 // that value is returned from the walk. Otherwise, the walk continues. 10 type WalkHandler func(childOneof *core.SetOperation_Child) interface{} 11 12 // WalkRewrite walks a userset rewrite tree, invoking the handler found on each node of the tree 13 // until the handler returns a non-nil value, which is in turn returned from this function. Returns 14 // nil if no valid value was found. If the rewrite is nil, returns nil. 15 func WalkRewrite(rewrite *core.UsersetRewrite, handler WalkHandler) (interface{}, error) { 16 if rewrite == nil { 17 return nil, nil 18 } 19 20 switch rw := rewrite.RewriteOperation.(type) { 21 case *core.UsersetRewrite_Union: 22 return walkRewriteChildren(rw.Union, handler) 23 case *core.UsersetRewrite_Intersection: 24 return walkRewriteChildren(rw.Intersection, handler) 25 case *core.UsersetRewrite_Exclusion: 26 return walkRewriteChildren(rw.Exclusion, handler) 27 default: 28 return nil, spiceerrors.MustBugf("unknown type of rewrite operation in walker: %T", rw) 29 } 30 } 31 32 // HasThis returns true if there exists a `_this` node anywhere within the given rewrite. If 33 // the rewrite is nil, returns false. 34 func HasThis(rewrite *core.UsersetRewrite) (bool, error) { 35 result, err := WalkRewrite(rewrite, func(childOneof *core.SetOperation_Child) interface{} { 36 switch childOneof.ChildType.(type) { 37 case *core.SetOperation_Child_XThis: 38 return true 39 default: 40 return nil 41 } 42 }) 43 return result != nil && result.(bool), err 44 } 45 46 func walkRewriteChildren(so *core.SetOperation, handler WalkHandler) (interface{}, error) { 47 for _, childOneof := range so.Child { 48 vle := handler(childOneof) 49 if vle != nil { 50 return vle, nil 51 } 52 53 switch child := childOneof.ChildType.(type) { 54 case *core.SetOperation_Child_UsersetRewrite: 55 rvle, err := WalkRewrite(child.UsersetRewrite, handler) 56 if err != nil { 57 return nil, err 58 } 59 60 if rvle != nil { 61 return rvle, nil 62 } 63 } 64 } 65 66 return nil, nil 67 }