If you benefit from web2py hope you feel encouraged to pay it forward by contributing back to society in whatever form you choose!
    This snippet builds a query specified as a Python dictionary
    Copyright (C) 2013  Alan Etkin

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

       Affero GPLv3 License

 

class QueryParser(object):
    """To be used with the web2py execution environment

    This class is intended as an interface for reading queries submitted
    via json or other client protocols
    """

    def __init__(self):
        self.dquery = None

    def parse(self, dquery):
        self.dquery = dquery
        return self.build(self.dquery)

    def build(self, d):
        op, first, second = (d["op"], d["first"],
                             d.get("second", None))
        built = None

        if op in ("AND", "OR"):
            if not (type(first), type(second)) == (dict, dict):
                raise SyntaxError("Invalid AND/OR query")
            if op == "AND":
                built = self.build(first) & self.build(second)
            else: built = self.build(first) | self.build(second)

        elif op == "NOT":
            if first is None:
                raise SyntaxError("Invalid NOT query")
            built = ~self.build(first)
        else:
            # normal operation (GT, EQ, LT, ...)
            if isinstance(second, dict) and "tablename" in second:
                right = db[second["tablename"]][second["fieldname"]]
            else: right = second
            left = db[first["tablename"]][first["fieldname"]]

            if op == "EQ": built = left == right
            elif op == "NE": built = left != right
            elif op == "GT": built = left > right
            elif op == "GE": built = left >= right
            elif op == "LT": built = left < right
            elif op == "LE": built = left <= right
            elif op == "CONTAINS": built = left.contains(right)
            elif op == "BELONGS": built = left.belongs(right)
            else: raise SyntaxError("Operator not supported")

        return built

# Simple test. Note that the syntax doesn't follow the output structure
# for the Query class

myql = [{
"op": "OR",
"first": {"op": "AND", "first":{"first": {"tablename": "auth_user", "fieldname": "id"}, "second": 0, "op": "GT"},
                      "second":{"first": {"tablename": "auth_user", "fieldname": "id"}, "second": 0, "op": "LT"}},
"second": {"op": "NOT", "first":{"first": {"tablename": "auth_user", "fieldname": "id"}, "second": 0, "op": "GE"},
                      "second":{"first": {"tablename": "auth_user", "fieldname": "id"}, "second": 0, "op": "LE"}}
}]

myparser = QueryParser()

for i, myqd in enumerate(myql):
    print "################### Query %s ########################" % i
    print myparser.parse(myqd)

Related slices

Comments (0)


Hosting graciously provided by:
Python Anywhere