github.com/weaviate/weaviate@v1.24.6/adapters/repos/db/sorter/comparable_value_extractor.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 sorter
    13  
    14  import (
    15  	"encoding/json"
    16  	"strconv"
    17  	"time"
    18  
    19  	"github.com/weaviate/weaviate/entities/filters"
    20  	"github.com/weaviate/weaviate/entities/models"
    21  	"github.com/weaviate/weaviate/entities/schema"
    22  	"github.com/weaviate/weaviate/entities/storobj"
    23  )
    24  
    25  type comparableValueExtractor struct {
    26  	dataTypesHelper *dataTypesHelper
    27  }
    28  
    29  func newComparableValueExtractor(dataTypesHelper *dataTypesHelper) *comparableValueExtractor {
    30  	return &comparableValueExtractor{dataTypesHelper}
    31  }
    32  
    33  func (e *comparableValueExtractor) extractFromBytes(objData []byte, propName string) interface{} {
    34  	value, success, _ := storobj.ParseAndExtractProperty(objData, propName)
    35  	// in case the property does not exist for the object return nil
    36  	if len(value) == 0 {
    37  		return nil
    38  	}
    39  	if success {
    40  		switch e.dataTypesHelper.getType(propName) {
    41  		case schema.DataTypeBlob:
    42  			return &value[0]
    43  		case schema.DataTypeText:
    44  			return &value[0]
    45  		case schema.DataTypeTextArray:
    46  			return &value
    47  		case schema.DataTypeDate:
    48  			d := e.mustExtractDates(value[:1])[0]
    49  			return &d
    50  		case schema.DataTypeDateArray:
    51  			da := e.mustExtractDates(value)
    52  			return &da
    53  		case schema.DataTypeNumber, schema.DataTypeInt:
    54  			n := e.mustExtractNumbers(value[:1])[0]
    55  			return &n
    56  		case schema.DataTypeNumberArray, schema.DataTypeIntArray:
    57  			na := e.mustExtractNumbers(value)
    58  			return &na
    59  		case schema.DataTypeBoolean:
    60  			b := e.mustExtractBools(value[:1])[0]
    61  			return &b
    62  		case schema.DataTypeBooleanArray:
    63  			ba := e.mustExtractBools(value)
    64  			return &ba
    65  		case schema.DataTypePhoneNumber:
    66  			fa := e.toFloatArrayFromPhoneNumber(e.mustExtractPhoneNumber(value))
    67  			return &fa
    68  		case schema.DataTypeGeoCoordinates:
    69  			fa := e.toFloatArrayFromGeoCoordinates(e.mustExtractGeoCoordinates(value))
    70  			return &fa
    71  		default:
    72  			return nil
    73  		}
    74  	}
    75  	return nil
    76  }
    77  
    78  func (e *comparableValueExtractor) extractFromObject(object *storobj.Object, propName string) interface{} {
    79  	if propName == filters.InternalPropID || propName == filters.InternalPropBackwardsCompatID {
    80  		id := object.ID().String()
    81  		return &id
    82  	}
    83  	if propName == filters.InternalPropCreationTimeUnix {
    84  		ts := float64(object.CreationTimeUnix())
    85  		return &ts
    86  	}
    87  	if propName == filters.InternalPropLastUpdateTimeUnix {
    88  		ts := float64(object.LastUpdateTimeUnix())
    89  		return &ts
    90  	}
    91  
    92  	propertiesMap, ok := object.Properties().(map[string]interface{})
    93  	if !ok {
    94  		return nil
    95  	}
    96  	value, ok := propertiesMap[propName]
    97  	if !ok {
    98  		return nil
    99  	}
   100  
   101  	switch e.dataTypesHelper.getType(propName) {
   102  	case schema.DataTypeBlob:
   103  		s := value.(string)
   104  		return &s
   105  	case schema.DataTypeText:
   106  		s := value.(string)
   107  		return &s
   108  	case schema.DataTypeTextArray:
   109  		sa := value.([]string)
   110  		return &sa
   111  	case schema.DataTypeDate:
   112  		d := e.mustExtractDates([]string{value.(string)})[0]
   113  		return &d
   114  	case schema.DataTypeDateArray:
   115  		da := e.mustExtractDates(value.([]string))
   116  		return &da
   117  	case schema.DataTypeNumber, schema.DataTypeInt:
   118  		n := value.(float64)
   119  		return &n
   120  	case schema.DataTypeNumberArray, schema.DataTypeIntArray:
   121  		na := value.([]float64)
   122  		return &na
   123  	case schema.DataTypeBoolean:
   124  		b := value.(bool)
   125  		return &b
   126  	case schema.DataTypeBooleanArray:
   127  		ba := value.([]bool)
   128  		return &ba
   129  	case schema.DataTypePhoneNumber:
   130  		fa := e.toFloatArrayFromPhoneNumber(value.(*models.PhoneNumber))
   131  		return &fa
   132  	case schema.DataTypeGeoCoordinates:
   133  		fa := e.toFloatArrayFromGeoCoordinates(value.(*models.GeoCoordinates))
   134  		return &fa
   135  	default:
   136  		return nil
   137  	}
   138  }
   139  
   140  func (e *comparableValueExtractor) mustExtractNumbers(value []string) []float64 {
   141  	numbers := make([]float64, len(value))
   142  	for i := range value {
   143  		number, err := strconv.ParseFloat(value[i], 64)
   144  		if err != nil {
   145  			panic("sorter: not a number")
   146  		}
   147  		numbers[i] = number
   148  	}
   149  	return numbers
   150  }
   151  
   152  func (e *comparableValueExtractor) mustExtractBools(value []string) []bool {
   153  	bools := make([]bool, len(value))
   154  	for i := range value {
   155  		switch value[i] {
   156  		case "true":
   157  			bools[i] = true
   158  		case "false":
   159  			bools[i] = false
   160  		default:
   161  			panic("sorter: not a bool")
   162  		}
   163  	}
   164  	return bools
   165  }
   166  
   167  func (e *comparableValueExtractor) mustExtractDates(value []string) []time.Time {
   168  	dates := make([]time.Time, len(value))
   169  	for i := range value {
   170  		date, err := time.Parse(time.RFC3339, value[i])
   171  		if err != nil {
   172  			panic("sorter: not a date")
   173  		}
   174  		dates[i] = date
   175  	}
   176  	return dates
   177  }
   178  
   179  func (e *comparableValueExtractor) mustExtractPhoneNumber(value []string) *models.PhoneNumber {
   180  	if len(value) == 1 {
   181  		var phoneNumber *models.PhoneNumber
   182  		if err := json.Unmarshal([]byte(value[0]), &phoneNumber); err == nil {
   183  			return phoneNumber
   184  		}
   185  	}
   186  	panic("sorter: not a phone number")
   187  }
   188  
   189  func (e *comparableValueExtractor) mustExtractGeoCoordinates(value []string) *models.GeoCoordinates {
   190  	if len(value) == 1 {
   191  		var geoCoordinates *models.GeoCoordinates
   192  		if err := json.Unmarshal([]byte(value[0]), &geoCoordinates); err == nil {
   193  			return geoCoordinates
   194  		}
   195  	}
   196  	panic("sorter: not a geo coordinates")
   197  }
   198  
   199  func (e *comparableValueExtractor) toFloatArrayFromPhoneNumber(value *models.PhoneNumber) []float64 {
   200  	return []float64{float64(value.CountryCode), float64(value.National)}
   201  }
   202  
   203  func (e *comparableValueExtractor) toFloatArrayFromGeoCoordinates(value *models.GeoCoordinates) []float64 {
   204  	fa := make([]float64, 2)
   205  	if value.Longitude != nil {
   206  		fa[0] = float64(*value.Longitude)
   207  	}
   208  	if value.Latitude != nil {
   209  		fa[1] = float64(*value.Latitude)
   210  	}
   211  	return fa
   212  }