summaryrefslogtreecommitdiff
path: root/alot/db
diff options
context:
space:
mode:
authorAnton Khirnov <anton@khirnov.net>2020-02-06 17:08:00 +0100
committerAnton Khirnov <anton@khirnov.net>2020-02-06 17:11:05 +0100
commit48dac1d9089ce2a36c55dc4768b24293d1257a37 (patch)
treecf4e0c5751da8e7689269ea88b180b4dee3c3002 /alot/db
parent72ed7d40ac68d7e91f41e94fbcf6cb7a3e28433a (diff)
db: rewrite the API for representing message trees
It should be cleaner and easier to use, and eventually replace the custom tree walker in the thread display buffer.
Diffstat (limited to 'alot/db')
-rw-r--r--alot/db/message.py8
-rw-r--r--alot/db/thread.py100
2 files changed, 50 insertions, 58 deletions
diff --git a/alot/db/message.py b/alot/db/message.py
index 0b59090d..f9e8e37b 100644
--- a/alot/db/message.py
+++ b/alot/db/message.py
@@ -35,7 +35,10 @@ class Message:
"""value of the Message-Id header (str)"""
id = None
- def __init__(self, dbman, msg, thread):
+ """A list of replies to this message"""
+ replies = None
+
+ def __init__(self, dbman, msg, thread, replies):
"""
:param dbman: db manager that is used for further lookups
:type dbman: alot.db.DBManager
@@ -43,10 +46,13 @@ class Message:
:type msg: notmuch.database.Message
:param thread: this messages thread
:type thread: :class:`~alot.db.Thread`
+ :param replies: a list of replies to this message
+ :type replies alot.db.message.Message
"""
self._dbman = dbman
self.id = msg.get_message_id()
self.thread = thread
+ self.replies = replies
try:
self.date = datetime.fromtimestamp(msg.get_date())
except ValueError:
diff --git a/alot/db/thread.py b/alot/db/thread.py
index bae48b1a..2792737c 100644
--- a/alot/db/thread.py
+++ b/alot/db/thread.py
@@ -36,6 +36,15 @@ class Thread:
"""Thread subject"""
subject = None
+ """A list of toplevel messages"""
+ toplevel_messages = None
+
+ """A list of ids of all messages in this thread in depth-first order"""
+ message_ids = None
+
+ """A dict mapping Message-Id strings to Message instances"""
+ messages = None
+
def __init__(self, dbman, thread):
"""
:param dbman: db manager that is used for further lookups
@@ -46,9 +55,12 @@ class Thread:
self._dbman = dbman
self._authors = None
self.id = thread.get_thread_id()
- self._messages = {}
self._tags = set()
+ self.toplevel_messages = []
+ self.message_ids = []
+ self.messages = {}
+
self.refresh(thread)
def refresh(self, thread=None):
@@ -84,8 +96,34 @@ class Thread:
self.newest_date = None
self._tags = {t for t in thread.get_tags()}
- self._messages = {} # this maps messages to its children
- self._toplevel_messages = []
+
+ self.messages, self.toplevel_messages, self.message_ids = self._gather_messages()
+
+ def _gather_messages(self):
+ query = self._dbman.query('thread:' + self.id)
+ nm_thread = next(query.search_threads())
+
+ msgs = {}
+ msg_tree = []
+ ids = []
+
+ def thread_tree_walk(nm_msg):
+ msg_id = nm_msg.get_message_id()
+ ids.append(msg_id)
+
+ replies = []
+ for m in nm_msg.get_replies():
+ replies.append(thread_tree_walk(m))
+ msg = Message(self._dbman, nm_msg, self, replies)
+
+ msgs[msg_id] = msg
+
+ return msg
+
+ for m in nm_thread.get_toplevel_messages():
+ msg_tree.append(thread_tree_walk(m))
+
+ return msgs, msg_tree, ids
def __str__(self):
return "thread:%s: %s" % (self.id, self.subject)
@@ -101,7 +139,7 @@ class Thread:
"""
tags = set(list(self._tags))
if intersection:
- for m in self.get_messages().keys():
+ for m in self.messages.values():
tags = tags.intersection(set(m.get_tags()))
return tags
@@ -172,7 +210,7 @@ class Thread:
if self._authors is None:
# Sort messages with date first (by date ascending), and those
# without a date last.
- msgs = sorted(self.get_messages().keys(),
+ msgs = sorted(self.messages.values(),
key=lambda m: m.date or datetime.max)
orderby = settings.get('thread_authors_order_by')
@@ -222,58 +260,6 @@ class Thread:
else:
return self._notmuch_authors_string
- def get_toplevel_messages(self):
- """
- returns all toplevel messages contained in this thread.
- This are all the messages without a parent message
- (identified by 'in-reply-to' or 'references' header.
-
- :rtype: list of :class:`~alot.db.message.Message`
- """
- if not self._messages:
- self.get_messages()
- return self._toplevel_messages
-
- def get_messages(self):
- """
- returns all messages in this thread as dict mapping all contained
- messages to their direct responses.
-
- :rtype: dict mapping :class:`~alot.db.message.Message` to a list of
- :class:`~alot.db.message.Message`.
- """
- if not self._messages: # if not already cached
- query = self._dbman.query('thread:' + self.id)
- thread = next(query.search_threads())
-
- def accumulate(acc, msg):
- M = Message(self._dbman, msg, thread=self)
- acc[M] = []
- r = msg.get_replies()
- if r is not None:
- for m in r:
- acc[M].append(accumulate(acc, m))
- return M
-
- self._messages = {}
- for m in thread.get_toplevel_messages():
- self._toplevel_messages.append(accumulate(self._messages, m))
- return self._messages
-
- def get_replies_to(self, msg):
- """
- returns all replies to the given message contained in this thread.
-
- :param msg: parent message to look up
- :type msg: :class:`~alot.db.message.Message`
- :returns: list of :class:`~alot.db.message.Message` or `None`
- """
- msg_hash = self.get_messages()
- for m in msg_hash.keys():
- if m.id == msg.id:
- return msg_hash[m]
- return None
-
def matches(self, query):
"""
Check if this thread matches the given notmuch query.