Здравствуйте, я пишу код, в котором осуществляются голые SQL запросы.
Я написал два следующих метода:
async def fetch_one(table_name: str,
column: str,
value: Any,
columns: list[str] = None) -> list:
query = f'select {columns} from {table_name} where {column}={value}'
return await connection.fetch(query)
async def fetchall(table_name: str, columns: list[str] = None) -> list:
query = f'select {columns} from {table_name}'
return await connection.fetch(query)
Здесь требуется аргумент columns, который является колонками, ожидаемыми при возврате. Соответственно если дефолтное значение не будет изменено на список с ожидаемыми колонками, то значит, что тот, кто использует функцию ожидает их все. Чтобы не дублировать следующий код:
columns = ', '.join(columns) if columns is not None else '*'
Я сделал следующий декоратор:
def defining_columns(func):
async def wrapper(*args, **kwargs):
param = 'columns'
params_separator = ', '
all_columns_expected = '*'
func_args = getfullargspec(func).args
if param in func_args and param not in kwargs:
args = [*args]
columns_arg_position = func_args.index(param)
try:
passed_parameters = args[columns_arg_position]
if passed_parameters is None:
passed_parameters = all_columns_expected
args[columns_arg_position] = passed_parameters
else:
passed_parameters = params_separator.join(passed_parameters)
args[columns_arg_position] = passed_parameters
except IndexError:
args.insert(columns_arg_position, all_columns_expected)
args = tuple(args)
else:
columns = kwargs.get('columns')
kwargs['columns'] = (
all_columns_expected if columns is None
else params_separator.join(columns)
)
return await func(*args, **kwargs)
return wrapper
Кажется, что дешевле обошлось бы дублирование кода)
В этом декораторе осуществляется получение нужного нам параметра из списка позиционных или именованных аргументов. Добавляя блок try: except: мы тем самым проверяем, передан ли был вообще этот параметр или во время выполнения функции будет использовано дефолтное значение. Если не поднялось исключение , то это значит, что параметр был передан. Соответственно нам нужно проверить, не является ли этим параметром None. Если является, то мы, как и в случае, если при вызове не было передано никакого значения, устанавливаем *, а если нет, то мы джоиним список и кладем обратно в позиционные или именованные.
Для того, чтобы избежать дублирования мне пришлось написать такую громадину. Посоветуйте, пожалуйста, лучшее решение проблемы.