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 }