SemanticSearchPOC / usecases /objects /references_delete.go
KevinStephenson
Adding in weaviate code
b110593
raw
history blame
4.51 kB
// _ _
// __ _____ __ ___ ___ __ _| |_ ___
// \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
// \ V V / __/ (_| |\ V /| | (_| | || __/
// \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
//
// Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
//
// CONTACT: [email protected]
//
package objects
import (
"context"
"errors"
"fmt"
"github.com/go-openapi/strfmt"
"github.com/weaviate/weaviate/entities/additional"
"github.com/weaviate/weaviate/entities/models"
"github.com/weaviate/weaviate/entities/schema/crossref"
)
// DeleteReferenceInput represents required inputs to delete a reference from an existing object.
type DeleteReferenceInput struct {
// Class name
Class string
// ID of an object
ID strfmt.UUID
// Property name
Property string
// Reference cross reference
Reference models.SingleRef
}
func (m *Manager) DeleteObjectReference(ctx context.Context, principal *models.Principal,
input *DeleteReferenceInput, repl *additional.ReplicationProperties, tenant string,
) *Error {
m.metrics.DeleteReferenceInc()
defer m.metrics.DeleteReferenceDec()
deprecatedEndpoint := input.Class == ""
beacon, err := crossref.Parse(input.Reference.Beacon.String())
if err != nil {
return &Error{"cannot parse beacon", StatusBadRequest, err}
}
if input.Class != "" && beacon.Class == "" {
toClass, toBeacon, replace, err := m.autodetectToClass(ctx, principal, input.Class, input.Property, beacon)
if err != nil {
return err
}
if replace {
input.Reference.Class = toClass
input.Reference.Beacon = toBeacon
}
}
res, err := m.getObjectFromRepo(ctx, input.Class, input.ID,
additional.Properties{}, nil, tenant)
if err != nil {
errnf := ErrNotFound{}
if errors.As(err, &errnf) {
return &Error{"source object", StatusNotFound, err}
} else if errors.As(err, &ErrMultiTenancy{}) {
return &Error{"source object", StatusUnprocessableEntity, err}
}
return &Error{"source object", StatusInternalServerError, err}
}
input.Class = res.ClassName
path := fmt.Sprintf("objects/%s/%s", input.Class, input.ID)
if err := m.authorizer.Authorize(principal, "update", path); err != nil {
return &Error{path, StatusForbidden, err}
}
unlock, err := m.locks.LockSchema()
if err != nil {
return &Error{"cannot lock", StatusInternalServerError, err}
}
defer unlock()
if err := input.validate(ctx, principal, m.schemaManager); err != nil {
if deprecatedEndpoint { // for backward comp reasons
return &Error{"bad inputs deprecated", StatusNotFound, err}
}
if errors.As(err, &ErrMultiTenancy{}) {
return &Error{"bad inputs", StatusUnprocessableEntity, err}
}
return &Error{"bad inputs", StatusBadRequest, err}
}
obj := res.Object()
obj.Tenant = tenant
ok, errmsg := removeReference(obj, input.Property, &input.Reference)
if errmsg != "" {
return &Error{errmsg, StatusInternalServerError, nil}
}
if !ok {
return nil
}
obj.LastUpdateTimeUnix = m.timeSource.Now()
err = m.vectorRepo.PutObject(ctx, obj, res.Vector, repl)
if err != nil {
return &Error{"repo.putobject", StatusInternalServerError, err}
}
if err := m.updateRefVector(ctx, principal, input.Class, input.ID, tenant); err != nil {
return &Error{"update ref vector", StatusInternalServerError, err}
}
return nil
}
func (req *DeleteReferenceInput) validate(
ctx context.Context,
principal *models.Principal,
sm schemaManager,
) error {
if err := validateReferenceName(req.Class, req.Property); err != nil {
return err
}
schema, err := sm.GetSchema(principal)
if err != nil {
return err
}
return validateReferenceSchema(req.Class, req.Property, schema)
}
// removeReference removes ref from object obj with property prop.
// It returns ok (removal took place) and an error message
func removeReference(obj *models.Object, prop string, ref *models.SingleRef) (ok bool, errmsg string) {
properties := obj.Properties.(map[string]interface{})
if properties == nil || properties[prop] == nil {
return false, ""
}
refs, ok := properties[prop].(models.MultipleRef)
if !ok {
return false, "source list is not well formed"
}
newrefs := make(models.MultipleRef, 0, len(refs))
for _, r := range refs {
if r.Beacon != ref.Beacon {
newrefs = append(newrefs, r)
}
}
properties[prop] = newrefs
return len(refs) != len(newrefs), ""
}