github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/pkg/validationfile/blocks/relationships.go (about)

     1  package blocks
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	v1 "github.com/authzed/authzed-go/proto/authzed/api/v1"
     8  	yamlv3 "gopkg.in/yaml.v3"
     9  
    10  	"github.com/authzed/spicedb/pkg/spiceerrors"
    11  	"github.com/authzed/spicedb/pkg/tuple"
    12  )
    13  
    14  // ParsedRelationships is the parsed relationships in a validationfile.
    15  type ParsedRelationships struct {
    16  	// RelationshipsString is the found string of newline-separated relationships.
    17  	RelationshipsString string
    18  
    19  	// SourcePosition is the position of the schema in the file.
    20  	SourcePosition spiceerrors.SourcePosition
    21  
    22  	// Relationships are the fully parsed relationships.
    23  	Relationships []*v1.Relationship
    24  }
    25  
    26  // UnmarshalYAML is a custom unmarshaller.
    27  func (pr *ParsedRelationships) UnmarshalYAML(node *yamlv3.Node) error {
    28  	err := node.Decode(&pr.RelationshipsString)
    29  	if err != nil {
    30  		return convertYamlError(err)
    31  	}
    32  
    33  	relationshipsString := pr.RelationshipsString
    34  	if relationshipsString == "" {
    35  		return nil
    36  	}
    37  
    38  	seenTuples := map[string]bool{}
    39  	lines := strings.Split(relationshipsString, "\n")
    40  	relationships := make([]*v1.Relationship, 0, len(lines))
    41  	for index, line := range lines {
    42  		trimmed := strings.TrimSpace(line)
    43  		if len(trimmed) == 0 || strings.HasPrefix(trimmed, "//") {
    44  			continue
    45  		}
    46  
    47  		tpl := tuple.Parse(trimmed)
    48  		if tpl == nil {
    49  			return spiceerrors.NewErrorWithSource(
    50  				fmt.Errorf("error parsing relationship `%s`", trimmed),
    51  				trimmed,
    52  				uint64(node.Line+1+(index*2)), // +1 for the key, and *2 for newlines in YAML
    53  				uint64(node.Column),
    54  			)
    55  		}
    56  
    57  		_, ok := seenTuples[tuple.StringWithoutCaveat(tpl)]
    58  		if ok {
    59  			return spiceerrors.NewErrorWithSource(
    60  				fmt.Errorf("found repeated relationship `%s`", trimmed),
    61  				trimmed,
    62  				uint64(node.Line+1+(index*2)), // +1 for the key, and *2 for newlines in YAML
    63  				uint64(node.Column),
    64  			)
    65  		}
    66  		seenTuples[tuple.StringWithoutCaveat(tpl)] = true
    67  		relationships = append(relationships, tuple.MustToRelationship(tpl))
    68  	}
    69  
    70  	pr.Relationships = relationships
    71  	pr.SourcePosition = spiceerrors.SourcePosition{LineNumber: node.Line, ColumnPosition: node.Column}
    72  	return nil
    73  }