feat: added development scripts
This commit is contained in:
@@ -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)
|
||||
@@ -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()
|
||||
Reference in New Issue
Block a user