Add in-memory message supply

This commit is contained in:
Joscha 2019-06-03 09:29:12 +00:00
parent 267f419603
commit f4c0416398
3 changed files with 118 additions and 21 deletions

View file

@ -1,9 +1,4 @@
__all__ = ["ElementException", "TreeException"] __all__ = ["MessageSupplyException"]
class MessageSupplyException(Exception):
class ElementException(Exception):
pass
class TreeException(Exception):
pass pass

View file

@ -1,6 +1,6 @@
import datetime import datetime
from dataclasses import dataclass from dataclasses import dataclass
from typing import Hashable, List from typing import Hashable, List, Optional
from .attributed_lines import AttributedLines from .attributed_lines import AttributedLines
from .markup import AT, AttributedText from .markup import AT, AttributedText
@ -25,7 +25,8 @@ class Message:
truncation status. truncation status.
""" """
message_id: Id id: Id
parent_id: Optional[Id]
time: datetime.datetime time: datetime.datetime
nick: str nick: str
content: str content: str
@ -42,7 +43,7 @@ class Message:
result.append(nick + AT(lines[0])) result.append(nick + AT(lines[0]))
result.extend(nick_spaces + AT(line) for line in lines[1:]) result.extend(nick_spaces + AT(line) for line in lines[1:])
return RenderedMessage(self.message_id, meta, result) return RenderedMessage(self.id, meta, result)
@dataclass @dataclass
class RenderedMessage: class RenderedMessage:

View file

@ -1,11 +1,13 @@
from typing import List, Optional import abc
from typing import Dict, List, Optional
from .exceptions import MessageSupplyException
from .message import Id, Message from .message import Id, Message
__all__ = ["MessageSupply"] __all__ = ["MessageSupply", "InMemoryMessageSupply"]
class MessageSupply: class MessageSupply(abc.ABC):
""" """
A MessageSupply holds all of a room's known messages. It can be queried in A MessageSupply holds all of a room's known messages. It can be queried in
different ways. Messages can also be added to or removed from the MessageSupply different ways. Messages can also be added to or removed from the MessageSupply
@ -16,24 +18,123 @@ class MessageSupply:
similar. similar.
""" """
# TODO should throw exception if it can't find the message @abc.abstractmethod
def get(self, message_id: Id) -> Message: def get(self, message_id: Id) -> Message:
pass # TODO pass
@abc.abstractmethod
def children_ids(self, message_id: Id) -> List[Id]: def children_ids(self, message_id: Id) -> List[Id]:
pass # TODO pass
@abc.abstractmethod
def sibling_ids(self, message_id: Id) -> List[Id]:
pass
@abc.abstractmethod
def parent_id(self, message_id: Id) -> Optional[Id]: def parent_id(self, message_id: Id) -> Optional[Id]:
pass # TODO pass
def oldest_ancestor_id(self, message_id: Id) -> Id: def oldest_ancestor_id(self, message_id: Id) -> Id:
pass # TODO ancestor_id = message_id
while True:
parent_id = self.parent_id(ancestor_id)
if parent_id is None: break
ancestor_id = parent_id
return ancestor_id
def previous_id(self, message_id: Id) -> Optional[Id]: def previous_id(self, message_id: Id) -> Optional[Id]:
pass # TODO sibling_ids = self.sibling_ids(message_id)
try:
i = sibling_ids.index(message_id)
if i <= 0:
return None
else:
return sibling_ids[i - 1]
except ValueError:
return None
def next_id(self, message_id: Id) -> Optional[Id]: def next_id(self, message_id: Id) -> Optional[Id]:
pass # TODO sibling_ids = self.sibling_ids(message_id)
try:
i = sibling_ids.index(message_id)
if i >= len(sibling_ids) - 1:
return None
else:
return sibling_ids[i + 1]
except ValueError:
return None
@abc.abstractmethod
def lowest_root_id(self) -> Optional[Id]:
pass
class InMemoryMessageSupply(MessageSupply):
"""
This message supply stores messages in memory. It orders the messages by
their ids.
"""
def __init__(self) -> None:
self._messages: Dict[Id, Message] = {}
self._children: Dict[Id, List[Message]] = {}
def add(self, message: Message) -> None:
if message.id in self._messages:
self.remove(message.id)
self._messages[message.id] = message
if message.parent_id is not None:
children = self._children.get(message.parent_id, [])
children.append(message)
children.sort(key=lambda m: m.id)
self._children[message.parent_id] = children
def remove(self, message_id: Id) -> None:
message = self._messages.get(message_id)
if message is None: return
self._messages.pop(message)
if message.parent_id is not None:
children = self._children.get(message.id)
if children is not None: # just to satisfy mypy
children.remove(message)
if not children:
self._children.pop(message.id)
def get(self, message_id: Id) -> Message:
message = self._messages.get(message_id)
if message is None:
raise MessageSupplyException(
f"message with id {message_id!r} does not exist")
return message
def child_ids(self, message_id: Id) -> List[Id]:
return [m.id for m in self._children.get(message_id, [])]
def parent_id(self, message_id: Id) -> Optional[Id]:
message = self.get(message_id)
return message.parent_id
def sibling_ids(self, message_id: Id) -> List[Id]:
parent_id = self.parent_id(message_id)
if parent_id is None:
roots = [m for m in self._messages.values() if m.parent_id is None]
sibling_ids = list(sorted(root.id for root in roots))
else:
sibling_ids = self.children_ids(parent_id)
return sibling_ids
def lowest_root_id(self) -> Optional[Id]: def lowest_root_id(self) -> Optional[Id]:
pass # TODO roots = list(sorted(self._messages.keys()))
return roots[-1] if roots else None