Ejemplo n.º 1
0
    def __init__(self, node, direction, relationship_type, related_classes):
        assert isinstance(direction, int) and not isinstance(direction, bool)
        self.node = node

        if isinstance(related_classes, list):
            self.related_classes = related_classes
        else:  # to keep backward compatibility
            self.related_classes = [related_classes]

        self.__related_objects = None
        if direction > 0:
            self.__match_args = (self.node, relationship_type, None)
            self.__start_node = False
            self.__end_node = True
            self.__relationship_pattern = "(a)-[_:%s]->(b)" % cypher_escape(
                relationship_type)
        elif direction < 0:
            self.__match_args = (None, relationship_type, self.node)
            self.__start_node = True
            self.__end_node = False
            self.__relationship_pattern = "(a)<-[_:%s]-(b)" % cypher_escape(
                relationship_type)
        else:
            self.__match_args = (self.node, relationship_type, None, True)
            self.__start_node = True
            self.__end_node = True
            self.__relationship_pattern = "(a)-[_:%s]-(b)" % cypher_escape(
                relationship_type)
Ejemplo n.º 2
0
    def top(self, query, fields, collect=None, sumfields=None):
        """Returns an iterator of:
        {fields: <fields>, count: <number of occurrence or sum of sumfields>,
         collected: <collected fields>}.

        WARNING/FIXME: this mutates the query
        """
        collect = collect or []
        sumfields = sumfields or []
        for flist in fields, collect, sumfields:
            for i in range(len(flist)):
                if flist[i].startswith("link."):
                    flist[i] = flist[i].replace("flow.", "link.")
                if "." not in flist[i]:
                    flist[i] = "link.%s" % flist[i]
                flist[i] = '.'.join(
                    cypher_escape(elt) for elt in flist[i].split("."))

        cy_fields = "[%s]" % ', '.join(fields)
        cy_collect = "[%s]" % ', '.join(collect)
        cy_sumfields = "SUM(%s)" % ' + '.join(sumfields)
        query.add_clause(
            "WITH src.elt as src, link.elt as link, dst.elt as dst\n"
            "WITH %s as fields, %s as count, %s as collected" %
            (cy_fields, "COUNT(*)" if not sumfields else cy_sumfields,
             "NULL" if not collect else "COLLECT(DISTINCT %s)" % cy_collect))
        query.ret = "RETURN fields, count, collected"
        query.orderby = "ORDER BY count DESC"
        top = self._cursor2top(self.run(query))
        return top
Ejemplo n.º 3
0
    def top(self, query, fields, collect=None, sumfields=None):
        """Returns an iterator of:
        {fields: <fields>, count: <number of occurrence or sum of sumfields>,
         collected: <collected fields>}.

        WARNING/FIXME: this mutates the query
        """
        collect = collect or []
        sumfields = sumfields or []
        for flist in fields, collect, sumfields:
            for i in range(len(flist)):
                if flist[i].startswith("link."):
                    flist[i] = flist[i].replace("flow.", "link.")
                if "." not in flist[i]:
                    flist[i] = "link.%s" % flist[i]
                flist[i] = '.'.join(cypher_escape(elt) for elt in
                                    flist[i].split("."))

        cy_fields = "[%s]" % ', '.join(fields)
        cy_collect = "[%s]" % ', '.join(collect)
        cy_sumfields = "SUM(%s)" % ' + '.join(sumfields)
        query.add_clause(
            "WITH src.elt as src, link.elt as link, dst.elt as dst\n"
            "WITH %s as fields, %s as count, %s as collected" %
            (cy_fields,
             "COUNT(*)" if not sumfields else cy_sumfields,
             "NULL" if not collect else "COLLECT(DISTINCT %s)" % cy_collect)
        )
        query.ret = "RETURN fields, count, collected"
        query.orderby = "ORDER BY count DESC"
        top = self._cursor2top(self.run(query))
        return top
Ejemplo n.º 4
0
 def __init__(self, node, direction, relationship_type, related_class):
     assert isinstance(direction, int) and not isinstance(direction, bool)
     self.node = node
     self.related_class = related_class
     self.__related_objects = None
     if direction > 0:
         self.__match_args = (self.node, relationship_type, None)
         self.__start_node = False
         self.__end_node = True
         self.__relationship_pattern = "(a)-[_:%s]->(b)" % cypher_escape(relationship_type)
     elif direction < 0:
         self.__match_args = (None, relationship_type, self.node)
         self.__start_node = True
         self.__end_node = False
         self.__relationship_pattern = "(a)<-[_:%s]-(b)" % cypher_escape(relationship_type)
     else:
         self.__match_args = (self.node, relationship_type, None, True)
         self.__start_node = True
         self.__end_node = True
         self.__relationship_pattern = "(a)-[_:%s]-(b)" % cypher_escape(relationship_type)
Ejemplo n.º 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()
Ejemplo n.º 6
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()