Add datetime and timestamp fields

This commit is contained in:
evilchili 2025-10-04 15:22:07 -07:00
parent 9449cc3937
commit 44ee664a77
3 changed files with 43 additions and 3 deletions

View File

@ -1,4 +1,4 @@
from grung.types import BackReference, Collection, Field, Integer, Password, Record from grung.types import BackReference, Collection, DateTime, Field, Integer, Password, Record, Timestamp
class User(Record): class User(Record):
@ -10,6 +10,8 @@ class User(Record):
Integer("number", default=0), Integer("number", default=0),
Field("email", unique=True), Field("email", unique=True),
Password("password"), Password("password"),
DateTime("created"),
Timestamp("last_updated"),
BackReference("groups", Group), BackReference("groups", Group),
] ]

View File

@ -6,6 +6,7 @@ import os
import re import re
from collections import namedtuple from collections import namedtuple
from dataclasses import dataclass, field from dataclasses import dataclass, field
from datetime import datetime
from typing import Dict, List from typing import Dict, List
import nanoid import nanoid
@ -37,7 +38,7 @@ class Field:
if value is not None: if value is not None:
return str(value) return str(value)
def deserialize(self, value: value_type, db: TinyDB, recurse: bool = False) -> value_type: def deserialize(self, value: str, db: TinyDB, recurse: bool = False) -> value_type:
return value return value
@ -50,6 +51,30 @@ class Integer(Field):
return int(value) return int(value)
@dataclass
class DateTime(Field):
value_type: datetime
default: datetime = datetime.utcfromtimestamp(0)
def serialize(self, value: value_type) -> str:
return (value - datetime.utcfromtimestamp(0)).total_seconds()
def deserialize(self, value: str, db: TinyDB, recurse: bool = False) -> value_type:
return datetime.utcfromtimestamp(int(value))
def before_insert(self, value: value_type, db: TinyDB, record: Record) -> None:
if not value:
record[self.name] = datetime.utcnow().replace(microsecond=0)
@dataclass
class Timestamp(DateTime):
value_type: datetime
def before_insert(self, value: value_type, db: TinyDB, record: Record) -> None:
super().before_insert(None, db, record)
@dataclass @dataclass
class Password(Field): class Password(Field):
value_type = str value_type = str
@ -67,7 +92,7 @@ class Password(Field):
try: try:
if passwd[offset] != ":": if passwd[offset] != ":":
return False return False
digest = passwd[offset + 1 :] digest = passwd[(offset + 1) :]
if len(digest) != cls.digest_size * 2: if len(digest) != cls.digest_size * 2:
return False return False
return re.match(r"^[0-9a-f]+$", digest) return re.match(r"^[0-9a-f]+$", digest)

View File

@ -1,4 +1,6 @@
from datetime import datetime
from pprint import pprint as print from pprint import pprint as print
from time import sleep
import pytest import pytest
from tinydb import Query from tinydb import Query
@ -133,3 +135,14 @@ def test_password(db):
assert check("fnord", user.password) assert check("fnord", user.password)
assert not check("wrong password", user.password) assert not check("wrong password", user.password)
assert not check("", user.password) assert not check("", user.password)
def test_datetime(db):
user = db.save(examples.User(name="john", email="john@foo", password="fnord", created=datetime.utcnow()))
assert user.created > datetime.utcfromtimestamp(0)
assert user.created < datetime.utcnow()
assert user.last_updated == user.created
sleep(1)
user = db.save(user)
assert user.last_updated >= user.created