Создание запроса FIQL с помощью peewee

Я пытаюсь создать функцию, которая будет принимать FIQL форматированная строка и возвращает peewee выражение.

Допустим, у меня есть параметры URL-адреса в формате FIQL, например:

fiql_str = "name==Foo,(country==USA;city==Kansas)"

Использование парсера FIQL Я могу вернуть этот объект:

['OR', ('name', '==', 'Foo'), ['AND', ('country', '==', 'USA'), ('city', '==', 'Kansas')]]

Что я хотел бы сделать, так это создать функцию, которая берет указанный выше объект и создает выражение, понятное peewee. Я привык к django и Объекты Q, где я могу объединить выражения следующим образом:

fm = Q()
for mapping in mappings:
    fm |= Q(subscription__approver=mapping.user)
return self.filter(fm)

Я попытался имитировать это с помощью Query Builder/Node от peewee. вот так:

def map_to_filter(expressions, node):
    expression = expressions.pop(0)
    if type(expression) == str:
        if expression == "OR":
            node |= map_to_filter(expressions, node)
        if expression == "AND":
            node &= map_to_filter(expressions, node)
    elif type(expression) == tuple:
        return getattr(Store, expression[0]) + expression[1] + expression[2]
    elif type(expression) == list:
        map_to_filter(expression, node)
    return node

result = map_to_filter(expressions, peewee.Node())

Но я получаю NotImplementedError:

/lib/python3.7/site-packages/peewee.py in __sql__(self, ctx)
    616
    617     def __sql__(self, ctx):
--> 618         raise NotImplementedError
    619
    620     @staticmethod

NotImplementedError:

Можно ли построить такую ​​функцию? В противном случае, какие другие инструменты/плагины доступны для устранения этой неполадки?


person Donato Perconti    schedule 06.02.2019    source источник


Ответы (1)


Ваша проблема возникает из-за использования голого Node, который не соответствует какому-либо SQL (следовательно, нет метода sql).

Я бы предложил составить список и использовать functools.reduce() для их объединения.

e.g.,

list_of_conds = [
    (model.field1 == 'val1'),
    (model.field2 == 'bar')]
reduce(operator.and_, list_of_conds)

Вы можете переключить функцию сокращения на operator.or_, где это необходимо, и продолжить поиск в глубину, как у вас.

person coleifer    schedule 06.02.2019