trove/trovedb/trove.py
Andrew Mulbrook 41480a39c9 Start API refactor to remove separate Tree
We want trees to just be notes. We want to reference notes
by Path instead of object ids. Stop thinking about the
fs implementation and the fuse service with the same terms -
they will be different backends.
2026-03-27 12:44:35 -05:00

168 lines
4.3 KiB
Python

from typing import Protocol, runtime_checkable, Optional, Dict, List, Self, NamedTuple, Iterable, TypedDict, Iterator
from uuid import UUID
import datetime as dt
import errno
type ObjectId = int | str | UUID
class TroveError(Exception):
"""Base class for all Trove errors."""
class ErrorWithErrno(TroveError):
"""Raised when an error occurs with an errno."""
def __init__(self, error: int, *args):
super().__init__(*args)
self.errno = error
class ErrorExists(ErrorWithErrno):
"""Raised when a note already exists."""
def __init__(self, *args):
super().__init__(errno.EEXIST, *args)
class ErrorNotFound(ErrorWithErrno):
"""Raised when a note is not found."""
def __init__(self, *args):
super().__init__(errno.ENOENT, *args)
class ErrorNotEmpty(ErrorWithErrno):
"""Raised when a directory is not empty."""
def __init__(self, *args):
super().__init__(errno.ENOTEMPTY, *args)
class BadNoteType(TypeError):
"""Raised when an invalid note type is encountered."""
class TreeExists(RuntimeError):
"""Raised when a label already exists."""
class NoteNotFound(KeyError):
"""Raised when a note is not found."""
class OpenArguments(TypedDict):
create: bool
class TreeEntry(NamedTuple):
name: str
object_id: ObjectId
DEFAULT_MIME = "application/octet-stream"
@runtime_checkable
class Note(Protocol):
"""
Protocol for a Note item.
Represents access to an individual note's content and metadata.
"""
@property
def object_id(self) -> ObjectId:
"""The unique identifier for this note."""
...
@property
def mime(self) -> str:
"""The MIME type of the note's content."""
...
@property
def readonly(self) -> bool:
"""Whether the note is read-only."""
...
@property
def mtime(self) -> dt.datetime:
"""The last modification time of the note."""
...
def get_raw_metadata(self, key: str) -> Optional[bytes]:
"""Retrieve metadata value for the given key."""
...
def set_raw_metadata(self, key: str, value: bytes) -> None:
"""Set metadata value for the given key."""
...
def read_content(self) -> bytes:
"""Read the raw content of the note."""
...
def write_content(self, data:bytes) -> None:
"""Write the raw content of the note."""
...
def children(self) -> Iterator[TreeEntry]:
"""Get all children of this note."""
...
def child(self, name: str) -> 'Note':
"""Retrieve a child note by name."""
...
def new_child(self, name: str, mime: str, content: bytes | None, executable: bool, hidden: bool) -> 'Note':
"""Create a new child note."""
...
def rm_child(self, name: str, recurse: bool):
"""Remove a child note."""
...
def has_children(self) -> bool:
"""Check if note has children."""
return next(self.children(), None) is not None
def new_child(note: Note, name: str, mime: str = DEFAULT_MIME, content: bytes | None = None, executable: bool = False, hidden: bool = False) -> Note:
return note.new_child(name=name, mime=mime, content=content, executable=executable, hidden=hidden)
@runtime_checkable
class Tree(Protocol):
def link(self, name: str, note: Note):
"""Link name to a given note."""
...
def unlink(self, name: str):
"""Remove name from the tree."""
...
def mkdir(self, name: str) -> Self:
"""Create a new Tree with the given name."""
...
def rmdir(self, name: str) -> None:
"""Remove a directory from the tree."""
...
def entries(self) -> Iterable[TreeEntry]:
"""Return all entries in the directory"""
...
@runtime_checkable
class TreeNote(Note, Tree, Protocol):
"""Tree Note"""
@runtime_checkable
class Trove(Protocol):
"""
Protocol for the Trove database API.
Provides high-level access to notes and trees.
"""
def get_raw_note(self, note: ObjectId) -> Note:
"""Retrieve a note by a object id"""
...
def create_blob(self, data: bytes | None = None) -> Note:
"""Create a new blob node at the given path with content"""
...
def get_root(self) -> TreeNote:
"""Get Tree Node at the given path"""
...