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  }