@Mikkkch

Хотел убрать дублирование кода в итоге написал большой декоратор?

Здравствуйте, я пишу код, в котором осуществляются голые 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. Если является, то мы, как и в случае, если при вызове не было передано никакого значения, устанавливаем *, а если нет, то мы джоиним список и кладем обратно в позиционные или именованные.

Для того, чтобы избежать дублирования мне пришлось написать такую громадину. Посоветуйте, пожалуйста, лучшее решение проблемы.
  • Вопрос задан
  • 91 просмотр
Пригласить эксперта
Ответы на вопрос 1
@o5a
Не особо понятно, от какого дублирования хотелось избавиться. Там итак всего лишь 1 строка была. Если хотелось еще уменьшить, можно было так:
в параметрах
columns: list[str] = ['*']
и саму строку
columns = ', '.join(columns)

Не написано, для какой базы делается, но вместо строковой замены where {column}={value}
лучше бы использовать передачу параметров.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы