split filepointer in to text and binary variants

This commit is contained in:
evilchili 2025-10-18 16:54:58 -07:00
parent 972d42531c
commit 7ddc9531bb
3 changed files with 66 additions and 11 deletions

View File

@ -1,15 +1,16 @@
from grung.types import ( from grung.types import (
BackReference, BackReference,
BinaryFilePointer,
Collection, Collection,
DateTime, DateTime,
Dict, Dict,
Field, Field,
FilePointer,
Integer, Integer,
List, List,
Password, Password,
Record, Record,
RecordDict, RecordDict,
TextFilePointer,
Timestamp, Timestamp,
) )
@ -50,7 +51,8 @@ class Album(Record):
Dict("credits"), Dict("credits"),
List("tracks"), List("tracks"),
BackReference("artist", Artist), BackReference("artist", Artist),
FilePointer("cover", extension=".jpg"), BinaryFilePointer("cover", extension=".jpg"),
TextFilePointer("review"),
] ]

View File

@ -283,14 +283,14 @@ class BackReference(Pointer):
@dataclass @dataclass
class FilePointer(Field): class BinaryFilePointer(Field):
""" """
Write the contents of this field to disk and store the path in the db. Write the contents of this field to disk and store the path in the db.
""" """
name: str name: str
value_type: type = bytes value_type: type = bytes
extension: str = ".txt" extension: str = ".blob"
def relpath(self, record): def relpath(self, record):
return Path(record._metadata.table) / record[record._metadata.primary_key] / f"{self.name}{self.extension}" 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: def deserialize(self, value: str, db: TinyDB, recurse: bool = True) -> value_type:
if not value: if not value:
return None 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: def before_insert(self, value: value_type, db: TinyDB, record: Record) -> None:
if not value:
return
relpath = self.relpath(record) relpath = self.relpath(record)
path = db.path / relpath path = db.path / relpath
path.parent.mkdir(parents=True, exist_ok=True) path.parent.mkdir(parents=True, exist_ok=True)
path.write_bytes( path.write_bytes(self.prepare(value))
record[self.name] if isinstance(record[self.name], FilePointer.value_type) else record[self.name].encode() record[self.name] = f"File::{self.relpath(record)}"
)
record[self.name] = str(relpath)
@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 @dataclass

View File

@ -156,12 +156,10 @@ def test_mapping(db):
name="The Impossible Kid", name="The Impossible Kid",
credits={"Produced By": "Aesop Rock", "Lyrics By": "Aesop Rock", "Puke in the MeowMix By": "Kirby"}, credits={"Produced By": "Aesop Rock", "Lyrics By": "Aesop Rock", "Puke in the MeowMix By": "Kirby"},
tracks=["Mystery Fish", "Rings", "Lotta Years", "Dorks"], tracks=["Mystery Fish", "Rings", "Lotta Years", "Dorks"],
cover=b"some jpg data",
) )
) )
assert album.credits["Produced By"] == "Aesop Rock" assert album.credits["Produced By"] == "Aesop Rock"
assert album.tracks[0] == "Mystery Fish" assert album.tracks[0] == "Mystery Fish"
assert album.cover == b"some jpg data"
aes = db.save( aes = db.save(
examples.Artist( examples.Artist(
@ -176,5 +174,31 @@ def test_mapping(db):
assert aes.albums[album.name].uid == album.uid assert aes.albums[album.name].uid == album.uid
assert "Kirby" in aes.albums[album.name].credits.values() 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) location_on_disk = db.path / album._metadata.fields["cover"].relpath(album)
assert location_on_disk.read_bytes() == album.cover 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