From 87dcfdb54bc391ed20789f849d11aff02a4e4854 Mon Sep 17 00:00:00 2001 From: Hellow Date: Sun, 19 Feb 2023 23:35:52 +0100 Subject: [PATCH] finished writing to database --- src/music_kraken/database/data_models.py | 2 + src/music_kraken/database/database.py | 68 +++++++++++++++++- src/music_kraken/database/write.py | 80 +++++++++++++++++++--- src/music_kraken/objects/formatted_text.py | 6 ++ src/music_kraken/objects/metadata.py | 1 + 5 files changed, 145 insertions(+), 12 deletions(-) diff --git a/src/music_kraken/database/data_models.py b/src/music_kraken/database/data_models.py index 7d29c67..6e3f88d 100644 --- a/src/music_kraken/database/data_models.py +++ b/src/music_kraken/database/data_models.py @@ -44,6 +44,7 @@ class Album(BaseModel): title: str = CharField(null=True) label: str = CharField(null=True) album_status: str = CharField(null=True) + album_type: str = CharField(null=True) language: str = CharField(null=True) date: str = CharField(null=True) date_format: str = CharField(null=True) @@ -57,6 +58,7 @@ class Artist(BaseModel): """A class representing an artist in the music database.""" name: str = CharField() + notes: str = CharField() class Song(BaseModel): diff --git a/src/music_kraken/database/database.py b/src/music_kraken/database/database.py index 002fad8..27c58a3 100644 --- a/src/music_kraken/database/database.py +++ b/src/music_kraken/database/database.py @@ -1,12 +1,20 @@ -from typing import Optional, Union +# Standard library +from typing import Optional, Union, List from enum import Enum + +# third party modules from peewee import ( SqliteDatabase, MySQLDatabase, PostgresqlDatabase, ) -from . import data_models +# own modules +from . import ( + data_models, + write, + objects, +) class DatabaseType(Enum): @@ -66,7 +74,7 @@ class Database: port=self.db_port, ) - raise ValueError("define a Valid database type") + raise ValueError("Invalid database type specified.") def initialize_database(self): """ @@ -91,6 +99,60 @@ class Database: # add the missing column to the table self.database.add_column(model._meta.db_table, field_name, field_obj) + def push(self, database_object: objects.MusicObject): + """ + Adds a new music object to the database using the corresponding method from the `write` session. + When possible, rather use the `push_many` function. + This gets even more important, when using a remote database server. + + Args: + database_object (objects.MusicObject): The music object to add to the database. + + Returns: + The newly added music object. + """ + + with write.WritingSession(self.database) as writing_session: + if isinstance(database_object, objects.Song): + return writing_session.add_song(database_object) + + if isinstance(database_object, objects.Album): + return writing_session.add_album(database_object) + + if isinstance(database_object, objects.Artist): + return writing_session.add_artist(database_object) + + + def push_many(self, database_objects: List[objects.MusicObject]) -> None: + """ + Adds a list of MusicObject instances to the database. + This function sends only needs one querry for each type of table added. + Beware that if you have for example an object like this: + - Album + - Song + - Song + you already have 3 different Tables. + + Unlike the function `push`, this function doesn't return the added database objects. + + Args: + database_objects: List of MusicObject instances to be added to the database. + """ + + with write.WritingSession(self.database) as writing_session: + for obj in database_objects: + if isinstance(obj, objects.Song): + writing_session.add_song(obj) + continue + + if isinstance(obj, objects.Album): + writing_session.add_album(obj) + continue + + if isinstance(obj, objects.Artist): + writing_session.add_artist(obj) + continue + def __del__(self): self.database.close() diff --git a/src/music_kraken/database/write.py b/src/music_kraken/database/write.py index 5bddeff..c6b08e3 100644 --- a/src/music_kraken/database/write.py +++ b/src/music_kraken/database/write.py @@ -1,4 +1,4 @@ -from typing import Union, Set, Optional, Dict, DefaultDict +from typing import Union, Optional, Dict, DefaultDict, Type, List from collections import defaultdict import traceback from peewee import ( @@ -15,7 +15,7 @@ from . import data_models Database = Union[SqliteDatabase, PostgresqlDatabase, MySQLDatabase] -class Session: +class WritingSession: """ Context manager for a database session @@ -43,9 +43,9 @@ class Session: self.added_album_ids: Dict[str] = dict() self.added_artist_ids: Dict[str] = dict() - self.db_objects: DefaultDict[data_models.BaseModel, list] = defaultdict(list) + self.db_objects: DefaultDict[data_models.BaseModel, List[data_models.BaseModel]] = defaultdict(list) - def __enter__(self, database: Database): + def __enter__(self) -> Type['WritingSession']: """ Enter the context of the database session @@ -55,7 +55,7 @@ class Session: Returns: self: The instance of the session object """ - self.__init__(database=database) + # self.__init__(database=database) return self def __exit__(self, exc_type, exc_val, exc_tb): @@ -138,7 +138,7 @@ class Session: ).use(self.database) self.db_objects[data_models.Song].append(db_song) - self.added_song_ids[song.id] = db_song + self.added_song_ids[song.id].append(db_song) for source in song.source_list: self.add_source(source=source, connected_to=db_song) @@ -152,6 +152,8 @@ class Session: artist=self.add_artist(main_artist), is_feature=False ) + + self.db_objects[data_models.SongArtist].append(db_song_artist) for feature_artist in song.feature_artist_collection: db_song_artist = data_models.SongArtist( @@ -159,12 +161,16 @@ class Session: artist=self.add_artist(feature_artist), is_feature=True ) + + self.db_objects[data_models.SongArtist].append(db_song_artist) for album in [song.album]: db_album_song = data_models.AlbumSong( song=db_song, album=self.add_album(album) ) + + self.db_objects[data_models.AlbumSong] = db_album_song return db_song @@ -180,10 +186,42 @@ class Session: if album.id in self.added_album_ids: return self.added_album_ids[album.id] - db_album = data_models.Album().use(self.database) + db_album = data_models.Album( + title = album.title, + label = album.label, + album_status = album.album_status, + album_type = album.album_type, + language = album.iso_639_2_language, + date = album.date.timestamp, + date_format = album.date.timeformat, + country = album.country, + barcode = album.barcode, + albumsort = album.albumsort, + is_split = album.is_split + ).use(self.database) self.db_objects[data_models.Album].append(db_album) self.added_album_ids.add(album.id) + + for source in album.source_list: + self.add_source(source, db_album) + + for song in album.tracklist: + db_song_album = data_models.AlbumSong( + id = album.id, + album = album, + song = self.add_song(song) + ) + + self.db_objects[data_models.AlbumSong].append(db_song_album) + + for artist in album.artists: + db_album_artist = data_models.AlbumArtist( + album = album, + artist = self.add_artist(artist) + ) + + self.db_objects[data_models.Artist].append(db_album_artist) return db_album @@ -199,10 +237,34 @@ class Session: if artist.id in self.added_artist_ids: return self.added_artist_ids[artist.id] - db_artist = data_models.Artist() + db_artist = data_models.Artist( + id = artist.id, + name = artist.name, + notes = artist.notes.json + ) self.db_objects[data_models.Artist].append(db_artist) self.added_artist_ids[artist.id] = db_artist + + for source in artist.source_list: + self.add_source(source, db_artist) + + for album in artist.main_albums: + db_album_artist = data_models.AlbumArtist( + artist = artist, + album = self.add_album(album) + ) + + self.db_objects[data_models.AlbumArtist].append(db_album_artist) + + for song in artist.feature_songs: + db_artist_song = data_models.SongArtist( + artist = artist, + song = self.add_song(song), + is_feature = True + ) + + self.db_objects[data_models.SongArtist].append(db_artist_song) return db_artist @@ -219,5 +281,5 @@ class Session: if __name__ == "__main__": - with Session(SqliteDatabase(":memory:")) as session: + with WritingSession(SqliteDatabase(":memory:")) as session: session.add_song(objects.Song(title="Hs")) \ No newline at end of file diff --git a/src/music_kraken/objects/formatted_text.py b/src/music_kraken/objects/formatted_text.py index c98ca3f..3abc6d1 100644 --- a/src/music_kraken/objects/formatted_text.py +++ b/src/music_kraken/objects/formatted_text.py @@ -51,6 +51,12 @@ class FormattedText: if self.doc is None: return None return pandoc.write(self.doc, format="plain").strip() + + @property + def json(self) -> str: + if self.doc is None: + return None + return pandoc.write(self.doc, format="json") plaintext = property(fget=get_plaintext, fset=set_plaintext) markdown = property(fget=get_markdown, fset=set_markdown) diff --git a/src/music_kraken/objects/metadata.py b/src/music_kraken/objects/metadata.py index c98e7de..dc01823 100644 --- a/src/music_kraken/objects/metadata.py +++ b/src/music_kraken/objects/metadata.py @@ -252,6 +252,7 @@ class ID3Timestamp: return self.timestamp timestamp: str = property(fget=get_timestamp) + timeformat: str = property(fget=get_time_format) class MetadataAttribute: