1

Certain packages like SQLAlchemy and RethinkDB (the latter I happen to be using) require predicate expressions to be passed into functions as arguments. For example, RethinkDB's filter method (https://rethinkdb.com/api/python/filter/) requires the first parameter to be a ReQL syntax expression and not a string.

However, I would like to build this expression programmatically based on a REST API query string I receive. For example, I might receive a query string such as:

/?filter=name%3D%3DNick&filter=score%3D%3DA,score%3D%3DB

In this case, I would like to convert this query string into the predicate:

r.row['name'] == 'Nick' & (r.row['score'] == 'A' | r.row['score'] == 'B')

I can generate this predicate as a string using a recursive function I wrote:

def process_filters(data):
    if isinstance(data, list):
        return ' & '.join([process_filters(val) for val in data])
    elif ',' in data:
        or_filters = data.split(',')
        return '(' + \
               ' | '.join(['(r.row["' + val.split('==', 1)[0] + '"] == ' + val.split('==', 1)[1] + ')' for val in or_filters]) + \
               ')'
    else:
        parts = data.split('==', 1)
        return '(r.row["' + parts[0] + '"] == ' + parts[1] + ')'

This function gives me the desired predicate as a string. However, RethinkDB will not process this argument as a string.

r.filter(process_filters(query_string))

The above command will not work properly because r.filter requires an expression, e.g.:

r.filter(r.row['name'] == 'Nick')

Not: r.filter("r.row['name'] == 'Nick'")

How do I convert the argument to an expression while still maintaining the flexibility to build the predicate programmatically from a string as I have?

Edit: eval actually does work, but as a commenter pointed out, this is generally frowned upon. I do believe in this particular case it may be the "best" solution, but I look forward to more ideas…

Nicholas Tulach
  • 1,023
  • 3
  • 12
  • 35
  • Functions arguments _are_ evaled before being passed to the function, so using `eval` should actually work - but I'd still avoid using it as far as I'm concerned. I have no experience with rethinkdb and don't have it installed so I can't test and post an answer, but there certainly are way to programmatically build your query without resorting to `eval`. A good starting point would be to find out what the `r.row['xxx'] == yyy` expression actually evals to - obviously it returns some object that can be used as predicate and/or combined with another (with the `&` and `|` operators). – bruno desthuilliers Sep 26 '17 at 12:58
  • Thanks, @brunodesthuilliers. I'll give it a shot and report back. – Nicholas Tulach Sep 26 '17 at 13:00

1 Answers1

0
x = "name=Nick"

key, value = x.split('=')
query = {r.row[key]: value}

r.filter(**query)

Refer: What does ** (double star/asterisk) and * (star/asterisk) do for parameters?

Vinayak Kaniyarakkal
  • 1,110
  • 17
  • 23