feat: added development scripts

This commit is contained in:
2024-04-09 11:59:29 +02:00
parent 81e57b645c
commit 88d618a3f8
22 changed files with 0 additions and 1846 deletions

View File

@@ -1,197 +0,0 @@
from typing import List, Union, Type, Optional
from peewee import (
SqliteDatabase,
PostgresqlDatabase,
MySQLDatabase,
Model,
CharField,
IntegerField,
BooleanField,
ForeignKeyField,
TextField
)
"""
**IMPORTANT**:
never delete, modify the datatype or add constrains to ANY existing collumns,
between the versions, that gets pushed out to the users.
Else my function can't update legacy databases, to new databases,
while keeping the data of the old ones.
EVEN if that means to for example keep decimal values stored in strings.
(not in my codebase though.)
"""
class BaseModel(Model):
notes: str = CharField(null=True)
class Meta:
database = None
@classmethod
def Use(cls, database: Union[SqliteDatabase, PostgresqlDatabase, MySQLDatabase]) -> Model:
cls._meta.database = database
return cls
def use(self, database: Union[SqliteDatabase, PostgresqlDatabase, MySQLDatabase]) -> Model:
self._meta.database = database
return self
class ObjectModel(BaseModel):
id: str = CharField(primary_key=True)
class MainModel(BaseModel):
additional_arguments: str = CharField(null=True)
notes: str = CharField(null=True)
class Song(MainModel):
"""A class representing a song in the music database."""
title: str = CharField(null=True)
isrc: str = CharField(null=True)
length: int = IntegerField(null=True)
tracksort: int = IntegerField(null=True)
genre: str = CharField(null=True)
class Album(MainModel):
"""A class representing an album in the music database."""
title: str = CharField(null=True)
album_status: str = CharField(null=True)
album_type: str = CharField(null=True)
language: str = CharField(null=True)
date_string: str = CharField(null=True)
date_format: str = CharField(null=True)
barcode: str = CharField(null=True)
albumsort: int = IntegerField(null=True)
class Artist(MainModel):
"""A class representing an artist in the music database."""
name: str = CharField(null=True)
country: str = CharField(null=True)
formed_in_date: str = CharField(null=True)
formed_in_format: str = CharField(null=True)
general_genre: str = CharField(null=True)
class Label(MainModel):
name: str = CharField(null=True)
class Target(ObjectModel):
"""A class representing a target of a song in the music database."""
file: str = CharField()
path: str = CharField()
song = ForeignKeyField(Song, backref='targets')
class Lyrics(ObjectModel):
"""A class representing lyrics of a song in the music database."""
text: str = TextField()
language: str = CharField()
song = ForeignKeyField(Song, backref='lyrics')
class Source(BaseModel):
"""A class representing a source of a song in the music database."""
ContentTypes = Union[Song, Album, Artist, Lyrics]
page: str = CharField()
url: str = CharField()
content_type: str = CharField()
content_id: int = CharField()
# content: ForeignKeyField = ForeignKeyField('self', backref='content_items', null=True)
@property
def content_object(self) -> Union[Song, Album, Artist]:
"""Get the content associated with the source as an object."""
if self.content_type == 'Song':
return Song.get(Song.id == self.content_id)
if self.content_type == 'Album':
return Album.get(Album.id == self.content_id)
if self.content_type == 'Artist':
return Artist.get(Artist.id == self.content_id)
if self.content_type == 'Label':
return Label.get(Label.id == self.content_id)
if self.content_type == 'Lyrics':
return Lyrics.get(Lyrics.id == self.content_id)
@content_object.setter
def content_object(self, value: Union[Song, Album, Artist]) -> None:
"""Set the content associated with the source as an object."""
self.content_type = value.__class__.__name__
self.content_id = value.id
class SongArtist(BaseModel):
"""A class representing the relationship between a song and an artist."""
song: ForeignKeyField = ForeignKeyField(Song, backref='song_artists')
artist: ForeignKeyField = ForeignKeyField(Artist, backref='song_artists')
is_feature: bool = BooleanField(default=False)
class ArtistAlbum(BaseModel):
"""A class representing the relationship between an album and an artist."""
album: ForeignKeyField = ForeignKeyField(Album, backref='album_artists')
artist: ForeignKeyField = ForeignKeyField(Artist, backref='album_artists')
class AlbumSong(BaseModel):
"""A class representing the relationship between an album and an song."""
album: ForeignKeyField = ForeignKeyField(Album, backref='album_artists')
song: ForeignKeyField = ForeignKeyField(Song, backref='album_artists')
class LabelAlbum(BaseModel):
label: ForeignKeyField = ForeignKeyField(Label, backref='label_album')
album: ForeignKeyField = ForeignKeyField(Album, backref='label_album')
class LabelArtist(BaseModel):
label: ForeignKeyField = ForeignKeyField(Label, backref='label_artist')
artist: ForeignKeyField = ForeignKeyField(Artist, backref='label_artists')
ALL_MODELS = [
Song,
Album,
Artist,
Source,
Lyrics,
ArtistAlbum,
Target,
SongArtist
]
if __name__ == "__main__":
database_1 = SqliteDatabase(":memory:")
database_1.create_tables([Song.Use(database_1)])
database_2 = SqliteDatabase(":memory:")
database_2.create_tables([Song.Use(database_2)])
# creating songs, adding it to db_2 if i is even, else to db_1
for i in range(100):
song = Song(name=str(i) + "hs")
db_to_use = database_2 if i % 2 == 0 else database_1
song.use(db_to_use).save()
print("database 1")
for song in Song.Use(database_1).select():
print(song.name)
print("database 2")
for song in Song.Use(database_1).select():
print(song.name)

View File

@@ -1,188 +0,0 @@
# Standard library
from typing import Optional, Union, List
from enum import Enum
from playhouse.migrate import *
# third party modules
from peewee import (
SqliteDatabase,
MySQLDatabase,
PostgresqlDatabase,
)
# own modules
from . import (
data_models,
write
)
from .. import objects
class DatabaseType(Enum):
SQLITE = "sqlite"
POSTGRESQL = "postgresql"
MYSQL = "mysql"
class Database:
database: Union[SqliteDatabase, PostgresqlDatabase, MySQLDatabase]
def __init__(
self,
db_type: DatabaseType,
db_name: str,
db_user: Optional[str] = None,
db_password: Optional[str] = None,
db_host: Optional[str] = None,
db_port: Optional[int] = None
):
self.db_type = db_type
self.db_name = db_name
self.db_user = db_user
self.db_password = db_password
self.db_host = db_host
self.db_port = db_port
self.initialize_database()
def create_database(self) -> Union[SqliteDatabase, PostgresqlDatabase, MySQLDatabase]:
"""Create a database instance based on the configured database type and parameters.
Returns:
The created database instance, or None if an invalid database type was specified.
"""
# SQLITE
if self.db_type == DatabaseType.SQLITE:
return SqliteDatabase(self.db_name)
# POSTGRES
if self.db_type == DatabaseType.POSTGRESQL:
return PostgresqlDatabase(
self.db_name,
user=self.db_user,
password=self.db_password,
host=self.db_host,
port=self.db_port,
)
# MYSQL
if self.db_type == DatabaseType.MYSQL:
return MySQLDatabase(
self.db_name,
user=self.db_user,
password=self.db_password,
host=self.db_host,
port=self.db_port,
)
raise ValueError("Invalid database type specified.")
@property
def migrator(self) -> SchemaMigrator:
if self.db_type == DatabaseType.SQLITE:
return SqliteMigrator(self.database)
if self.db_type == DatabaseType.MYSQL:
return MySQLMigrator(self.database)
if self.db_type == DatabaseType.POSTGRESQL:
return PostgresqlMigrator(self.database)
def initialize_database(self):
"""
Connect to the database
initialize the previously defined databases
create tables if they don't exist.
"""
self.database = self.create_database()
self.database.connect()
migrator = self.migrator
for model in data_models.ALL_MODELS:
model = model.Use(self.database)
if self.database.table_exists(model):
migration_operations = [
migrator.add_column(
"some field", field[0], field[1]
)
for field in model._meta.fields.items()
]
migrate(*migration_operations)
else:
self.database.create_tables([model], safe=True)
#self.database.create_tables([model.Use(self.database) for model in data_models.ALL_MODELS], safe=True)
"""
upgrade old databases.
If a collumn has been added in a new version this adds it to old Tables,
without deleting the data in legacy databases
"""
for model in data_models.ALL_MODELS:
model = model.Use(self.database)
print(model._meta.fields)
def push(self, database_object: objects.DatabaseObject):
"""
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.DatabaseObject]) -> 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()