From a930b2cf0ecfd49d793e92992a20c6978cc55cbb Mon Sep 17 00:00:00 2001 From: Jonathan Zernik Date: Mon, 28 Dec 2020 17:08:46 -0800 Subject: [PATCH] Use TZDateTime as type for time columns in database (#525) --- ..._all.py => 82c409b96c66_initialize_all.py} | 6 ++-- squeaknode/db/models.py | 36 ++++++++++++++----- squeaknode/db/squeak_db.py | 9 +++-- 3 files changed, 35 insertions(+), 16 deletions(-) rename squeaknode/db/alembic/versions/{b92797939348_initialize_all.py => 82c409b96c66_initialize_all.py} (98%) diff --git a/squeaknode/db/alembic/versions/b92797939348_initialize_all.py b/squeaknode/db/alembic/versions/82c409b96c66_initialize_all.py similarity index 98% rename from squeaknode/db/alembic/versions/b92797939348_initialize_all.py rename to squeaknode/db/alembic/versions/82c409b96c66_initialize_all.py index 06856fa0..aef17807 100644 --- a/squeaknode/db/alembic/versions/b92797939348_initialize_all.py +++ b/squeaknode/db/alembic/versions/82c409b96c66_initialize_all.py @@ -1,8 +1,8 @@ """Initialize all -Revision ID: b92797939348 +Revision ID: 82c409b96c66 Revises: -Create Date: 2020-12-27 22:22:09.374933 +Create Date: 2020-12-28 15:35:10.195043 """ from alembic import op @@ -10,7 +10,7 @@ import sqlalchemy as sa # revision identifiers, used by Alembic. -revision = 'b92797939348' +revision = '82c409b96c66' down_revision = None branch_labels = None depends_on = None diff --git a/squeaknode/db/models.py b/squeaknode/db/models.py index 6998cdea..f99623fd 100644 --- a/squeaknode/db/models.py +++ b/squeaknode/db/models.py @@ -1,5 +1,6 @@ import logging +from sqlalchemy.types import TypeDecorator from sqlalchemy import ( Binary, Boolean, @@ -11,11 +12,30 @@ from sqlalchemy import ( Table, func, ) -from sqlalchemy.types import TIMESTAMP logger = logging.getLogger(__name__) +import datetime + +class TZDateTime(TypeDecorator): + impl = DateTime + + def process_bind_param(self, value, dialect): + if value is not None: + if not value.tzinfo: + raise TypeError("tzinfo is required") + value = value.astimezone(datetime.timezone.utc).replace( + tzinfo=None + ) + return value + + def process_result_value(self, value, dialect): + if value is not None: + value = value.replace(tzinfo=datetime.timezone.utc) + return value + + class Models: def __init__(self, schema=None): self.schema = schema @@ -25,7 +45,7 @@ class Models: "squeak", self.metadata, Column("hash", String(64), primary_key=True), - Column("created", TIMESTAMP, server_default=func.now(), nullable=False), + Column("created", TZDateTime, server_default=func.now(), nullable=False), Column("squeak", Binary, nullable=False), Column("hash_reply_sqk", String(64), nullable=False), Column("hash_block", String(64), nullable=False), @@ -40,7 +60,7 @@ class Models: "profile", self.metadata, Column("profile_id", Integer, primary_key=True), - Column("created", TIMESTAMP, server_default=func.now(), nullable=False), + Column("created", TZDateTime, server_default=func.now(), nullable=False), Column("profile_name", String, unique=True, nullable=False), Column("private_key", Binary), Column("address", String(35), unique=True, nullable=False), @@ -52,7 +72,7 @@ class Models: "peer", self.metadata, Column("id", Integer, primary_key=True), - Column("created", TIMESTAMP, server_default=func.now(), nullable=False), + Column("created", TZDateTime, server_default=func.now(), nullable=False), Column("peer_name", String), Column("server_host", String, nullable=False), Column("server_port", Integer, nullable=False), @@ -64,7 +84,7 @@ class Models: "offer", self.metadata, Column("offer_id", Integer, primary_key=True), - Column("created", TIMESTAMP, server_default=func.now(), nullable=False), + Column("created", TZDateTime, server_default=func.now(), nullable=False), Column("squeak_hash", String(64), nullable=False), Column("payment_hash", String(64), nullable=False), Column("nonce", String(64), nullable=False), @@ -83,7 +103,7 @@ class Models: "sent_payment", self.metadata, Column("sent_payment_id", Integer, primary_key=True), - Column("created", TIMESTAMP, server_default=func.now(), nullable=False), + Column("created", TZDateTime, server_default=func.now(), nullable=False), Column("offer_id", Integer, nullable=False), Column("peer_id", Integer, nullable=False), Column("squeak_hash", String(64), nullable=False), @@ -97,7 +117,7 @@ class Models: "sent_offer", self.metadata, Column("sent_offer_id", Integer, primary_key=True), - Column("created", TIMESTAMP, server_default=func.now(), nullable=False), + Column("created", TZDateTime, server_default=func.now(), nullable=False), Column("squeak_hash", String(64), nullable=False), Column("payment_hash", String(64), unique=True, nullable=False), Column("secret_key", String(64), nullable=False), @@ -113,7 +133,7 @@ class Models: "received_payment", self.metadata, Column("received_payment_id", Integer, primary_key=True), - Column("created", TIMESTAMP, server_default=func.now(), nullable=False), + Column("created", TZDateTime, server_default=func.now(), nullable=False), Column("squeak_hash", String(64), nullable=False), Column("payment_hash", String(64), unique=True, nullable=False), Column("price_msat", Integer, nullable=False), diff --git a/squeaknode/db/squeak_db.py b/squeaknode/db/squeak_db.py index 90f4cac8..4cc250da 100644 --- a/squeaknode/db/squeak_db.py +++ b/squeaknode/db/squeak_db.py @@ -1,7 +1,6 @@ import logging from contextlib import contextmanager -from datetime import datetime, timedelta -import time +from datetime import datetime, timedelta, timezone import sqlalchemy from sqlalchemy import func, literal @@ -308,7 +307,7 @@ class SqueakDb: select([self.squeaks.c.hash]) .where(self.squeaks.c.author_address.in_(addresses)) .where( - self.squeaks.c.created > time.time() - interval_seconds + self.squeaks.c.created > datetime.now(timezone.utc) - timedelta(seconds=interval_seconds) ) .where( or_( @@ -834,7 +833,7 @@ class SqueakDb: def delete_expired_offers(self): """ Delete all expired offers. """ s = self.offers.delete().where( - time.time() > self.offers.c.invoice_timestamp + self.offers.c.invoice_expiry + datetime.now(timezone.utc).timestamp() > self.offers.c.invoice_timestamp + self.offers.c.invoice_expiry ) with self.get_connection() as connection: res = connection.execute(s) @@ -968,7 +967,7 @@ class SqueakDb: def delete_expired_sent_offers(self): """ Delete all expired sent offers. """ s = self.sent_offers.delete().where( - time.time() > self.sent_offers.c.invoice_timestamp + self.sent_offers.c.invoice_expiry + datetime.now(timezone.utc).timestamp() > self.sent_offers.c.invoice_timestamp + self.sent_offers.c.invoice_expiry ) with self.get_connection() as connection: res = connection.execute(s)