github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/internal/datastore/memdb/schema.go (about) 1 package memdb 2 3 import ( 4 v1 "github.com/authzed/authzed-go/proto/authzed/api/v1" 5 "github.com/hashicorp/go-memdb" 6 "github.com/jzelinskie/stringz" 7 "github.com/rs/zerolog" 8 "google.golang.org/protobuf/types/known/structpb" 9 10 "github.com/authzed/spicedb/pkg/datastore" 11 core "github.com/authzed/spicedb/pkg/proto/core/v1" 12 ) 13 14 const ( 15 tableNamespace = "namespace" 16 17 tableRelationship = "relationship" 18 indexID = "id" 19 indexNamespace = "namespace" 20 indexNamespaceAndRelation = "namespaceAndRelation" 21 indexSubjectNamespace = "subjectNamespace" 22 23 tableChangelog = "changelog" 24 indexRevision = "id" 25 ) 26 27 type namespace struct { 28 name string 29 configBytes []byte 30 updated datastore.Revision 31 } 32 33 func (ns namespace) MarshalZerologObject(e *zerolog.Event) { 34 e.Stringer("rev", ns.updated).Str("name", ns.name) 35 } 36 37 type relationship struct { 38 namespace string 39 resourceID string 40 relation string 41 subjectNamespace string 42 subjectObjectID string 43 subjectRelation string 44 caveat *contextualizedCaveat 45 } 46 47 type contextualizedCaveat struct { 48 caveatName string 49 context map[string]any 50 } 51 52 func (cr *contextualizedCaveat) ContextualizedCaveat() (*core.ContextualizedCaveat, error) { 53 if cr == nil { 54 return nil, nil 55 } 56 v, err := structpb.NewStruct(cr.context) 57 if err != nil { 58 return nil, err 59 } 60 return &core.ContextualizedCaveat{ 61 CaveatName: cr.caveatName, 62 Context: v, 63 }, nil 64 } 65 66 func (r relationship) String() string { 67 caveat := "" 68 if r.caveat != nil { 69 caveat = "[" + r.caveat.caveatName + "]" 70 } 71 72 return r.namespace + ":" + r.resourceID + "#" + r.relation + "@" + r.subjectNamespace + ":" + r.subjectObjectID + "#" + r.subjectRelation + caveat 73 } 74 75 func (r relationship) MarshalZerologObject(e *zerolog.Event) { 76 e.Str("rel", r.String()) 77 } 78 79 func (r relationship) Relationship() *v1.Relationship { 80 return &v1.Relationship{ 81 Resource: &v1.ObjectReference{ 82 ObjectType: r.namespace, 83 ObjectId: r.resourceID, 84 }, 85 Relation: r.relation, 86 Subject: &v1.SubjectReference{ 87 Object: &v1.ObjectReference{ 88 ObjectType: r.subjectNamespace, 89 ObjectId: r.subjectObjectID, 90 }, 91 OptionalRelation: stringz.Default(r.subjectRelation, "", datastore.Ellipsis), 92 }, 93 } 94 } 95 96 func (r relationship) RelationTuple() (*core.RelationTuple, error) { 97 cr, err := r.caveat.ContextualizedCaveat() 98 if err != nil { 99 return nil, err 100 } 101 return &core.RelationTuple{ 102 ResourceAndRelation: &core.ObjectAndRelation{ 103 Namespace: r.namespace, 104 ObjectId: r.resourceID, 105 Relation: r.relation, 106 }, 107 Subject: &core.ObjectAndRelation{ 108 Namespace: r.subjectNamespace, 109 ObjectId: r.subjectObjectID, 110 Relation: r.subjectRelation, 111 }, 112 Caveat: cr, 113 }, nil 114 } 115 116 type changelog struct { 117 revisionNanos int64 118 changes datastore.RevisionChanges 119 } 120 121 var schema = &memdb.DBSchema{ 122 Tables: map[string]*memdb.TableSchema{ 123 tableNamespace: { 124 Name: tableNamespace, 125 Indexes: map[string]*memdb.IndexSchema{ 126 indexID: { 127 Name: indexID, 128 Unique: true, 129 Indexer: &memdb.StringFieldIndex{Field: "name"}, 130 }, 131 }, 132 }, 133 tableChangelog: { 134 Name: tableChangelog, 135 Indexes: map[string]*memdb.IndexSchema{ 136 indexRevision: { 137 Name: indexRevision, 138 Unique: true, 139 Indexer: &memdb.IntFieldIndex{Field: "revisionNanos"}, 140 }, 141 }, 142 }, 143 tableRelationship: { 144 Name: tableRelationship, 145 Indexes: map[string]*memdb.IndexSchema{ 146 indexID: { 147 Name: indexID, 148 Unique: true, 149 Indexer: &memdb.CompoundIndex{ 150 Indexes: []memdb.Indexer{ 151 &memdb.StringFieldIndex{Field: "namespace"}, 152 &memdb.StringFieldIndex{Field: "resourceID"}, 153 &memdb.StringFieldIndex{Field: "relation"}, 154 &memdb.StringFieldIndex{Field: "subjectNamespace"}, 155 &memdb.StringFieldIndex{Field: "subjectObjectID"}, 156 &memdb.StringFieldIndex{Field: "subjectRelation"}, 157 }, 158 }, 159 }, 160 indexNamespace: { 161 Name: indexNamespace, 162 Unique: false, 163 Indexer: &memdb.StringFieldIndex{Field: "namespace"}, 164 }, 165 indexNamespaceAndRelation: { 166 Name: indexNamespaceAndRelation, 167 Unique: false, 168 Indexer: &memdb.CompoundIndex{ 169 Indexes: []memdb.Indexer{ 170 &memdb.StringFieldIndex{Field: "namespace"}, 171 &memdb.StringFieldIndex{Field: "relation"}, 172 }, 173 }, 174 }, 175 indexSubjectNamespace: { 176 Name: indexSubjectNamespace, 177 Unique: false, 178 Indexer: &memdb.StringFieldIndex{Field: "subjectNamespace"}, 179 }, 180 }, 181 }, 182 tableCaveats: { 183 Name: tableCaveats, 184 Indexes: map[string]*memdb.IndexSchema{ 185 indexID: { 186 Name: indexID, 187 Unique: true, 188 Indexer: &memdb.StringFieldIndex{Field: "name"}, 189 }, 190 }, 191 }, 192 }, 193 }