aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorWolfgang Müller2021-05-05 17:19:22 +0200
committerWolfgang Müller2021-05-05 17:19:22 +0200
commit517458eeb9c7e1f3c41d8071978e48bc9822a1b2 (patch)
tree8ddb696813487ae070097006618b9842c4acc7dd
parentf67f0f93e1c90eb778a51016c9777c9f7dae7839 (diff)
downloadquarg-517458eeb9c7e1f3c41d8071978e48bc9822a1b2.tar.gz
tables: Correctly handle Integer timestamps from the SQLite backend
Quassel stores its timestamps as INTEGERs when using the SQLite backend. Since SQLAlchemy expects strings here instead[1], we have to handle this manually. This commit extends the existing process_result_value() function to handle a conversion from a unix timestamp to a proper datetime object, makes sure that the right impl is chosen for both SQLite and PostgreSQL, and adds the process_bind_param() function which takes care of the conversion back to a unix timestamp when binding values for SELECT statements. [1] https://docs.sqlalchemy.org/en/14/core/type_basics.html#sqlalchemy.types.DateTime
Diffstat (limited to '')
-rw-r--r--quarg/database/tables.py28
1 files changed, 22 insertions, 6 deletions
diff --git a/quarg/database/tables.py b/quarg/database/tables.py
index 743ffa2..cdb3b68 100644
--- a/quarg/database/tables.py
+++ b/quarg/database/tables.py
@@ -1,7 +1,7 @@
import datetime
from sqlalchemy.schema import Column, ForeignKey
-from sqlalchemy.types import BigInteger, Boolean, DateTime, Integer, Text, TypeDecorator
+from sqlalchemy.types import BigInteger, Boolean, DateTime, Integer, Text, TypeDecorator, TypeEngine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
@@ -10,17 +10,33 @@ from sqlalchemy.orm import relationship
# Timestamps are saved in the database in UTC without timezone info, so attach
# a UTC timezone to the datetime object
class DateTimeUTC(TypeDecorator):
- # pylint complains that process_{bind,literal}_param and python_type are
+ # pylint complains that process_literal_param and python_type are
# abstract but not overriden. This seems to not be necessary with
# SQLAlchemy, so squash those warnings
# pylint: disable=abstract-method
- impl = DateTime
+ impl = TypeEngine
+
+ def load_dialect_impl(self, dialect):
+ if dialect.name == 'sqlite':
+ return dialect.type_descriptor(Integer)
+
+ return dialect.type_descriptor(DateTime)
+
+ def process_bind_param(self, value, dialect):
+ if dialect.name == 'sqlite':
+ return value.timestamp() * 1000
- def process_result_value(self, value, dialect):
- if value is not None:
- value = value.replace(tzinfo=datetime.timezone.utc)
return value
+ def process_result_value(self, value, dialect):
+ if value is None:
+ return value
+
+ if dialect.name == 'sqlite':
+ return datetime.datetime.fromtimestamp(value / 1000, datetime.timezone.utc)
+
+ return value.replace(tzinfo=datetime.timezone.utc)
+
Base = declarative_base()
# Note: We have commented out unused columns to keep SQLAlchemy from selecting