KevinStephenson
Adding in weaviate code
b110593
raw
history blame
33.2 kB
// _ _
// __ _____ __ ___ ___ __ _| |_ ___
// \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
// \ V V / __/ (_| |\ V /| | (_| | || __/
// \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
//
// Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
//
// CONTACT: [email protected]
//
package rest
import (
"context"
"errors"
"fmt"
"strings"
middleware "github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/strfmt"
"github.com/sirupsen/logrus"
"github.com/weaviate/weaviate/adapters/handlers/rest/operations"
"github.com/weaviate/weaviate/adapters/handlers/rest/operations/objects"
"github.com/weaviate/weaviate/entities/additional"
"github.com/weaviate/weaviate/entities/models"
"github.com/weaviate/weaviate/entities/schema/crossref"
autherrs "github.com/weaviate/weaviate/usecases/auth/authorization/errors"
"github.com/weaviate/weaviate/usecases/config"
"github.com/weaviate/weaviate/usecases/monitoring"
uco "github.com/weaviate/weaviate/usecases/objects"
"github.com/weaviate/weaviate/usecases/replica"
)
type objectHandlers struct {
manager objectsManager
logger logrus.FieldLogger
config config.Config
modulesProvider ModulesProvider
metricRequestsTotal restApiRequestsTotal
}
type ModulesProvider interface {
RestApiAdditionalProperties(includeProp string, class *models.Class) map[string]interface{}
GetMeta() (map[string]interface{}, error)
HasMultipleVectorizers() bool
}
type objectsManager interface {
AddObject(context.Context, *models.Principal, *models.Object,
*additional.ReplicationProperties) (*models.Object, error)
ValidateObject(context.Context, *models.Principal,
*models.Object, *additional.ReplicationProperties) error
GetObject(context.Context, *models.Principal, string, strfmt.UUID,
additional.Properties, *additional.ReplicationProperties, string) (*models.Object, error)
DeleteObject(context.Context, *models.Principal, string,
strfmt.UUID, *additional.ReplicationProperties, string) error
UpdateObject(context.Context, *models.Principal, string, strfmt.UUID,
*models.Object, *additional.ReplicationProperties) (*models.Object, error)
HeadObject(ctx context.Context, principal *models.Principal, class string, id strfmt.UUID,
repl *additional.ReplicationProperties, tenant string) (bool, *uco.Error)
GetObjects(context.Context, *models.Principal, *int64, *int64,
*string, *string, *string, additional.Properties, string) ([]*models.Object, error)
Query(ctx context.Context, principal *models.Principal,
params *uco.QueryParams) ([]*models.Object, *uco.Error)
MergeObject(context.Context, *models.Principal, *models.Object,
*additional.ReplicationProperties) *uco.Error
AddObjectReference(context.Context, *models.Principal, *uco.AddReferenceInput,
*additional.ReplicationProperties, string) *uco.Error
UpdateObjectReferences(context.Context, *models.Principal,
*uco.PutReferenceInput, *additional.ReplicationProperties, string) *uco.Error
DeleteObjectReference(context.Context, *models.Principal, *uco.DeleteReferenceInput,
*additional.ReplicationProperties, string) *uco.Error
GetObjectsClass(ctx context.Context, principal *models.Principal, id strfmt.UUID) (*models.Class, error)
GetObjectClassFromName(ctx context.Context, principal *models.Principal, className string) (*models.Class, error)
}
func (h *objectHandlers) addObject(params objects.ObjectsCreateParams,
principal *models.Principal,
) middleware.Responder {
repl, err := getReplicationProperties(params.ConsistencyLevel, nil)
if err != nil {
h.metricRequestsTotal.logError("", err)
return objects.NewObjectsCreateBadRequest().
WithPayload(errPayloadFromSingleErr(err))
}
className := getClassName(params.Body)
object, err := h.manager.AddObject(params.HTTPRequest.Context(),
principal, params.Body, repl)
if err != nil {
h.metricRequestsTotal.logError(className, err)
if errors.As(err, &uco.ErrInvalidUserInput{}) {
return objects.NewObjectsCreateUnprocessableEntity().
WithPayload(errPayloadFromSingleErr(err))
} else if errors.As(err, &uco.ErrMultiTenancy{}) {
return objects.NewObjectsCreateUnprocessableEntity().
WithPayload(errPayloadFromSingleErr(err))
} else if errors.As(err, &autherrs.Forbidden{}) {
return objects.NewObjectsCreateForbidden().
WithPayload(errPayloadFromSingleErr(err))
} else {
return objects.NewObjectsCreateInternalServerError().
WithPayload(errPayloadFromSingleErr(err))
}
}
propertiesMap, ok := object.Properties.(map[string]interface{})
if ok {
object.Properties = h.extendPropertiesWithAPILinks(propertiesMap)
}
h.metricRequestsTotal.logOk(className)
return objects.NewObjectsCreateOK().WithPayload(object)
}
func (h *objectHandlers) validateObject(params objects.ObjectsValidateParams,
principal *models.Principal,
) middleware.Responder {
className := getClassName(params.Body)
err := h.manager.ValidateObject(params.HTTPRequest.Context(), principal, params.Body, nil)
if err != nil {
h.metricRequestsTotal.logError(className, err)
switch err.(type) {
case autherrs.Forbidden:
return objects.NewObjectsValidateForbidden().
WithPayload(errPayloadFromSingleErr(err))
case uco.ErrInvalidUserInput:
return objects.NewObjectsValidateUnprocessableEntity().
WithPayload(errPayloadFromSingleErr(err))
case uco.ErrMultiTenancy:
return objects.NewObjectsValidateUnprocessableEntity().
WithPayload(errPayloadFromSingleErr(err))
default:
return objects.NewObjectsValidateInternalServerError().
WithPayload(errPayloadFromSingleErr(err))
}
}
h.metricRequestsTotal.logOk(className)
return objects.NewObjectsValidateOK()
}
// getObject gets object of a specific class
func (h *objectHandlers) getObject(params objects.ObjectsClassGetParams,
principal *models.Principal,
) middleware.Responder {
var additional additional.Properties
// The process to extract additional params depends on knowing the schema
// which in turn requires a preflight load of the object. We can save this
// second db request if we know that the user did not specify any additional
// params. This could potentially be optimized further by checking if only
// non-module specific params are contained and decide then, but we do not
// know if this path is critical enough for this level of optimization.
if params.Include != nil {
var class *models.Class
var err error
if params.ClassName == "" { // deprecated request without classname
class, err = h.manager.GetObjectsClass(params.HTTPRequest.Context(), principal, params.ID)
} else {
class, err = h.manager.GetObjectClassFromName(params.HTTPRequest.Context(), principal, params.ClassName)
}
if err != nil {
h.metricRequestsTotal.logUserError(params.ClassName)
return objects.NewObjectsClassGetBadRequest().
WithPayload(errPayloadFromSingleErr(err))
}
additional, err = parseIncludeParam(params.Include, h.modulesProvider, true, class)
if err != nil {
h.metricRequestsTotal.logError(params.ClassName, err)
return objects.NewObjectsClassGetBadRequest().
WithPayload(errPayloadFromSingleErr(err))
}
}
replProps, err := getReplicationProperties(params.ConsistencyLevel, params.NodeName)
if err != nil {
h.metricRequestsTotal.logError(params.ClassName, err)
return objects.NewObjectsClassGetBadRequest().
WithPayload(errPayloadFromSingleErr(err))
}
tenant := getTenant(params.Tenant)
object, err := h.manager.GetObject(params.HTTPRequest.Context(), principal,
params.ClassName, params.ID, additional, replProps, tenant)
if err != nil {
h.metricRequestsTotal.logError(getClassName(object), err)
switch err.(type) {
case autherrs.Forbidden:
return objects.NewObjectsClassGetForbidden().
WithPayload(errPayloadFromSingleErr(err))
case uco.ErrNotFound:
return objects.NewObjectsClassGetNotFound()
case uco.ErrMultiTenancy:
return objects.NewObjectsClassGetUnprocessableEntity().
WithPayload(errPayloadFromSingleErr(err))
default:
return objects.NewObjectsClassGetInternalServerError().
WithPayload(errPayloadFromSingleErr(err))
}
}
propertiesMap, ok := object.Properties.(map[string]interface{})
if ok {
object.Properties = h.extendPropertiesWithAPILinks(propertiesMap)
}
h.metricRequestsTotal.logOk(getClassName(object))
return objects.NewObjectsClassGetOK().WithPayload(object)
}
func (h *objectHandlers) getObjects(params objects.ObjectsListParams,
principal *models.Principal,
) middleware.Responder {
if params.Class != nil && *params.Class != "" {
return h.query(params, principal)
}
additional, err := parseIncludeParam(params.Include, h.modulesProvider, h.shouldIncludeGetObjectsModuleParams(), nil)
if err != nil {
h.metricRequestsTotal.logError("", err)
return objects.NewObjectsListBadRequest().
WithPayload(errPayloadFromSingleErr(err))
}
var deprecationsRes []*models.Deprecation
list, err := h.manager.GetObjects(params.HTTPRequest.Context(), principal,
params.Offset, params.Limit, params.Sort, params.Order, params.After, additional,
getTenant(params.Tenant))
if err != nil {
h.metricRequestsTotal.logError("", err)
switch err.(type) {
case autherrs.Forbidden:
return objects.NewObjectsListForbidden().
WithPayload(errPayloadFromSingleErr(err))
case uco.ErrMultiTenancy:
return objects.NewObjectsListUnprocessableEntity().
WithPayload(errPayloadFromSingleErr(err))
default:
return objects.NewObjectsListInternalServerError().
WithPayload(errPayloadFromSingleErr(err))
}
}
for i, object := range list {
propertiesMap, ok := object.Properties.(map[string]interface{})
if ok {
list[i].Properties = h.extendPropertiesWithAPILinks(propertiesMap)
}
}
h.metricRequestsTotal.logOk("")
return objects.NewObjectsListOK().
WithPayload(&models.ObjectsListResponse{
Objects: list,
TotalResults: int64(len(list)),
Deprecations: deprecationsRes,
})
}
func (h *objectHandlers) query(params objects.ObjectsListParams,
principal *models.Principal,
) middleware.Responder {
additional, err := parseIncludeParam(params.Include, h.modulesProvider, h.shouldIncludeGetObjectsModuleParams(), nil)
if err != nil {
h.metricRequestsTotal.logError(*params.Class, err)
return objects.NewObjectsListBadRequest().
WithPayload(errPayloadFromSingleErr(err))
}
req := uco.QueryParams{
Class: *params.Class,
Offset: params.Offset,
Limit: params.Limit,
After: params.After,
Sort: params.Sort,
Order: params.Order,
Tenant: params.Tenant,
Additional: additional,
}
resultSet, rerr := h.manager.Query(params.HTTPRequest.Context(), principal, &req)
if rerr != nil {
h.metricRequestsTotal.logError(req.Class, rerr)
switch rerr.Code {
case uco.StatusForbidden:
return objects.NewObjectsListForbidden().
WithPayload(errPayloadFromSingleErr(rerr))
case uco.StatusNotFound:
return objects.NewObjectsListNotFound()
case uco.StatusBadRequest:
return objects.NewObjectsListUnprocessableEntity().
WithPayload(errPayloadFromSingleErr(rerr))
case uco.StatusUnprocessableEntity:
return objects.NewObjectsListUnprocessableEntity().
WithPayload(errPayloadFromSingleErr(rerr))
default:
return objects.NewObjectsListInternalServerError().
WithPayload(errPayloadFromSingleErr(rerr))
}
}
for i, object := range resultSet {
propertiesMap, ok := object.Properties.(map[string]interface{})
if ok {
resultSet[i].Properties = h.extendPropertiesWithAPILinks(propertiesMap)
}
}
h.metricRequestsTotal.logOk(req.Class)
return objects.NewObjectsListOK().
WithPayload(&models.ObjectsListResponse{
Objects: resultSet,
TotalResults: int64(len(resultSet)),
Deprecations: []*models.Deprecation{},
})
}
// deleteObject delete a single object of giving class
func (h *objectHandlers) deleteObject(params objects.ObjectsClassDeleteParams,
principal *models.Principal,
) middleware.Responder {
repl, err := getReplicationProperties(params.ConsistencyLevel, nil)
if err != nil {
h.metricRequestsTotal.logError(params.ClassName, err)
return objects.NewObjectsCreateBadRequest().
WithPayload(errPayloadFromSingleErr(err))
}
tenant := getTenant(params.Tenant)
err = h.manager.DeleteObject(params.HTTPRequest.Context(),
principal, params.ClassName, params.ID, repl, tenant)
if err != nil {
h.metricRequestsTotal.logError(params.ClassName, err)
switch err.(type) {
case autherrs.Forbidden:
return objects.NewObjectsClassDeleteForbidden().
WithPayload(errPayloadFromSingleErr(err))
case uco.ErrNotFound:
return objects.NewObjectsClassDeleteNotFound()
case uco.ErrMultiTenancy:
return objects.NewObjectsClassDeleteUnprocessableEntity().
WithPayload(errPayloadFromSingleErr(err))
default:
return objects.NewObjectsClassDeleteInternalServerError().
WithPayload(errPayloadFromSingleErr(err))
}
}
h.metricRequestsTotal.logOk(params.ClassName)
return objects.NewObjectsClassDeleteNoContent()
}
func (h *objectHandlers) updateObject(params objects.ObjectsClassPutParams,
principal *models.Principal,
) middleware.Responder {
className := getClassName(params.Body)
repl, err := getReplicationProperties(params.ConsistencyLevel, nil)
if err != nil {
h.metricRequestsTotal.logError(className, err)
return objects.NewObjectsCreateBadRequest().
WithPayload(errPayloadFromSingleErr(err))
}
object, err := h.manager.UpdateObject(params.HTTPRequest.Context(),
principal, params.ClassName, params.ID, params.Body, repl)
if err != nil {
h.metricRequestsTotal.logError(className, err)
if errors.As(err, &uco.ErrInvalidUserInput{}) {
return objects.NewObjectsClassPutUnprocessableEntity().
WithPayload(errPayloadFromSingleErr(err))
} else if errors.As(err, &uco.ErrMultiTenancy{}) {
return objects.NewObjectsClassPutUnprocessableEntity().
WithPayload(errPayloadFromSingleErr(err))
} else if errors.As(err, &autherrs.Forbidden{}) {
return objects.NewObjectsClassPutForbidden().
WithPayload(errPayloadFromSingleErr(err))
} else {
return objects.NewObjectsClassPutInternalServerError().
WithPayload(errPayloadFromSingleErr(err))
}
}
propertiesMap, ok := object.Properties.(map[string]interface{})
if ok {
object.Properties = h.extendPropertiesWithAPILinks(propertiesMap)
}
h.metricRequestsTotal.logOk(className)
return objects.NewObjectsClassPutOK().WithPayload(object)
}
func (h *objectHandlers) headObject(params objects.ObjectsClassHeadParams,
principal *models.Principal,
) middleware.Responder {
repl, err := getReplicationProperties(params.ConsistencyLevel, nil)
if err != nil {
h.metricRequestsTotal.logError(params.ClassName, err)
return objects.NewObjectsCreateBadRequest().
WithPayload(errPayloadFromSingleErr(err))
}
tenant := getTenant(params.Tenant)
exists, objErr := h.manager.HeadObject(params.HTTPRequest.Context(),
principal, params.ClassName, params.ID, repl, tenant)
if objErr != nil {
h.metricRequestsTotal.logError(params.ClassName, objErr)
switch {
case objErr.Forbidden():
return objects.NewObjectsClassHeadForbidden().
WithPayload(errPayloadFromSingleErr(objErr))
case objErr.UnprocessableEntity():
return objects.NewObjectsClassHeadUnprocessableEntity().
WithPayload(errPayloadFromSingleErr(objErr))
default:
return objects.NewObjectsClassHeadInternalServerError().
WithPayload(errPayloadFromSingleErr(objErr))
}
}
h.metricRequestsTotal.logOk(params.ClassName)
if !exists {
return objects.NewObjectsClassHeadNotFound()
}
return objects.NewObjectsClassHeadNoContent()
}
func (h *objectHandlers) patchObject(params objects.ObjectsClassPatchParams, principal *models.Principal) middleware.Responder {
updates := params.Body
updates.ID = params.ID
updates.Class = params.ClassName
repl, err := getReplicationProperties(params.ConsistencyLevel, nil)
if err != nil {
h.metricRequestsTotal.logError(getClassName(updates), err)
return objects.NewObjectsCreateBadRequest().
WithPayload(errPayloadFromSingleErr(err))
}
objErr := h.manager.MergeObject(params.HTTPRequest.Context(), principal, updates, repl)
if objErr != nil {
h.metricRequestsTotal.logError(getClassName(updates), objErr)
switch {
case objErr.NotFound():
return objects.NewObjectsClassPatchNotFound()
case objErr.Forbidden():
return objects.NewObjectsClassPatchForbidden().
WithPayload(errPayloadFromSingleErr(objErr))
case objErr.BadRequest():
return objects.NewObjectsClassPatchUnprocessableEntity().
WithPayload(errPayloadFromSingleErr(objErr))
case objErr.UnprocessableEntity():
return objects.NewObjectsClassPatchUnprocessableEntity().
WithPayload(errPayloadFromSingleErr(objErr))
default:
return objects.NewObjectsClassPatchInternalServerError().
WithPayload(errPayloadFromSingleErr(objErr))
}
}
h.metricRequestsTotal.logOk(getClassName(updates))
return objects.NewObjectsClassPatchNoContent()
}
func (h *objectHandlers) addObjectReference(
params objects.ObjectsClassReferencesCreateParams,
principal *models.Principal,
) middleware.Responder {
input := uco.AddReferenceInput{
Class: params.ClassName,
ID: params.ID,
Property: params.PropertyName,
Ref: *params.Body,
}
repl, err := getReplicationProperties(params.ConsistencyLevel, nil)
if err != nil {
h.metricRequestsTotal.logError(params.ClassName, err)
return objects.NewObjectsCreateBadRequest().
WithPayload(errPayloadFromSingleErr(err))
}
tenant := getTenant(params.Tenant)
objErr := h.manager.AddObjectReference(params.HTTPRequest.Context(), principal, &input, repl, tenant)
if objErr != nil {
h.metricRequestsTotal.logError(params.ClassName, objErr)
switch {
case objErr.Forbidden():
return objects.NewObjectsClassReferencesCreateForbidden().
WithPayload(errPayloadFromSingleErr(objErr))
case objErr.NotFound():
return objects.NewObjectsClassReferencesCreateNotFound()
case objErr.BadRequest():
return objects.NewObjectsClassReferencesCreateUnprocessableEntity().
WithPayload(errPayloadFromSingleErr(objErr))
case objErr.UnprocessableEntity():
return objects.NewObjectsClassReferencesCreateUnprocessableEntity().
WithPayload(errPayloadFromSingleErr(objErr))
default:
return objects.NewObjectsClassReferencesCreateInternalServerError().
WithPayload(errPayloadFromSingleErr(objErr))
}
}
h.metricRequestsTotal.logOk(params.ClassName)
return objects.NewObjectsClassReferencesCreateOK()
}
func (h *objectHandlers) putObjectReferences(params objects.ObjectsClassReferencesPutParams,
principal *models.Principal,
) middleware.Responder {
input := uco.PutReferenceInput{
Class: params.ClassName,
ID: params.ID,
Property: params.PropertyName,
Refs: params.Body,
}
repl, err := getReplicationProperties(params.ConsistencyLevel, nil)
if err != nil {
h.metricRequestsTotal.logError(params.ClassName, err)
return objects.NewObjectsCreateBadRequest().
WithPayload(errPayloadFromSingleErr(err))
}
tenant := getTenant(params.Tenant)
objErr := h.manager.UpdateObjectReferences(params.HTTPRequest.Context(), principal, &input, repl, tenant)
if objErr != nil {
h.metricRequestsTotal.logError(params.ClassName, objErr)
switch {
case objErr.Forbidden():
return objects.NewObjectsClassReferencesPutForbidden().
WithPayload(errPayloadFromSingleErr(objErr))
case objErr.NotFound():
return objects.NewObjectsClassReferencesPutNotFound()
case objErr.BadRequest():
return objects.NewObjectsClassReferencesPutUnprocessableEntity().
WithPayload(errPayloadFromSingleErr(objErr))
case objErr.UnprocessableEntity():
return objects.NewObjectsClassReferencesPutUnprocessableEntity().
WithPayload(errPayloadFromSingleErr(objErr))
default:
return objects.NewObjectsClassReferencesPutInternalServerError().
WithPayload(errPayloadFromSingleErr(objErr))
}
}
h.metricRequestsTotal.logOk(params.ClassName)
return objects.NewObjectsClassReferencesPutOK()
}
func (h *objectHandlers) deleteObjectReference(params objects.ObjectsClassReferencesDeleteParams,
principal *models.Principal,
) middleware.Responder {
input := uco.DeleteReferenceInput{
Class: params.ClassName,
ID: params.ID,
Property: params.PropertyName,
Reference: *params.Body,
}
repl, err := getReplicationProperties(params.ConsistencyLevel, nil)
if err != nil {
h.metricRequestsTotal.logError(params.ClassName, err)
return objects.NewObjectsCreateBadRequest().
WithPayload(errPayloadFromSingleErr(err))
}
tenant := getTenant(params.Tenant)
objErr := h.manager.DeleteObjectReference(params.HTTPRequest.Context(), principal, &input, repl, tenant)
if objErr != nil {
h.metricRequestsTotal.logError(params.ClassName, objErr)
switch objErr.Code {
case uco.StatusForbidden:
return objects.NewObjectsClassReferencesDeleteForbidden().
WithPayload(errPayloadFromSingleErr(objErr))
case uco.StatusNotFound:
return objects.NewObjectsClassReferencesDeleteNotFound()
case uco.StatusBadRequest:
return objects.NewObjectsClassReferencesDeleteUnprocessableEntity().
WithPayload(errPayloadFromSingleErr(objErr))
case uco.StatusUnprocessableEntity:
return objects.NewObjectsClassReferencesDeleteUnprocessableEntity().
WithPayload(errPayloadFromSingleErr(objErr))
default:
return objects.NewObjectsClassReferencesDeleteInternalServerError().
WithPayload(errPayloadFromSingleErr(objErr))
}
}
h.metricRequestsTotal.logOk(params.ClassName)
return objects.NewObjectsClassReferencesDeleteNoContent()
}
func setupObjectHandlers(api *operations.WeaviateAPI,
manager *uco.Manager, config config.Config, logger logrus.FieldLogger,
modulesProvider ModulesProvider, metrics *monitoring.PrometheusMetrics,
) {
h := &objectHandlers{manager, logger, config, modulesProvider, newObjectsRequestsTotal(metrics, logger)}
api.ObjectsObjectsCreateHandler = objects.
ObjectsCreateHandlerFunc(h.addObject)
api.ObjectsObjectsValidateHandler = objects.
ObjectsValidateHandlerFunc(h.validateObject)
api.ObjectsObjectsClassGetHandler = objects.
ObjectsClassGetHandlerFunc(h.getObject)
api.ObjectsObjectsClassHeadHandler = objects.
ObjectsClassHeadHandlerFunc(h.headObject)
api.ObjectsObjectsClassDeleteHandler = objects.
ObjectsClassDeleteHandlerFunc(h.deleteObject)
api.ObjectsObjectsListHandler = objects.
ObjectsListHandlerFunc(h.getObjects)
api.ObjectsObjectsClassPutHandler = objects.
ObjectsClassPutHandlerFunc(h.updateObject)
api.ObjectsObjectsClassPatchHandler = objects.
ObjectsClassPatchHandlerFunc(h.patchObject)
api.ObjectsObjectsClassReferencesCreateHandler = objects.
ObjectsClassReferencesCreateHandlerFunc(h.addObjectReference)
api.ObjectsObjectsClassReferencesDeleteHandler = objects.
ObjectsClassReferencesDeleteHandlerFunc(h.deleteObjectReference)
api.ObjectsObjectsClassReferencesPutHandler = objects.
ObjectsClassReferencesPutHandlerFunc(h.putObjectReferences)
// deprecated handlers
api.ObjectsObjectsGetHandler = objects.
ObjectsGetHandlerFunc(h.getObjectDeprecated)
api.ObjectsObjectsDeleteHandler = objects.
ObjectsDeleteHandlerFunc(h.deleteObjectDeprecated)
api.ObjectsObjectsHeadHandler = objects.
ObjectsHeadHandlerFunc(h.headObjectDeprecated)
api.ObjectsObjectsUpdateHandler = objects.
ObjectsUpdateHandlerFunc(h.updateObjectDeprecated)
api.ObjectsObjectsPatchHandler = objects.
ObjectsPatchHandlerFunc(h.patchObjectDeprecated)
api.ObjectsObjectsReferencesCreateHandler = objects.
ObjectsReferencesCreateHandlerFunc(h.addObjectReferenceDeprecated)
api.ObjectsObjectsReferencesUpdateHandler = objects.
ObjectsReferencesUpdateHandlerFunc(h.updateObjectReferencesDeprecated)
api.ObjectsObjectsReferencesDeleteHandler = objects.
ObjectsReferencesDeleteHandlerFunc(h.deleteObjectReferenceDeprecated)
}
func (h *objectHandlers) getObjectDeprecated(params objects.ObjectsGetParams,
principal *models.Principal,
) middleware.Responder {
h.logger.Warn("deprecated endpoint: ", "GET "+params.HTTPRequest.URL.Path)
ps := objects.ObjectsClassGetParams{
HTTPRequest: params.HTTPRequest,
ID: params.ID,
Include: params.Include,
}
return h.getObject(ps, principal)
}
func (h *objectHandlers) headObjectDeprecated(params objects.ObjectsHeadParams,
principal *models.Principal,
) middleware.Responder {
h.logger.Warn("deprecated endpoint: ", "HEAD "+params.HTTPRequest.URL.Path)
r := objects.ObjectsClassHeadParams{
HTTPRequest: params.HTTPRequest,
ID: params.ID,
}
return h.headObject(r, principal)
}
func (h *objectHandlers) patchObjectDeprecated(params objects.ObjectsPatchParams, principal *models.Principal) middleware.Responder {
h.logger.Warn("deprecated endpoint: ", "PATCH "+params.HTTPRequest.URL.Path)
args := objects.ObjectsClassPatchParams{
HTTPRequest: params.HTTPRequest,
ID: params.ID,
Body: params.Body,
}
if params.Body != nil {
args.ClassName = params.Body.Class
}
return h.patchObject(args, principal)
}
func (h *objectHandlers) updateObjectDeprecated(params objects.ObjectsUpdateParams,
principal *models.Principal,
) middleware.Responder {
h.logger.Warn("deprecated endpoint: ", "PUT "+params.HTTPRequest.URL.Path)
ps := objects.ObjectsClassPutParams{
HTTPRequest: params.HTTPRequest,
ClassName: params.Body.Class,
Body: params.Body,
ID: params.ID,
}
return h.updateObject(ps, principal)
}
func (h *objectHandlers) deleteObjectDeprecated(params objects.ObjectsDeleteParams,
principal *models.Principal,
) middleware.Responder {
h.logger.Warn("deprecated endpoint: ", "DELETE "+params.HTTPRequest.URL.Path)
ps := objects.ObjectsClassDeleteParams{
HTTPRequest: params.HTTPRequest,
ID: params.ID,
}
return h.deleteObject(ps, principal)
}
func (h *objectHandlers) addObjectReferenceDeprecated(params objects.ObjectsReferencesCreateParams,
principal *models.Principal,
) middleware.Responder {
h.logger.Warn("deprecated endpoint: ", "POST "+params.HTTPRequest.URL.Path)
req := objects.ObjectsClassReferencesCreateParams{
HTTPRequest: params.HTTPRequest,
Body: params.Body,
ID: params.ID,
PropertyName: params.PropertyName,
}
return h.addObjectReference(req, principal)
}
func (h *objectHandlers) updateObjectReferencesDeprecated(params objects.ObjectsReferencesUpdateParams,
principal *models.Principal,
) middleware.Responder {
h.logger.Warn("deprecated endpoint: ", "PUT "+params.HTTPRequest.URL.Path)
req := objects.ObjectsClassReferencesPutParams{
HTTPRequest: params.HTTPRequest,
ID: params.ID,
PropertyName: params.PropertyName,
Body: params.Body,
}
return h.putObjectReferences(req, principal)
}
func (h *objectHandlers) deleteObjectReferenceDeprecated(params objects.ObjectsReferencesDeleteParams,
principal *models.Principal,
) middleware.Responder {
h.logger.Warn("deprecated endpoint: ", "DELETE "+params.HTTPRequest.URL.Path)
req := objects.ObjectsClassReferencesDeleteParams{
HTTPRequest: params.HTTPRequest,
Body: params.Body,
ID: params.ID,
PropertyName: params.PropertyName,
}
return h.deleteObjectReference(req, principal)
}
func (h *objectHandlers) extendPropertiesWithAPILinks(schema map[string]interface{}) map[string]interface{} {
if schema == nil {
return schema
}
for key, value := range schema {
asMultiRef, ok := value.(models.MultipleRef)
if !ok {
continue
}
schema[key] = h.extendReferencesWithAPILinks(asMultiRef)
}
return schema
}
func (h *objectHandlers) extendReferencesWithAPILinks(refs models.MultipleRef) models.MultipleRef {
for i, ref := range refs {
refs[i] = h.extendReferenceWithAPILink(ref)
}
return refs
}
func (h *objectHandlers) extendReferenceWithAPILink(ref *models.SingleRef) *models.SingleRef {
parsed, err := crossref.Parse(ref.Beacon.String())
if err != nil {
// ignore return unchanged
return ref
}
href := fmt.Sprintf("%s/v1/objects/%s/%s", h.config.Origin, parsed.Class, parsed.TargetID)
if parsed.Class == "" {
href = fmt.Sprintf("%s/v1/objects/%s", h.config.Origin, parsed.TargetID)
}
ref.Href = strfmt.URI(href)
return ref
}
func (h *objectHandlers) shouldIncludeGetObjectsModuleParams() bool {
if h.modulesProvider == nil || !h.modulesProvider.HasMultipleVectorizers() {
return true
}
return false
}
type objectsRequestsTotal struct {
*restApiRequestsTotalImpl
}
func newObjectsRequestsTotal(metrics *monitoring.PrometheusMetrics, logger logrus.FieldLogger) restApiRequestsTotal {
return &objectsRequestsTotal{
restApiRequestsTotalImpl: &restApiRequestsTotalImpl{newRequestsTotalMetric(metrics, "rest"), "rest", "objects", logger},
}
}
func (e *objectsRequestsTotal) logError(className string, err error) {
switch err := err.(type) {
case uco.ErrMultiTenancy:
e.logUserError(className)
case errReplication, errUnregonizedProperty:
e.logUserError(className)
case autherrs.Forbidden:
e.logUserError(className)
case uco.ErrInvalidUserInput, uco.ErrNotFound:
e.logUserError(className)
case *uco.Error:
switch err.Code {
case uco.StatusInternalServerError:
e.logServerError(className, err)
default:
e.logUserError(className)
}
default:
if errors.As(err, &uco.ErrInvalidUserInput{}) ||
errors.As(err, &uco.ErrMultiTenancy{}) ||
errors.As(err, &autherrs.Forbidden{}) {
e.logUserError(className)
} else {
e.logServerError(className, err)
}
}
}
func parseIncludeParam(in *string, modulesProvider ModulesProvider, includeModuleParams bool,
class *models.Class,
) (additional.Properties, error) {
out := additional.Properties{}
if in == nil {
return out, nil
}
parts := strings.Split(*in, ",")
for _, prop := range parts {
if prop == "classification" {
out.Classification = true
out.RefMeta = true
continue
}
if prop == "vector" {
out.Vector = true
continue
}
if includeModuleParams && modulesProvider != nil {
moduleParams := modulesProvider.RestApiAdditionalProperties(prop, class)
if len(moduleParams) > 0 {
out.ModuleParams = getModuleParams(out.ModuleParams)
for param, value := range moduleParams {
out.ModuleParams[param] = value
}
continue
}
}
return out, newErrUnregonizedProperty(fmt.Errorf("unrecognized property '%s' in ?include list", prop))
}
return out, nil
}
func getModuleParams(moduleParams map[string]interface{}) map[string]interface{} {
if moduleParams == nil {
return map[string]interface{}{}
}
return moduleParams
}
func getReplicationProperties(consistencyLvl, nodeName *string) (*additional.ReplicationProperties, error) {
if nodeName == nil && consistencyLvl == nil {
return nil, nil
}
repl := additional.ReplicationProperties{}
if nodeName != nil {
repl.NodeName = *nodeName
}
cl, err := getConsistencyLevel(consistencyLvl)
if err != nil {
return nil, newErrReplication(err)
}
repl.ConsistencyLevel = cl
if repl.ConsistencyLevel != "" && repl.NodeName != "" {
return nil, newErrReplication(fmt.Errorf("consistency_level and node_name are mutually exclusive"))
}
return &repl, nil
}
func getConsistencyLevel(lvl *string) (string, error) {
if lvl != nil {
switch replica.ConsistencyLevel(*lvl) {
case replica.One, replica.Quorum, replica.All:
return *lvl, nil
default:
return "", fmt.Errorf("unrecognized consistency level '%v', "+
"try one of the following: ['ONE', 'QUORUM', 'ALL']", *lvl)
}
}
return "", nil
}
func getTenant(maybeKey *string) string {
if maybeKey != nil {
return *maybeKey
}
return ""
}
func getClassName(obj *models.Object) string {
if obj != nil {
return obj.Class
}
return ""
}
type errReplication struct {
err error
}
func newErrReplication(err error) errReplication {
return errReplication{err}
}
func (e errReplication) Error() string {
return fmt.Sprintf("%v", e.err)
}
type errUnregonizedProperty struct {
err error
}
func newErrUnregonizedProperty(err error) errUnregonizedProperty {
return errUnregonizedProperty{err}
}
func (e errUnregonizedProperty) Error() string {
return fmt.Sprintf("%v", e.err)
}