""" Helper functions for use with the SQLite database. """ import sqlite3 from sqlite3 import Connection, Cursor import time from typing import Optional from swingmusic.models import Album, Playlist, Track from swingmusic import settings def tuple_to_track(track: tuple): """ Takes a tuple and returns a Track object """ return Track(*track[1:]) # rowid is removed from the tuple def tuples_to_tracks(tracks: list[tuple]): """ Takes a list of tuples and returns a generator that yields a Track object for each tuple """ for track in tracks: yield tuple_to_track(track) def tuple_to_album(album: tuple): """ Takes a tuple and returns an Album object """ return Album(*album[1:]) # rowid is removed from the tuple def tuples_to_albums(albums: list[tuple]): """ Takes a list of tuples and returns a generator that yields an album object for each tuple """ for album in albums: yield tuple_to_album(album) def tuple_to_playlist(playlist: tuple): """ Takes a tuple and returns a Playlist object """ return Playlist(*playlist) def tuples_to_playlists(playlists: list[tuple]): """ Takes a list of tuples and returns a list of Playlist objects """ for playlist in playlists: yield tuple_to_playlist(playlist) class SQLiteManager: """ This is a context manager that handles the connection and cursor for you. It also commits and closes the connection when you're done. """ def __init__( self, conn: Optional[Connection] = None, userdata_db=False, test_db_path: str = None, ) -> None: """ When a connection is passed in, don't close the connection, because it's a connection to the search database [in memory db]. """ self.conn = conn self.CLOSE_CONN = True self.userdata_db = userdata_db self.test_db_path = test_db_path if conn: self.conn = conn self.CLOSE_CONN = False def __enter__(self) -> Cursor: if self.conn is not None: cur = self.conn.cursor() cur.execute("PRAGMA foreign_keys = ON") return cur if self.test_db_path: db_path = self.test_db_path else: db_path = settings.DbPaths.get_app_db_path() if self.userdata_db: db_path = settings.DbPaths.get_userdata_db_path() self.conn = sqlite3.connect( db_path, timeout=15, ) cur = self.conn.cursor() cur.execute("PRAGMA foreign_keys = ON") return cur def __exit__(self, exc_type, exc_value, exc_traceback): trial_count = 0 while trial_count < 10: try: self.conn.commit() if self.CLOSE_CONN: self.conn.close() return except sqlite3.OperationalError: trial_count += 1 time.sleep(3) self.conn.close()