Repository: weaviate/weaviate
Pull request #4001 (2024-01-11 07:03:00)

Fix uuid casing for references added with object, single refs and bat…
### What's being changed:

Closes https://github.com/weaviate/weaviate-python-client/issues/714

When adding object their UUID is lower-cased. This did not happen when adding references and an upper-case reference would not point towards a lower-case object-uuid.

Now the reference target is lower-cased for:
- references added with an object
- single refs
- batch refs

### Review checklist

- [x] Documentation has been updated, if necessary. Link to changed documentation:
- [x] Chaos pipeline run or not necessary. Link to pipeline:
- [x] All new code is covered by tests where it is reasonable.
- [x] Performance tests have been run or not necessary.



Patch:
diff --git a/usecases/objects/batch_references_add.go b/usecases/objects/batch_references_add.go
index 63433606ac..dd7b9983c4 100644
--- a/usecases/objects/batch_references_add.go
+++ b/usecases/objects/batch_references_add.go
@@ -154,6 +154,9 @@ func (b *BatchManager) validateReference(ctx context.Context, principal *models.
 			target.PeerName))
 	}
 
+	// target id must be lowercase
+	target.TargetID = strfmt.UUID(strings.ToLower(target.TargetID.String()))
+
 	if len(validateErrors) == 0 {
 		err = nil
 	} else {
diff --git a/usecases/objects/validation/model_validation.go b/usecases/objects/validation/model_validation.go
index 219104638c..75adf7f206 100644
--- a/usecases/objects/validation/model_validation.go
+++ b/usecases/objects/validation/model_validation.go
@@ -14,6 +14,7 @@ package validation
 import (
 	"context"
 	"fmt"
+	"strings"
 
 	"github.com/go-openapi/strfmt"
 	"github.com/weaviate/weaviate/entities/additional"
@@ -104,6 +105,9 @@ func (v *Validator) ValidateSingleRef(cref *models.SingleRef) (*crossref.Ref, er
 		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")
 	}
diff --git a/usecases/objects/validation/properties_validation.go b/usecases/objects/validation/properties_validation.go
index f5c2701e36..d6bf2b21b7 100644
--- a/usecases/objects/validation/properties_validation.go
+++ b/usecases/objects/validation/properties_validation.go
@@ -118,7 +118,6 @@ func (v *Validator) properties(ctx context.Context, class *models.Class,
 					}
 					toClass := prop.DataType[0] // datatype is the name of the class that is referenced
 					toBeacon := crossref.NewLocalhost(toClass, beaconParsed.TargetID).String()
-
 					propertyValue.([]interface{})[i].(map[string]interface{})["beacon"] = toBeacon
 				}
 			}


Test patch:
diff --git a/usecases/objects/validation/model_validation_test.go b/usecases/objects/validation/model_validation_test.go
new file mode 100644
index 0000000000..04f9863369
--- /dev/null
+++ b/usecases/objects/validation/model_validation_test.go
@@ -0,0 +1,64 @@
+//                           _       _
+// __      _____  __ ___   ___  __ _| |_ ___
+// \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
+//  \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
+//   \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
+//
+//  Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
+//
+//  CONTACT: hello@weaviate.io
+//
+
+package validation
+
+import (
+	"context"
+	"strings"
+	"testing"
+
+	"github.com/go-openapi/strfmt"
+
+	"github.com/stretchr/testify/require"
+	"github.com/weaviate/weaviate/entities/models"
+	"github.com/weaviate/weaviate/usecases/config"
+)
+
+const BEACON = "weaviate://localhost/"
+
+var (
+	UuidUpper = "4E5CD755-4F43-44C5-B23C-0C7D6F6C21E6"
+	UuidLower = strings.ToLower(UuidUpper)
+)
+
+func TestValidationReferencesInObject(t *testing.T) {
+	validator := New(fakeExists, &config.WeaviateConfig{}, nil)
+
+	class := &models.Class{
+		Class: "From",
+		Properties: []*models.Property{
+			{Name: "ref", DataType: []string{"To"}},
+		},
+	}
+
+	obj := &models.Object{
+		Class: "From",
+		Properties: map[string]interface{}{
+			"ref": []interface{}{
+				map[string]interface{}{"beacon": BEACON + "To/" + UuidUpper},
+			},
+		},
+	}
+
+	err := validator.properties(context.Background(), class, obj, nil)
+	require.Nil(t, err)
+	require.Equal(t, obj.Properties.(map[string]interface{})["ref"].(models.MultipleRef)[0].Beacon.String(), BEACON+"To/"+UuidLower)
+}
+
+func TestValidationReference(t *testing.T) {
+	validator := New(fakeExists, &config.WeaviateConfig{}, nil)
+
+	cref := &models.SingleRef{Beacon: strfmt.URI(BEACON + "To/" + UuidUpper)}
+	ref, err := validator.ValidateSingleRef(cref)
+	require.Nil(t, err)
+	require.Equal(t, ref.TargetID.String(), UuidLower)
+}