Python – create wrapper function for SQL queries

Question:

In my project I have lots of functions that carry out SQL queries. These queries include SELECT, UPDATE, INSERT etc… When writing functions for SELECT queries for example, I write the same structure of code in every single function. e.g.

def generic_select_function(self):
    result = self.cursor.execute("""
        SQL CODE
    """)
    return result.fetchall()

To avoid repeating this code over and over I though I could create a wrapper function that inserts the SQL code into a template for SELECT queries.

I understand that a wrapper function may not even be necessary for this but I would like to try and implement one to develop my understanding of them.

What I have tried:

class DatabaseManagment():

    def __init__(self) -> None:
        self.con = sqlite3.connect("...")
        self.cursor = self.con.cursor()
        self.lock = threading.Lock()


    def sql_select(self):
        def inner(func):
            result = self.cursor.execute(f"""
                {func}
            """)
            return result.fetchall()
        return inner


    @sql_select
    def test(self):
        return "SELECT * FROM App_price"

‘function’ object has no attribute ‘cursor’

Asked By: logan_9997

||

Answers:

Here an example of wrapper using inheritance:

class MyQueries:

    @staticmethod
    def App_price():
        return "SELECT * FROM App_price"


class MyQueriesExe(MyQueries):

    def select(self, func):
        return f"{self.con} executing: {func()}"

    def __init__(self):
        self.con = 'con id: xxx:'

    def App_price(self):
        return self.select(super().App_price)


print(MyQueriesExe().App_price())
#con id: xxx: executing: SELECT * FROM App_price

Here a very basic example with a metaclass-decoration to illustrate the basic syntax

import sqlite3 


class SqlQueriesExe(type):
    def __new__(mcs, name:str, bases:tuple, class_dict:dict) -> type:
        cls = super().__new__(mcs, name, bases, class_dict)

        # decoration phase
        for method_name in ('create_table', 'insert_into_table', 'show_table'):
            app_price = getattr(cls, method_name)
            setattr(cls, app_price.__name__, mcs.executer(app_price))

        return cls

    @staticmethod
    def executer(func):
        return lambda self, *args: self.con.execute(func(self, *args))
        return lambda self, *args: self.con.executescript(func(self, *args))


class Db(metaclass=SqlQueriesExe):
    
    def __str__(self):
        # sqlite3.sqlite_version
        # some db-info for ex pragma-stuffs
        return str(self)

    def __init__(self, database=":memory:"):
        self.database = database

    def __enter__(self):
        self.con = sqlite3.connect(self.database)
        self.cursor = self.con.cursor()
        return self

    def __exit__(self, exc_type, exc_value, exc_tb):
        print('db-self.database is closing.')
        # display table when closing
        print(*self.show_table())
        #self.con.rollback() # self.con.commit()
        self.con.close()

    def create_table(self):
        return """CREATE TABLE IF NOT EXISTS test_table (A TEXT);"""

    def insert_into_table(self):
        return """INSERT INTO test_table (A) VALUES (2);"""

    def show_table(self):
        return """SELECT * FROM test_table;"""


with Db(":memory:") as db:
    db.create_table()
    db.insert_into_table()
Answered By: cards