Add in-memory message supply
This commit is contained in:
parent
267f419603
commit
f4c0416398
3 changed files with 118 additions and 21 deletions
|
|
@ -1,9 +1,4 @@
|
||||||
__all__ = ["ElementException", "TreeException"]
|
__all__ = ["MessageSupplyException"]
|
||||||
|
|
||||||
|
class MessageSupplyException(Exception):
|
||||||
class ElementException(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class TreeException(Exception):
|
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue