Skip to content

Commit b468606

Browse files
author
Ivan Dlugos
committed
process entity properties in the model
1 parent 57b5857 commit b468606

5 files changed

Lines changed: 163 additions & 18 deletions

File tree

objectbox/c.py

Lines changed: 98 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@
1010
obx_id = ctypes.c_uint64
1111
obx_qb_cond = ctypes.c_int
1212

13+
# enums
14+
OBXPropertyType = ctypes.c_int
15+
OBXPropertyFlags = ctypes.c_int
16+
OBXDebugFlags = ctypes.c_int
17+
OBXPutMode = ctypes.c_int
18+
OBXOrderFlags = ctypes.c_int
19+
1320

1421
class OBX_model(ctypes.Structure):
1522
pass
@@ -102,22 +109,109 @@ class OBX_query(ctypes.Structure):
102109
OBX_query_p = ctypes.POINTER(OBX_query)
103110

104111

112+
class CError(Exception):
113+
def __init__(self, code):
114+
self.code = code
115+
self.message = ctypes.c_char_p(C.obx_last_error_message()).value.decode("utf8")
116+
super(CError, self).__init__(self.message)
117+
118+
119+
# check obx_err and raise an error
120+
def errcheck(code: obx_err, func, args):
121+
if code != 0:
122+
raise CError(code)
123+
124+
105125
# creates a global function "name" with the given restype & argtypes, calling C function with the same name
106126
def fn(name: str, restype: type, argtypes):
107127
func = C.__getattr__(name)
108128

109129
if restype == obx_err:
110-
# TODO func.errcheck
111-
pass
130+
func.errcheck = errcheck
112131
else:
113132
func.restype = restype
114133

115134
func.argtypes = argtypes
116135
return func
117136

118137

119-
# OBX_model* obx_model_create(void);
138+
def c_str(string: str) -> ctypes.c_char_p:
139+
return string.encode('utf-8')
140+
141+
142+
# OBX_model* (void);
120143
obx_model_create = fn('obx_model_create', OBX_model_p, [])
121144

122-
# obx_err obx_model_entity(OBX_model* model, const char* name, obx_schema_id entity_id, obx_uid entity_uid);
145+
# obx_err (OBX_model* model, const char* name, obx_schema_id entity_id, obx_uid entity_uid);
123146
obx_model_entity = fn('obx_model_entity', obx_err, [OBX_model_p, ctypes.c_char_p, obx_schema_id, obx_uid])
147+
148+
# obx_err (OBX_model* model, const char* name, OBXPropertyType type, obx_schema_id property_id, obx_uid property_uid);
149+
obx_model_property = fn('obx_model_property', obx_err,
150+
[OBX_model_p, ctypes.c_char_p, OBXPropertyType, obx_schema_id, obx_uid])
151+
152+
OBXPropertyType_Bool = 1
153+
OBXPropertyType_Byte = 2
154+
OBXPropertyType_Short = 3
155+
OBXPropertyType_Char = 4
156+
OBXPropertyType_Int = 5
157+
OBXPropertyType_Long = 6
158+
OBXPropertyType_Float = 7
159+
OBXPropertyType_Double = 8
160+
OBXPropertyType_String = 9
161+
OBXPropertyType_Date = 10
162+
OBXPropertyType_Relation = 11
163+
OBXPropertyType_ByteVector = 23
164+
OBXPropertyType_StringVector = 30
165+
166+
OBXPropertyFlags_ID = 1
167+
OBXPropertyFlags_NON_PRIMITIVE_TYPE = 2
168+
OBXPropertyFlags_NOT_NULL = 4
169+
OBXPropertyFlags_INDEXED = 8
170+
OBXPropertyFlags_RESERVED = 16
171+
OBXPropertyFlags_UNIQUE = 32
172+
OBXPropertyFlags_ID_MONOTONIC_SEQUENCE = 64
173+
OBXPropertyFlags_ID_SELF_ASSIGNABLE = 128
174+
OBXPropertyFlags_INDEX_PARTIAL_SKIP_NULL = 256
175+
OBXPropertyFlags_INDEX_PARTIAL_SKIP_ZERO = 512
176+
OBXPropertyFlags_VIRTUAL = 1024
177+
OBXPropertyFlags_INDEX_HASH = 2048
178+
OBXPropertyFlags_INDEX_HASH64 = 4096
179+
OBXPropertyFlags_UNSIGNED = 8192
180+
181+
OBXDebugFlags_LOG_TRANSACTIONS_READ = 1,
182+
OBXDebugFlags_LOG_TRANSACTIONS_WRITE = 2,
183+
OBXDebugFlags_LOG_QUERIES = 4,
184+
OBXDebugFlags_LOG_QUERY_PARAMETERS = 8,
185+
OBXDebugFlags_LOG_ASYNC_QUEUE = 16,
186+
187+
188+
# Standard put ("insert or update")
189+
OBXPutMode_PUT = 1,
190+
191+
# Put succeeds only if the entity does not exist yet.
192+
OBXPutMode_INSERT = 2,
193+
194+
# Put succeeds only if the entity already exist.
195+
OBXPutMode_UPDATE = 3,
196+
197+
# The given ID (non-zero) is guaranteed to be new; don't use unless you know exactly what you are doing!
198+
# This is primarily used internally. Wrong usage leads to inconsistent data (e.g. index data not updated)!
199+
OBXPutMode_PUT_ID_GUARANTEED_TO_BE_NEW = 4
200+
201+
202+
# Reverts the order from ascending (default) to descending.
203+
OBXOrderFlags_DESCENDING = 1,
204+
205+
# Makes upper case letters (e.g. "Z") be sorted before lower case letters (e.g. "a").
206+
# If not specified, the default is case insensitive for ASCII characters.
207+
OBXOrderFlags_CASE_SENSITIVE = 2,
208+
209+
# For scalars only: changes the comparison to unsigned (default is signed).
210+
OBXOrderFlags_UNSIGNED = 4,
211+
212+
# null values will be put last.
213+
# If not specified, by default null values will be put first.
214+
OBXOrderFlags_NULLS_LAST = 8,
215+
216+
# null values should be treated equal to zero (scalars only).
217+
OBXOrderFlags_NULLS_ZERO = 16,

objectbox/model/entity.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,40 @@
1+
from typing import List, Dict
2+
3+
from objectbox.model.properties import Property
4+
5+
16
# entity decorator
27
class _Entity(object):
38
def __init__(self, cls, id: int, uid: int):
4-
self.cls = cls
5-
self.name: str = cls.__name__
6-
self.id = id
7-
self.uid = uid
8-
99
# currently, ID and UID are mandatory and are not fetched from the model.json
1010
if id <= 0:
1111
raise ValueError("invalid or no 'id; given in the @Entity annotation")
1212

1313
if uid <= 0:
1414
raise ValueError("invalid or no 'uid' given in the @Entity annotation")
1515

16+
self.cls = cls
17+
self.name: str = cls.__name__
18+
self.id = id
19+
self.uid = uid
20+
21+
self.properties: List[Property] = list()
22+
self.fillProperties()
23+
1624
def __call__(self):
1725
return self.cls()
1826

27+
def fillProperties(self):
28+
# TODO allow subclassing and support entities with __slots__ defined
29+
variables = dict(vars(self.cls))
30+
31+
# filter only subclasses of Property
32+
variables = {k: v for k, v in variables.items() if issubclass(type(v), Property)}
33+
34+
for k, v in variables.items():
35+
v.__name = k
36+
self.properties.append(v)
37+
1938

2039
# wrap _Entity to allow @Entity(id=, uid=), i.e. no class argument
2140
def Entity(cls=None, id: int = 0, uid: int = 0):

objectbox/model/model.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ def entity(self, entity: _Entity):
3131
raise ValueError("Given type is not an Entity. Are you passing an instance instead of a type or did you "
3232
"forget the '@Entity' annotation?")
3333

34-
obx_model_entity(self.__model, entity.name.encode('utf-8'), entity.id, entity.uid)
34+
obx_model_entity(self.__model, c_str(entity.name), entity.id, entity.uid)
3535

36-
self.__entities.append(entity)
36+
for v in entity.properties:
37+
obx_model_property(self.__model, c_str(v._Property__name), v._Property__ob_type, v._Property__id, v._Property__uid)

objectbox/model/properties.py

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,43 @@
1-
class Property:
2-
__is_id: bool
3-
__py_type: type
1+
from objectbox.c import *
2+
import flatbuffers.number_types
3+
44

5-
def __init__(self, py_type: type):
5+
# base property
6+
class Property:
7+
def __init__(self, py_type: type, id: int, uid: int):
68
self.__is_id = isinstance(self, Id)
79
self.__py_type = py_type
10+
self.__id = id
11+
self.__uid = uid
12+
self.__name: str = "" # set when in Entity.fillProperties()
13+
14+
self.__ob_type: OBXPropertyType
15+
self.__fb_type: object # flatbuffers.number_types
16+
self._set_basic_type()
17+
18+
def _set_basic_type(self) -> OBXPropertyType:
19+
ts = self.__py_type
20+
if ts == str:
21+
self.__ob_type = OBXPropertyType_String
22+
self.__fb_type = flatbuffers.number_types.UOffsetTFlags
23+
elif ts == int:
24+
self.__ob_type = OBXPropertyType_Long
25+
self.__fb_type = flatbuffers.number_types.Int64Flags
26+
# TODO support
27+
# elif ts == bytes or ts == bytearray:
28+
# self.__ob_type = OBXPropertyType_ByteVector
29+
# self.__fb_type = flatbuffers.number_types.UOffsetTFlags
30+
elif ts == float:
31+
self.__ob_type = OBXPropertyType_Double
32+
self.__fb_type = flatbuffers.number_types.Float64Flags
33+
elif ts == bool:
34+
self.__ob_type = OBXPropertyType_Bool
35+
self.__fb_type = flatbuffers.number_types.BoolFlags
36+
else:
37+
raise TypeError("unknown property type %s" % ts)
838

939

40+
# ID property (primary key)
1041
class Id(Property):
11-
def __init__(self, py_type: type = int):
12-
super(Id, self).__init__(py_type)
42+
def __init__(self, py_type: type = int, id: int = 0, uid: int = 0):
43+
super(Id, self).__init__(py_type, id, uid)

tests/model.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33

44
@Entity(id=1, uid=1)
55
class TestEntity:
6-
id = Id()
6+
id = Id(id=1, uid=1001)

0 commit comments

Comments
 (0)