github.com/weaviate/weaviate@v1.24.6/adapters/handlers/grpc/v1/mapping.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 v1 13 14 import ( 15 "github.com/pkg/errors" 16 "github.com/weaviate/weaviate/entities/models" 17 "github.com/weaviate/weaviate/entities/schema" 18 "github.com/weaviate/weaviate/entities/search" 19 pb "github.com/weaviate/weaviate/grpc/generated/protocol/v1" 20 "google.golang.org/protobuf/runtime/protoimpl" 21 ) 22 23 func parseArray[T float64 | bool | string](v interface{}, innerDt schema.DataType) (*pb.Value, error) { 24 if _, ok := v.([]interface{}); ok { 25 return &pb.Value{Kind: &pb.Value_ListValue{ListValue: &pb.ListValue{Values: []*pb.Value{}}}}, nil 26 } 27 val, ok := v.([]T) 28 if !ok { 29 return nil, protoimpl.X.NewError("invalid type: %T when serializing %v", v, innerDt.String()) 30 } 31 list, err := NewPrimitiveList(val, innerDt) 32 if err != nil { 33 return nil, errors.Wrapf(err, "serializing array with type %v", innerDt) 34 } 35 return NewListValue(list), nil 36 } 37 38 func NewPrimitiveValue(v interface{}, dt schema.DataType) (*pb.Value, error) { 39 if v == nil { 40 return NewNilValue(), nil 41 } 42 innerDt, ok := schema.IsArrayType(dt) 43 if ok { 44 switch dt { 45 case schema.DataTypeBooleanArray: 46 return parseArray[bool](v, innerDt) 47 case schema.DataTypeDateArray: 48 return parseArray[string](v, innerDt) 49 case schema.DataTypeNumberArray: 50 return parseArray[float64](v, innerDt) 51 case schema.DataTypeIntArray: 52 return parseArray[float64](v, innerDt) 53 case schema.DataTypeStringArray: 54 return parseArray[string](v, innerDt) 55 case schema.DataTypeTextArray: 56 return parseArray[string](v, innerDt) 57 case schema.DataTypeUUIDArray: 58 return parseArray[string](v, innerDt) 59 default: 60 return nil, protoimpl.X.NewError("invalid type: %T", v) 61 } 62 } else { 63 switch dt { 64 case schema.DataTypeBoolean: 65 val, ok := v.(bool) 66 if !ok { 67 return nil, protoimpl.X.NewError("invalid type: %T expected bool when serializing bool", v) 68 } 69 return NewBoolValue(val), nil 70 case schema.DataTypeDate: 71 val, ok := v.(string) 72 if !ok { 73 return nil, protoimpl.X.NewError("invalid type: %T expected string when serializing date", v) 74 } 75 return NewDateValue(val), nil 76 case schema.DataTypeNumber: 77 val, ok := v.(float64) 78 if !ok { 79 return nil, protoimpl.X.NewError("invalid type: %T expected float64 when serializing number", v) 80 } 81 return NewNumberValue(val), nil 82 case schema.DataTypeInt: 83 val, ok := v.(float64) 84 if !ok { // integers are returned as float64 from search 85 return nil, protoimpl.X.NewError("invalid type: %T expected float64 when serializing int property", v) 86 } 87 return NewIntValue(int64(val)), nil 88 case schema.DataTypeString: 89 val, ok := v.(string) 90 if !ok { 91 return nil, protoimpl.X.NewError("invalid type: %T expected string when serializing string property", v) 92 } 93 return NewStringValue(val), nil 94 case schema.DataTypeText: 95 val, ok := v.(string) 96 if !ok { 97 return nil, protoimpl.X.NewError("invalid type: %T expected string when serializing text property", v) 98 } 99 return NewStringValue(val), nil 100 case schema.DataTypeUUID: 101 val, ok := v.(string) 102 if !ok { 103 return nil, protoimpl.X.NewError("invalid type: %T expected string when serializing uuid property", v) 104 } 105 return NewUuidValue(val), nil 106 case schema.DataTypeGeoCoordinates: 107 val, ok := v.(*models.GeoCoordinates) 108 if !ok { 109 return nil, protoimpl.X.NewError("invalid type: %T expected *models.GeoCoordinates when serializing geocoordinate property", v) 110 } 111 return NewGeoValue(val), nil 112 case schema.DataTypeBlob: 113 val, ok := v.(string) 114 if !ok { 115 return nil, protoimpl.X.NewError("invalid type: %T expected string when serializing blob property", v) 116 } 117 return NewBlobValue(val), nil 118 case schema.DataTypePhoneNumber: 119 val, ok := v.(*models.PhoneNumber) 120 if !ok { 121 return nil, protoimpl.X.NewError("invalid type: %T expected *models.PhoneNumber when serializing phone number property", v) 122 } 123 return NewPhoneNumberValue(val), nil 124 default: 125 return nil, protoimpl.X.NewError("invalid type: %T", v) 126 } 127 } 128 } 129 130 func NewNestedValue[P schema.PropertyInterface](v interface{}, dt schema.DataType, parent P, prop search.SelectProperty) (*pb.Value, error) { 131 switch dt { 132 case schema.DataTypeObject: 133 if _, ok := v.(map[string]interface{}); !ok { 134 return nil, protoimpl.X.NewError("invalid type: %T expected map[string]interface{}", v) 135 } 136 obj, err := NewObject(v.(map[string]interface{}), parent, prop) 137 if err != nil { 138 return nil, errors.Wrap(err, "creating nested object") 139 } 140 return NewObjectValue(obj), nil 141 case schema.DataTypeObjectArray: 142 if _, ok := v.([]interface{}); !ok { 143 return nil, protoimpl.X.NewError("invalid type: %T expected []map[string]interface{}", v) 144 } 145 list, err := NewObjectList(v.([]interface{}), parent, prop) 146 if err != nil { 147 return nil, errors.Wrap(err, "creating nested object array") 148 } 149 return NewListValue(list), nil 150 default: 151 return nil, protoimpl.X.NewError("invalid type: %T", v) 152 } 153 } 154 155 // NewStruct constructs a Struct from a general-purpose Go map. 156 // The map keys must be valid UTF-8. 157 // The map values are converted using NewValue. 158 func NewObject[P schema.PropertyInterface](v map[string]interface{}, parent P, selectProp search.SelectProperty) (*pb.Properties, error) { 159 if !selectProp.IsObject { 160 return nil, errors.New("select property is not an object") 161 } 162 x := &pb.Properties{Fields: make(map[string]*pb.Value, len(v))} 163 for _, selectProp := range selectProp.Props { 164 val, ok := v[selectProp.Name] 165 if !ok { 166 continue 167 } 168 169 dt, err := schema.GetNestedPropertyDataType(parent, selectProp.Name) 170 if err != nil { 171 return nil, errors.Wrapf(err, "getting data type of nested property %s", selectProp.Name) 172 } 173 if *dt == schema.DataTypeObject || *dt == schema.DataTypeObjectArray { 174 nested, err := schema.GetNestedPropertyByName(parent, selectProp.Name) 175 if err != nil { 176 return nil, errors.Wrapf(err, "getting nested property %s", selectProp.Name) 177 } 178 x.Fields[selectProp.Name], err = NewNestedValue(val, *dt, &NestedProperty{NestedProperty: nested}, selectProp) 179 if err != nil { 180 return nil, errors.Wrapf(err, "creating nested object value %s", selectProp.Name) 181 } 182 } else { 183 x.Fields[selectProp.Name], err = NewPrimitiveValue(val, *dt) 184 if err != nil { 185 return nil, errors.Wrapf(err, "creating nested primitive value %s", selectProp.Name) 186 } 187 } 188 if err != nil { 189 return nil, errors.Wrapf(err, "serializing field %s", selectProp.Name) 190 } 191 } 192 return x, nil 193 } 194 195 // NewList constructs a ListValue from a general-purpose Go slice. 196 // The slice elements are converted using NewValue. 197 func NewPrimitiveList[T bool | float64 | string](v []T, dt schema.DataType) (*pb.ListValue, error) { 198 var err error 199 x := &pb.ListValue{Values: make([]*pb.Value, len(v))} 200 for i, v := range v { 201 x.Values[i], err = NewPrimitiveValue(v, dt) 202 if err != nil { 203 return nil, err 204 } 205 } 206 return x, nil 207 } 208 209 // NewList constructs a ListValue from a general-purpose Go slice. 210 // The slice elements are converted using NewValue. 211 func NewObjectList[P schema.PropertyInterface](v []interface{}, parent P, selectProp search.SelectProperty) (*pb.ListValue, error) { 212 if !selectProp.IsObject { 213 return nil, errors.New("select property is not an object") 214 } 215 x := &pb.ListValue{Values: make([]*pb.Value, len(v))} 216 for i, v := range v { 217 if _, ok := v.(map[string]interface{}); !ok { 218 return nil, protoimpl.X.NewError("invalid type: %T expected map[string]interface{}", v) 219 } 220 value, err := NewObject(v.(map[string]interface{}), parent, selectProp) 221 if err != nil { 222 return nil, err 223 } 224 x.Values[i] = NewObjectValue(value) 225 } 226 return x, nil 227 } 228 229 // NewBoolValue constructs a new boolean Value. 230 func NewBoolValue(v bool) *pb.Value { 231 return &pb.Value{Kind: &pb.Value_BoolValue{BoolValue: v}} 232 } 233 234 // NewNumberValue constructs a new number Value. 235 func NewNumberValue(v float64) *pb.Value { 236 return &pb.Value{Kind: &pb.Value_NumberValue{NumberValue: v}} 237 } 238 239 // NewIntValue constructs a new number Value. 240 func NewIntValue(v int64) *pb.Value { 241 return &pb.Value{Kind: &pb.Value_IntValue{IntValue: v}} 242 } 243 244 // NewStringValue constructs a new string Value. 245 func NewStringValue(v string) *pb.Value { 246 return &pb.Value{Kind: &pb.Value_StringValue{StringValue: v}} 247 } 248 249 // NewDateValue constructs a new string Value. 250 func NewDateValue(v string) *pb.Value { 251 return &pb.Value{Kind: &pb.Value_DateValue{DateValue: v}} 252 } 253 254 // NewUuidValue constructs a new string Value. 255 func NewUuidValue(v string) *pb.Value { 256 return &pb.Value{Kind: &pb.Value_UuidValue{UuidValue: v}} 257 } 258 259 // NewGeoValue constructs a new geo Value. 260 func NewGeoValue(v *models.GeoCoordinates) *pb.Value { 261 return &pb.Value{Kind: &pb.Value_GeoValue{GeoValue: &pb.GeoCoordinate{Latitude: *v.Latitude, Longitude: *v.Longitude}}} 262 } 263 264 // NewObjectValue constructs a new struct Value. 265 func NewObjectValue(v *pb.Properties) *pb.Value { 266 return &pb.Value{Kind: &pb.Value_ObjectValue{ObjectValue: v}} 267 } 268 269 // NewListValue constructs a new list Value. 270 func NewListValue(v *pb.ListValue) *pb.Value { 271 return &pb.Value{Kind: &pb.Value_ListValue{ListValue: v}} 272 } 273 274 // NewBlobValue constructs a new blob Value. 275 func NewBlobValue(v string) *pb.Value { 276 return &pb.Value{Kind: &pb.Value_BlobValue{BlobValue: v}} 277 } 278 279 // NewPhoneNumberValue constructs a new phone number Value. 280 func NewPhoneNumberValue(v *models.PhoneNumber) *pb.Value { 281 return &pb.Value{Kind: &pb.Value_PhoneValue{ 282 PhoneValue: &pb.PhoneNumber{ 283 CountryCode: v.CountryCode, 284 DefaultCountry: v.DefaultCountry, 285 Input: v.Input, 286 InternationalFormatted: v.InternationalFormatted, 287 National: v.National, 288 NationalFormatted: v.NationalFormatted, 289 Valid: v.Valid, 290 }, 291 }} 292 } 293 294 // NewNilValue constructs a new nil Value. 295 func NewNilValue() *pb.Value { 296 return &pb.Value{Kind: &pb.Value_NullValue{}} 297 }