Example #1
0
    def _add_clause_from_filter(self, flt):
        """
        Returns a clause object computed from the given filter
        flt format is
        "[!|-|~][ANY |ALL |ONE |NONE |LEN ]<attr>[operator <value>]"
        """
        clause = {
            "neg": False,
            "array_mode": None,
            "len_mode": False,
            "attr": None,
            "operator": None,
            "value": None,
        }
        if not flt:
            return None
        # Ignore labels (neo4j compatibility)
        if flt[0] == "#":
            return None
        if flt[0] in "-!~":
            clause["neg"] = True
            flt = flt[1:]
        array_modes = ["ANY", "ALL", "ONE", "NONE"]
        for array_mode in array_modes:
            if flt.startswith(array_mode + " "):
                clause["array_mode"] = array_mode
                flt = flt[len(array_mode) + 1:]
                break
        if clause["array_mode"] is None and flt.startswith("LEN "):
            clause["len_mode"] = True
            flt = flt[4:]

        try:
            clause["operator"] = self.operators_re.search(flt).group()
        except AttributeError:
            clause["operator"] = None
            clause["attr"] = flt
        else:
            clause["attr"], value = [
                elt.strip() for elt in flt.split(clause["operator"], 1)
            ]
            clause["value"] = utils.str2pyval(value)
        # Validate field
        # 'addr' is a shortcut for src.addr OR dst.addr
        if clause["attr"] != "addr":
            validate_field(clause["attr"])
        return clause
Example #2
0
    def _add_clause_from_filter(self, flt):
        """
        Returns a clause object computed from the given filter
        flt format is
        "[!|-|~][ANY |ALL |ONE |NONE |LEN ]<attr>[operator <value>]"
        """
        clause = {
            'neg': False,
            'array_mode': None,
            'len_mode': False,
            'attr': None,
            'operator': None,
            'value': None
        }
        if not flt:
            return None
        # Ignore labels (neo4j compatibility)
        if flt[0] == '#':
            return None
        if flt[0] in "-!~":
            clause['neg'] = True
            flt = flt[1:]
        array_modes = ['ANY', 'ALL', 'ONE', 'NONE']
        for array_mode in array_modes:
            if flt.startswith(array_mode + ' '):
                clause['array_mode'] = array_mode
                flt = flt[len(array_mode) + 1:]
                break
        if clause['array_mode'] is None and flt.startswith("LEN "):
            clause['len_mode'] = True
            flt = flt[4:]

        try:
            clause['operator'] = self.operators_re.search(flt).group()
        except AttributeError:
            clause['operator'] = None
            clause['attr'] = flt
        else:
            clause['attr'], value = [
                elt.strip() for elt in flt.split(clause['operator'], 1)
            ]
            clause['value'] = utils.str2pyval(value)
        return clause
Example #3
0
    def _add_clause_from_filter(self, flt, mode="node"):
        """Returns a WHERE clause (tuple (query, parameters)) from a single
        filter (no OR).

        Devs: `flt` **can** be set from an untrusted source.

        """
        if not flt:
            return None

        if flt[0] in "-!~":
            neg = True
            flt = flt[1:]
        else:
            neg = False

        array_mode = None
        len_mode = None
        if flt.startswith("ANY "):
            array_mode = "ANY"
            flt = flt[4:]
        elif flt.startswith("ALL "):
            array_mode = "ALL"
            flt = flt[4:]
        elif flt.startswith("ONE "):
            array_mode = "SINGLE"
            flt = flt[4:]
        elif flt.startswith("NONE "):
            array_mode = "NONE"
            flt = flt[5:]
        elif flt.startswith("LEN "):
            len_mode = "LENGTH"
            flt = flt[4:]

        try:
            operator = self.operators_re.search(flt).group()
        except AttributeError:
            operator = None
            attr = flt
        else:
            attr, value = [elt.strip() for elt in flt.split(operator, 1)]
            value = utils.str2pyval(value)
        if attr[0] in "@#":
            qtype = attr[0]
            attr = attr[1:]
        else:
            qtype = "@"
        try:
            # Sorry for the horrendous code -- jalet
            elements, attr = attr.rsplit('.', 1)
            if elements == "meta":
                if mode == "edge":
                    elements = ["linkmeta"]
                    self.meta_link = True
                elif mode == "node":
                    elements = ["srcmeta", "dstmeta"]
                    self.meta_src = True
                    self.meta_dst = True
            elif elements == "src.meta":
                elements = ["srcmeta"]
                self.meta_src = True
            elif elements == "dst.meta":
                elements = ["dstmeta"]
                self.meta_dst = True
            else:
                elements = [elements]
        except ValueError:
            if mode == "node":
                elements = ["src", "dst"]
            elif mode == "edge":
                elements = ["link"]
            else:
                raise ValueError()
        else:
            assert all(self.identifier.search(elt) for elt in elements)
        assert self.identifier.search(attr)
        if operator is None:
            if qtype == "@":
                return (
                    "%s(%s)" % (
                        "NOT " if neg else "",
                        " OR ".join("EXISTS(`%s`.`%s`)" % (elt, attr)
                                    for elt in elements),
                    ),
                    {},
                )
            if qtype == "#":
                identifier = self.nextid()
                return (
                    "%s(%s)" % (
                        "NOT " if neg else "",
                        " OR ".join("{%s} IN labels(`%s`)" % (identifier, elt)
                                    for elt in elements),
                    ),
                    {
                        identifier: attr
                    },
                )
        if qtype == "@":
            identifier = self.nextid()
            operator = self.operators[operator]

            clauses = []
            for elt in elements:
                attr_expr = "%s.%s" % tuple(
                    cypher_escape(s) for s in (elt, attr))
                if array_mode is not None:
                    lval = "x"
                elif len_mode is not None:
                    lval = "%s(%s)" % (len_mode, attr_expr)
                else:
                    lval = attr_expr
                clause_part = "%s %s {%s}" % (lval, operator, identifier)
                if array_mode is not None:
                    if array_mode in ["ALL", "ANY", "SINGLE"]:
                        prereq = "LENGTH(%s) <> 0 AND" % attr_expr
                    elif array_mode in ["NONE"]:
                        prereq = "LENGTH(%s) = 0 OR"
                    clause_part = "%s %s(x IN %s WHERE %s)" % (
                        prereq,
                        array_mode,
                        attr_expr,
                        clause_part,
                    )
                clauses.append(clause_part)

            clause = " OR ".join(clauses)

            if neg:
                clause = "%s OR NOT (%s)" % (
                    " OR ".join("NOT EXISTS(`%s`.`%s`)" % (elt, attr)
                                for elt in elements),
                    clause,
                )
            value = Neo4jDB.to_dbprop(attr, value)
            return (
                "%s" % clause,
                {
                    identifier: value
                },
            )
        raise ValueError()
Example #4
0
    def _add_clause_from_filter(self, flt, mode="node"):
        """Returns a WHERE clause (tuple (query, parameters)) from a single
filter (no OR).

        Devs: `flt` **can** be set from an untrusted source.

        """
        if not flt:
            return None
        try:
            operator = self.operators_re.search(flt).group()
        except AttributeError:
            operator = None
            attr = flt
        else:
            attr, value = [elt.strip() for elt in flt.split(operator, 1)]
            value = utils.str2pyval(value)
        if attr[0] in "-!~":
            neg = True
            attr = attr[1:]
        else:
            neg = False
        if attr[0] in "@#":
            qtype = attr[0]
            attr = attr[1:]
        else:
            qtype = "@"
        try:
            # Sorry for the horrendous code -- jalet
            elements, attr = attr.rsplit('.', 1)
            if elements == "meta":
                if mode == "edge":
                    elements = ["linkmeta"]
                    self.meta_link = True
                elif mode == "node":
                    elements = ["srcmeta", "dstmeta"]
                    self.meta_src = True
                    self.meta_dst = True
            elif elements == "src.meta":
                elements = ["srcmeta"]
                self.meta_src = True
            elif elements == "dst.meta":
                elements = ["dstmeta"]
                self.meta_dst = True
            else:
                elements = [elements]
        except ValueError:
            if mode == "node":
                elements = ["src", "dst"]
            elif mode == "edge":
                elements = ["link"]
            else:
                raise ValueError()
        else:
            assert all(self.identifier.search(elt) for elt in elements)
        assert self.identifier.search(attr)
        if operator is None:
            if qtype == "@":
                return (
                    "%s(%s)" % (
                        "NOT " if neg else "",
                        " OR ".join(
                            "EXISTS(`%s`.`%s`)" % (elt, attr)
                            for elt in elements
                        ),
                    ),
                    {},
                )
            if qtype == "#":
                identifier = self.nextid()
                return (
                    "%s(%s)" % (
                        "NOT " if neg else "",
                        " OR ".join(
                            "{%s} IN labels(`%s`)" % (identifier, elt)
                            for elt in elements
                        ),
                    ),
                    {identifier: attr},
                )
        if qtype == "@":
            identifier = self.nextid()
            operator = self.operators[operator]
            clause = " OR ".join(
                "`%s`.`%s` %s {%s}"
                "" % (elt, attr, operator, identifier)
                for elt in elements
            )
            if neg:
                clause = "%s OR NOT (%s)" % (
                    " OR ".join("NOT EXISTS(`%s`.`%s`)" % (elt, attr)
                                for elt in elements),
                    clause,
                )
            value = Neo4jDB.to_dbprop(attr, value)
            return (
                "%s" % clause,
                {identifier: value},
            )
        raise ValueError()
Example #5
0
    def _add_clause_from_filter(self, flt, mode="node"):
        """Returns a WHERE clause (tuple (query, parameters)) from a single
        filter (no OR).

        Devs: `flt` **can** be set from an untrusted source.

        """
        if not flt:
            return None

        if flt[0] in "-!~":
            neg = True
            flt = flt[1:]
        else:
            neg = False

        array_mode = None
        len_mode = None
        if flt.startswith("ANY "):
            array_mode = "ANY"
            flt = flt[4:]
        elif flt.startswith("ALL "):
            array_mode = "ALL"
            flt = flt[4:]
        elif flt.startswith("ONE "):
            array_mode = "SINGLE"
            flt = flt[4:]
        elif flt.startswith("NONE "):
            array_mode = "NONE"
            flt = flt[5:]
        elif flt.startswith("LEN "):
            len_mode = "LENGTH"
            flt = flt[4:]

        try:
            operator = self.operators_re.search(flt).group()
        except AttributeError:
            operator = None
            attr = flt
        else:
            attr, value = [elt.strip() for elt in flt.split(operator, 1)]
            value = utils.str2pyval(value)
        if attr[0] in "@#":
            qtype = attr[0]
            attr = attr[1:]
        else:
            qtype = "@"
        try:
            # Sorry for the horrendous code -- jalet
            elements, attr = attr.rsplit('.', 1)
            if elements == "meta":
                if mode == "edge":
                    elements = ["linkmeta"]
                    self.meta_link = True
                elif mode == "node":
                    elements = ["srcmeta", "dstmeta"]
                    self.meta_src = True
                    self.meta_dst = True
            elif elements == "src.meta":
                elements = ["srcmeta"]
                self.meta_src = True
            elif elements == "dst.meta":
                elements = ["dstmeta"]
                self.meta_dst = True
            else:
                elements = [elements]
        except ValueError:
            if mode == "node":
                elements = ["src", "dst"]
            elif mode == "edge":
                elements = ["link"]
            else:
                raise ValueError()
        else:
            assert all(self.identifier.search(elt) for elt in elements)
        assert self.identifier.search(attr)
        if operator is None:
            if qtype == "@":
                return (
                    "%s(%s)" % (
                        "NOT " if neg else "",
                        " OR ".join(
                            "EXISTS(`%s`.`%s`)" % (elt, attr)
                            for elt in elements
                        ),
                    ),
                    {},
                )
            if qtype == "#":
                identifier = self.nextid()
                return (
                    "%s(%s)" % (
                        "NOT " if neg else "",
                        " OR ".join(
                            "{%s} IN labels(`%s`)" % (identifier, elt)
                            for elt in elements
                        ),
                    ),
                    {identifier: attr},
                )
        if qtype == "@":
            identifier = self.nextid()
            operator = self.operators[operator]

            clauses = []
            for elt in elements:
                attr_expr = "%s.%s" % tuple(cypher_escape(s) for s in
                                            (elt, attr))
                if array_mode is not None:
                    lval = "x"
                elif len_mode is not None:
                    lval = "%s(%s)" % (len_mode, attr_expr)
                else:
                    lval = attr_expr
                clause_part = "%s %s {%s}" % (lval, operator, identifier)
                if array_mode is not None:
                    if array_mode in ["ALL", "ANY", "SINGLE"]:
                        prereq = "LENGTH(%s) <> 0 AND" % attr_expr
                    elif array_mode in ["NONE"]:
                        prereq = "LENGTH(%s) = 0 OR"
                    clause_part = "%s %s(x IN %s WHERE %s)" % (
                        prereq, array_mode, attr_expr, clause_part,
                    )
                clauses.append(clause_part)

            clause = " OR ".join(clauses)

            if neg:
                clause = "%s OR NOT (%s)" % (
                    " OR ".join("NOT EXISTS(`%s`.`%s`)" % (elt, attr)
                                for elt in elements),
                    clause,
                )
            value = Neo4jDB.to_dbprop(attr, value)
            return (
                "%s" % clause,
                {identifier: value},
            )
        raise ValueError()