Spaces:
Running
Running
File size: 4,505 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 |
// _ _
// __ _____ __ ___ ___ __ _| |_ ___
// \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
// \ 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), ""
}
|