github.com/weaviate/weaviate@v1.24.6/entities/schema/crossref/crossref_source.go (about)

     1  //                           _       _
     2  // __      _____  __ ___   ___  __ _| |_ ___
     3  // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
     4  //  \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
     5  //   \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
     6  //
     7  //  Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
     8  //
     9  //  CONTACT: hello@weaviate.io
    10  //
    11  
    12  package crossref
    13  
    14  import (
    15  	"fmt"
    16  	"net/url"
    17  	"strings"
    18  	"unicode"
    19  
    20  	"github.com/go-openapi/strfmt"
    21  	"github.com/weaviate/weaviate/entities/schema"
    22  )
    23  
    24  // RefSource is an abstraction of the source of a cross-ref. The opposite would
    25  // be Ref which represents the target instead. A RefSource is specified in a URI
    26  // format in the API. When this type is used it is safe to assume that a Ref is
    27  // semantically valid. This guarantee would not be possible on the URI format,
    28  // as the URI can be well-formed, but not contain the data we expect in it.  Do
    29  // not use directly, such as crossref.RefSource{}, as you won't have any
    30  // guarantees in this case. Always use one of the parsing options or New()
    31  type RefSource struct {
    32  	Local    bool                `json:"local"`
    33  	PeerName string              `json:"peerName"`
    34  	Property schema.PropertyName `json:"property"`
    35  	Class    schema.ClassName    `json:"class"`
    36  	TargetID strfmt.UUID         `json:"targetID"`
    37  }
    38  
    39  func NewSource(className schema.ClassName,
    40  	property schema.PropertyName, id strfmt.UUID,
    41  ) *RefSource {
    42  	return &RefSource{
    43  		Local:    true,
    44  		PeerName: "localhost",
    45  		Class:    className,
    46  		TargetID: id,
    47  		Property: property,
    48  	}
    49  }
    50  
    51  // ParseSource is a safe way to generate a RefSource, as it will error if any
    52  // of the input parameters are not as expected.
    53  func ParseSource(uriString string) (*RefSource, error) {
    54  	uri, err := url.Parse(uriString)
    55  	if err != nil {
    56  		return nil, fmt.Errorf("invalid cref URI: %s", err)
    57  	}
    58  
    59  	pathSegments := strings.Split(uri.Path, "/")
    60  	if len(pathSegments) != 4 {
    61  		return nil, fmt.Errorf(
    62  			"invalid cref URI: must use long-form: path must be of format '/<className>/<uuid>/<propertyName>', but got '%s'",
    63  			uri.Path)
    64  	}
    65  
    66  	if ok := strfmt.IsUUID(pathSegments[2]); !ok {
    67  		return nil, fmt.Errorf("invalid cref URI: 2nd path segment must be uuid, but got '%s'",
    68  			pathSegments[3])
    69  	}
    70  
    71  	class := pathSegments[1]
    72  	if class == "" {
    73  		return nil, fmt.Errorf("className cannot be empty")
    74  	}
    75  
    76  	if unicode.IsLower(rune(class[0])) {
    77  		return nil, fmt.Errorf("className must start with an uppercase letter, but got %s", class)
    78  	}
    79  
    80  	property := pathSegments[3]
    81  	if property == "" {
    82  		return nil, fmt.Errorf("property cannot be empty")
    83  	}
    84  
    85  	return &RefSource{
    86  		Local:    (uri.Host == "localhost"),
    87  		PeerName: uri.Host,
    88  		TargetID: strfmt.UUID(pathSegments[2]),
    89  		Class:    schema.ClassName(class),
    90  		Property: schema.PropertyName(property),
    91  	}, nil
    92  }
    93  
    94  func (r *RefSource) String() string {
    95  	uri := url.URL{
    96  		Host:   r.PeerName,
    97  		Scheme: "weaviate",
    98  		Path:   fmt.Sprintf("/%s/%s/%s", r.Class, r.TargetID, r.Property),
    99  	}
   100  
   101  	return uri.String()
   102  }