github.com/weaviate/weaviate@v1.24.6/usecases/objects/validation/model_validation.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 validation 13 14 import ( 15 "context" 16 "fmt" 17 "strings" 18 19 "github.com/go-openapi/strfmt" 20 "github.com/weaviate/weaviate/entities/additional" 21 "github.com/weaviate/weaviate/entities/models" 22 "github.com/weaviate/weaviate/entities/schema/crossref" 23 "github.com/weaviate/weaviate/usecases/config" 24 ) 25 26 type exists func(_ context.Context, class string, _ strfmt.UUID, _ *additional.ReplicationProperties, _ string) (bool, error) 27 28 const ( 29 // ErrorMissingActionObjects message 30 ErrorMissingActionObjects string = "no objects, object and subject, are added. Add 'objects' by using the 'objects' key in the root of the JSON" 31 // ErrorMissingActionObjectsObject message 32 ErrorMissingActionObjectsObject string = "no object-thing is added. Add the 'object' inside the 'objects' part of the JSON" 33 // ErrorMissingActionObjectsSubject message 34 ErrorMissingActionObjectsSubject string = "no subject-thing is added. Add the 'subject' inside the 'objects' part of the JSON" 35 // ErrorMissingActionObjectsObjectLocation message 36 ErrorMissingActionObjectsObjectLocation string = "no 'locationURL' is found in the object-thing. Add the 'locationURL' inside the 'object-thing' part of the JSON" 37 // ErrorMissingActionObjectsObjectType message 38 ErrorMissingActionObjectsObjectType string = "no 'type' is found in the object-thing. Add the 'type' inside the 'object-thing' part of the JSON" 39 // ErrorInvalidActionObjectsObjectType message 40 ErrorInvalidActionObjectsObjectType string = "object-thing requires one of the following values in 'type': '%s', '%s' or '%s'" 41 // ErrorMissingActionObjectsSubjectLocation message 42 ErrorMissingActionObjectsSubjectLocation string = "no 'locationURL' is found in the subject-thing. Add the 'locationURL' inside the 'subject-thing' part of the JSON" 43 // ErrorMissingActionObjectsSubjectType message 44 ErrorMissingActionObjectsSubjectType string = "no 'type' is found in the subject-thing. Add the 'type' inside the 'subject-thing' part of the JSON" 45 // ErrorInvalidActionObjectsSubjectType message 46 ErrorInvalidActionObjectsSubjectType string = "subject-thing requires one of the following values in 'type': '%s', '%s' or '%s'" 47 // ErrorMisingObject message 48 ErrorMissingObject = "the given object is empty" 49 // ErrorMissingClass message 50 ErrorMissingClass string = "the given class is empty" 51 // ErrorMissingContext message 52 ErrorMissingContext string = "the given context is empty" 53 // ErrorNoExternalCredentials message 54 ErrorNoExternalCredentials string = "no credentials available for the Weaviate instance for %s given in the %s" 55 // ErrorExternalNotFound message 56 ErrorExternalNotFound string = "given statuscode of '%s' is '%d', but 200 was expected for LocationURL given in the %s" 57 // ErrorInvalidCRefType message 58 ErrorInvalidCRefType string = "'cref' type '%s' does not exists" 59 // ErrorNotFoundInDatabase message 60 ErrorNotFoundInDatabase string = "%s: no object with id %s found" 61 // ErrorInvalidProperties message 62 ErrorInvalidProperties string = "properties of object %v must be of type map[string]interface" 63 ) 64 65 type Validator struct { 66 exists exists 67 config *config.WeaviateConfig 68 replicationProps *additional.ReplicationProperties 69 } 70 71 func New(exists exists, config *config.WeaviateConfig, 72 repl *additional.ReplicationProperties, 73 ) *Validator { 74 return &Validator{ 75 exists: exists, 76 config: config, 77 replicationProps: repl, 78 } 79 } 80 81 func (v *Validator) Object(ctx context.Context, class *models.Class, 82 incoming *models.Object, existing *models.Object, 83 ) error { 84 if err := validateClass(incoming.Class); err != nil { 85 return err 86 } 87 88 return v.properties(ctx, class, incoming, existing) 89 } 90 91 func validateClass(class string) error { 92 // If the given class is empty, return an error 93 if class == "" { 94 return fmt.Errorf(ErrorMissingClass) 95 } 96 97 // No error 98 return nil 99 } 100 101 // ValidateSingleRef validates a single ref based on location URL and existence of the object in the database 102 func (v *Validator) ValidateSingleRef(cref *models.SingleRef) (*crossref.Ref, error) { 103 ref, err := crossref.ParseSingleRef(cref) 104 if err != nil { 105 return nil, fmt.Errorf("invalid reference: %w", err) 106 } 107 108 // target id must be lowercase 109 ref.TargetID = strfmt.UUID(strings.ToLower(ref.TargetID.String())) 110 111 if !ref.Local { 112 return nil, fmt.Errorf("unrecognized cross-ref ref format") 113 } 114 115 return ref, nil 116 } 117 118 func (v *Validator) ValidateExistence(ctx context.Context, ref *crossref.Ref, errorVal string, tenant string) error { 119 // locally check for object existence 120 ok, err := v.exists(ctx, ref.Class, ref.TargetID, v.replicationProps, tenant) 121 if err != nil { 122 if tenant == "" { 123 return err 124 } 125 // since refs can be created to non-MT classes, check again if non-MT object exists 126 // (use empty tenant, if previously was given) 127 ok2, err2 := v.exists(ctx, ref.Class, ref.TargetID, v.replicationProps, "") 128 if err2 != nil { 129 // return orig error 130 return err 131 } 132 ok = ok2 133 } 134 if !ok { 135 return fmt.Errorf(ErrorNotFoundInDatabase, errorVal, ref.TargetID) 136 } 137 138 return nil 139 } 140 141 func (v *Validator) ValidateMultipleRef(ctx context.Context, refs models.MultipleRef, 142 errorVal string, tenant string, 143 ) ([]*crossref.Ref, error) { 144 parsedRefs := make([]*crossref.Ref, len(refs)) 145 146 if refs == nil { 147 return parsedRefs, nil 148 } 149 150 for i, ref := range refs { 151 parsedRef, err := v.ValidateSingleRef(ref) 152 if err != nil { 153 return nil, err 154 } 155 parsedRefs[i] = parsedRef 156 157 } 158 return parsedRefs, nil 159 }