From 30f06de70b66add149bbd94527f43ec9946d6ddb Mon Sep 17 00:00:00 2001 From: Korbinian Habereder Date: Sat, 29 Oct 2022 15:00:42 +0200 Subject: [PATCH 1/3] feature property types :sparkles: - implemented datetime property type --- example/__main__.py | 9 ++++----- example/model.py | 5 +++-- objectbox/__init__.py | 2 +- objectbox/model/entity.py | 10 ++++++++-- objectbox/model/properties.py | 7 +++++-- 5 files changed, 21 insertions(+), 12 deletions(-) diff --git a/example/__main__.py b/example/__main__.py index 66d3ddd..e0b9457 100644 --- a/example/__main__.py +++ b/example/__main__.py @@ -1,17 +1,16 @@ from cmd import Cmd import objectbox -import datetime +from datetime import datetime from example.model import * # objectbox expects date timestamp in milliseconds since UNIX epoch def now_ms() -> int: - seconds: float = datetime.datetime.utcnow().timestamp() - return round(seconds * 1000) + return datetime.utcnow() -def format_date(timestamp_ms: int) -> str: - return "" if timestamp_ms == 0 else str(datetime.datetime.fromtimestamp(timestamp_ms / 1000)) +def format_date(timestamp_ms: datetime) -> str: + return "" if timestamp_ms == 0 else str(timestamp_ms) class TasklistCmd(Cmd): diff --git a/example/model.py b/example/model.py index 88c7142..74adb5a 100644 --- a/example/model.py +++ b/example/model.py @@ -1,3 +1,4 @@ +from datetime import datetime from objectbox.model import * @@ -7,8 +8,8 @@ class Task: text = Property(str, id=2, uid=1002) # TODO property type DATE - date_created = Property(int, id=3, uid=1003) - date_finished = Property(int, id=4, uid=1004) + date_created = Property(datetime, id=3, uid=1003) + date_finished = Property(datetime, id=4, uid=1004) def get_objectbox_model(): diff --git a/objectbox/__init__.py b/objectbox/__init__.py index b08cfed..584be96 100644 --- a/objectbox/__init__.py +++ b/objectbox/__init__.py @@ -31,7 +31,7 @@ ] # Python binding version -version = Version(0, 4, 0) +version = Version(0, 5, 0) def version_info(): diff --git a/objectbox/model/entity.py b/objectbox/model/entity.py index 2f83e59..ddb39a7 100644 --- a/objectbox/model/entity.py +++ b/objectbox/model/entity.py @@ -13,6 +13,7 @@ # limitations under the License. +from datetime import datetime import flatbuffers from objectbox.c import * from objectbox.model.properties import Property @@ -78,8 +79,10 @@ def fill_properties(self): def get_value(self, object, prop: Property): # in case value is not overwritten on the object, it's the Property object itself (= as defined in the Class) val = getattr(object, prop._name) - if val == prop: - return prop._py_type() # default (empty) value for the given type + if isinstance(val, datetime): # handle datetimes first + return int(val.timestamp()) + elif val == prop: + return prop._py_type() if not hasattr(prop._py_type, "timestamp") else 0 # default (empty) value for the given type return val def get_object_id(self, object) -> int: @@ -143,6 +146,9 @@ def unmarshal(self, data: bytes): # slice the vector as a requested type val = prop._py_type(table.Bytes[start:start+size]) + elif prop._ob_type == OBXPropertyType_Date: + table_val = table.Get(prop._fb_type, o + table.Pos) + val = datetime.fromtimestamp(table_val) if table_val != 0 else 0 # default timestamp else: val = table.Get(prop._fb_type, o + table.Pos) diff --git a/objectbox/model/properties.py b/objectbox/model/properties.py index 08810f2..d3a0c7c 100644 --- a/objectbox/model/properties.py +++ b/objectbox/model/properties.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from datetime import datetime from enum import IntEnum from objectbox.c import * @@ -28,7 +29,7 @@ class PropertyType(IntEnum): float = OBXPropertyType_Float double = OBXPropertyType_Double string = OBXPropertyType_String - # date = OBXPropertyType_Date + date = OBXPropertyType_Date # relation = OBXPropertyType_Relation byteVector = OBXPropertyType_ByteVector # stringVector = OBXPropertyType_StringVector @@ -44,7 +45,7 @@ class PropertyType(IntEnum): PropertyType.float: flatbuffers.number_types.Float32Flags, PropertyType.double: flatbuffers.number_types.Float64Flags, PropertyType.string: flatbuffers.number_types.UOffsetTFlags, - # PropertyType.date: flatbuffers.number_types.Int64Flags, + PropertyType.date: flatbuffers.number_types.Int64Flags, # PropertyType.relation: flatbuffers.number_types.Int64Flags, PropertyType.byteVector: flatbuffers.number_types.UOffsetTFlags, # PropertyType.stringVector: flatbuffers.number_types.UOffsetTFlags, @@ -81,6 +82,8 @@ def __determine_ob_type(self) -> OBXPropertyType: return OBXPropertyType_Double elif ts == bool: return OBXPropertyType_Bool + elif ts == datetime: + return OBXPropertyType_Date else: raise Exception("unknown property type %s" % ts) From 32f526b15e4f5365de6032d36f4cfd24eca12d06 Mon Sep 17 00:00:00 2001 From: Korbinian Habereder Date: Sun, 30 Oct 2022 10:22:00 +0100 Subject: [PATCH 2/3] implemented dateNano --- example/model.py | 3 +-- objectbox/c.py | 1 + objectbox/model/entity.py | 4 ++-- objectbox/model/properties.py | 2 ++ 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/example/model.py b/example/model.py index 74adb5a..3ac14c3 100644 --- a/example/model.py +++ b/example/model.py @@ -7,8 +7,7 @@ class Task: id = Id(id=1, uid=1001) text = Property(str, id=2, uid=1002) - # TODO property type DATE - date_created = Property(datetime, id=3, uid=1003) + date_created = Property(datetime, type=PropertyType.dateNano, id=3, uid=1003) date_finished = Property(datetime, id=4, uid=1004) diff --git a/objectbox/c.py b/objectbox/c.py index 339b530..33aef62 100644 --- a/objectbox/c.py +++ b/objectbox/c.py @@ -394,6 +394,7 @@ def c_voidp_as_bytes(voidp, size): OBXPropertyType_String = 9 OBXPropertyType_Date = 10 OBXPropertyType_Relation = 11 +OBXPropertyType_DateNano = 12 OBXPropertyType_ByteVector = 23 OBXPropertyType_StringVector = 30 diff --git a/objectbox/model/entity.py b/objectbox/model/entity.py index ddb39a7..da67b51 100644 --- a/objectbox/model/entity.py +++ b/objectbox/model/entity.py @@ -80,7 +80,7 @@ def get_value(self, object, prop: Property): # in case value is not overwritten on the object, it's the Property object itself (= as defined in the Class) val = getattr(object, prop._name) if isinstance(val, datetime): # handle datetimes first - return int(val.timestamp()) + return int(val.timestamp()) if prop._ob_type == OBXPropertyType_Date else val.timestamp() elif val == prop: return prop._py_type() if not hasattr(prop._py_type, "timestamp") else 0 # default (empty) value for the given type return val @@ -146,7 +146,7 @@ def unmarshal(self, data: bytes): # slice the vector as a requested type val = prop._py_type(table.Bytes[start:start+size]) - elif prop._ob_type == OBXPropertyType_Date: + elif prop._ob_type == OBXPropertyType_Date or prop._ob_type == OBXPropertyType_DateNano: table_val = table.Get(prop._fb_type, o + table.Pos) val = datetime.fromtimestamp(table_val) if table_val != 0 else 0 # default timestamp else: diff --git a/objectbox/model/properties.py b/objectbox/model/properties.py index d3a0c7c..3b0c9a9 100644 --- a/objectbox/model/properties.py +++ b/objectbox/model/properties.py @@ -30,6 +30,7 @@ class PropertyType(IntEnum): double = OBXPropertyType_Double string = OBXPropertyType_String date = OBXPropertyType_Date + dateNano = OBXPropertyType_DateNano # relation = OBXPropertyType_Relation byteVector = OBXPropertyType_ByteVector # stringVector = OBXPropertyType_StringVector @@ -46,6 +47,7 @@ class PropertyType(IntEnum): PropertyType.double: flatbuffers.number_types.Float64Flags, PropertyType.string: flatbuffers.number_types.UOffsetTFlags, PropertyType.date: flatbuffers.number_types.Int64Flags, + PropertyType.dateNano: flatbuffers.number_types.Float64Flags, # PropertyType.relation: flatbuffers.number_types.Int64Flags, PropertyType.byteVector: flatbuffers.number_types.UOffsetTFlags, # PropertyType.stringVector: flatbuffers.number_types.UOffsetTFlags, From efb7779c70cc0f8ff1223b94c5c1db51eed6fb5f Mon Sep 17 00:00:00 2001 From: Korbinian Habereder Date: Wed, 2 Nov 2022 16:14:58 +0100 Subject: [PATCH 3/3] implemented requested PR changes --- example/__main__.py | 4 ++-- objectbox/model/entity.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/example/__main__.py b/example/__main__.py index e0b9457..726f42c 100644 --- a/example/__main__.py +++ b/example/__main__.py @@ -1,12 +1,12 @@ from cmd import Cmd import objectbox -from datetime import datetime +from datetime import datetime, timezone from example.model import * # objectbox expects date timestamp in milliseconds since UNIX epoch def now_ms() -> int: - return datetime.utcnow() + return datetime.now(timezone.utc) def format_date(timestamp_ms: datetime) -> str: diff --git a/objectbox/model/entity.py b/objectbox/model/entity.py index da67b51..dc33a54 100644 --- a/objectbox/model/entity.py +++ b/objectbox/model/entity.py @@ -79,8 +79,8 @@ def fill_properties(self): def get_value(self, object, prop: Property): # in case value is not overwritten on the object, it's the Property object itself (= as defined in the Class) val = getattr(object, prop._name) - if isinstance(val, datetime): # handle datetimes first - return int(val.timestamp()) if prop._ob_type == OBXPropertyType_Date else val.timestamp() + if hasattr(val, "timestamp"): # handle datetimes first + return int(val.timestamp()) elif val == prop: return prop._py_type() if not hasattr(prop._py_type, "timestamp") else 0 # default (empty) value for the given type return val