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 }