github.com/weaviate/weaviate@v1.24.6/usecases/objects/references_delete.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 objects 13 14 import ( 15 "context" 16 "errors" 17 "fmt" 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 ) 24 25 // DeleteReferenceInput represents required inputs to delete a reference from an existing object. 26 type DeleteReferenceInput struct { 27 // Class name 28 Class string 29 // ID of an object 30 ID strfmt.UUID 31 // Property name 32 Property string 33 // Reference cross reference 34 Reference models.SingleRef 35 } 36 37 func (m *Manager) DeleteObjectReference(ctx context.Context, principal *models.Principal, 38 input *DeleteReferenceInput, repl *additional.ReplicationProperties, tenant string, 39 ) *Error { 40 m.metrics.DeleteReferenceInc() 41 defer m.metrics.DeleteReferenceDec() 42 43 deprecatedEndpoint := input.Class == "" 44 beacon, err := crossref.Parse(input.Reference.Beacon.String()) 45 if err != nil { 46 return &Error{"cannot parse beacon", StatusBadRequest, err} 47 } 48 if input.Class != "" && beacon.Class == "" { 49 toClass, toBeacon, replace, err := m.autodetectToClass(ctx, principal, input.Class, input.Property, beacon) 50 if err != nil { 51 return err 52 } 53 if replace { 54 input.Reference.Class = toClass 55 input.Reference.Beacon = toBeacon 56 } 57 } 58 59 res, err := m.getObjectFromRepo(ctx, input.Class, input.ID, 60 additional.Properties{}, nil, tenant) 61 if err != nil { 62 errnf := ErrNotFound{} 63 if errors.As(err, &errnf) { 64 return &Error{"source object", StatusNotFound, err} 65 } else if errors.As(err, &ErrMultiTenancy{}) { 66 return &Error{"source object", StatusUnprocessableEntity, err} 67 } 68 return &Error{"source object", StatusInternalServerError, err} 69 } 70 input.Class = res.ClassName 71 72 path := fmt.Sprintf("objects/%s/%s", input.Class, input.ID) 73 if err := m.authorizer.Authorize(principal, "update", path); err != nil { 74 return &Error{path, StatusForbidden, err} 75 } 76 77 unlock, err := m.locks.LockSchema() 78 if err != nil { 79 return &Error{"cannot lock", StatusInternalServerError, err} 80 } 81 defer unlock() 82 83 if err := input.validate(ctx, principal, m.schemaManager); err != nil { 84 if deprecatedEndpoint { // for backward comp reasons 85 return &Error{"bad inputs deprecated", StatusNotFound, err} 86 } 87 if errors.As(err, &ErrMultiTenancy{}) { 88 return &Error{"bad inputs", StatusUnprocessableEntity, err} 89 } 90 return &Error{"bad inputs", StatusBadRequest, err} 91 } 92 93 obj := res.Object() 94 obj.Tenant = tenant 95 ok, errmsg := removeReference(obj, input.Property, &input.Reference) 96 if errmsg != "" { 97 return &Error{errmsg, StatusInternalServerError, nil} 98 } 99 if !ok { 100 return nil 101 } 102 obj.LastUpdateTimeUnix = m.timeSource.Now() 103 104 err = m.vectorRepo.PutObject(ctx, obj, res.Vector, res.Vectors, repl) 105 if err != nil { 106 return &Error{"repo.putobject", StatusInternalServerError, err} 107 } 108 109 if err := m.updateRefVector(ctx, principal, input.Class, input.ID, tenant); err != nil { 110 return &Error{"update ref vector", StatusInternalServerError, err} 111 } 112 113 return nil 114 } 115 116 func (req *DeleteReferenceInput) validate( 117 ctx context.Context, 118 principal *models.Principal, 119 sm schemaManager, 120 ) error { 121 if err := validateReferenceName(req.Class, req.Property); err != nil { 122 return err 123 } 124 125 schema, err := sm.GetSchema(principal) 126 if err != nil { 127 return err 128 } 129 return validateReferenceSchema(req.Class, req.Property, schema) 130 } 131 132 // removeReference removes ref from object obj with property prop. 133 // It returns ok (removal took place) and an error message 134 func removeReference(obj *models.Object, prop string, ref *models.SingleRef) (ok bool, errmsg string) { 135 properties := obj.Properties.(map[string]interface{}) 136 if properties == nil || properties[prop] == nil { 137 return false, "" 138 } 139 140 refs, ok := properties[prop].(models.MultipleRef) 141 if !ok { 142 return false, "source list is not well formed" 143 } 144 145 newrefs := make(models.MultipleRef, 0, len(refs)) 146 for _, r := range refs { 147 if r.Beacon != ref.Beacon { 148 newrefs = append(newrefs, r) 149 } 150 } 151 properties[prop] = newrefs 152 return len(refs) != len(newrefs), "" 153 }