objectbox-api 5.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- objectbox/__init__.py +145 -0
- objectbox/box.py +294 -0
- objectbox/builder.py +42 -0
- objectbox/c.py +1572 -0
- objectbox/condition.py +300 -0
- objectbox/exceptions.py +238 -0
- objectbox/experimental.py +78 -0
- objectbox/logger.py +18 -0
- objectbox/model/__init__.py +63 -0
- objectbox/model/codegen.py +399 -0
- objectbox/model/entity.py +490 -0
- objectbox/model/fast_builder.py +324 -0
- objectbox/model/idsync.py +401 -0
- objectbox/model/iduid.py +32 -0
- objectbox/model/model.py +158 -0
- objectbox/model/properties.py +865 -0
- objectbox/objectbox.py +24 -0
- objectbox/query.py +468 -0
- objectbox/query_builder.py +450 -0
- objectbox/store.py +400 -0
- objectbox/store_options.py +136 -0
- objectbox/sync.py +1101 -0
- objectbox/transaction.py +60 -0
- objectbox/utils.py +60 -0
- objectbox/version.py +39 -0
- objectbox_api-5.0.0.dist-info/METADATA +63 -0
- objectbox_api-5.0.0.dist-info/RECORD +30 -0
- objectbox_api-5.0.0.dist-info/WHEEL +5 -0
- objectbox_api-5.0.0.dist-info/licenses/LICENSE +202 -0
- objectbox_api-5.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import ctypes
|
|
4
|
+
from enum import IntEnum
|
|
5
|
+
from typing import *
|
|
6
|
+
|
|
7
|
+
from objectbox.c import *
|
|
8
|
+
from objectbox.condition import QueryCondition
|
|
9
|
+
from objectbox.exceptions import IllegalArgumentError, IllegalStateError
|
|
10
|
+
from objectbox.model.properties import Property, Relation
|
|
11
|
+
from objectbox.store import Store
|
|
12
|
+
from objectbox.query import Query
|
|
13
|
+
from objectbox.utils import check_float_vector
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
import numpy as np
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class OrderFlags(IntEnum):
|
|
20
|
+
""" Flags to adjust the order of query results, see :func:`QueryBuilder.order`.
|
|
21
|
+
Combine multiple flags using ``|``. """
|
|
22
|
+
|
|
23
|
+
DESCENDING = OBXOrderFlags_DESCENDING
|
|
24
|
+
"""Reverses the order from ascending (default) to descending."""
|
|
25
|
+
|
|
26
|
+
CASE_SENSITIVE = OBXOrderFlags_CASE_SENSITIVE
|
|
27
|
+
"""Sorts upper case letters before lower case letters.
|
|
28
|
+
If not specified, the default is case insensitive for ASCII characters."""
|
|
29
|
+
|
|
30
|
+
UNSIGNED = OBXOrderFlags_UNSIGNED
|
|
31
|
+
"""For scalars only: changes the comparison to unsigned (default is signed)."""
|
|
32
|
+
|
|
33
|
+
NULLS_LAST = OBXOrderFlags_NULLS_LAST
|
|
34
|
+
"""Null values will be put last.
|
|
35
|
+
If not specified, by default null values will be put first."""
|
|
36
|
+
|
|
37
|
+
NULLS_ZERO = OBXOrderFlags_NULLS_ZERO
|
|
38
|
+
"""Null values should be treated equal to zero (scalars only)."""
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class QueryBuilder:
|
|
42
|
+
"""
|
|
43
|
+
Query builder
|
|
44
|
+
"""
|
|
45
|
+
def __init__(self, store: Store, box: 'Box'):
|
|
46
|
+
self._box = box
|
|
47
|
+
self._entity = box._entity
|
|
48
|
+
self._c_builder_or_none = obx_query_builder(store._c_store, box._entity._id) # None once closed
|
|
49
|
+
# Entity and property ID of the conditions' aliases; for Query.set_parameter_alias()
|
|
50
|
+
self._alias_properties: Dict[str, Tuple['_Entity', int]] = {}
|
|
51
|
+
self._root: Optional[QueryBuilder] = None # For a builder of a linked entity (see link()): the query's builder
|
|
52
|
+
self._last_condition_prop_id: Optional[int] = None # Property of the last condition, for alias()
|
|
53
|
+
store._add_native_resource(self)
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def _c_builder(self):
|
|
57
|
+
root = self._root or self
|
|
58
|
+
if root._c_builder_or_none is None:
|
|
59
|
+
self._box._store._c_store # Raises if the store is closed (which closed the builder)
|
|
60
|
+
raise IllegalStateError("The query builder is closed: build() closes it")
|
|
61
|
+
return self._c_builder_or_none
|
|
62
|
+
|
|
63
|
+
def _linked(self, c_builder, entity: '_Entity', condition: Optional[QueryCondition]) -> 'QueryBuilder':
|
|
64
|
+
""" Creates the builder for a linked entity, owned by the C builder of the query. """
|
|
65
|
+
linked = QueryBuilder.__new__(QueryBuilder)
|
|
66
|
+
linked._box = self._box
|
|
67
|
+
linked._entity = entity
|
|
68
|
+
linked._c_builder_or_none = c_builder # Owned by the root's C builder
|
|
69
|
+
linked._alias_properties = self._alias_properties
|
|
70
|
+
linked._root = self._root or self
|
|
71
|
+
linked._last_condition_prop_id = None
|
|
72
|
+
if condition is not None:
|
|
73
|
+
condition.apply(linked)
|
|
74
|
+
return linked
|
|
75
|
+
|
|
76
|
+
def _assert_root(self, method: str):
|
|
77
|
+
if self._root is not None:
|
|
78
|
+
raise IllegalStateError(f"{method}() is not supported on the builder of a linked entity (returned by "
|
|
79
|
+
f"link() or backlink()); call it on the query's builder (e.g. from box.query())")
|
|
80
|
+
|
|
81
|
+
def link(self, relation: Relation, condition: Optional[QueryCondition] = None) -> 'QueryBuilder':
|
|
82
|
+
""" Adds conditions on the target of a to-one relation of this builder's entity: matches objects whose
|
|
83
|
+
related object matches the condition. Returns the builder of the target entity, e.g. to link further.
|
|
84
|
+
Results are still objects of the query's entity.
|
|
85
|
+
|
|
86
|
+
Example (orders of customers named "Ann")::
|
|
87
|
+
|
|
88
|
+
qb = box.query(Order.text.starts_with("A"))
|
|
89
|
+
qb.link(Order.customer_id, Customer.name.equals("Ann"))
|
|
90
|
+
query = qb.build()
|
|
91
|
+
|
|
92
|
+
:param relation:
|
|
93
|
+
A :class:`Relation` property of this builder's entity.
|
|
94
|
+
:param condition:
|
|
95
|
+
The condition(s) on the target entity (optional, e.g. to only link further).
|
|
96
|
+
:return:
|
|
97
|
+
The builder of the target entity; call ``build()`` on the query's builder, not on this one.
|
|
98
|
+
"""
|
|
99
|
+
self._assert_relation(relation)
|
|
100
|
+
if relation._entity._name != self._entity._name:
|
|
101
|
+
raise IllegalArgumentError(f"link(): relation {relation._entity._name}.{relation.name} is not a property "
|
|
102
|
+
f"of entity {self._entity._name}")
|
|
103
|
+
target = self._entity_by_name(relation._target_name)
|
|
104
|
+
return self._linked(obx_qb_link_property(self._c_builder, relation.id), target, condition)
|
|
105
|
+
|
|
106
|
+
def backlink(self, relation: Relation, condition: Optional[QueryCondition] = None) -> 'QueryBuilder':
|
|
107
|
+
""" Adds conditions on the objects whose to-one relation points to the objects of this builder's entity
|
|
108
|
+
(the relation used in reverse): matches objects referred to by at least one object that matches the condition.
|
|
109
|
+
Returns the builder of the relation's entity, e.g. to link further.
|
|
110
|
+
Results are still objects of the query's entity.
|
|
111
|
+
|
|
112
|
+
Example (customers with an order of more than 100)::
|
|
113
|
+
|
|
114
|
+
qb = customer_box.query()
|
|
115
|
+
qb.backlink(Order.customer_id, Order.total.greater_than(100))
|
|
116
|
+
query = qb.build()
|
|
117
|
+
|
|
118
|
+
:param relation:
|
|
119
|
+
A :class:`Relation` property of another entity (or of this one) targeting this builder's entity.
|
|
120
|
+
:param condition:
|
|
121
|
+
The condition(s) on the relation's entity (optional, e.g. to only link further).
|
|
122
|
+
:return:
|
|
123
|
+
The builder of the relation's entity; call ``build()`` on the query's builder, not on this one.
|
|
124
|
+
"""
|
|
125
|
+
self._assert_relation(relation)
|
|
126
|
+
if relation._target_name != self._entity._name:
|
|
127
|
+
raise IllegalArgumentError(f"backlink(): relation {relation._entity._name}.{relation.name} targets entity "
|
|
128
|
+
f"{relation._target_name}, not {self._entity._name}")
|
|
129
|
+
source = self._entity_by_name(relation._entity._name)
|
|
130
|
+
c_builder = obx_qb_backlink_property(self._c_builder, source._id, relation.id)
|
|
131
|
+
return self._linked(c_builder, source, condition)
|
|
132
|
+
|
|
133
|
+
@staticmethod
|
|
134
|
+
def _assert_relation(relation):
|
|
135
|
+
if not isinstance(relation, Relation):
|
|
136
|
+
raise TypeError(f"Expected a Relation property, got {relation!r}")
|
|
137
|
+
relation._assert_ids_assigned()
|
|
138
|
+
|
|
139
|
+
def _entity_by_name(self, name: str) -> '_Entity':
|
|
140
|
+
""" The entity of the store's model (the entity of a relation may be an equal one of another model). """
|
|
141
|
+
model = self._box._store._model
|
|
142
|
+
if model is not None:
|
|
143
|
+
for entity in model.entities:
|
|
144
|
+
if entity._name == name:
|
|
145
|
+
return entity
|
|
146
|
+
raise IllegalArgumentError(f"Entity {name} is not in the store's model")
|
|
147
|
+
|
|
148
|
+
def close(self):
|
|
149
|
+
""" Closes the builder, freeing its native resources; ``build()`` does this, so only needed for a builder
|
|
150
|
+
that is not built. Closing again does nothing. """
|
|
151
|
+
self._assert_root("close")
|
|
152
|
+
c_builder = self._c_builder_or_none
|
|
153
|
+
if c_builder is not None:
|
|
154
|
+
self._c_builder_or_none = None
|
|
155
|
+
self._box._store._remove_native_resource(self)
|
|
156
|
+
obx_qb_close(c_builder)
|
|
157
|
+
|
|
158
|
+
def __del__(self):
|
|
159
|
+
if getattr(self, "_root", True) is None: # A root builder (a linked one is owned by it)
|
|
160
|
+
try:
|
|
161
|
+
self.close()
|
|
162
|
+
except Exception: # E.g. during interpreter shutdown
|
|
163
|
+
pass
|
|
164
|
+
|
|
165
|
+
def error_code(self) -> int:
|
|
166
|
+
return obx_qb_error_code(self._c_builder)
|
|
167
|
+
|
|
168
|
+
def error_message(self) -> str:
|
|
169
|
+
return obx_qb_error_message(self._c_builder)
|
|
170
|
+
|
|
171
|
+
def equals_string(self, prop: Union[int, str, Property], value: str, case_sensitive: bool = True) -> obx_qb_cond:
|
|
172
|
+
prop_id = self._condition_property_id(prop)
|
|
173
|
+
cond = obx_qb_equals_string(self._c_builder, prop_id, c_str(value), case_sensitive)
|
|
174
|
+
return cond
|
|
175
|
+
|
|
176
|
+
def not_equals_string(self, prop: Union[int, str, Property], value: str,
|
|
177
|
+
case_sensitive: bool = True) -> obx_qb_cond:
|
|
178
|
+
prop_id = self._condition_property_id(prop)
|
|
179
|
+
cond = obx_qb_not_equals_string(self._c_builder, prop_id, c_str(value), case_sensitive)
|
|
180
|
+
return cond
|
|
181
|
+
|
|
182
|
+
def contains_string(self, prop: Union[int, str, Property], value: str, case_sensitive: bool = True) -> obx_qb_cond:
|
|
183
|
+
"""Checks if value is contained by the given string property."""
|
|
184
|
+
prop_id = self._condition_property_id(prop)
|
|
185
|
+
cond = obx_qb_contains_string(self._c_builder, prop_id, c_str(value), case_sensitive)
|
|
186
|
+
return cond
|
|
187
|
+
|
|
188
|
+
def starts_with_string(self, prop: Union[int, str, Property], value: str,
|
|
189
|
+
case_sensitive: bool = True) -> obx_qb_cond:
|
|
190
|
+
prop_id = self._condition_property_id(prop)
|
|
191
|
+
cond = obx_qb_starts_with_string(self._c_builder, prop_id, c_str(value), case_sensitive)
|
|
192
|
+
return cond
|
|
193
|
+
|
|
194
|
+
def ends_with_string(self, prop: Union[int, str, Property], value: str, case_sensitive: bool = True) -> obx_qb_cond:
|
|
195
|
+
prop_id = self._condition_property_id(prop)
|
|
196
|
+
cond = obx_qb_ends_with_string(self._c_builder, prop_id, c_str(value), case_sensitive)
|
|
197
|
+
return cond
|
|
198
|
+
|
|
199
|
+
def greater_than_string(self, prop: Union[int, str, Property], value: str,
|
|
200
|
+
case_sensitive: bool = True) -> obx_qb_cond:
|
|
201
|
+
prop_id = self._condition_property_id(prop)
|
|
202
|
+
cond = obx_qb_greater_than_string(self._c_builder, prop_id, c_str(value), case_sensitive)
|
|
203
|
+
return cond
|
|
204
|
+
|
|
205
|
+
def greater_or_equal_string(self, prop: Union[int, str, Property], value: str,
|
|
206
|
+
case_sensitive: bool = True) -> obx_qb_cond:
|
|
207
|
+
prop_id = self._condition_property_id(prop)
|
|
208
|
+
cond = obx_qb_greater_or_equal_string(self._c_builder, prop_id, c_str(value), case_sensitive)
|
|
209
|
+
return cond
|
|
210
|
+
|
|
211
|
+
def less_than_string(self, prop: Union[int, str, Property], value: str, case_sensitive: bool = True) -> obx_qb_cond:
|
|
212
|
+
prop_id = self._condition_property_id(prop)
|
|
213
|
+
cond = obx_qb_less_than_string(self._c_builder, prop_id, c_str(value), case_sensitive)
|
|
214
|
+
return cond
|
|
215
|
+
|
|
216
|
+
def less_or_equal_string(self, prop: Union[int, str, Property], value: str,
|
|
217
|
+
case_sensitive: bool = True) -> obx_qb_cond:
|
|
218
|
+
prop_id = self._condition_property_id(prop)
|
|
219
|
+
cond = obx_qb_less_or_equal_string(self._c_builder, prop_id, c_str(value), case_sensitive)
|
|
220
|
+
return cond
|
|
221
|
+
|
|
222
|
+
def in_strings(self, prop: Union[int, str, Property], values: List[str],
|
|
223
|
+
case_sensitive: bool = True) -> obx_qb_cond:
|
|
224
|
+
""" Matches if the string property equals any of the given values. """
|
|
225
|
+
prop_id = self._condition_property_id(prop)
|
|
226
|
+
# The C array references the encoded strings, so they stay alive for the duration of the call
|
|
227
|
+
c_values = c_array([c_str(value) for value in values], ctypes.c_char_p)
|
|
228
|
+
cond = obx_qb_in_strings(self._c_builder, prop_id, c_values, len(values), case_sensitive)
|
|
229
|
+
return cond
|
|
230
|
+
|
|
231
|
+
def equals_int(self, prop: Union[int, str, Property], value: int) -> obx_qb_cond:
|
|
232
|
+
prop_id = self._condition_property_id(prop)
|
|
233
|
+
cond = obx_qb_equals_int(self._c_builder, prop_id, value)
|
|
234
|
+
return cond
|
|
235
|
+
|
|
236
|
+
def not_equals_int(self, prop: Union[int, str, Property], value: int) -> obx_qb_cond:
|
|
237
|
+
prop_id = self._condition_property_id(prop)
|
|
238
|
+
cond = obx_qb_not_equals_int(self._c_builder, prop_id, value)
|
|
239
|
+
return cond
|
|
240
|
+
|
|
241
|
+
def in_ints(self, prop: Union[int, str, Property], values: List[int]) -> obx_qb_cond:
|
|
242
|
+
""" Matches if the integer property equals any of the given values.
|
|
243
|
+
Supported for 32-bit (Int32) and 64-bit (Int64, Id, Date, DateNano) integer properties. """
|
|
244
|
+
prop_id = self._condition_property_id(prop)
|
|
245
|
+
if self._is_int32_property(prop_id):
|
|
246
|
+
c_values = c_array([int(value) for value in values], ctypes.c_int32)
|
|
247
|
+
return obx_qb_in_int32s(self._c_builder, prop_id, c_values, len(values))
|
|
248
|
+
else:
|
|
249
|
+
c_values = c_array([int(value) for value in values], ctypes.c_int64)
|
|
250
|
+
return obx_qb_in_int64s(self._c_builder, prop_id, c_values, len(values))
|
|
251
|
+
|
|
252
|
+
def not_in_ints(self, prop: Union[int, str, Property], values: List[int]) -> obx_qb_cond:
|
|
253
|
+
""" Matches if the integer property equals none of the given values.
|
|
254
|
+
Supported for 32-bit (Int32) and 64-bit (Int64, Id, Date, DateNano) integer properties. """
|
|
255
|
+
prop_id = self._condition_property_id(prop)
|
|
256
|
+
if self._is_int32_property(prop_id):
|
|
257
|
+
c_values = c_array([int(value) for value in values], ctypes.c_int32)
|
|
258
|
+
return obx_qb_not_in_int32s(self._c_builder, prop_id, c_values, len(values))
|
|
259
|
+
else:
|
|
260
|
+
c_values = c_array([int(value) for value in values], ctypes.c_int64)
|
|
261
|
+
return obx_qb_not_in_int64s(self._c_builder, prop_id, c_values, len(values))
|
|
262
|
+
|
|
263
|
+
def _is_int32_property(self, prop_id: int) -> bool:
|
|
264
|
+
""" The C API has separate functions for 32-bit and 64-bit integer properties (e.g. for "in" conditions). """
|
|
265
|
+
for prop in self._entity._properties:
|
|
266
|
+
if prop.id == prop_id:
|
|
267
|
+
return prop._ob_type == OBXPropertyType_Int
|
|
268
|
+
raise IllegalArgumentError(f"Property ID {prop_id} not found in Entity \"{self._entity._name}\"")
|
|
269
|
+
|
|
270
|
+
def greater_than_int(self, prop: Union[int, str, Property], value: int) -> obx_qb_cond:
|
|
271
|
+
prop_id = self._condition_property_id(prop)
|
|
272
|
+
cond = obx_qb_greater_than_int(self._c_builder, prop_id, value)
|
|
273
|
+
return cond
|
|
274
|
+
|
|
275
|
+
def greater_than_double(self, prop: Union[int, str, Property], value: float) -> obx_qb_cond:
|
|
276
|
+
prop_id = self._condition_property_id(prop)
|
|
277
|
+
cond = obx_qb_greater_than_double(self._c_builder, prop_id, value)
|
|
278
|
+
return cond
|
|
279
|
+
|
|
280
|
+
def greater_or_equal_int(self, prop: Union[int, str, Property], value: int) -> obx_qb_cond:
|
|
281
|
+
prop_id = self._condition_property_id(prop)
|
|
282
|
+
cond = obx_qb_greater_or_equal_int(self._c_builder, prop_id, value)
|
|
283
|
+
return cond
|
|
284
|
+
|
|
285
|
+
def greater_or_equal_double(self, prop: Union[int, str, Property], value: float) -> obx_qb_cond:
|
|
286
|
+
prop_id = self._condition_property_id(prop)
|
|
287
|
+
cond = obx_qb_greater_or_equal_double(self._c_builder, prop_id, value)
|
|
288
|
+
return cond
|
|
289
|
+
|
|
290
|
+
def less_than_int(self, prop: Union[int, str, Property], value: int) -> obx_qb_cond:
|
|
291
|
+
prop_id = self._condition_property_id(prop)
|
|
292
|
+
cond = obx_qb_less_than_int(self._c_builder, prop_id, value)
|
|
293
|
+
return cond
|
|
294
|
+
|
|
295
|
+
def less_than_double(self, prop: Union[int, str, Property], value: float) -> obx_qb_cond:
|
|
296
|
+
prop_id = self._condition_property_id(prop)
|
|
297
|
+
cond = obx_qb_less_than_double(self._c_builder, prop_id, value)
|
|
298
|
+
return cond
|
|
299
|
+
|
|
300
|
+
def less_or_equal_int(self, prop: Union[int, str, Property], value: int) -> obx_qb_cond:
|
|
301
|
+
prop_id = self._condition_property_id(prop)
|
|
302
|
+
cond = obx_qb_less_or_equal_int(self._c_builder, prop_id, value)
|
|
303
|
+
return cond
|
|
304
|
+
|
|
305
|
+
def less_or_equal_double(self, prop: Union[int, str, Property], value: float) -> obx_qb_cond:
|
|
306
|
+
prop_id = self._condition_property_id(prop)
|
|
307
|
+
cond = obx_qb_less_or_equal_double(self._c_builder, prop_id, value)
|
|
308
|
+
return cond
|
|
309
|
+
|
|
310
|
+
def between_2ints(self, prop: Union[int, str, Property], value_a: int, value_b: int) -> obx_qb_cond:
|
|
311
|
+
prop_id = self._condition_property_id(prop)
|
|
312
|
+
cond = obx_qb_between_2ints(self._c_builder, prop_id, value_a, value_b)
|
|
313
|
+
return cond
|
|
314
|
+
|
|
315
|
+
def between_2doubles(self, prop: Union[int, str, Property], value_a: float, value_b: float) -> obx_qb_cond:
|
|
316
|
+
prop_id = self._condition_property_id(prop)
|
|
317
|
+
cond = obx_qb_between_2doubles(self._c_builder, prop_id, value_a, value_b)
|
|
318
|
+
return cond
|
|
319
|
+
|
|
320
|
+
def equals_bytes(self, prop: Union[int, str, Property], value: bytes) -> obx_qb_cond:
|
|
321
|
+
prop_id = self._condition_property_id(prop)
|
|
322
|
+
cond = obx_qb_equals_bytes(self._c_builder, prop_id, value, len(value))
|
|
323
|
+
return cond
|
|
324
|
+
|
|
325
|
+
def greater_than_bytes(self, prop: Union[int, str, Property], value: bytes) -> obx_qb_cond:
|
|
326
|
+
prop_id = self._condition_property_id(prop)
|
|
327
|
+
cond = obx_qb_greater_than_bytes(self._c_builder, prop_id, value, len(value))
|
|
328
|
+
return cond
|
|
329
|
+
|
|
330
|
+
def greater_or_equal_bytes(self, prop: Union[int, str, Property], value: bytes) -> obx_qb_cond:
|
|
331
|
+
prop_id = self._condition_property_id(prop)
|
|
332
|
+
cond = obx_qb_greater_or_equal_bytes(self._c_builder, prop_id, value, len(value))
|
|
333
|
+
return cond
|
|
334
|
+
|
|
335
|
+
def less_than_bytes(self, prop: Union[int, str, Property], value: bytes) -> obx_qb_cond:
|
|
336
|
+
prop_id = self._condition_property_id(prop)
|
|
337
|
+
cond = obx_qb_less_than_bytes(self._c_builder, prop_id, value, len(value))
|
|
338
|
+
return cond
|
|
339
|
+
|
|
340
|
+
def less_or_equal_bytes(self, prop: Union[int, str, Property], value: bytes) -> obx_qb_cond:
|
|
341
|
+
prop_id = self._condition_property_id(prop)
|
|
342
|
+
cond = obx_qb_less_or_equal_bytes(self._c_builder, prop_id, value, len(value))
|
|
343
|
+
return cond
|
|
344
|
+
|
|
345
|
+
def nearest_neighbors_f32(self,
|
|
346
|
+
prop: Union[int, str, Property],
|
|
347
|
+
query_vector: Union[np.ndarray, List[float]],
|
|
348
|
+
element_count: int):
|
|
349
|
+
check_float_vector(query_vector, "query_vector")
|
|
350
|
+
prop_id = self._condition_property_id(prop)
|
|
351
|
+
c_query_vector = c_array(query_vector, ctypes.c_float)
|
|
352
|
+
cond = obx_qb_nearest_neighbors_f32(self._c_builder, prop_id, c_query_vector, element_count)
|
|
353
|
+
return cond
|
|
354
|
+
|
|
355
|
+
def is_null(self, prop: Union[int, str, Property]) -> obx_qb_cond:
|
|
356
|
+
""" Matches objects without a value for the given property (null, i.e. put with None). """
|
|
357
|
+
return obx_qb_null(self._c_builder, self._condition_property_id(prop))
|
|
358
|
+
|
|
359
|
+
def not_null(self, prop: Union[int, str, Property]) -> obx_qb_cond:
|
|
360
|
+
""" Matches objects with a value for the given property (not null). """
|
|
361
|
+
return obx_qb_not_null(self._c_builder, self._condition_property_id(prop))
|
|
362
|
+
|
|
363
|
+
def contains_key_value(self, prop: Union[int, str, Property], key: str, value: str,
|
|
364
|
+
case_sensitive: bool = True) -> obx_qb_cond:
|
|
365
|
+
""" Checks whether the given Flex property, interpreted as a dictionary and indexed at key, has a value
|
|
366
|
+
corresponding to the given value.
|
|
367
|
+
|
|
368
|
+
:param case_sensitive:
|
|
369
|
+
If false, ignore case when matching value
|
|
370
|
+
"""
|
|
371
|
+
prop_id = self._condition_property_id(prop)
|
|
372
|
+
cond = obx_qb_contains_key_value_string(self._c_builder, prop_id, c_str(key), c_str(value), case_sensitive)
|
|
373
|
+
return cond
|
|
374
|
+
|
|
375
|
+
def _condition_property_id(self, prop: Union[int, str, Property]) -> int:
|
|
376
|
+
""" The ID of the property of a new condition, remembered for alias(). """
|
|
377
|
+
prop_id = self._entity._get_property_id(prop)
|
|
378
|
+
self._last_condition_prop_id = prop_id
|
|
379
|
+
return prop_id
|
|
380
|
+
|
|
381
|
+
def any(self, conditions: List[obx_qb_cond]) -> obx_qb_cond:
|
|
382
|
+
self._last_condition_prop_id = None # A group: alias() has no property
|
|
383
|
+
c_conditions = c_array(conditions, obx_qb_cond)
|
|
384
|
+
cond = obx_qb_any(self._c_builder, c_conditions, len(conditions))
|
|
385
|
+
return cond
|
|
386
|
+
|
|
387
|
+
def all(self, conditions: List[obx_qb_cond]) -> obx_qb_cond:
|
|
388
|
+
self._last_condition_prop_id = None # A group: alias() has no property
|
|
389
|
+
c_conditions = c_array_pointer(conditions, obx_qb_cond)
|
|
390
|
+
cond = obx_qb_all(self._c_builder, c_conditions, len(conditions))
|
|
391
|
+
return cond
|
|
392
|
+
|
|
393
|
+
def order(self, prop: Union[int, str, Property], flags: Union[OrderFlags, int] = 0) -> 'QueryBuilder':
|
|
394
|
+
""" Orders the query results by the given property, ascending by default.
|
|
395
|
+
Call multiple times to order by multiple properties: the first call sets the primary order,
|
|
396
|
+
the following ones are used for results that are equal according to the preceding orders.
|
|
397
|
+
Applies to ``find()`` and ``find_ids()``; note that ordering requires to sort all matching objects.
|
|
398
|
+
|
|
399
|
+
Example: ``box.query(Person.age.greater_than(17)).order(Person.name).build()``
|
|
400
|
+
|
|
401
|
+
:param prop:
|
|
402
|
+
The property (or its name or ID) to order by.
|
|
403
|
+
:param flags:
|
|
404
|
+
:class:`OrderFlags` to adjust the order; combine multiple using ``|``,
|
|
405
|
+
e.g. ``OrderFlags.DESCENDING | OrderFlags.CASE_SENSITIVE``.
|
|
406
|
+
:return:
|
|
407
|
+
This QueryBuilder (to chain calls).
|
|
408
|
+
"""
|
|
409
|
+
self._assert_root("order") # The core ignores orders of linked entities
|
|
410
|
+
prop_id = self._entity._get_property_id(prop) # Not a condition (alias() does not apply)
|
|
411
|
+
obx_qb_order(self._c_builder, prop_id, flags)
|
|
412
|
+
return self
|
|
413
|
+
|
|
414
|
+
def order_desc(self, prop: Union[int, str, Property], flags: Union[OrderFlags, int] = 0) -> 'QueryBuilder':
|
|
415
|
+
""" Orders the query results by the given property, descending;
|
|
416
|
+
the same as ``order(prop, OrderFlags.DESCENDING | flags)``, see :meth:`order`.
|
|
417
|
+
|
|
418
|
+
Example: ``box.query().order_desc(Person.age).build()``
|
|
419
|
+
|
|
420
|
+
:param prop:
|
|
421
|
+
The property (or its name or ID) to order by.
|
|
422
|
+
:param flags:
|
|
423
|
+
Further :class:`OrderFlags` to adjust the order, e.g. ``OrderFlags.CASE_SENSITIVE``.
|
|
424
|
+
:return:
|
|
425
|
+
This QueryBuilder (to chain calls).
|
|
426
|
+
"""
|
|
427
|
+
return self.order(prop, OrderFlags.DESCENDING | flags)
|
|
428
|
+
|
|
429
|
+
def build(self) -> Query:
|
|
430
|
+
""" Builds the query; this closes the builder (it can not be used afterwards). """
|
|
431
|
+
self._assert_root("build")
|
|
432
|
+
try:
|
|
433
|
+
c_query = obx_query(self._c_builder)
|
|
434
|
+
finally:
|
|
435
|
+
self.close()
|
|
436
|
+
return Query(c_query, self._box, self._alias_properties)
|
|
437
|
+
|
|
438
|
+
def alias(self, alias: str):
|
|
439
|
+
""" Sets an alias for the last condition added to this builder, to change its value(s) on the built query via
|
|
440
|
+
``Query.set_parameter_alias()``; that then knows the condition's property (and so how to set the value).
|
|
441
|
+
Conditions passed to ``box.query()`` set their aliases via ``PropertyQueryCondition.alias()``. """
|
|
442
|
+
obx_qb_param_alias(self._c_builder, c_str(alias)) # Raises if the last condition has no property (a group)
|
|
443
|
+
if self._last_condition_prop_id is not None:
|
|
444
|
+
self._alias_properties[alias] = (self._entity, self._last_condition_prop_id)
|
|
445
|
+
return self
|
|
446
|
+
|
|
447
|
+
def _alias_for_property(self, alias: str, prop_id: int):
|
|
448
|
+
""" Like alias(), for the condition of the given property (for Query.set_parameter_alias()). """
|
|
449
|
+
self._last_condition_prop_id = prop_id
|
|
450
|
+
return self.alias(alias)
|