I'd like to wrap all my sqlite statement functions with a decorator which collects the statement and the lists of values I will inject in place of placeholders in my statement (to avoid sql injection). Code looks like this:
#decorator
def dbexecute(func):
def withcon(*args):
conn = sqlite3.connect(sqlite_file_name)
conn.row_factory = sqlite3.Row
with conn:
fa = func(*args)
if isinstance(fa, tuple):
s, v = fa
else:
s, v = fa, ()
out = conn.execute(s, v).fetchall()
conn.close()
return out
return withcon
#statement functions that are decorated
@dbexecute
def create_user(user_settings: dict):
user_settings['id'] = str(uuid.uuid4())
columns = tuple([key for (key,value) in user_settings.items()])
values = tuple([value for (key,value) in user_settings.items()])
qmarks = tuple(['?']*len(values))
statement = f"INSERT INTO users {columns} VALUES {qmarks}".replace("'","")
return statement, values
@dbexecute
def get_all_users():
statement = "SELECT * FROM users"
return statement
First function returns values to replace the question marks with, but the second not. I had to handle this directly in the decorator, but I am not sure this is the good way to do it or maybe there is a more pythonic way than an if...else... block that checks the type of the inputs args.
Thanks for your feedback!