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  }