From fa05073a6ebaf46e8f72bec10a3dc03021ce704c Mon Sep 17 00:00:00 2001
From: Christian Heller <c.heller@plomlompom.de>
Date: Fri, 14 Jun 2024 20:37:44 +0200
Subject: [PATCH] Enhance BaseModel comparisons by hashing versioned and
 relations attributes.

---
 plomtask/db.py                   | 15 ++++++++++-----
 plomtask/versioned_attributes.py |  6 ++++++
 2 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/plomtask/db.py b/plomtask/db.py
index b2f2142..a47dff1 100644
--- a/plomtask/db.py
+++ b/plomtask/db.py
@@ -250,14 +250,19 @@ class BaseModel(Generic[BaseModelId]):
             raise HandledException(msg)
         self.id_ = id_
 
+    def __hash__(self) -> int:
+        hashable = [self.id_] + [getattr(self, name) for name in self.to_save]
+        for definition in self.to_save_relations:
+            attr = getattr(self, definition[2])
+            hashable += [tuple(rel.id_ for rel in attr)]
+        for name in self.to_save_versioned:
+            hashable += [hash(getattr(self, name))]
+        return hash(tuple(hashable))
+
     def __eq__(self, other: object) -> bool:
         if not isinstance(other, self.__class__):
             return False
-        to_hash_me = tuple([self.id_] +
-                           [getattr(self, name) for name in self.to_save])
-        to_hash_other = tuple([other.id_] +
-                              [getattr(other, name) for name in other.to_save])
-        return hash(to_hash_me) == hash(to_hash_other)
+        return hash(self) == hash(other)
 
     def __lt__(self, other: Any) -> bool:
         if not isinstance(other, self.__class__):
diff --git a/plomtask/versioned_attributes.py b/plomtask/versioned_attributes.py
index d3c3649..cbd1c8e 100644
--- a/plomtask/versioned_attributes.py
+++ b/plomtask/versioned_attributes.py
@@ -19,6 +19,12 @@ class VersionedAttribute:
         self.default = default
         self.history: dict[str, str | float] = {}
 
+    def __hash__(self) -> int:
+        history_tuples = tuple((k, v) for k, v in self.history.items())
+        hashable = (self.parent.id_, self.table_name, self.default,
+                    history_tuples)
+        return hash(hashable)
+
     @property
     def _newest_timestamp(self) -> str:
         """Return most recent timestamp."""
-- 
2.30.2