github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/internal/datasets/subjectsetbytype.go (about)

     1  package datasets
     2  
     3  import (
     4  	core "github.com/authzed/spicedb/pkg/proto/core/v1"
     5  	v1 "github.com/authzed/spicedb/pkg/proto/dispatch/v1"
     6  	"github.com/authzed/spicedb/pkg/tuple"
     7  )
     8  
     9  // SubjectByTypeSet is a set of SubjectSet's, grouped by their subject types.
    10  type SubjectByTypeSet struct {
    11  	byType map[string]SubjectSet
    12  }
    13  
    14  // NewSubjectByTypeSet creates and returns a new SubjectByTypeSet.
    15  func NewSubjectByTypeSet() *SubjectByTypeSet {
    16  	return &SubjectByTypeSet{
    17  		byType: map[string]SubjectSet{},
    18  	}
    19  }
    20  
    21  // AddSubjectOf adds the subject found in the given relationship, along with its caveat.
    22  func (s *SubjectByTypeSet) AddSubjectOf(relationship *core.RelationTuple) error {
    23  	return s.AddSubject(relationship.Subject, relationship.Caveat)
    24  }
    25  
    26  // AddConcreteSubject adds a non-caveated subject to the set.
    27  func (s *SubjectByTypeSet) AddConcreteSubject(subject *core.ObjectAndRelation) error {
    28  	return s.AddSubject(subject, nil)
    29  }
    30  
    31  // AddSubject adds the specified subject to the set.
    32  func (s *SubjectByTypeSet) AddSubject(subject *core.ObjectAndRelation, caveat *core.ContextualizedCaveat) error {
    33  	key := tuple.JoinRelRef(subject.Namespace, subject.Relation)
    34  	if _, ok := s.byType[key]; !ok {
    35  		s.byType[key] = NewSubjectSet()
    36  	}
    37  
    38  	return s.byType[key].Add(&v1.FoundSubject{
    39  		SubjectId:        subject.ObjectId,
    40  		CaveatExpression: wrapCaveat(caveat),
    41  	})
    42  }
    43  
    44  // ForEachType invokes the handler for each type of ObjectAndRelation found in the set, along
    45  // with all IDs of objects of that type.
    46  func (s *SubjectByTypeSet) ForEachType(handler func(rr *core.RelationReference, subjects SubjectSet)) {
    47  	for key, subjects := range s.byType {
    48  		ns, rel := tuple.MustSplitRelRef(key)
    49  		handler(&core.RelationReference{
    50  			Namespace: ns,
    51  			Relation:  rel,
    52  		}, subjects)
    53  	}
    54  }
    55  
    56  // ForEachTypeUntil invokes the handler for each type of ObjectAndRelation found in the set, along
    57  // with all IDs of objects of that type, until the handler returns an error or false.
    58  func (s *SubjectByTypeSet) ForEachTypeUntil(handler func(rr *core.RelationReference, subjects SubjectSet) (bool, error)) error {
    59  	for key, subjects := range s.byType {
    60  		ns, rel := tuple.MustSplitRelRef(key)
    61  		ok, err := handler(&core.RelationReference{
    62  			Namespace: ns,
    63  			Relation:  rel,
    64  		}, subjects)
    65  		if err != nil {
    66  			return err
    67  		}
    68  		if !ok {
    69  			return nil
    70  		}
    71  	}
    72  	return nil
    73  }
    74  
    75  // Map runs the mapper function over each type of object in the set, returning a new ONRByTypeSet with
    76  // the object type replaced by that returned by the mapper function.
    77  func (s *SubjectByTypeSet) Map(mapper func(rr *core.RelationReference) (*core.RelationReference, error)) (*SubjectByTypeSet, error) {
    78  	mapped := NewSubjectByTypeSet()
    79  	for key, subjectset := range s.byType {
    80  		ns, rel := tuple.MustSplitRelRef(key)
    81  		updatedType, err := mapper(&core.RelationReference{
    82  			Namespace: ns,
    83  			Relation:  rel,
    84  		})
    85  		if err != nil {
    86  			return nil, err
    87  		}
    88  		if updatedType == nil {
    89  			continue
    90  		}
    91  
    92  		key := tuple.JoinRelRef(updatedType.Namespace, updatedType.Relation)
    93  		if existing, ok := mapped.byType[key]; ok {
    94  			cloned := subjectset.Clone()
    95  			if err := cloned.UnionWithSet(existing); err != nil {
    96  				return nil, err
    97  			}
    98  			mapped.byType[key] = cloned
    99  		} else {
   100  			mapped.byType[key] = subjectset
   101  		}
   102  	}
   103  	return mapped, nil
   104  }
   105  
   106  // IsEmpty returns true if the set is empty.
   107  func (s *SubjectByTypeSet) IsEmpty() bool {
   108  	return len(s.byType) == 0
   109  }
   110  
   111  // Len returns the number of keys in the set.
   112  func (s *SubjectByTypeSet) Len() int {
   113  	return len(s.byType)
   114  }
   115  
   116  // SubjectSetForType returns the subject set associated with the given subject type, if any.
   117  func (s *SubjectByTypeSet) SubjectSetForType(rr *core.RelationReference) (SubjectSet, bool) {
   118  	found, ok := s.byType[tuple.JoinRelRef(rr.Namespace, rr.Relation)]
   119  	return found, ok
   120  }
   121  
   122  func wrapCaveat(caveat *core.ContextualizedCaveat) *core.CaveatExpression {
   123  	if caveat == nil {
   124  		return nil
   125  	}
   126  
   127  	return &core.CaveatExpression{
   128  		OperationOrCaveat: &core.CaveatExpression_Caveat{
   129  			Caveat: caveat,
   130  		},
   131  	}
   132  }