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
objectbox/__init__.py
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Copyright 2019-2024 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
|
+
"""ObjectBox Python API"""
|
|
16
|
+
|
|
17
|
+
from objectbox.store import Store
|
|
18
|
+
from objectbox.box import Box
|
|
19
|
+
from objectbox.model.entity import Entity, SyncEntity
|
|
20
|
+
from objectbox.model.properties import Id, String, Index, Bool, Int8, Int16, Int32, Int64, Float32, Float64, Bytes, BoolVector, Int8Vector, Int16Vector, Int32Vector, Int64Vector, Float32Vector, Float64Vector, CharVector, BoolList, Int8List, Int16List, Int32List, Int64List, Float32List, Float64List, CharList, Date, DateNano, Flex, Relation, IndexType, Unique, ConflictStrategy, HnswIndex, VectorDistanceType, HnswFlags, SyncClock, SyncPrecedence
|
|
21
|
+
from objectbox.model.model import Model
|
|
22
|
+
from objectbox.c import version_core, DebugFlags
|
|
23
|
+
# The exceptions most likely handled by applications (all are in objectbox.exceptions; its TimeoutError is not
|
|
24
|
+
# exported here, as it would shadow the built-in TimeoutError on "from objectbox import *")
|
|
25
|
+
from objectbox.exceptions import (DbError, IllegalArgumentError, IllegalStateError, UniqueViolatedError,
|
|
26
|
+
ConstraintViolatedError, NonUniqueResultError, IdNotFoundError,
|
|
27
|
+
FeatureNotAvailableError, SchemaError, DbFullError, MaxDataSizeExceededError,
|
|
28
|
+
MaxReadersExceededError, StoreMustShutdownError, FileCorruptError,
|
|
29
|
+
FilePagesCorruptError, NumericOverflowError)
|
|
30
|
+
from objectbox.version import Version
|
|
31
|
+
from objectbox.condition import PropertyQueryCondition
|
|
32
|
+
from objectbox.query import Query, ObjectWithScore, IdWithScore
|
|
33
|
+
from objectbox.query_builder import QueryBuilder
|
|
34
|
+
from objectbox.builder import Builder
|
|
35
|
+
from objectbox.objectbox import ObjectBox
|
|
36
|
+
from objectbox.query_builder import OrderFlags
|
|
37
|
+
|
|
38
|
+
__all__ = [
|
|
39
|
+
'Box',
|
|
40
|
+
'Builder',
|
|
41
|
+
'Model',
|
|
42
|
+
'Entity',
|
|
43
|
+
'Id',
|
|
44
|
+
'Bool',
|
|
45
|
+
'Int8',
|
|
46
|
+
'Int16',
|
|
47
|
+
'Int32',
|
|
48
|
+
'Int64',
|
|
49
|
+
'Float32',
|
|
50
|
+
'Float64',
|
|
51
|
+
'Bytes',
|
|
52
|
+
'String',
|
|
53
|
+
'BoolVector',
|
|
54
|
+
'Int8Vector',
|
|
55
|
+
'Int16Vector',
|
|
56
|
+
'Int32Vector',
|
|
57
|
+
'Int64Vector',
|
|
58
|
+
'Float32Vector',
|
|
59
|
+
'Float64Vector',
|
|
60
|
+
'CharVector',
|
|
61
|
+
'BoolList',
|
|
62
|
+
'Int8List',
|
|
63
|
+
'Int16List',
|
|
64
|
+
'Int32List',
|
|
65
|
+
'Int64List',
|
|
66
|
+
'Float32List',
|
|
67
|
+
'Float64List',
|
|
68
|
+
'CharList',
|
|
69
|
+
'Date',
|
|
70
|
+
'DateNano',
|
|
71
|
+
'Flex',
|
|
72
|
+
'Relation',
|
|
73
|
+
'Index',
|
|
74
|
+
'IndexType',
|
|
75
|
+
'Unique',
|
|
76
|
+
'ConflictStrategy',
|
|
77
|
+
'HnswIndex',
|
|
78
|
+
'VectorDistanceType',
|
|
79
|
+
'Store',
|
|
80
|
+
'ObjectBox',
|
|
81
|
+
'DbError',
|
|
82
|
+
'IllegalArgumentError',
|
|
83
|
+
'IllegalStateError',
|
|
84
|
+
'UniqueViolatedError',
|
|
85
|
+
'ConstraintViolatedError',
|
|
86
|
+
'NonUniqueResultError',
|
|
87
|
+
'IdNotFoundError',
|
|
88
|
+
'FeatureNotAvailableError',
|
|
89
|
+
'SchemaError',
|
|
90
|
+
'DbFullError',
|
|
91
|
+
'MaxDataSizeExceededError',
|
|
92
|
+
'MaxReadersExceededError',
|
|
93
|
+
'StoreMustShutdownError',
|
|
94
|
+
'FileCorruptError',
|
|
95
|
+
'FilePagesCorruptError',
|
|
96
|
+
'NumericOverflowError',
|
|
97
|
+
'version',
|
|
98
|
+
'version_info',
|
|
99
|
+
'DebugFlags',
|
|
100
|
+
'PropertyQueryCondition',
|
|
101
|
+
'HnswFlags',
|
|
102
|
+
'Query',
|
|
103
|
+
'ObjectWithScore',
|
|
104
|
+
'IdWithScore',
|
|
105
|
+
'QueryBuilder',
|
|
106
|
+
'SyncEntity',
|
|
107
|
+
'SyncClock',
|
|
108
|
+
'SyncPrecedence',
|
|
109
|
+
'OrderFlags',
|
|
110
|
+
# Sync (loaded on first use; see __getattr__)
|
|
111
|
+
'Sync',
|
|
112
|
+
'SyncClient',
|
|
113
|
+
'SyncCredentials',
|
|
114
|
+
'SyncState',
|
|
115
|
+
'SyncRequestUpdatesMode',
|
|
116
|
+
'SyncFlags',
|
|
117
|
+
'SyncStats',
|
|
118
|
+
'SyncCode',
|
|
119
|
+
'SyncChange',
|
|
120
|
+
'SyncListener',
|
|
121
|
+
'SyncLoginListener',
|
|
122
|
+
'SyncConnectionListener',
|
|
123
|
+
'SyncCompletedListener',
|
|
124
|
+
'SyncTimeListener',
|
|
125
|
+
'SyncChangeListener',
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
_sync_names = frozenset(__all__[__all__.index('Sync'):])
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def __getattr__(name: str):
|
|
132
|
+
# Sync names are imported on first use: importing objectbox.sync takes a few milliseconds, also for apps without
|
|
133
|
+
# Sync (a module __getattr__, PEP 562; also used by "from objectbox import *")
|
|
134
|
+
if name in _sync_names:
|
|
135
|
+
import objectbox.sync
|
|
136
|
+
return getattr(objectbox.sync, name)
|
|
137
|
+
raise AttributeError(f"module 'objectbox' has no attribute '{name}'")
|
|
138
|
+
|
|
139
|
+
# Python binding version
|
|
140
|
+
version = Version(5, 0, 0)
|
|
141
|
+
"""ObjectBox Python package version"""
|
|
142
|
+
|
|
143
|
+
def version_info():
|
|
144
|
+
"""Returns a string with Python and core version information."""
|
|
145
|
+
return "ObjectBox Python version " + str(version) + " using dynamic library version " + str(version_core)
|
objectbox/box.py
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
# Copyright 2019-2024 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
|
+
|
|
16
|
+
from objectbox.model.entity import _Entity
|
|
17
|
+
from objectbox.store import Store
|
|
18
|
+
from objectbox.query_builder import QueryBuilder
|
|
19
|
+
from objectbox.condition import QueryCondition
|
|
20
|
+
from objectbox.c import *
|
|
21
|
+
from objectbox.exceptions import DbError, IllegalArgumentError, IllegalStateError
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Box:
|
|
25
|
+
"""Interface to Entities"""
|
|
26
|
+
def __init__(self, store: Store, entity: _Entity):
|
|
27
|
+
if not isinstance(entity, _Entity):
|
|
28
|
+
raise TypeError(f"Expected an entity (a class decorated with @Entity()), got {entity!r}")
|
|
29
|
+
|
|
30
|
+
self._store = store
|
|
31
|
+
self._entity = entity
|
|
32
|
+
self._c_box_of_open_store = obx_box(store._c_store, entity._id)
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def _c_box(self):
|
|
36
|
+
if self._store._c_store_or_none is None: # The C box would be invalid
|
|
37
|
+
raise IllegalStateError("Store is closed")
|
|
38
|
+
return self._c_box_of_open_store
|
|
39
|
+
|
|
40
|
+
def contains(self, object_id: int) -> bool:
|
|
41
|
+
"""Checks whether the box contains the given object ID."""
|
|
42
|
+
contained = ctypes.c_bool()
|
|
43
|
+
obx_box_contains(self._c_box, object_id, ctypes.byref(contained))
|
|
44
|
+
return bool(contained.value)
|
|
45
|
+
|
|
46
|
+
def is_empty(self) -> bool:
|
|
47
|
+
"""Returns true if box is empty (i.e. no objects of entity type are available)."""
|
|
48
|
+
is_empty = ctypes.c_bool()
|
|
49
|
+
obx_box_is_empty(self._c_box, ctypes.byref(is_empty))
|
|
50
|
+
return bool(is_empty.value)
|
|
51
|
+
|
|
52
|
+
def count(self, limit: int = 0) -> int:
|
|
53
|
+
"""Returns the count of existing objects."""
|
|
54
|
+
count = ctypes.c_uint64()
|
|
55
|
+
obx_box_count(self._c_box, limit, ctypes.byref(count))
|
|
56
|
+
return int(count.value)
|
|
57
|
+
|
|
58
|
+
def put(self, *objects):
|
|
59
|
+
"""Puts an object and returns its ID; puts a list (or tuple) of objects, or several objects passed as
|
|
60
|
+
arguments, in one transaction and returns their IDs (a list, in the same order).
|
|
61
|
+
|
|
62
|
+
A new object has the ID 0 and gets its ID assigned (set on the object). An object with a non-zero ID is
|
|
63
|
+
updated (or inserted if it does not exist, e.g. was removed); its ID must have been assigned by ObjectBox
|
|
64
|
+
before (else raises IllegalArgumentError), unless the ID property is ``Id(assignable=True)``."""
|
|
65
|
+
|
|
66
|
+
if len(objects) != 1:
|
|
67
|
+
return self._put_many(objects)
|
|
68
|
+
elif isinstance(objects[0], (list, tuple)):
|
|
69
|
+
return self._put_many(objects[0])
|
|
70
|
+
else:
|
|
71
|
+
return self._put_one(objects[0])
|
|
72
|
+
|
|
73
|
+
def _put_one(self, obj) -> int:
|
|
74
|
+
# A new object (ID 0) gets its ID assigned while putting (saves a C call to reserve it); this writes the ID
|
|
75
|
+
# into the data, so it must be a writable copy. A non-zero ID must have been assigned by ObjectBox before
|
|
76
|
+
# (the C library checks it), unless the ID property is assignable.
|
|
77
|
+
self._check_type(obj)
|
|
78
|
+
id = self._entity._get_object_id(obj)
|
|
79
|
+
if id: # The C library does not write into the data (the ID is set)
|
|
80
|
+
data = bytes(self._entity._marshal(obj, id))
|
|
81
|
+
return obx_box_put_object4(self._c_box, data, len(data), OBXPutMode_PUT)
|
|
82
|
+
data = self._entity._marshal(obj, 0)
|
|
83
|
+
size = len(data)
|
|
84
|
+
id = obx_box_put_object4(self._c_box, ctypes.create_string_buffer(bytes(data), size), size, OBXPutMode_PUT)
|
|
85
|
+
self._entity._set_object_id(obj, id)
|
|
86
|
+
return id
|
|
87
|
+
|
|
88
|
+
def _put_many(self, objects) -> List[int]:
|
|
89
|
+
if not objects:
|
|
90
|
+
return []
|
|
91
|
+
# retrieve IDs from the objects (to distinguish new objects and updates)
|
|
92
|
+
new = {}
|
|
93
|
+
ids = {}
|
|
94
|
+
for k in range(len(objects)):
|
|
95
|
+
self._check_type(objects[k])
|
|
96
|
+
id = self._entity._get_object_id(objects[k])
|
|
97
|
+
if not id:
|
|
98
|
+
new[k] = 0
|
|
99
|
+
ids[k] = id
|
|
100
|
+
|
|
101
|
+
with self._store.write_tx(): # One transaction for checking/reserving the IDs and putting
|
|
102
|
+
self._put_many_in_tx(objects, new, ids)
|
|
103
|
+
|
|
104
|
+
# assign new IDs on the object
|
|
105
|
+
for k in new.keys():
|
|
106
|
+
self._entity._set_object_id(objects[k], ids[k])
|
|
107
|
+
return list(ids.values())
|
|
108
|
+
|
|
109
|
+
def _put_many_in_tx(self, objects, new, ids) -> None:
|
|
110
|
+
# Check the given IDs: obx_box_put_many() takes them as reserved; obx_box_id_for_put() raises for an ID not
|
|
111
|
+
# assigned by ObjectBox before (and advances the ID sequence for assignable IDs). Checking the highest ID
|
|
112
|
+
# covers all: lower IDs were assigned before, too.
|
|
113
|
+
max_id = max(ids.values(), default=0)
|
|
114
|
+
if max_id:
|
|
115
|
+
obx_box_id_for_put(self._c_box, max_id)
|
|
116
|
+
|
|
117
|
+
# acquire IDs for the new objects and set them
|
|
118
|
+
if len(new) > 0:
|
|
119
|
+
c_next_id = obx_id()
|
|
120
|
+
obx_box_ids_for_put(self._c_box, len(new), ctypes.byref(c_next_id))
|
|
121
|
+
next_id = c_next_id.value
|
|
122
|
+
for k in new.keys():
|
|
123
|
+
ids[k] = next_id
|
|
124
|
+
next_id += 1
|
|
125
|
+
|
|
126
|
+
# allocate a C bytes array structure where we will push the object data
|
|
127
|
+
# OBX_bytes_array with .count = len(objects)
|
|
128
|
+
c_bytes_array_p = obx_bytes_array(len(objects))
|
|
129
|
+
|
|
130
|
+
try:
|
|
131
|
+
# we need to keep the data around until put_many is executed because obx_bytes_array_set doesn't do a copy
|
|
132
|
+
data = {}
|
|
133
|
+
for k in range(len(objects)):
|
|
134
|
+
data[k] = bytes(self._entity._marshal(objects[k], ids[k]))
|
|
135
|
+
key = ctypes.c_size_t(k)
|
|
136
|
+
|
|
137
|
+
# OBX_bytes_array.data[k] = data
|
|
138
|
+
obx_bytes_array_set(c_bytes_array_p, key,
|
|
139
|
+
data[k], len(data[k]))
|
|
140
|
+
|
|
141
|
+
c_ids = (obx_id * len(ids))(*ids.values())
|
|
142
|
+
obx_box_put_many(self._c_box, c_bytes_array_p,
|
|
143
|
+
c_ids, OBXPutMode_PUT)
|
|
144
|
+
|
|
145
|
+
finally:
|
|
146
|
+
obx_bytes_array_free(c_bytes_array_p)
|
|
147
|
+
|
|
148
|
+
def update(self, object_):
|
|
149
|
+
"""Updates the existing object having the same ID as the given object.
|
|
150
|
+
|
|
151
|
+
Raises if the object has no ID (i.e. it was never put) or the ID doesn't match any stored object."""
|
|
152
|
+
self._check_type(object_)
|
|
153
|
+
object_id = self._entity._get_object_id(object_)
|
|
154
|
+
if not object_id:
|
|
155
|
+
raise IllegalArgumentError("Cannot update an object without an ID; use put() for new objects")
|
|
156
|
+
data = self._entity._marshal(object_, object_id)
|
|
157
|
+
obx_box_update(self._c_box, object_id, bytes(data), len(data))
|
|
158
|
+
|
|
159
|
+
def get(self, id: int):
|
|
160
|
+
"""Get object by given Id or None if not found."""
|
|
161
|
+
c_box = self._c_box # Raises if the store is closed
|
|
162
|
+
tx = obx_txn_read(self._store._c_store_or_none) # not via read_tx(): less overhead for this hot path
|
|
163
|
+
try:
|
|
164
|
+
c_data = ctypes.c_void_p()
|
|
165
|
+
c_size = ctypes.c_size_t()
|
|
166
|
+
code : obx_err = obx_box_get(c_box, id, ctypes.byref(
|
|
167
|
+
c_data), ctypes.byref(c_size))
|
|
168
|
+
if code == 404:
|
|
169
|
+
return None
|
|
170
|
+
elif code != 0:
|
|
171
|
+
raise DbError.from_code(code)
|
|
172
|
+
data = c_voidp_as_bytes(c_data, c_size.value)
|
|
173
|
+
finally:
|
|
174
|
+
obx_txn_close(tx)
|
|
175
|
+
return self._entity._unmarshal(data)
|
|
176
|
+
|
|
177
|
+
def get_many(self, id_array: List[int]) -> list:
|
|
178
|
+
"""Gets objects matching the given ID list.
|
|
179
|
+
|
|
180
|
+
:return: objects matching the ID list, preserving the order.
|
|
181
|
+
If an invalid ID is supplied, the corresponding object is None.
|
|
182
|
+
"""
|
|
183
|
+
|
|
184
|
+
if not id_array: # Empty
|
|
185
|
+
return []
|
|
186
|
+
|
|
187
|
+
c_ids = (obx_id * len(id_array))(*id_array)
|
|
188
|
+
c_id_array = OBX_id_array(ctypes.cast(c_ids, ctypes.POINTER(obx_id)), len(id_array))
|
|
189
|
+
|
|
190
|
+
with self._store.read_tx():
|
|
191
|
+
c_bytes_array_p = obx_box_get_many(self._c_box, ctypes.byref(c_id_array))
|
|
192
|
+
|
|
193
|
+
result = []
|
|
194
|
+
try:
|
|
195
|
+
c_bytes_array = c_bytes_array_p.contents
|
|
196
|
+
for i in range(c_bytes_array.count):
|
|
197
|
+
c_bytes = c_bytes_array.data[i]
|
|
198
|
+
if c_bytes.data is None or c_bytes.size == 0: # User supplied an invalid ID
|
|
199
|
+
result.append(None)
|
|
200
|
+
else:
|
|
201
|
+
data = c_voidp_as_bytes(c_bytes.data, c_bytes.size)
|
|
202
|
+
result.append(self._entity._unmarshal(data))
|
|
203
|
+
finally:
|
|
204
|
+
obx_bytes_array_free(c_bytes_array_p)
|
|
205
|
+
return result
|
|
206
|
+
|
|
207
|
+
def get_all(self) -> list:
|
|
208
|
+
"""Get all objects."""
|
|
209
|
+
with self._store.read_tx():
|
|
210
|
+
# OBX_bytes_array*
|
|
211
|
+
c_bytes_array_p = obx_box_get_all(self._c_box)
|
|
212
|
+
|
|
213
|
+
try:
|
|
214
|
+
# OBX_bytes_array
|
|
215
|
+
c_bytes_array = c_bytes_array_p.contents
|
|
216
|
+
|
|
217
|
+
result = list()
|
|
218
|
+
for i in range(c_bytes_array.count):
|
|
219
|
+
# OBX_bytes
|
|
220
|
+
c_bytes = c_bytes_array.data[i]
|
|
221
|
+
data = c_voidp_as_bytes(c_bytes.data, c_bytes.size)
|
|
222
|
+
result.append(self._entity._unmarshal(data))
|
|
223
|
+
|
|
224
|
+
return result
|
|
225
|
+
finally:
|
|
226
|
+
obx_bytes_array_free(c_bytes_array_p)
|
|
227
|
+
|
|
228
|
+
def remove(self, id_or_object) -> bool:
|
|
229
|
+
"""Removes the object with the given ID (or the given object); returns False if it did not exist.
|
|
230
|
+
See :meth:`remove_many` for several objects."""
|
|
231
|
+
if isinstance(id_or_object, (list, tuple)):
|
|
232
|
+
raise TypeError("remove() takes one ID or object; use remove_many() for several")
|
|
233
|
+
id = self._id_of(id_or_object)
|
|
234
|
+
code : obx_err = obx_box_remove(self._c_box, id)
|
|
235
|
+
if code == 404:
|
|
236
|
+
return False
|
|
237
|
+
elif code != 0:
|
|
238
|
+
raise DbError.from_code(code)
|
|
239
|
+
return True
|
|
240
|
+
|
|
241
|
+
def remove_many(self, ids_or_objects) -> int:
|
|
242
|
+
"""Removes the objects with the given IDs (or the given objects) in one transaction; IDs that do not exist
|
|
243
|
+
are skipped. Returns the number of removed objects."""
|
|
244
|
+
ids = [self._id_of(item) for item in ids_or_objects]
|
|
245
|
+
if not ids:
|
|
246
|
+
return 0
|
|
247
|
+
c_ids = (obx_id * len(ids))(*ids)
|
|
248
|
+
c_id_array = OBX_id_array(ctypes.cast(c_ids, ctypes.POINTER(obx_id)), len(ids))
|
|
249
|
+
count = ctypes.c_uint64()
|
|
250
|
+
obx_box_remove_many(self._c_box, ctypes.byref(c_id_array), ctypes.byref(count))
|
|
251
|
+
return int(count.value)
|
|
252
|
+
|
|
253
|
+
def _id_of(self, id_or_object) -> int:
|
|
254
|
+
if self._is_entity_object(id_or_object):
|
|
255
|
+
return self._entity._get_object_id(id_or_object)
|
|
256
|
+
if not isinstance(id_or_object, int) or isinstance(id_or_object, bool):
|
|
257
|
+
raise TypeError(f"Expected an ID (int) or an object of entity {self._entity._name}, got {id_or_object!r}")
|
|
258
|
+
return id_or_object
|
|
259
|
+
|
|
260
|
+
def _check_type(self, obj):
|
|
261
|
+
if not self._is_entity_object(obj):
|
|
262
|
+
raise TypeError(f"Expected an object of entity {self._entity._name}, got {obj!r}")
|
|
263
|
+
|
|
264
|
+
def _is_entity_object(self, obj) -> bool:
|
|
265
|
+
# Also accepts the same class defined again, e.g. by re-running a notebook cell
|
|
266
|
+
user_type = self._entity._user_type
|
|
267
|
+
return isinstance(obj, user_type) or type(obj).__name__ == user_type.__name__
|
|
268
|
+
|
|
269
|
+
def remove_all(self) -> int:
|
|
270
|
+
"""Removes all objects and returns number of removed."""
|
|
271
|
+
count = ctypes.c_uint64()
|
|
272
|
+
obx_box_remove_all(self._c_box, ctypes.byref(count))
|
|
273
|
+
return int(count.value)
|
|
274
|
+
|
|
275
|
+
def query(self, condition: Optional[QueryCondition] = None) -> QueryBuilder:
|
|
276
|
+
""" Initiates Query creation for the Entity associated by this Box.
|
|
277
|
+
Technically, it creates a QueryBuilder object, and you have to call build() on it to get the Query object.
|
|
278
|
+
|
|
279
|
+
:param condition:
|
|
280
|
+
Applies the given condition(s) to the new QueryBuilder object.
|
|
281
|
+
For example, assuming you defined an @Entity called "MyEntity" with a string property "name":
|
|
282
|
+
|
|
283
|
+
``query = box.query(MyEntity.name.equals("Johnny")).build()``
|
|
284
|
+
|
|
285
|
+
It's also possible to pass multiple conditions:
|
|
286
|
+
|
|
287
|
+
``query = box.query(MyEntity.name.equals("Johnny") & MyEntity.age.greater_than(21)).build()``
|
|
288
|
+
|
|
289
|
+
Note: ``&`` is the logical AND operator, and ``|`` is the logical OR operator.
|
|
290
|
+
"""
|
|
291
|
+
qb = QueryBuilder(self._store, self)
|
|
292
|
+
if condition is not None:
|
|
293
|
+
condition.apply(qb)
|
|
294
|
+
return qb
|
objectbox/builder.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Copyright 2019-2024 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
|
+
|
|
16
|
+
from objectbox.c import *
|
|
17
|
+
from objectbox.model.model import Model
|
|
18
|
+
from objectbox.store import Store
|
|
19
|
+
from objectbox.store_options import StoreOptions
|
|
20
|
+
from warnings import warn
|
|
21
|
+
|
|
22
|
+
class Builder:
|
|
23
|
+
"""*Deprecated Interface*"""
|
|
24
|
+
def __init__(self):
|
|
25
|
+
"""This throws a deprecation warning on initialization."""
|
|
26
|
+
warn(f'Using {self.__class__.__name__} is deprecated, please use Store(model=, directory= ...) from objectbox.store.', DeprecationWarning, stacklevel=2)
|
|
27
|
+
self._kwargs = { }
|
|
28
|
+
|
|
29
|
+
def directory(self, path: str) -> 'Builder':
|
|
30
|
+
self._kwargs['directory'] = path
|
|
31
|
+
return self
|
|
32
|
+
|
|
33
|
+
def max_db_size_in_kb(self, size_in_kb: int) -> 'Builder':
|
|
34
|
+
self._kwargs['max_db_size_in_kb'] = size_in_kb
|
|
35
|
+
return self
|
|
36
|
+
|
|
37
|
+
def model(self, model: Model) -> 'Builder':
|
|
38
|
+
self._kwargs['model'] = model
|
|
39
|
+
return self
|
|
40
|
+
|
|
41
|
+
def build(self) -> 'Store':
|
|
42
|
+
return Store(**self._kwargs)
|