1+ from __future__ import annotations
2+
13from enum import Enum
24from typing import *
35import numpy as np
46
7+ if TYPE_CHECKING :
8+ from objectbox .c import obx_qb_cond
9+ from objectbox .query_builder import QueryBuilder
10+
11+
12+ class QueryCondition :
13+ def and_ (self , other : QueryCondition ) -> QueryCondition :
14+ return LogicQueryCondition (self , other , LogicQueryConditionOp .AND )
15+
16+ def or_ (self , other : QueryCondition ) -> QueryCondition :
17+ return LogicQueryCondition (self , other , LogicQueryConditionOp .OR )
18+
19+ def apply (self , qb : QueryBuilder ) -> obx_qb_cond :
20+ """ Applies the QueryCondition to the supplied QueryBuilder.
21+
22+ :return:
23+ The C handle for the applied condition.
24+ """
25+ raise NotImplementedError
26+
27+
28+ class LogicQueryConditionOp (Enum ):
29+ AND = 1
30+ OR = 2
31+
32+
33+ class LogicQueryCondition (QueryCondition ):
34+ """ A QueryCondition describing a logical operation between two inner QueryCondition's (e.g. AND/OR). """
535
6- class _QueryConditionOp (Enum ):
36+ def __init__ (self , cond1 : QueryCondition , cond2 : QueryCondition , op : LogicQueryConditionOp ):
37+ self ._cond1 = cond1
38+ self ._cond2 = cond2
39+ self ._op = op
40+
41+ def _apply_conditions (self , qb : QueryBuilder ) -> List [obx_qb_cond ]:
42+ return [self ._cond1 .apply (qb ), self ._cond2 .apply (qb )]
43+
44+ def _apply_and (self , qb : QueryBuilder ) -> obx_qb_cond :
45+ return qb .all (self ._apply_conditions (qb ))
46+
47+ def _apply_or (self , qb : QueryBuilder ) -> obx_qb_cond :
48+ return qb .any (self ._apply_conditions (qb ))
49+
50+ def apply (self , qb : QueryBuilder ) -> obx_qb_cond :
51+ if self ._op == LogicQueryConditionOp .AND :
52+ return self ._apply_and (qb )
53+ elif self ._op == LogicQueryConditionOp .OR :
54+ return self ._apply_or (qb )
55+ else :
56+ raise Exception (f"Unknown LogicQueryCondition op: { self ._op .name } " )
57+
58+
59+ class PropertyQueryConditionOp (Enum ):
760 EQ = 1
861 NOT_EQ = 2
962 CONTAINS = 3
@@ -18,8 +71,10 @@ class _QueryConditionOp(Enum):
1871 CONTAINS_KEY_VALUE = 12
1972
2073
21- class QueryCondition :
22- def __init__ (self , property_id : int , op : _QueryConditionOp , args : Dict [str , Any ]):
74+ class PropertyQueryCondition (QueryCondition ):
75+ """ A QueryCondition describing an operation to be applied on a property (e.g. name == "John", age == 24) """
76+
77+ def __init__ (self , property_id : int , op : PropertyQueryConditionOp , args : Dict [str , Any ]):
2378 if op not in self ._get_op_map ():
2479 raise Exception (f"Invalid query condition op with ID: { op } " )
2580
@@ -29,119 +84,120 @@ def __init__(self, property_id: int, op: _QueryConditionOp, args: Dict[str, Any]
2984 self ._alias = None
3085
3186 def alias (self , value : str ):
87+ """ Sets an alias for this condition that can later be used with Query's set_parameter_* methods. """
3288 self ._alias = value
3389 return self
3490
3591 def _get_op_map (self ):
3692 return {
37- _QueryConditionOp .EQ : self ._apply_eq ,
38- _QueryConditionOp .NOT_EQ : self ._apply_not_eq ,
39- _QueryConditionOp .CONTAINS : self ._apply_contains ,
40- _QueryConditionOp .STARTS_WITH : self ._apply_starts_with ,
41- _QueryConditionOp .ENDS_WITH : self ._apply_ends_with ,
42- _QueryConditionOp .GT : self ._apply_gt ,
43- _QueryConditionOp .GTE : self ._apply_gte ,
44- _QueryConditionOp .LT : self ._apply_lt ,
45- _QueryConditionOp .LTE : self ._apply_lte ,
46- _QueryConditionOp .BETWEEN : self ._apply_between ,
47- _QueryConditionOp .NEAREST_NEIGHBOR : self ._apply_nearest_neighbor ,
48- _QueryConditionOp .CONTAINS_KEY_VALUE : self ._contains_key_value
49- # ... new query condition here ... :)
93+ PropertyQueryConditionOp .EQ : self ._apply_eq ,
94+ PropertyQueryConditionOp .NOT_EQ : self ._apply_not_eq ,
95+ PropertyQueryConditionOp .CONTAINS : self ._apply_contains ,
96+ PropertyQueryConditionOp .STARTS_WITH : self ._apply_starts_with ,
97+ PropertyQueryConditionOp .ENDS_WITH : self ._apply_ends_with ,
98+ PropertyQueryConditionOp .GT : self ._apply_gt ,
99+ PropertyQueryConditionOp .GTE : self ._apply_gte ,
100+ PropertyQueryConditionOp .LT : self ._apply_lt ,
101+ PropertyQueryConditionOp .LTE : self ._apply_lte ,
102+ PropertyQueryConditionOp .BETWEEN : self ._apply_between ,
103+ PropertyQueryConditionOp .NEAREST_NEIGHBOR : self ._apply_nearest_neighbor ,
104+ PropertyQueryConditionOp .CONTAINS_KEY_VALUE : self ._contains_key_value
105+ # ... new property query condition here ... :)
50106 }
51107
52- def _apply_eq (self , qb : ' QueryBuilder' ) :
108+ def _apply_eq (self , qb : QueryBuilder ) -> obx_qb_cond :
53109 value = self ._args ['value' ]
54110 case_sensitive = self ._args ['case_sensitive' ]
55111 if isinstance (value , str ):
56- qb .equals_string (self ._property_id , value , case_sensitive )
112+ return qb .equals_string (self ._property_id , value , case_sensitive )
57113 elif isinstance (value , int ):
58- qb .equals_int (self ._property_id , value )
114+ return qb .equals_int (self ._property_id , value )
59115 else :
60116 raise Exception (f"Unsupported type for 'EQ': { type (value )} " )
61117
62- def _apply_not_eq (self , qb : ' QueryBuilder' ) :
118+ def _apply_not_eq (self , qb : QueryBuilder ) -> obx_qb_cond :
63119 value = self ._args ['value' ]
64120 case_sensitive = self ._args ['case_sensitive' ]
65121 if isinstance (value , str ):
66- qb .not_equals_string (self ._property_id , value , case_sensitive )
122+ return qb .not_equals_string (self ._property_id , value , case_sensitive )
67123 elif isinstance (value , int ):
68- qb .not_equals_int (self ._property_id , value )
124+ return qb .not_equals_int (self ._property_id , value )
69125 else :
70126 raise Exception (f"Unsupported type for 'NOT_EQ': { type (value )} " )
71127
72- def _apply_contains (self , qb : ' QueryBuilder' ) :
128+ def _apply_contains (self , qb : QueryBuilder ) -> obx_qb_cond :
73129 value = self ._args ['value' ]
74130 case_sensitive = self ._args ['case_sensitive' ]
75131 if isinstance (value , str ):
76- qb .contains_string (self ._property_id , value , case_sensitive )
132+ return qb .contains_string (self ._property_id , value , case_sensitive )
77133 else :
78134 raise Exception (f"Unsupported type for 'CONTAINS': { type (value )} " )
79135
80- def _apply_starts_with (self , qb : ' QueryBuilder' ) :
136+ def _apply_starts_with (self , qb : QueryBuilder ) -> obx_qb_cond :
81137 value = self ._args ['value' ]
82138 case_sensitive = self ._args ['case_sensitive' ]
83139 if isinstance (value , str ):
84- qb .starts_with_string (self ._property_id , value , case_sensitive )
140+ return qb .starts_with_string (self ._property_id , value , case_sensitive )
85141 else :
86142 raise Exception (f"Unsupported type for 'STARTS_WITH': { type (value )} " )
87143
88- def _apply_ends_with (self , qb : ' QueryBuilder' ) :
144+ def _apply_ends_with (self , qb : QueryBuilder ) -> obx_qb_cond :
89145 value = self ._args ['value' ]
90146 case_sensitive = self ._args ['case_sensitive' ]
91147 if isinstance (value , str ):
92- qb .ends_with_string (self ._property_id , value , case_sensitive )
148+ return qb .ends_with_string (self ._property_id , value , case_sensitive )
93149 else :
94150 raise Exception (f"Unsupported type for 'ENDS_WITH': { type (value )} " )
95151
96- def _apply_gt (self , qb : ' QueryBuilder' ) :
152+ def _apply_gt (self , qb : QueryBuilder ) -> obx_qb_cond :
97153 value = self ._args ['value' ]
98154 case_sensitive = self ._args ['case_sensitive' ]
99155 if isinstance (value , str ):
100- qb .greater_than_string (self ._property_id , value , case_sensitive )
156+ return qb .greater_than_string (self ._property_id , value , case_sensitive )
101157 elif isinstance (value , int ):
102- qb .greater_than_int (self ._property_id , value )
158+ return qb .greater_than_int (self ._property_id , value )
103159 else :
104160 raise Exception (f"Unsupported type for 'GT': { type (value )} " )
105161
106- def _apply_gte (self , qb : ' QueryBuilder' ) :
162+ def _apply_gte (self , qb : QueryBuilder ) -> obx_qb_cond :
107163 value = self ._args ['value' ]
108164 case_sensitive = self ._args ['case_sensitive' ]
109165 if isinstance (value , str ):
110- qb .greater_or_equal_string (self ._property_id , value , case_sensitive )
166+ return qb .greater_or_equal_string (self ._property_id , value , case_sensitive )
111167 elif isinstance (value , int ):
112- qb .greater_or_equal_int (self ._property_id , value )
168+ return qb .greater_or_equal_int (self ._property_id , value )
113169 else :
114170 raise Exception (f"Unsupported type for 'GTE': { type (value )} " )
115171
116- def _apply_lt (self , qb : 'QueryCondition' ) :
172+ def _apply_lt (self , qb : QueryBuilder ) -> obx_qb_cond :
117173 value = self ._args ['value' ]
118174 case_sensitive = self ._args ['case_sensitive' ]
119175 if isinstance (value , str ):
120- qb .less_than_string (self ._property_id , value , case_sensitive )
176+ return qb .less_than_string (self ._property_id , value , case_sensitive )
121177 elif isinstance (value , int ):
122- qb .less_than_int (self ._property_id , value )
178+ return qb .less_than_int (self ._property_id , value )
123179 else :
124180 raise Exception ("Unsupported type for 'LT': " + str (type (value )))
125181
126- def _apply_lte (self , qb : ' QueryBuilder' ) :
182+ def _apply_lte (self , qb : QueryBuilder ) -> obx_qb_cond :
127183 value = self ._args ['value' ]
128184 case_sensitive = self ._args ['case_sensitive' ]
129185 if isinstance (value , str ):
130- qb .less_or_equal_string (self ._property_id , value , case_sensitive )
186+ return qb .less_or_equal_string (self ._property_id , value , case_sensitive )
131187 elif isinstance (value , int ):
132- qb .less_or_equal_int (self ._property_id , value )
188+ return qb .less_or_equal_int (self ._property_id , value )
133189 else :
134190 raise Exception (f"Unsupported type for 'LTE': { type (value )} " )
135191
136- def _apply_between (self , qb : ' QueryBuilder' ) :
192+ def _apply_between (self , qb : QueryBuilder ) -> obx_qb_cond :
137193 a = self ._args ['a' ]
138194 b = self ._args ['b' ]
139195 if isinstance (a , int ):
140- qb .between_2ints (self ._property_id , a , b )
196+ return qb .between_2ints (self ._property_id , a , b )
141197 else :
142198 raise Exception (f"Unsupported type for 'BETWEEN': { type (a )} " )
143199
144- def _apply_nearest_neighbor (self , qb : ' QueryBuilder' ) :
200+ def _apply_nearest_neighbor (self , qb : QueryBuilder ) -> obx_qb_cond :
145201 query_vector = self ._args ['query_vector' ]
146202 element_count = self ._args ['element_count' ]
147203
@@ -152,19 +208,18 @@ def _apply_nearest_neighbor(self, qb: 'QueryBuilder'):
152208 is_float_vector |= isinstance (query_vector , np .ndarray ) and query_vector .dtype == np .float32
153209 is_float_vector |= isinstance (query_vector , list ) and type (query_vector [0 ]) == float
154210 if is_float_vector :
155- qb .nearest_neighbors_f32 (self ._property_id , query_vector , element_count )
211+ return qb .nearest_neighbors_f32 (self ._property_id , query_vector , element_count )
156212 else :
157213 raise Exception (f"Unsupported type for 'NEAREST_NEIGHBOR': { type (query_vector )} " )
158214
159- def _contains_key_value (self , qb : ' QueryBuilder' ) :
215+ def _contains_key_value (self , qb : QueryBuilder ) -> obx_qb_cond :
160216 key = self ._args ['key' ]
161217 value = self ._args ['value' ]
162218 case_sensitive = self ._args ['case_sensitive' ]
163- qb .contains_key_value (self ._property_id , key , value , case_sensitive )
164-
165- def apply (self , qb : 'QueryBuilder' ):
166- """ Applies the stored condition to the supplied query builder. """
167- self ._get_op_map ()[self ._op ](qb )
219+ return qb .contains_key_value (self ._property_id , key , value , case_sensitive )
168220
221+ def apply (self , qb : QueryBuilder ) -> obx_qb_cond :
222+ c_cond = self ._get_op_map ()[self ._op ](qb )
169223 if self ._alias is not None :
170224 qb .alias (self ._alias )
225+ return c_cond
0 commit comments