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  }