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