Esempio n. 1
0
 def test_query_cast_list_in_resutls(self):
     prop = u"prop%s" % text_type(datetime.now().strftime('%s%f'))
     a = self.gdb.nodes.create(prop=prop)
     b = self.gdb.nodes.create()
     a.relationships.create("relates", b)
     c = self.gdb.nodes.create()
     a.relationships.create("relates", c)
     q = """
         start a=node(*)
         match (a)--(b) with a, collect(b) as bs
         where (has(a.prop) AND a.prop = {prop})
         return a, bs limit 1
     """
     result = self.gdb.query(
         q, returns=[client.Node, (client.Node, )], params={"prop": prop}
     )[-1]
     self.assertEqual(a, result[0])
     self.assertTrue(isinstance(result[1], tuple))
     self.assertEqual(set([b, c]), set(result[1]))
     result = self.gdb.query(
         q, returns=[client.Node, [client.Node, ]], params={"prop": prop}
     )[-1]
     self.assertTrue(isinstance(result[1], list))
     result = self.gdb.query(
         q,
         returns=[client.Node, client.Iterable(client.Node)],
         params={"prop": prop}
     )[-1]
     bs = [node for node in result[1]]
     self.assertEqual(set([b, c]), set(bs))
Esempio n. 2
0
 def test_query_raw_returns_tuple(self):
     n1 = self.gdb.nodes.create(name="John")
     n2 = self.gdb.nodes.create(name="William")
     rel_type = u"rel%s" % text_type(datetime.now().strftime("%s%f"))
     r = n1.relationships.create(rel_type, n2, since=1982)
     q = """start n=node(*) match n-[r:%s]-() """ """return n, n.name, r, r.since""" % rel_type
     results = self.gdb.query(q, returns=(client.Node, text_type, client.Relationship))
     for node, name, rel, date in results:
         self.assertTrue(node in (n1, n2))
         self.assertTrue(name in (u"John", u"William"))
         self.assertEqual(rel, r)
         self.assertEqual(date, 1982)
Esempio n. 3
0
 def test_filter_nodes_start_index(self):
     Q = query.Q
     t = text_type(datetime.now().strftime('%s%f'))
     index_name = "filter_nodes_start_index_%s" % t
     index = self.gdb.nodes.indexes.create(name=index_name)
     for i in range(5):
         n = self.gdb.nodes.create(name="William %s" % i)
         index["name"]["William"] = n
     lookup = Q("name", istartswith="william")
     williams = self.gdb.nodes.filter(lookup, start=index)
     self.assertTrue(len(williams) == 5)
     williams = self.gdb.nodes.filter(lookup, start=index["name"])
     self.assertTrue(len(williams) == 5)
Esempio n. 4
0
 def test_filter_nodes_start_index(self):
     Q = query.Q
     t = text_type(datetime.now().strftime("%s%f"))
     index_name = "filter_nodes_start_index_%s" % t
     index = self.gdb.nodes.indexes.create(name=index_name)
     for i in range(5):
         n = self.gdb.nodes.create(name="William %s" % i)
         index["name"]["William"] = n
     lookup = Q("name", istartswith="william")
     williams = self.gdb.nodes.filter(lookup, start=index)
     self.assertTrue(len(williams) == 5)
     williams = self.gdb.nodes.filter(lookup, start=index["name"])
     self.assertTrue(len(williams) == 5)
Esempio n. 5
0
 def test_query_raw_no_return(self):
     property_name = u"rel%s" % text_type(datetime.now().strftime("%s%f"))
     self.gdb.nodes.create(name="John")
     # This sets a property which we will check later
     q = """start n=node(*) WHERE HAS(n.name) AND n.name='John' """ """SET n.`v{}`=True;""".format(property_name)
     # Notice there is NO return value
     self.gdb.query(q=q)
     # Here, we find all nodes that have this property set
     q = """start n=node(*) """ """WHERE HAS(n.`v{}`) return n;""".format(property_name)
     result = self.gdb.query(q=q)
     self.assertTrue(result is not None)
     # Assuming the properties are set according for the first cypher
     # query, this should always be True
     self.assertTrue(len(result) > 0)
Esempio n. 6
0
 def test_query_raw_returns_tuple(self):
     n1 = self.gdb.nodes.create(name="John")
     n2 = self.gdb.nodes.create(name="William")
     rel_type = u"rel%s" % text_type(datetime.now().strftime('%s%f'))
     r = n1.relationships.create(rel_type, n2, since=1982)
     q = """start n=node(*) match n-[r:%s]-() """ \
         """return n, n.name, r, r.since""" % rel_type
     results = self.gdb.query(q, returns=(client.Node, text_type,
                                          client.Relationship))
     for node, name, rel, date in results:
         self.assertTrue(node in (n1, n2))
         self.assertTrue(name in (u"John", u"William"))
         self.assertEqual(rel, r)
         self.assertEqual(date, 1982)
Esempio n. 7
0
 def test_filter_relationships_start_index(self):
     Q = query.Q
     t = text_type(datetime.now().strftime('%s%f'))
     index_name = "filter_relationships_start_index_%s" % t
     index = self.gdb.relationships.indexes.create(name=index_name)
     for i in range(5):
         n1 = self.gdb.nodes.create(name="William %s" % i)
         n2 = self.gdb.nodes.create(name="Rose %s" % i)
         r = n1.loves(n2, since=(1990 + i))
         index["since"][1990] = r
     lookup = Q("since", lte=2000)
     old_loves = self.gdb.relationships.filter(lookup, start=index)
     self.assertTrue(len(old_loves) == 5)
     old_loves = self.gdb.relationships.filter(lookup, start=index["since"])
     self.assertTrue(len(old_loves) == 5)
Esempio n. 8
0
 def test_filter_relationships_start_index(self):
     Q = query.Q
     t = text_type(datetime.now().strftime("%s%f"))
     index_name = "filter_relationships_start_index_%s" % t
     index = self.gdb.relationships.indexes.create(name=index_name)
     for i in range(5):
         n1 = self.gdb.nodes.create(name="William %s" % i)
         n2 = self.gdb.nodes.create(name="Rose %s" % i)
         r = n1.loves(n2, since=(1990 + i))
         index["since"][1990] = r
     lookup = Q("since", lte=2000)
     old_loves = self.gdb.relationships.filter(lookup, start=index)
     self.assertTrue(len(old_loves) == 5)
     old_loves = self.gdb.relationships.filter(lookup, start=index["since"])
     self.assertTrue(len(old_loves) == 5)
Esempio n. 9
0
 def test_query_transaction_returns_tuple(self):
     n1 = self.gdb.nodes.create(name="John")
     n2 = self.gdb.nodes.create(name="William")
     rel_type = u"rel%s" % text_type(datetime.now().strftime("%s%f"))
     r = n1.relationships.create(rel_type, n2, since=1982)
     q = """start n=node(*) match n-[r:`{rel}`]-() """ """return n, n.name, r, r.since"""
     params = {"rel": rel_type}
     with self.gdb.transaction(for_query=True) as tx:
         results = self.gdb.query(q, params=params, returns=(client.Node, text_type, client.Relationship))
     self.assertTrue(tx.finished)
     for node, name, rel, date in results:
         self.assertTrue(node in (n1, n2))
         self.assertTrue(name in (u"John", u"William"))
         self.assertEqual(rel, r)
         self.assertEqual(date, 1982)
Esempio n. 10
0
 def test_query_raw_no_return(self):
     property_name = u"rel%s" % text_type(datetime.now().strftime('%s%f'))
     self.gdb.nodes.create(name="John")
     # This sets a property which we will check later
     q = ("""start n=node(*) WHERE HAS(n.name) AND n.name='John' """
          """SET n.`v{}`=True;""".format(property_name))
     # Notice there is NO return value
     self.gdb.query(q=q)
     # Here, we find all nodes that have this property set
     q = ("""start n=node(*) """
          """WHERE HAS(n.`v{}`) return n;""".format(property_name))
     result = self.gdb.query(q=q)
     self.assertTrue(result is not None)
     # Assuming the properties are set according for the first cypher
     # query, this should always be True
     self.assertTrue(len(result) > 0)
Esempio n. 11
0
 def test_query_transaction_returns_tuple(self):
     n1 = self.gdb.nodes.create(name="John")
     n2 = self.gdb.nodes.create(name="William")
     rel_type = u"rel%s" % text_type(datetime.now().strftime('%s%f'))
     r = n1.relationships.create(rel_type, n2, since=1982)
     q = """start n=node(*) match n-[r:`{rel}`]-() """ \
         """return n, n.name, r, r.since"""
     params = {
         "rel": rel_type,
     }
     with self.gdb.transaction(for_query=True) as tx:
         results = self.gdb.query(q, params=params,
                                  returns=(client.Node, text_type,
                                           client.Relationship))
     self.assertTrue(tx.finished)
     for node, name, rel, date in results:
         self.assertTrue(node in (n1, n2))
         self.assertTrue(name in (u"John", u"William"))
         self.assertEqual(rel, r)
         self.assertEqual(date, 1982)
Esempio n. 12
0
 def __eq__(self, obj):
     try:
         return obj._label == self._label
     except AttributeError:
         return text_type(obj) == self._label
Esempio n. 13
0
 def __unicode__(self):
     return text_type(self._labels)
Esempio n. 14
0
    def _plot_graph(self, graph, title=None, width=None, height=None):
        """
        Return a HTML representation for a particular QuerySequence.
        Mainly for IPython Notebook.
        """
        if not self._elements_row and not self._elements_graph:
            raise ValueError('Unable to display the graph or the table')
        title = title or self.q
        width = width or json.dumps(None)
        height = height or 300
        d3_uuid = text_type(uuid.uuid1())
        d3_graph = self._transform_graph_to_d3(graph)
        d3_id = "d3_id_" + d3_uuid
        d3_title = title
        d3_container_id = d3_id + "_d3c"
        style = """
        #{d3_id} path.link {{
            fill: none;
            stroke-width: 1.5px;
        }}
        #{d3_id} .node {{
            /*fill: #ccc;*/
            stroke: #333;
            stroke-width: 1.5px;
        }}
        #{d3_id} text {{
            font: 10px sans-serif;
            pointer-events: none;
        }}
        #{d3_id} text.shadow {{
            stroke: #fff;
            stroke-width: 3px;
            stroke-opacity: .8;
        }}
        #{d3_id} .node.sticky {{
            /* stroke-width: 2px; */
        }}
        """.format(d3_id=d3_id)
        js = """
        var links = graph.links;
        var nodes = graph.nodes;

        // Compute the distinct nodes from the links.
        links.forEach(function(link) {
            link.source = (nodes[link.source] ||
                           (nodes[link.source] = {name: link.source}));
            link.target = (nodes[link.target] ||
                           (nodes[link.target] = {name: link.target}));
        });

        var w = width || $(container).width(), h = height;

        var force = d3.layout.force()
            .nodes(d3.values(nodes))
            .links(links)
            .size([w, h])
            .linkDistance(60)
            .charge(-300)
            .on("tick", tick)
            .start();

        var svg = d3.select(container).append("svg:svg")
            .attr("width", w)
            .attr("height", h);

        // Per-type markers, as they don't inherit styles.
        svg.append("svg:defs").selectAll("marker")
            .data(["arrow"])
            .enter().append("svg:marker")
            .attr("id", String)
            .attr("viewBox", "0 -5 10 10")
            .attr("refX", 15)
            .attr("refY", -1.5)
            .attr("markerWidth", 6)
            .attr("markerHeight", 6)
            .attr("orient", "auto")
            .append("svg:path")
            .attr("d", "M0,-5L10,0L0,5");

        var path = svg.append("svg:g").selectAll("path")
            .data(force.links())
            .enter().append("svg:path")
            .attr("class", function(d) { return "link " + d.stroke; })
            .attr("stroke", function(d) { return d.stroke; })
            .attr("marker-end", function(d) { return "url(#arrow)"; });

        var circle = svg.append("svg:g").selectAll("circle")
            .data(force.nodes())
            .enter().append("svg:circle")
            .attr("fill", function(d) { return d.fill; })
            .attr("r", 6)
            .attr("class", "node")
            .call(force.drag)
            .on("mousedown", function(d) {
                d.fixed = true;
                d3.select(this).classed("sticky", true);
            });

        var text = svg.append("svg:g").selectAll("g")
            .data(force.nodes())
            .enter().append("svg:g");

        // A copy of the text with a thick white stroke for legibility.
        text.append("svg:text")
            .attr("x", 8)
            .attr("y", ".31em")
            .attr("class", "shadow")
            .text(function(d) { return d.label; });

        text.append("svg:text")
            .attr("x", 8)
            .attr("y", ".31em")
            .attr("class", "front")
            .text(function(d) { return d.label; });

        // Use elliptical arc path segments to doubly-encode directionality.
        function tick() {
            path.attr("d", function(d) {
                var dx = d.target.x - d.source.x,
                dy = d.target.y - d.source.y,
                dr = Math.sqrt(dx * dx + dy * dy);
                return ("M" + d.source.x + "," + d.source.y + "A"
                        + dr + "," + dr + " 0 0,1 " + d.target.x + ","
                        + d.target.y);
            });

            circle.attr("transform", function(d) {
                return "translate(" + d.x + "," + d.y + ")";
            });

            text.attr("transform", function(d) {
                return "translate(" + d.x + "," + d.y + ")";
            });
        }

        // Display options
        var display = $(container + "_display");
        graph.properties.forEach(function (property) {
            var option = $("<OPTION/>");
            option.text(property);
            option.attr("value", property);
            display.append(option);
        });
        display.on("change", function () {
            var selected = $(this).find(":selected").val(),
                displayFunc;
            if (selected.length !== 0) {
                displayFunc = function(d) {
                    return d.properties[selected];
                }
            } else {
                displayFunc = function(d) {
                    return d.label;
                }
            }
            text.select("text.front").text(displayFunc);
            text.select("text.shadow").text(displayFunc);
        });
        """
        return ("""
        <style type="text/css">
        {style}
        </style>

        <div class="accordion">
            <div class="accordion-group">
                <div class="accordion-heading">
                    <a class="accordion-toggle collapsed"
                       data-toggle="collapse" data-parent=""
                       href="#{d3_id}">
                        {d3_title}
                    </a>
                </div>
                <div id="{d3_id}" class="accordion-body in collapse">
                    <div class="accordion-inner">
                        <div id="{d3_container_id}">
                            <select id="{d3_container_id}_display">
                                <option value="">ID</option>
                            </select>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <script>
            var neo4jrestclient = window.neo4jrestclient || {{}};
            neo4jrestclient['{d3_uuid}'] = {{}};
            neo4jrestclient['{d3_uuid}'].graph = {d3_graph};
            neo4jrestclient['{d3_uuid}'].container_id = "{d3_container_id}";
            neo4jrestclient['{d3_uuid}'].container = "#{d3_container_id}";
            neo4jrestclient['{d3_uuid}'].render = function () {{
                (function (graph, container, width, height) {{
                    {js}
                }})(
                    neo4jrestclient['{d3_uuid}'].graph,
                    neo4jrestclient['{d3_uuid}'].container,
                    {width},
                    {height}
                );
            }}
            if (!window.d3) {{
                $.getScript(
                    "//d3js.org/d3.v2.js?2.9.1",
                    neo4jrestclient['{d3_uuid}'].render
                );
            }} else {{
                neo4jrestclient['{d3_uuid}'].render();
            }}
        </script>
        """.format(
            style=style,
            js=js,
            d3_graph=json.dumps(d3_graph),
            d3_id=d3_id,
            d3_uuid=d3_uuid,
            d3_title=d3_title,
            d3_container_id=d3_container_id,
            width=width,
            height=height,
        ))
Esempio n. 15
0
 def get_query_objects(self, var=None, prefix=None, params=None,
                       version=None):
     if var:
         self.var = var
     if not params:
         params = {}
     if not prefix:
         prefix = u""
     else:
         params.update(params)
     if self._and is not None:
         left_and = self._and[0].get_query_objects(params=params,
                                                   version=version)
         params.update(left_and[1])
         right_and = self._and[1].get_query_objects(params=params,
                                                    version=version)
         params.update(right_and[1])
         if self._and[0].is_valid() and self._and[1].is_valid():
             query = u"( {0} AND {1} )".format(left_and[0], right_and[0])
         elif self._and[0].is_valid() and not self._and[1].is_valid():
             query = u" {0} ".format(left_and[0])
         elif not self._and[0].is_valid() and self._and[1].is_valid():
             query = u" {0} ".format(right_and[0])
         else:
             query = u" "
     elif self._not is not None:
         op_not = self._not.get_query_objects(params=params,
                                              version=version)
         params.update(op_not[1])
         query = u"NOT ( {0} )".format(op_not[0])
     elif self._or is not None:
         left_or = self._or[0].get_query_objects(params=params,
                                                 version=version)
         params.update(left_or[1])
         right_or = self._or[1].get_query_objects(params=params,
                                                  version=version)
         params.update(right_or[1])
         if self._or[0].is_valid() and self._or[1].is_valid():
             query = u"( {0} OR {1} )".format(left_or[0], right_or[0])
         elif self._or[0].is_valid() and not self._or[1].is_valid():
             query = u" {0} ".format(left_or[0])
         elif not self._or[0].is_valid() and self._or[1].is_valid():
             query = u" {0} ".format(right_or[0])
         else:
             query = u" "
     else:
         query = u""
         lookup, match = self._get_lookup_and_match()
     if self.property is not None and self.var is not None:
         key = u"{0}p{1}".format(prefix, len(params))
         prop = text_type(self.property).replace(u"`", u"\\`")
         NEO4J_V2 = version and version.split(".")[0] >= "2"
         if not NEO4J_V2 and self.nullable is None:
             # Backwards compatibility for Neo5j versions prior 2.0
             self.nullable = True
         if self.lookup == 'isnull':
             query_format = ("{0}.`{1}` {2} NULL")
             query = query_format.format(self.var, prop, lookup)
         elif NEO4J_V2 and self.nullable is not None:
             warnings.warn("Deprecated, Neo4j +2.0.0 does not support "
                           "the use of 'nullable' ('!' and '?' operators).",
                           DeprecationWarning)
             if self.nullable is True:
                 try:
                     query_format = (u"(has({0}.`{1}`) and {2}.`{3}` "
                                     u"{4} {{{5}}})")
                     query = query_format.format(self.var, prop,
                                                 self.var, prop,
                                                 lookup, key)
                 except AttributeError:
                     query = (u"( has(%s.`%s`) and %s.`%s` %s {%s} )"
                              % (self.var, prop, self.var, prop, lookup,
                                 key))
             elif self.nullable is False:
                 try:
                     query_format = (u"(not(has({0}.`{1}`)) or {2}.`{3}` "
                                     u"{4} {{{5}}})")
                     query = query_format.format(self.var, prop,
                                                 self.var, prop,
                                                 lookup, key)
                 except AttributeError:
                     query = (u"( not(has(%s.`%s`)) or %s.`%s` %s {%s} )"
                              % (self.var, prop, self.var, prop, lookup,
                                 key))
         else:
             if NEO4J_V2:
                 nullable = u""
             elif self.nullable is True:
                 nullable = u"!"
             elif self.nullable is False:
                 nullable = u"?"
             else:
                 nullable = u""
             try:
                 query_format = u"{0}.`{1}`{2} {3} {{{4}}}"
                 query = query_format.format(self.var, prop, nullable,
                                             lookup, key)
             except AttributeError:
                 query = u"%s.`%s`%s %s {%s}" % (self.var, prop,
                                                 nullable, lookup, key)
         params[key] = match
     return query, params
Esempio n. 16
0
 def get_query_objects(self, var=None, prefix=None, params=None,
                       version=None):
     if var:
         self.var = var
     if not params:
         params = {}
     if not prefix:
         prefix = u""
     else:
         params.update(params)
     if self._and is not None:
         left_and = self._and[0].get_query_objects(params=params,
                                                   version=version)
         params.update(left_and[1])
         right_and = self._and[1].get_query_objects(params=params,
                                                    version=version)
         params.update(right_and[1])
         if self._and[0].is_valid() and self._and[1].is_valid():
             query = u"( {0} AND {1} )".format(left_and[0], right_and[0])
         elif self._and[0].is_valid() and not self._and[1].is_valid():
             query = u" {0} ".format(left_and[0])
         elif not self._and[0].is_valid() and self._and[1].is_valid():
             query = u" {0} ".format(right_and[0])
         else:
             query = u" "
     elif self._not is not None:
         op_not = self._not.get_query_objects(params=params,
                                              version=version)
         params.update(op_not[1])
         query = u"NOT ( {0} )".format(op_not[0])
     elif self._or is not None:
         left_or = self._or[0].get_query_objects(params=params,
                                                 version=version)
         params.update(left_or[1])
         right_or = self._or[1].get_query_objects(params=params,
                                                  version=version)
         params.update(right_or[1])
         if self._or[0].is_valid() and self._or[1].is_valid():
             query = u"( {0} OR {1} )".format(left_or[0], right_or[0])
         elif self._or[0].is_valid() and not self._or[1].is_valid():
             query = u" {0} ".format(left_or[0])
         elif not self._or[0].is_valid() and self._or[1].is_valid():
             query = u" {0} ".format(right_or[0])
         else:
             query = u" "
     else:
         query = u""
         lookup, match = self._get_lookup_and_match()
     if self.property is not None and self.var is not None:
         key = u"{0}p{1}".format(prefix, len(params))
         prop = text_type(self.property).replace(u"`", u"\\`")
         NEO4J_V2 = version and version.split(".")[0] >= "2"
         if NEO4J_V2 and self.nullable is True:
             try:
                 query_format = (u"(has({0}.`{1}`) and {2}.`{3}` "
                                 u"{4} {{{5}}})")
                 query = query_format.format(self.var, prop,
                                             self.var, prop,
                                             lookup, key)
             except AttributeError:
                 query = (u"( has(%s.`%s`) and %s.`%s` %s {%s} )"
                          % (self.var, prop, self.var, prop, lookup, key))
         if NEO4J_V2 and self.nullable is False:
             try:
                 query_format = (u"(not(has({0}.`{1}`)) or {2}.`{3}` "
                                 u"{4} {{{5}}})")
                 query = query_format.format(self.var, prop,
                                             self.var, prop,
                                             lookup, key)
             except AttributeError:
                 query = (u"( not(has(%s.`%s`)) or %s.`%s` %s {%s} )"
                          % (self.var, prop, self.var, prop, lookup, key))
         else:
             if NEO4J_V2:
                 nullable = u""
             elif self.nullable is True:
                 nullable = u"!"
             elif self.nullable is False:
                 nullable = u"?"
             else:
                 nullable = u""
             try:
                 query_format = u"{0}.`{1}`{2} {3} {{{4}}}"
                 query = query_format.format(self.var, prop, nullable,
                                             lookup, key)
             except AttributeError:
                 query = u"%s.`%s`%s %s {%s}" % (self.var, prop,
                                                 nullable, lookup, key)
         params[key] = match
     return query, params
Esempio n. 17
0
 def get_query_objects(self,
                       var=None,
                       prefix=None,
                       params=None,
                       version=None):
     if var:
         self.var = var
     if not params:
         params = {}
     if not prefix:
         prefix = u""
     else:
         params.update(params)
     if self._and is not None:
         left_and = self._and[0].get_query_objects(params=params,
                                                   version=version)
         params.update(left_and[1])
         right_and = self._and[1].get_query_objects(params=params,
                                                    version=version)
         params.update(right_and[1])
         if self._and[0].is_valid() and self._and[1].is_valid():
             query = u"( {0} AND {1} )".format(left_and[0], right_and[0])
         elif self._and[0].is_valid() and not self._and[1].is_valid():
             query = u" {0} ".format(left_and[0])
         elif not self._and[0].is_valid() and self._and[1].is_valid():
             query = u" {0} ".format(right_and[0])
         else:
             query = u" "
     elif self._not is not None:
         op_not = self._not.get_query_objects(params=params,
                                              version=version)
         params.update(op_not[1])
         query = u"NOT ( {0} )".format(op_not[0])
     elif self._or is not None:
         left_or = self._or[0].get_query_objects(params=params,
                                                 version=version)
         params.update(left_or[1])
         right_or = self._or[1].get_query_objects(params=params,
                                                  version=version)
         params.update(right_or[1])
         if self._or[0].is_valid() and self._or[1].is_valid():
             query = u"( {0} OR {1} )".format(left_or[0], right_or[0])
         elif self._or[0].is_valid() and not self._or[1].is_valid():
             query = u" {0} ".format(left_or[0])
         elif not self._or[0].is_valid() and self._or[1].is_valid():
             query = u" {0} ".format(right_or[0])
         else:
             query = u" "
     else:
         query = u""
         lookup, match = self._get_lookup_and_match()
     if self.property is not None and self.var is not None:
         key = u"{0}p{1}".format(prefix, len(params))
         prop = text_type(self.property).replace(u"`", u"\\`")
         NEO4J_V2 = version and version.split(".")[0] >= "2"
         if NEO4J_V2 and self.nullable is True:
             try:
                 query_format = (u"(has({0}.`{1}`) and {2}.`{3}` "
                                 u"{4} {{{5}}})")
                 query = query_format.format(self.var, prop, self.var, prop,
                                             lookup, key)
             except AttributeError:
                 query = (u"( has(%s.`%s`) and %s.`%s` %s {%s} )" %
                          (self.var, prop, self.var, prop, lookup, key))
         if NEO4J_V2 and self.nullable is False:
             try:
                 query_format = (u"(not(has({0}.`{1}`)) or {2}.`{3}` "
                                 u"{4} {{{5}}})")
                 query = query_format.format(self.var, prop, self.var, prop,
                                             lookup, key)
             except AttributeError:
                 query = (u"( not(has(%s.`%s`)) or %s.`%s` %s {%s} )" %
                          (self.var, prop, self.var, prop, lookup, key))
         else:
             if NEO4J_V2:
                 nullable = u""
             elif self.nullable is True:
                 nullable = u"!"
             elif self.nullable is False:
                 nullable = u"?"
             else:
                 nullable = u""
             try:
                 query_format = u"{0}.`{1}`{2} {3} {{{4}}}"
                 query = query_format.format(self.var, prop, nullable,
                                             lookup, key)
             except AttributeError:
                 query = u"%s.`%s`%s %s {%s}" % (self.var, prop, nullable,
                                                 lookup, key)
         params[key] = match
     return query, params