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 }