From 7ddc9531bb752a87994c10e4f663057e0bfc5607 Mon Sep 17 00:00:00 2001 From: evilchili Date: Sat, 18 Oct 2025 16:54:58 -0700 Subject: [PATCH] split filepointer in to text and binary variants --- src/grung/examples.py | 6 ++++-- src/grung/types.py | 43 ++++++++++++++++++++++++++++++++++++------- test/test_db.py | 28 ++++++++++++++++++++++++++-- 3 files changed, 66 insertions(+), 11 deletions(-) diff --git a/src/grung/examples.py b/src/grung/examples.py index a833e9d..7753a78 100644 --- a/src/grung/examples.py +++ b/src/grung/examples.py @@ -1,15 +1,16 @@ from grung.types import ( BackReference, + BinaryFilePointer, Collection, DateTime, Dict, Field, - FilePointer, Integer, List, Password, Record, RecordDict, + TextFilePointer, Timestamp, ) @@ -50,7 +51,8 @@ class Album(Record): Dict("credits"), List("tracks"), BackReference("artist", Artist), - FilePointer("cover", extension=".jpg"), + BinaryFilePointer("cover", extension=".jpg"), + TextFilePointer("review"), ] diff --git a/src/grung/types.py b/src/grung/types.py index 2c67954..bcac032 100644 --- a/src/grung/types.py +++ b/src/grung/types.py @@ -283,14 +283,14 @@ class BackReference(Pointer): @dataclass -class FilePointer(Field): +class BinaryFilePointer(Field): """ Write the contents of this field to disk and store the path in the db. """ name: str value_type: type = bytes - extension: str = ".txt" + extension: str = ".blob" def relpath(self, record): return Path(record._metadata.table) / record[record._metadata.primary_key] / f"{self.name}{self.extension}" @@ -298,16 +298,45 @@ class FilePointer(Field): def deserialize(self, value: str, db: TinyDB, recurse: bool = True) -> value_type: if not value: return None - return (db.path / str(value)).read_bytes() + _, relpath = value.split("::") + return self.value_type((db.path / relpath).read_bytes()) + + def prepare(self, data: value_type): + if not data: + return + if not isinstance(data, self.value_type): + return data.encode() + return data def before_insert(self, value: value_type, db: TinyDB, record: Record) -> None: + if not value: + return relpath = self.relpath(record) path = db.path / relpath path.parent.mkdir(parents=True, exist_ok=True) - path.write_bytes( - record[self.name] if isinstance(record[self.name], FilePointer.value_type) else record[self.name].encode() - ) - record[self.name] = str(relpath) + path.write_bytes(self.prepare(value)) + record[self.name] = f"File::{self.relpath(record)}" + + +@dataclass +class TextFilePointer(BinaryFilePointer): + """ + Write the contents of this field to disk and store the path in the db. + """ + + name: str + value_type: type = str + extension: str = ".txt" + + def prepare(self, data: value_type): + if data: + return str(data).encode() + + def deserialize(self, value: str, db: TinyDB, recurse: bool = True) -> value_type: + if not value: + return None + _, relpath = value.split("::") + return (db.path / relpath).read_text() @dataclass diff --git a/test/test_db.py b/test/test_db.py index 35c6d40..cad3716 100644 --- a/test/test_db.py +++ b/test/test_db.py @@ -156,12 +156,10 @@ def test_mapping(db): name="The Impossible Kid", credits={"Produced By": "Aesop Rock", "Lyrics By": "Aesop Rock", "Puke in the MeowMix By": "Kirby"}, tracks=["Mystery Fish", "Rings", "Lotta Years", "Dorks"], - cover=b"some jpg data", ) ) assert album.credits["Produced By"] == "Aesop Rock" assert album.tracks[0] == "Mystery Fish" - assert album.cover == b"some jpg data" aes = db.save( examples.Artist( @@ -176,5 +174,31 @@ def test_mapping(db): assert aes.albums[album.name].uid == album.uid assert "Kirby" in aes.albums[album.name].credits.values() + +def test_file_pointers(db): + album = db.save( + examples.Album( + name="The Impossible Kid", + credits={"Produced By": "Aesop Rock", "Lyrics By": "Aesop Rock", "Puke in the MeowMix By": "Kirby"}, + tracks=["Mystery Fish", "Rings", "Lotta Years", "Dorks"], + cover=b"some jpg data", + review="10/10 no notes", + ) + ) + assert album.cover == b"some jpg data" + assert album.review == "10/10 no notes" + + db.save( + examples.Artist( + name="Aesop Rock", + albums={"The Impossible Kid": album}, + ) + ) + + album = db.Album.get(doc_id=album.doc_id) + location_on_disk = db.path / album._metadata.fields["cover"].relpath(album) assert location_on_disk.read_bytes() == album.cover + + location_on_disk = db.path / album._metadata.fields["review"].relpath(album) + assert location_on_disk.read_text() == album.review