github.com/weaviate/weaviate@v1.24.6/usecases/objects/get.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  	"strings"
    19  
    20  	"github.com/go-openapi/strfmt"
    21  	"github.com/weaviate/weaviate/entities/additional"
    22  	"github.com/weaviate/weaviate/entities/filters"
    23  	"github.com/weaviate/weaviate/entities/models"
    24  	"github.com/weaviate/weaviate/entities/schema"
    25  	"github.com/weaviate/weaviate/entities/search"
    26  )
    27  
    28  // GetObject Class from the connected DB
    29  func (m *Manager) GetObject(ctx context.Context, principal *models.Principal,
    30  	class string, id strfmt.UUID, additional additional.Properties,
    31  	replProps *additional.ReplicationProperties, tenant string,
    32  ) (*models.Object, error) {
    33  	path := fmt.Sprintf("objects/%s", id)
    34  	if class != "" {
    35  		path = fmt.Sprintf("objects/%s/%s", class, id)
    36  	}
    37  	err := m.authorizer.Authorize(principal, "get", path)
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  
    42  	unlock, err := m.locks.LockConnector()
    43  	if err != nil {
    44  		return nil, NewErrInternal("could not acquire lock: %v", err)
    45  	}
    46  	defer unlock()
    47  
    48  	m.metrics.GetObjectInc()
    49  	defer m.metrics.GetObjectDec()
    50  
    51  	res, err := m.getObjectFromRepo(ctx, class, id, additional, replProps, tenant)
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  
    56  	if additional.Vector {
    57  		m.trackUsageSingle(res)
    58  	}
    59  
    60  	return res.ObjectWithVector(additional.Vector), nil
    61  }
    62  
    63  // GetObjects Class from the connected DB
    64  func (m *Manager) GetObjects(ctx context.Context, principal *models.Principal,
    65  	offset *int64, limit *int64, sort *string, order *string, after *string,
    66  	addl additional.Properties, tenant string,
    67  ) ([]*models.Object, error) {
    68  	err := m.authorizer.Authorize(principal, "list", "objects")
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  
    73  	unlock, err := m.locks.LockConnector()
    74  	if err != nil {
    75  		return nil, NewErrInternal("could not acquire lock: %v", err)
    76  	}
    77  	defer unlock()
    78  
    79  	m.metrics.GetObjectInc()
    80  	defer m.metrics.GetObjectDec()
    81  	return m.getObjectsFromRepo(ctx, offset, limit, sort, order, after, addl, tenant)
    82  }
    83  
    84  func (m *Manager) GetObjectsClass(ctx context.Context, principal *models.Principal,
    85  	id strfmt.UUID,
    86  ) (*models.Class, error) {
    87  	err := m.authorizer.Authorize(principal, "get", fmt.Sprintf("objects/%s", id.String()))
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  
    92  	unlock, err := m.locks.LockConnector()
    93  	if err != nil {
    94  		return nil, NewErrInternal("could not acquire lock: %v", err)
    95  	}
    96  	defer unlock()
    97  	m.metrics.GetObjectInc()
    98  	defer m.metrics.GetObjectDec()
    99  
   100  	res, err := m.getObjectFromRepo(ctx, "", id, additional.Properties{}, nil, "")
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  
   105  	s, err := m.schemaManager.GetSchema(principal)
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  
   110  	return s.GetClass(schema.ClassName(res.ClassName)), nil
   111  }
   112  
   113  func (m *Manager) GetObjectClassFromName(ctx context.Context, principal *models.Principal,
   114  	className string,
   115  ) (*models.Class, error) {
   116  	s, err := m.schemaManager.GetSchema(principal)
   117  	if err != nil {
   118  		return nil, err
   119  	}
   120  
   121  	return s.GetClass(schema.ClassName(className)), nil
   122  }
   123  
   124  func (m *Manager) getObjectFromRepo(ctx context.Context, class string, id strfmt.UUID,
   125  	adds additional.Properties, repl *additional.ReplicationProperties, tenant string,
   126  ) (res *search.Result, err error) {
   127  	if class != "" {
   128  		res, err = m.vectorRepo.Object(ctx, class, id, search.SelectProperties{}, adds, repl, tenant)
   129  	} else {
   130  		res, err = m.vectorRepo.ObjectByID(ctx, id, search.SelectProperties{}, adds, tenant)
   131  	}
   132  	if err != nil {
   133  		switch err.(type) {
   134  		case ErrMultiTenancy:
   135  			return nil, NewErrMultiTenancy(fmt.Errorf("repo: object by id: %w", err))
   136  		default:
   137  			return nil, NewErrInternal("repo: object by id: %v", err)
   138  		}
   139  	}
   140  
   141  	if res == nil {
   142  		return nil, NewErrNotFound("no object with id '%s'", id)
   143  	}
   144  
   145  	if m.modulesProvider != nil {
   146  		res, err = m.modulesProvider.GetObjectAdditionalExtend(ctx, res, adds.ModuleParams)
   147  		if err != nil {
   148  			return nil, fmt.Errorf("get extend: %v", err)
   149  		}
   150  	}
   151  
   152  	return res, nil
   153  }
   154  
   155  func (m *Manager) getObjectsFromRepo(ctx context.Context,
   156  	offset, limit *int64, sort, order *string, after *string,
   157  	additional additional.Properties, tenant string,
   158  ) ([]*models.Object, error) {
   159  	smartOffset, smartLimit, err := m.localOffsetLimit(offset, limit)
   160  	if err != nil {
   161  		return nil, NewErrInternal("list objects: %v", err)
   162  	}
   163  	if after != nil {
   164  		return nil, NewErrInternal("list objects: after parameter not allowed, cursor must be specific to one class, set class query param")
   165  	}
   166  	res, err := m.vectorRepo.ObjectSearch(ctx, smartOffset, smartLimit,
   167  		nil, m.getSort(sort, order), additional, tenant)
   168  	if err != nil {
   169  		return nil, NewErrInternal("list objects: %v", err)
   170  	}
   171  
   172  	if m.modulesProvider != nil {
   173  		res, err = m.modulesProvider.ListObjectsAdditionalExtend(ctx, res, additional.ModuleParams)
   174  		if err != nil {
   175  			return nil, NewErrInternal("list extend: %v", err)
   176  		}
   177  	}
   178  
   179  	if additional.Vector {
   180  		m.trackUsageList(res)
   181  	}
   182  
   183  	return res.ObjectsWithVector(additional.Vector), nil
   184  }
   185  
   186  func (m *Manager) getSort(sort, order *string) []filters.Sort {
   187  	if sort != nil {
   188  		sortParams := strings.Split(*sort, ",")
   189  		var orderParams []string
   190  		if order != nil {
   191  			orderParams = strings.Split(*order, ",")
   192  		}
   193  		var res []filters.Sort
   194  		for i := range sortParams {
   195  			res = append(res, filters.Sort{
   196  				Path:  []string{sortParams[i]},
   197  				Order: m.getOrder(orderParams, i),
   198  			})
   199  		}
   200  		return res
   201  	}
   202  	return nil
   203  }
   204  
   205  func (m *Manager) getOrder(order []string, i int) string {
   206  	if len(order) > i {
   207  		switch order[i] {
   208  		case "asc", "desc":
   209  			return order[i]
   210  		default:
   211  			return "asc"
   212  		}
   213  	}
   214  	return "asc"
   215  }
   216  
   217  func (m *Manager) localOffsetOrZero(paramOffset *int64) int {
   218  	offset := int64(0)
   219  	if paramOffset != nil {
   220  		offset = *paramOffset
   221  	}
   222  
   223  	return int(offset)
   224  }
   225  
   226  func (m *Manager) localLimitOrGlobalLimit(offset int64, paramMaxResults *int64) int {
   227  	limit := int64(m.config.Config.QueryDefaults.Limit)
   228  	// Get the max results from params, if exists
   229  	if paramMaxResults != nil {
   230  		limit = *paramMaxResults
   231  	}
   232  
   233  	return int(limit)
   234  }
   235  
   236  func (m *Manager) localOffsetLimit(paramOffset *int64, paramLimit *int64) (int, int, error) {
   237  	offset := m.localOffsetOrZero(paramOffset)
   238  	limit := m.localLimitOrGlobalLimit(int64(offset), paramLimit)
   239  
   240  	if int64(offset+limit) > m.config.Config.QueryMaximumResults {
   241  		return 0, 0, errors.New("query maximum results exceeded")
   242  	}
   243  
   244  	return offset, limit, nil
   245  }
   246  
   247  func (m *Manager) trackUsageSingle(res *search.Result) {
   248  	if res == nil {
   249  		return
   250  	}
   251  	m.metrics.AddUsageDimensions(res.ClassName, "get_rest", "single_include_vector", res.Dims)
   252  }
   253  
   254  func (m *Manager) trackUsageList(res search.Results) {
   255  	if len(res) == 0 {
   256  		return
   257  	}
   258  	m.metrics.AddUsageDimensions(res[0].ClassName, "get_rest", "list_include_vector", res[0].Dims)
   259  }
   260  
   261  func (m *Manager) getCursor(after *string, limit *int64) *filters.Cursor {
   262  	if after != nil {
   263  		if limit == nil {
   264  			// limit -1 means that no limit param was set
   265  			return &filters.Cursor{After: *after, Limit: -1}
   266  		}
   267  		return &filters.Cursor{After: *after, Limit: int(*limit)}
   268  	}
   269  	return nil
   270  }