from abc import ABC, abstractmethod

import mysql.connector

# db.py - Database related classes
# NOTE: You do not need to modify this source file

__all__ = (
    'MySQLConnection', 'MySQLObject'
)

class MySQLConnection:
    """A class to handle all database related functions for this assingment."""

    def __init__(self, host, user, password, database=None):
        """Initialize connection to MySQL server.

        Create database if needed automatically. 
        """
        self.db = mysql.connector.connect(
            host=host, 
            user=user, 
            password=password
        )
        if database is not None:
            with self.db.cursor() as cursor:
                cursor.execute(f"CREATE DATABASE IF NOT EXISTS {database};")
                self.db.commit()
            self.db.database = database

    def close(self):
        """Closes the database connection."""
        self.db.close()

    def cursor(self):
        """Returns a database cursor, for executing multiple statments 
        in a single transaction.
        """
        return self.db.cursor()

    def commit(self):
        """Commit changes to database."""
        self.db.commit()

    def execute(self, query):
        """Commit: Python -> Database

        e.g. CREATE, INSERT and UPDATE
        """
        with self.db.cursor() as cursor:
            cursor.execute(query)
            self.db.commit()

    def fetchone(self, query):
        """Fetch: Python <- Database
        
        e.g. SELECT and SHOW
        """
        with self.db.cursor() as cursor:
            cursor.execute(query)
            return cursor.fetchone()

    def fetchall(self, query):
        """Fetch: Python <- Database
        
        e.g. SELECT and SHOW
        """
        with self.db.cursor() as cursor:
            cursor.execute(query)
            return cursor.fetchall()

class MySQLObject(ABC):
    """A database managed object."""
    @staticmethod
    @abstractmethod
    def fetchall(db):
        """Returns a list of object imported from database."""
        return NotImplemented
