0
\$\begingroup\$

I am learning dependency injection and trying to use this pattern on practice. I am trying to write simple program where the user can write something to database, delete row and clear all rows from db. So is it right realization of dependency injection?

import os
from enum import Enum

import pymysql


class Properties(Enum):
    ID = 0
    NAME = 1


class ConsoleManager:
    def print_line(self) -> None:
        print('-----------------\n')

        return None


    def print_data(self, data) -> None:
        for row in data:
            print(f"{row[Properties.ID.value]}\t|\t{row[Properties.NAME.value]}")

        return None


class DatabaseManager:
    def __init__(self, connection) -> None:
        self.connection = connection
        self.cursor = connection.cursor()

        return None
    

    def get_count_abobas(self) -> int:
        self.cursor.execute('SELECT COUNT(*) FROM abobas')
        count = self.cursor.fetchone()[0]

        self.connection.commit()
        
        return count
        
    
    def insert_id_and_name(self, count, name) -> None:
        sql = f'INSERT INTO abobas (id, abobas.aboba_name) VALUES ({count + 1}, \'{name}\')'
        self.cursor.execute(sql)

        self.connection.commit()

        return None


    def select_and_get_all_rows(self) -> tuple:
        sql = "SELECT * FROM abobas ORDER BY id"
        self.cursor.execute(sql)
        result = self.cursor.fetchall()  

        self.connection.commit()

        return result
    

    def delete_by_name(self, name) -> None:
        sql = f"DELETE FROM abobas WHERE aboba_name = '{name}'"
        self.cursor.execute(sql)

        self.connection.commit()

        return None
    

    def clear_table(self) -> None:
        sql = 'DELETE FROM abobas'
        self.cursor.execute(sql)

        self.connection.commit()

        return None


    def update_id(self) -> None:
        count = self.get_count_abobas()

        for i in range(1, count + 1):
            sql = f'UPDATE abobas SET id = {i} WHERE id > {i - 1} LIMIT 1'
            self.cursor.execute(sql)

        return None


class ConsoleService:
    def __init__(self, console_manager, database_manager) -> None:
        self.console_manager = console_manager
        self.database_manager = database_manager

    @staticmethod
    def console_output(func):
        def wrap(*args):
            args[0].console_manager.print_line()
            func(*args)
            args[0].console_manager.print_line()

        return wrap

    @console_output
    def write_to_db(self) -> None:
        name = input("Enter name: ")
        count = self.database_manager.get_count_abobas()
        self.database_manager.insert_id_and_name(count, name)
        print("Row successfully added to the table.")

    @console_output
    def read_from_file(self) -> None:
        print('id\t|\tname')
        self.console_manager.print_line()
        result = self.database_manager.select_and_get_all_rows()
        self.console_manager.print_data(result)

    @console_output
    def delete_by_name(self) -> None:
        name = input('Enter the name to delete: ')
        self.database_manager.delete_by_name(name)
        self.database_manager.update_id()
        print(f"An element with name {name} was successfully deleted.")

    @console_output
    def clear_all(self) -> None:
        self.database_manager.clear_table()
        print('Table is now clear.')



def main():
    connection = pymysql.connect(
        host='localhost',
        user='sqluser',
        password='password',
        database='abobadb'
    )

    console_manager = ConsoleManager()
    database_manager = DatabaseManager(connection)
    console_service = ConsoleService(console_manager, database_manager)

    while True:
        os.system('cls||clear')
        console_service.read_from_file()

        print('Choose the option:\n\t1. Write to db.\n\t2. Delete by name.\n\t3. Clear all elements.')
        choice = int(input("Enter your choice: "))

        if choice == 1:
            console_service.write_to_db()
        elif choice == 2:
            console_service.delete_by_name()
        elif choice == 3:
            console_service.clear_all()
        else:
            break

    connection.close()

    return None


if __name__ == '__main__':
    main()

Also you can check my code and give me some advices in order to make my code clear and readable.

I have tried to implement dependency injection using classes DatabaseManager, ConsoleManager and ConsoleService.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Welcome to Code Review! To help reviewers give you better answers, we need to know what the code is intended to achieve. Please add sufficient context to your question to describe the purpose of the code. We want to know why much more than how. The more you tell us about what your code is for, the easier it will be for reviewers to help you. Also, edit the title to simply summarise the task, rather than your concerns about the code. \$\endgroup\$ Commented Jun 13, 2023 at 7:47

1 Answer 1

1
\$\begingroup\$

Congrats, you nailed dependency injection! Although for a case where it is really useful you would need several implementations of e.g. ConsoleManager that you can choose from, or several instances of DatabaseManager that use the same dependency. Otherwise it may be hard to see the actual benefits of DI.

As for the code itself:

MySql databases come with an auto-generated id, so you're essentially making a second one. Not saying that it's bad, especially for an exercise like this, just keep that feature in mind when designing a scheme for a real database.

There is no need to return None as it's returned implicitly (and no, explicit return doesn't make the code more readable, if that was the concern).

Nitpick: method name print_line is associated with "printing the text and then a \n character (a new line)", so something like draw_horizontal_line would fit better.

print_data will print something like

9 | Lupa
10 | Pupa

if strings in the first column have different width. As you can see vertical lines are not aligned. Python has some built-in methods of dealing with this.

get_count_abobas doesn't need to commit as it's not changing anything. update_id, on the other hand, does!

Overall very clean code, keep it up!

\$\endgroup\$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.