github.com/weaviate/weaviate@v1.24.6/adapters/handlers/rest/filterext/parse.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 filterext 13 14 import ( 15 "fmt" 16 17 "github.com/weaviate/weaviate/entities/filters" 18 "github.com/weaviate/weaviate/entities/models" 19 ) 20 21 // Parse Filter from REST construct to entities filter 22 func Parse(in *models.WhereFilter, rootClass string) (*filters.LocalFilter, error) { 23 if in == nil { 24 return nil, nil 25 } 26 27 operator, err := parseOperator(in.Operator) 28 if err != nil { 29 return nil, err 30 } 31 32 if operator.OnValue() { 33 filter, err := parseValueFilter(in, operator, rootClass) 34 if err != nil { 35 return nil, fmt.Errorf("invalid where filter: %v", err) 36 } 37 return filter, nil 38 } 39 40 filter, err := parseNestedFilter(in, operator, rootClass) 41 if err != nil { 42 return nil, fmt.Errorf("invalid where filter: %v", err) 43 } 44 return filter, nil 45 } 46 47 func parseValueFilter(in *models.WhereFilter, 48 operator filters.Operator, rootClass string, 49 ) (*filters.LocalFilter, error) { 50 value, err := parseValue(in) 51 if err != nil { 52 return nil, err 53 } 54 55 path, err := parsePath(in.Path, rootClass) 56 if err != nil { 57 return nil, err 58 } 59 60 return &filters.LocalFilter{ 61 Root: &filters.Clause{ 62 Operator: operator, 63 Value: value, 64 On: path, 65 }, 66 }, nil 67 } 68 69 func parseNestedFilter(in *models.WhereFilter, 70 operator filters.Operator, rootClass string, 71 ) (*filters.LocalFilter, error) { 72 if in.Path != nil { 73 return nil, fmt.Errorf( 74 "operator '%s' not compatible with field 'path', remove 'path' "+ 75 "or switch to compare operator (eg. Equal, NotEqual, etc.)", 76 operator.Name()) 77 } 78 79 if !allValuesNil(in) { 80 return nil, fmt.Errorf( 81 "operator '%s' not compatible with field 'value<Type>', "+ 82 "remove value field or switch to compare operator "+ 83 "(eg. Equal, NotEqual, etc.)", 84 operator.Name()) 85 } 86 87 if in.Operands == nil || len(in.Operands) == 0 { 88 return nil, fmt.Errorf( 89 "operator '%s', but no operands set - add at least one operand", 90 operator.Name()) 91 } 92 93 operands, err := parseOperands(in.Operands, rootClass) 94 if err != nil { 95 return nil, err 96 } 97 98 return &filters.LocalFilter{ 99 Root: &filters.Clause{ 100 Operator: operator, 101 Operands: operands, 102 }, 103 }, nil 104 } 105 106 func parseOperands(ops []*models.WhereFilter, rootClass string) ([]filters.Clause, error) { 107 out := make([]filters.Clause, len(ops)) 108 for i, operand := range ops { 109 res, err := Parse(operand, rootClass) 110 if err != nil { 111 return nil, fmt.Errorf("operand %d: %v", i, err) 112 } 113 114 out[i] = *res.Root 115 } 116 117 return out, nil 118 } 119 120 func parseOperator(in string) (filters.Operator, error) { 121 switch in { 122 case models.WhereFilterOperatorEqual: 123 return filters.OperatorEqual, nil 124 case models.WhereFilterOperatorLike: 125 return filters.OperatorLike, nil 126 case models.WhereFilterOperatorLessThan: 127 return filters.OperatorLessThan, nil 128 case models.WhereFilterOperatorLessThanEqual: 129 return filters.OperatorLessThanEqual, nil 130 case models.WhereFilterOperatorGreaterThan: 131 return filters.OperatorGreaterThan, nil 132 case models.WhereFilterOperatorGreaterThanEqual: 133 return filters.OperatorGreaterThanEqual, nil 134 case models.WhereFilterOperatorNotEqual: 135 return filters.OperatorNotEqual, nil 136 case models.WhereFilterOperatorWithinGeoRange: 137 return filters.OperatorWithinGeoRange, nil 138 case models.WhereFilterOperatorAnd: 139 return filters.OperatorAnd, nil 140 case models.WhereFilterOperatorOr: 141 return filters.OperatorOr, nil 142 case models.WhereFilterOperatorIsNull: 143 return filters.OperatorIsNull, nil 144 case models.WhereFilterOperatorContainsAny: 145 return filters.ContainsAny, nil 146 case models.WhereFilterOperatorContainsAll: 147 return filters.ContainsAll, nil 148 default: 149 return -1, fmt.Errorf("unrecognized operator: %s", in) 150 } 151 } 152 153 func parsePath(in []string, rootClass string) (*filters.Path, error) { 154 if len(in) == 0 { 155 return nil, fmt.Errorf("field 'path': must have at least one element") 156 } 157 158 pathElements := make([]interface{}, len(in)) 159 for i, elem := range in { 160 pathElements[i] = elem 161 } 162 163 return filters.ParsePath(pathElements, rootClass) 164 } 165 166 func allValuesNil(in *models.WhereFilter) bool { 167 return in.ValueBoolean == nil && 168 in.ValueDate == nil && 169 in.ValueString == nil && 170 in.ValueText == nil && 171 in.ValueInt == nil && 172 in.ValueNumber == nil && 173 in.ValueGeoRange == nil && 174 len(in.ValueBooleanArray) == 0 && 175 len(in.ValueDateArray) == 0 && 176 len(in.ValueStringArray) == 0 && 177 len(in.ValueTextArray) == 0 && 178 len(in.ValueIntArray) == 0 && 179 len(in.ValueNumberArray) == 0 180 }