github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/pkg/typesystem/resolver.go (about)

     1  package typesystem
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"slices"
     7  
     8  	"github.com/authzed/spicedb/pkg/datastore"
     9  	core "github.com/authzed/spicedb/pkg/proto/core/v1"
    10  	"github.com/authzed/spicedb/pkg/schemadsl/compiler"
    11  )
    12  
    13  // Resolver is an interface defined for resolving referenced namespaces and caveats when constructing
    14  // and validating a type system.
    15  type Resolver interface {
    16  	// LookupNamespace lookups up a namespace.
    17  	LookupNamespace(ctx context.Context, name string) (*core.NamespaceDefinition, error)
    18  
    19  	// LookupCaveat lookups up a caveat.
    20  	LookupCaveat(ctx context.Context, name string) (*core.CaveatDefinition, error)
    21  
    22  	// WithPredefinedElements adds the given predefined elements to this resolver, returning a new
    23  	// resolver.
    24  	WithPredefinedElements(predefined PredefinedElements) Resolver
    25  }
    26  
    27  // ResolverForDatastoreReader returns a Resolver for a datastore reader.
    28  func ResolverForDatastoreReader(ds datastore.Reader) Resolver {
    29  	return &resolver{
    30  		ds: ds,
    31  	}
    32  }
    33  
    34  // PredefinedElements are predefined namespaces and/or caveats to give to a resolver.
    35  type PredefinedElements struct {
    36  	Namespaces []*core.NamespaceDefinition
    37  	Caveats    []*core.CaveatDefinition
    38  }
    39  
    40  func (pe PredefinedElements) combineWith(other PredefinedElements) PredefinedElements {
    41  	return PredefinedElements{
    42  		Namespaces: append(slices.Clone(pe.Namespaces), other.Namespaces...),
    43  		Caveats:    append(slices.Clone(pe.Caveats), other.Caveats...),
    44  	}
    45  }
    46  
    47  // ResolverForPredefinedDefinitions returns a resolver for predefined namespaces and caveats.
    48  func ResolverForPredefinedDefinitions(predefined PredefinedElements) Resolver {
    49  	return &resolver{
    50  		predefined: predefined,
    51  	}
    52  }
    53  
    54  // ResolverForSchema returns a resolver for a schema.
    55  func ResolverForSchema(schema compiler.CompiledSchema) Resolver {
    56  	return ResolverForPredefinedDefinitions(
    57  		PredefinedElements{
    58  			Namespaces: schema.ObjectDefinitions,
    59  			Caveats:    schema.CaveatDefinitions,
    60  		},
    61  	)
    62  }
    63  
    64  type resolver struct {
    65  	ds         datastore.Reader
    66  	predefined PredefinedElements
    67  }
    68  
    69  func (r *resolver) LookupNamespace(ctx context.Context, name string) (*core.NamespaceDefinition, error) {
    70  	if len(r.predefined.Namespaces) > 0 {
    71  		for _, def := range r.predefined.Namespaces {
    72  			if def.Name == name {
    73  				return def, nil
    74  			}
    75  		}
    76  	}
    77  
    78  	if r.ds == nil {
    79  		return nil, asTypeError(NewNamespaceNotFoundErr(name))
    80  	}
    81  
    82  	ns, _, err := r.ds.ReadNamespaceByName(ctx, name)
    83  	return ns, err
    84  }
    85  
    86  func (r *resolver) WithPredefinedElements(predefined PredefinedElements) Resolver {
    87  	return &resolver{
    88  		ds:         r.ds,
    89  		predefined: predefined.combineWith(r.predefined),
    90  	}
    91  }
    92  
    93  func (r *resolver) LookupCaveat(ctx context.Context, name string) (*core.CaveatDefinition, error) {
    94  	if len(r.predefined.Caveats) > 0 {
    95  		for _, caveat := range r.predefined.Caveats {
    96  			if caveat.Name == name {
    97  				return caveat, nil
    98  			}
    99  		}
   100  	}
   101  
   102  	if r.ds == nil {
   103  		return nil, asTypeError(NewCaveatNotFoundErr(name))
   104  	}
   105  
   106  	cr, ok := r.ds.(datastore.CaveatReader)
   107  	if !ok {
   108  		return nil, fmt.Errorf("caveats are not supported on this datastore type")
   109  	}
   110  
   111  	caveatDef, _, err := cr.ReadCaveatByName(ctx, name)
   112  	return caveatDef, err
   113  }