Skip to content

Commit 44721d9

Browse files
ivahnenkoAnnagreenrobot
authored andcommitted
Queries: minimal support for str and int properties #17
c.py: rename fn() and add a separate method for functions returning obx_err
1 parent 7997091 commit 44721d9

File tree

7 files changed

+677
-45
lines changed

7 files changed

+677
-45
lines changed

objectbox/box.py

+6
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
from objectbox.model.entity import _Entity
1717
from objectbox.objectbox import ObjectBox
18+
from objectbox.query_builder import QueryBuilder
19+
from objectbox.condition import QueryCondition
1820
from objectbox.c import *
1921

2022

@@ -147,3 +149,7 @@ def remove_all(self) -> int:
147149
count = ctypes.c_uint64()
148150
obx_box_remove_all(self._c_box, ctypes.byref(count))
149151
return int(count.value)
152+
153+
def query(self, condition: QueryCondition) -> QueryBuilder:
154+
qb = QueryBuilder(self._ob, self, self._entity, condition)
155+
return qb

objectbox/c.py

+258-45
Large diffs are not rendered by default.

objectbox/condition.py

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
from enum import Enum
2+
3+
class _ConditionOp(Enum):
4+
eq = 1
5+
notEq = 2
6+
contains = 3
7+
startsWith = 4
8+
endsWith = 5
9+
gt = 6
10+
greaterOrEq = 7
11+
lt = 8
12+
lessOrEq = 9
13+
between = 10
14+
15+
16+
class QueryCondition:
17+
def __init__(self, property_id: int, op: _ConditionOp, value, value_b = None, case_sensitive: bool = True):
18+
self._property_id = property_id
19+
self._op = op
20+
self._value = value
21+
self._value_b = value_b
22+
self._case_sensitive = case_sensitive
23+
24+
def apply(self, builder: 'QueryBuilder'):
25+
if self._op == _ConditionOp.eq:
26+
if isinstance(self._value, str):
27+
builder.equals_string(self._property_id, self._value, self._case_sensitive)
28+
elif isinstance(self._value, int):
29+
builder.equals_int(self._property_id, self._value)
30+
else:
31+
raise Exception("Unsupported type for 'eq': " + str(type(self._value)))
32+
33+
elif self._op == _ConditionOp.notEq:
34+
if isinstance(self._value, str):
35+
builder.not_equals_string(self._property_id, self._value, self._case_sensitive)
36+
elif isinstance(self._value, int):
37+
builder.not_equals_int(self._property_id, self._value)
38+
else:
39+
raise Exception("Unsupported type for 'notEq': " + str(type(self._value)))
40+
41+
elif self._op == _ConditionOp.contains:
42+
if isinstance(self._value, str):
43+
builder.contains_string(self._property_id, self._value, self._case_sensitive)
44+
else:
45+
raise Exception("Unsupported type for 'contains': " + str(type(self._value)))
46+
47+
elif self._op == _ConditionOp.startsWith:
48+
if isinstance(self._value, str):
49+
builder.starts_with_string(self._property_id, self._value, self._case_sensitive)
50+
else:
51+
raise Exception("Unsupported type for 'startsWith': " + str(type(self._value)))
52+
53+
elif self._op == _ConditionOp.endsWith:
54+
if isinstance(self._value, str):
55+
builder.ends_with_string(self._property_id, self._value, self._case_sensitive)
56+
else:
57+
raise Exception("Unsupported type for 'endsWith': " + str(type(self._value)))
58+
59+
elif self._op == _ConditionOp.gt:
60+
if isinstance(self._value, str):
61+
builder.greater_than_string(self._property_id, self._value, self._case_sensitive)
62+
elif isinstance(self._value, int):
63+
builder.greater_than_int(self._property_id, self._value)
64+
else:
65+
raise Exception("Unsupported type for 'gt': " + str(type(self._value)))
66+
67+
elif self._op == _ConditionOp.greaterOrEq:
68+
if isinstance(self._value, str):
69+
builder.greater_or_equal_string(self._property_id, self._value, self._case_sensitive)
70+
elif isinstance(self._value, int):
71+
builder.greater_or_equal_int(self._property_id, self._value)
72+
else:
73+
raise Exception("Unsupported type for 'greaterOrEq': " + str(type(self._value)))
74+
75+
elif self._op == _ConditionOp.lt:
76+
if isinstance(self._value, str):
77+
builder.less_than_string(self._property_id, self._value, self._case_sensitive)
78+
elif isinstance(self._value, int):
79+
builder.less_than_int(self._property_id, self._value)
80+
else:
81+
raise Exception("Unsupported type for 'lt': " + str(type(self._value)))
82+
83+
elif self._op == _ConditionOp.lessOrEq:
84+
if isinstance(self._value, str):
85+
builder.less_or_equal_string(self._property_id, self._value, self._case_sensitive)
86+
elif isinstance(self._value, int):
87+
builder.less_or_equal_int(self._property_id, self._value)
88+
else:
89+
raise Exception("Unsupported type for 'lessOrEq': " + str(type(self._value)))
90+
91+
elif self._op == _ConditionOp.between:
92+
if isinstance(self._value, int):
93+
builder.between_2ints(self._property_id, self._value, self._value_b)
94+
else:
95+
raise Exception("Unsupported type for 'between': " + str(type(self._value)))

objectbox/model/properties.py

+34
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
from enum import IntEnum
1616

17+
from objectbox.condition import QueryCondition, _ConditionOp
1718
from objectbox.c import *
1819
import flatbuffers.number_types
1920
import numpy as np
@@ -127,6 +128,39 @@ def __set_flags(self):
127128
if self._is_id:
128129
self._flags = OBXPropertyFlags_ID
129130

131+
def op(self, op: _ConditionOp, value, case_sensitive: bool = True) -> QueryCondition:
132+
return QueryCondition(self._id, op, value, case_sensitive)
133+
134+
def equals(self, value, case_sensitive: bool = True) -> QueryCondition:
135+
return self.op(_ConditionOp.eq, value, case_sensitive)
136+
137+
def not_equals(self, value, case_sensitive: bool = True) -> QueryCondition:
138+
return self.op(_ConditionOp.notEq, value, case_sensitive)
139+
140+
def contains(self, value: str, case_sensitive: bool = True) -> QueryCondition:
141+
return self.op(_ConditionOp.contains, value, case_sensitive)
142+
143+
def starts_with(self, value: str, case_sensitive: bool = True) -> QueryCondition:
144+
return self.op(_ConditionOp.startsWith, value, case_sensitive)
145+
146+
def ends_with(self, value: str, case_sensitive: bool = True) -> QueryCondition:
147+
return self.op(_ConditionOp.endsWith, value, case_sensitive)
148+
149+
def greater_than(self, value, case_sensitive: bool = True) -> QueryCondition:
150+
return self.op(_ConditionOp.gt, value, case_sensitive)
151+
152+
def greater_or_equal(self, value, case_sensitive: bool = True) -> QueryCondition:
153+
return self.op(_ConditionOp.greaterOrEq, value, case_sensitive)
154+
155+
def less_than(self, value, case_sensitive: bool = True) -> QueryCondition:
156+
return self.op(_ConditionOp.lt, value, case_sensitive)
157+
158+
def less_or_equal(self, value, case_sensitive: bool = True) -> QueryCondition:
159+
return self.op(_ConditionOp.lessOrEq, value, case_sensitive)
160+
161+
def between(self, value_a, value_b) -> QueryCondition:
162+
return QueryCondition(self._id, _ConditionOp.between, value_a, value_b)
163+
130164

131165
# ID property (primary key)
132166
class Id(Property):

objectbox/query.py

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Copyright 2019-2023 ObjectBox Ltd. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from objectbox.c import *
16+
17+
18+
class Query:
19+
def __init__(self, c_query, box: 'Box'):
20+
self._c_query = c_query
21+
self._box = box
22+
self._ob = box._ob
23+
24+
def find(self) -> list:
25+
with self._ob.read_tx():
26+
# OBX_bytes_array*
27+
c_bytes_array_p = obx_query_find(self._c_query)
28+
29+
try:
30+
# OBX_bytes_array
31+
c_bytes_array = c_bytes_array_p.contents
32+
33+
result = list()
34+
for i in range(c_bytes_array.count):
35+
# OBX_bytes
36+
c_bytes = c_bytes_array.data[i]
37+
data = c_voidp_as_bytes(c_bytes.data, c_bytes.size)
38+
result.append(self._box._entity.unmarshal(data))
39+
40+
return result
41+
finally:
42+
obx_bytes_array_free(c_bytes_array_p)
43+
44+
def count(self) -> int:
45+
count = ctypes.c_uint64()
46+
obx_query_count(self._c_query, ctypes.byref(count))
47+
return int(count.value)
48+
49+
def remove(self) -> int:
50+
count = ctypes.c_uint64()
51+
obx_query_remove(self._c_query, ctypes.byref(count))
52+
return int(count.value)
53+
54+
def offset(self, offset: int):
55+
return obx_query_offset(self._c_query, offset)
56+
57+
def limit(self, limit: int):
58+
return obx_query_limit(self._c_query, limit)

objectbox/query_builder.py

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
from objectbox.model.entity import _Entity
2+
from objectbox.objectbox import ObjectBox
3+
from objectbox.query import Query
4+
from objectbox.c import *
5+
6+
7+
class QueryBuilder:
8+
def __init__(self, ob: ObjectBox, box: 'Box', entity: '_Entity', condition: 'QueryCondition'):
9+
if not isinstance(entity, _Entity):
10+
raise Exception("Given type is not an Entity")
11+
self._box = box
12+
self._entity = entity
13+
self._condition = condition
14+
self._c_builder = obx_query_builder(ob._c_store, entity.id)
15+
16+
def close(self) -> int:
17+
return obx_qb_close(self)
18+
19+
def error_code(self) -> int:
20+
return obx_qb_error_code(self)
21+
22+
def error_message(self) -> str:
23+
return obx_qb_error_message(self)
24+
25+
def equals_string(self, property_id: int, value: str, case_sensitive: bool):
26+
obx_qb_equals_string(self._c_builder, property_id, c_str(value), case_sensitive)
27+
return self
28+
29+
def not_equals_string(self, property_id: int, value: str, case_sensitive: bool):
30+
obx_qb_not_equals_string(self._c_builder, property_id, c_str(value), case_sensitive)
31+
return self
32+
33+
def contains_string(self, property_id: int, value: str, case_sensitive: bool):
34+
obx_qb_contains_string(self._c_builder, property_id, c_str(value), case_sensitive)
35+
return self
36+
37+
def starts_with_string(self, property_id: int, value: str, case_sensitive: bool):
38+
obx_qb_starts_with_string(self._c_builder, property_id, c_str(value), case_sensitive)
39+
return self
40+
41+
def ends_with_string(self, property_id: int, value: str, case_sensitive: bool):
42+
obx_qb_ends_with_string(self._c_builder, property_id, c_str(value), case_sensitive)
43+
return self
44+
45+
def greater_than_string(self, property_id: int, value: str, case_sensitive: bool):
46+
obx_qb_greater_than_string(self._c_builder, property_id, c_str(value), case_sensitive)
47+
return self
48+
49+
def greater_or_equal_string(self, property_id: int, value: str, case_sensitive: bool):
50+
obx_qb_greater_or_equal_string(self._c_builder, property_id, c_str(value), case_sensitive)
51+
return self
52+
53+
def less_than_string(self, property_id: int, value: str, case_sensitive: bool):
54+
obx_qb_less_than_string(self._c_builder, property_id, c_str(value), case_sensitive)
55+
return self
56+
57+
def less_or_equal_string(self, property_id: int, value: str, case_sensitive: bool):
58+
obx_qb_less_or_equal_string(self._c_builder, property_id, c_str(value), case_sensitive)
59+
return self
60+
61+
def equals_int(self, property_id: int, value: int):
62+
obx_qb_equals_int(self._c_builder, property_id, value)
63+
return self
64+
65+
def not_equals_int(self, property_id: int, value: int):
66+
obx_qb_not_equals_int(self._c_builder, property_id, value)
67+
return self
68+
69+
def greater_than_int(self, property_id: int, value: int):
70+
obx_qb_greater_than_int(self._c_builder, property_id, value)
71+
return self
72+
73+
def greater_or_equal_int(self, property_id: int, value: int):
74+
obx_qb_greater_or_equal_int(self._c_builder, property_id, value)
75+
return self
76+
77+
def less_than_int(self, property_id: int, value: int):
78+
obx_qb_less_than_int(self._c_builder, property_id, value)
79+
return self
80+
81+
def less_or_equal_int(self, property_id: int, value: int):
82+
obx_qb_less_or_equal_int(self._c_builder, property_id, value)
83+
return self
84+
85+
def between_2ints(self, property_id: int, value_a: int, value_b: int):
86+
obx_qb_between_2ints(self._c_builder, property_id, value_a, value_b)
87+
return self
88+
89+
def apply_condition(self):
90+
self._condition.apply(self)
91+
92+
def build(self) -> Query:
93+
self.apply_condition()
94+
c_query = obx_query(self._c_builder)
95+
return Query(c_query, self._box)

0 commit comments

Comments
 (0)