Blob is no more. Notes now always have content.

This commit is contained in:
Andrew Mulbrook 2026-03-26 00:36:01 -05:00
parent 5df3c81417
commit ffefe4dd21
4 changed files with 28 additions and 48 deletions

View file

@ -4,7 +4,9 @@ import tempfile
import datetime as dt
from pathlib import Path
from typing import Optional, Dict, List, Self, Iterable
from .trove import Note, Trove, TreeNote, BlobNote, Blob, Tree, BadNoteType, TreeEntry, NoteNotFound
from .trove import Note, Trove, TreeNote, BadNoteType, TreeEntry, NoteNotFound
from . import fs_util as fsu
class FSNote(Note):
@ -61,22 +63,17 @@ class FSNote(Note):
def set_raw_metadata(self, key: str, value: bytes) -> None:
self._trove._set_metadata(self._inode, key, value)
class FSBlobNote(FSNote, BlobNote):
def read(self) -> bytes:
if self._inode is None:
return b""
return self._path.read_bytes()
def read_content(self) -> bytes:
"""Read the raw content of the note."""
content_file = fsu.get_content_path(self._path)
if content_file.exists():
return content_file.read_bytes()
return b""
def write(self, data: bytes) -> None:
self._path.write_bytes(data)
# Update cache just in case inode changed (some editors do this)
try:
new_inode = self._path.stat().st_ino
if new_inode != self._inode:
self._trove._update_cache(new_inode, self._path)
self._inode = new_inode
except OSError:
pass
def write_content(self, data:bytes) -> None:
"""Write the raw content of the note."""
content_file = fsu.get_content_path(self._path)
content_file.write_bytes(data)
class FSTreeNote(FSNote, TreeNote):
@property
@ -85,7 +82,7 @@ class FSTreeNote(FSNote, TreeNote):
return "inode/directory"
def link(self, name: str, note: Note):
if not isinstance(note, FSBlobNote):
if not isinstance(note, FSNote):
raise BadNoteType("Only blob notes can be linked")
target_path = self._path / name
@ -239,7 +236,7 @@ class FSTrove(Trove):
if target_path.is_dir():
return FSTreeNote(self, inode=note_id, path=target_path)
else:
return FSBlobNote(self, inode=note_id, path=target_path)
return FSNote(self, inode=note_id, path=target_path)
def get_raw_note(self, note_id: int) -> Note:
p = self.get_path_by_inode(note_id)
@ -248,7 +245,7 @@ class FSTrove(Trove):
return self.get_raw_note_by_path(p)
def create_blob(self, data: bytes | None = None) -> BlobNote:
def create_blob(self, data: bytes | None = None) -> Note:
fd, temp_path = tempfile.mkstemp(dir=self.working)
try:
if data:
@ -258,7 +255,7 @@ class FSTrove(Trove):
p = Path(temp_path)
inode = p.stat().st_ino
self._update_cache(inode, p)
return FSBlobNote(self, inode=inode, path=p)
return FSNote(self, inode=inode, path=p)
def get_root(self) -> TreeNote:
return FSTreeNote(self, inode=self._root_inode, path=self.root)

View file

@ -18,11 +18,5 @@ class ToolBasicEditor(Tool):
layout.addWidget(self._text_edit)
self.refresh()
def _refresh_blob(self, note: tr.Blob):
self._text_edit.setPlainText(note.read().decode("utf-8"))
def refresh(self):
if isinstance(self.note, tr.Blob):
self._refresh_blob(cast(tr.Blob, self.note))
self._text_edit.setPlainText(self.note.read_content().decode("utf-8"))

View file

@ -56,14 +56,12 @@ class Note(Protocol):
"""Set metadata value for the given key."""
...
@runtime_checkable
class Blob(Protocol):
def read(self) -> bytes:
def read_content(self) -> bytes:
"""Read the raw content of the note."""
...
def write(self, data: bytes) -> None:
"""Write new content to the note."""
def write_content(self, data:bytes) -> None:
"""Write the raw content of the note."""
...
@ -101,10 +99,6 @@ class Tree(Protocol):
"""Return all entries as {name: object_id}."""
...
@runtime_checkable
class BlobNote(Note, Blob, Protocol):
"""Blob Note"""
@runtime_checkable
class TreeNote(Note, Tree, Protocol):
"""Tree Note"""
@ -121,7 +115,7 @@ class Trove(Protocol):
"""Retrieve a note by a object id"""
...
def create_blob(self, data: bytes | None = None) -> BlobNote:
def create_blob(self, data: bytes | None = None) -> Note:
"""Create a new blob node at the given path with content"""
...

View file

@ -13,7 +13,7 @@ from .db import Sqlite3Trove, NOTE_ROOT_ID
from . import trove as tr
from .trove import Note, Trove, TreeNote, BlobNote, TreeEntry, NoteNotFound, ObjectId
from .trove import Note, Trove, TreeNote, TreeEntry, NoteNotFound, ObjectId
class NoteImpl(Note):
@ -50,16 +50,11 @@ class NoteImpl(Note):
def set_raw_metadata(self, key: str, value: bytes) -> None:
self._db.write_metadata(self._object_id, key, value)
class BlobNoteImpl(NoteImpl, BlobNote):
"""Concrete BlobNote: a blob object in the store with metadata access."""
# Blob protocol
def read(self) -> bytes:
def read_content(self) -> bytes:
data = self._db.read_object(self._object_id)
return data if data is not None else b""
def write(self, data: bytes) -> None:
def write_content(self, data: bytes) -> None:
self._db.write_content(self._object_id, data)
@ -147,13 +142,13 @@ class TroveImpl:
raise NoteNotFound(note_id)
if self._db.is_tree(note_id) or info.type == "inode/directory":
return TreeNoteImpl(self, note_id)
return BlobNoteImpl(self, note_id)
return NoteImpl(self, note_id)
def create_blob(self, data: bytes | None = None,
dtype: str = "application/octet-stream") -> BlobNote:
dtype: str = "application/octet-stream") -> Note:
"""Create a new blob object and return a BlobNote for it."""
obj_id = self._db.write_blob(data or b"", dtype=dtype)
return BlobNoteImpl(self, obj_id)
return NoteImpl(self, obj_id)
def get_root(self) -> TreeNote:
"""Return the root TreeNote (always id=NOTE_ROOT_ID)."""