Пошаговое построение запроса в Pony ORM

Я рассматриваю возможность перехода с peewee на Pony ORM. Одна приятная вещь, которая была доступна в peewee, — это возможность составить запрос из таких частей:

def Entry(BaseModel):
    # peewee fields go here

def where_entry_category(category, recurse=False):
    """ Generate a where clause for a particular category """

    if category or not recurse:
        cat_where = (Entry.category == str(category))

        if recurse:
            # We're recursing and aren't in /, so add the prefix clause
            cat_where = cat_where | (
                Entry.category.startswith(str(category) + '/'))
    else:
        cat_where = True

    return cat_where

query = Entry.select().where(where_entry_category("test"))

Это работает следующим образом: различные перегрузки операторов для типа модели peewee просто возвращают дерево компонентов запроса, и эти поддеревья могут быть составлены из дополнительных перегрузок операторов. Также легко иметь несколько компонентов запроса, которые объединяются в цепочку с операторами & или |, например. model.Entry.select().where(some_test() & some_other_test()). Это очень полезно, так как многие мои фильтрующие запросы составлены по модульному принципу, и большинство базовых частей запроса часто используются повторно, и многие из них нетривиальны (например, в приведенном выше примере).

Однако в Pony ORM, похоже, есть только (довольно умный!) Анализатор генератора AST и чистый SQL. Поскольку необработанная форма SQL не позволяет мне напрямую передать необходимые части запроса, я бы предпочел использовать некоторые функции построения запросов более высокого уровня, если это вообще возможно.

Если я попытаюсь определить части запроса как методы модели, например:

class Entry(db.Entity):
    ...
    def in_category(self, category, recurse=False):
        # return a test on the parameters

orm.select(entry for entry in model.Entry if entry.in_category('foo', True)) 

Я получаю NotImplementedError, что неудивительно.

Существует ли механизм построения выражения запроса из существующих частей для передачи в построитель запросов SQL? (Возможно, самостоятельно создав AST и передав его в соответствующую часть Pony, или используя механизм, в котором я передаю запрос для фильтрации другим подзапросом.)


person fluffy    schedule 17.09.2018    source источник


Ответы (1)


В PonyORM есть два способа пошагового составления запроса. Первый — это filter метод запроса:

def where_entry_category(query, category, recourse)
    if category:
        category = str(category)
        if recurse:
            query = query.filter(lambda x: x.category == category or
                                 x.category.startswith(category + '/')
        else:
            query = query.filter(lambda x: x.category == category)
    return query

query = Entry.select()
query = where_entry_category(query, "test")

Начиная с версии 0.7.6 также можно использовать предыдущий запрос в качестве источника для нового запроса:

def where_entry_category(query, category, recourse)
    if category:
        category = str(category)
        if recurse:
            query = select(x for x in query
                           if x.category == category or
                              x.category.startswith(category + '/'))
        else:
            query = select(x for x in query if x.category == category)
    return query

Единственная проблема, с которой вы можете столкнуться, это если вы хотите постепенно построить предложение or с переменным количеством подвыражений, на данный момент у Pony нет API для этого. Возможно, мы добавим возможность постепенно добавлять подвыражения в предложение or в будущих версиях.

person Alexander Kozlovsky    schedule 18.09.2018
comment
Отлично, похоже, это именно то, что мне нужно. Большое спасибо! - person fluffy; 18.09.2018