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))
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
def __eq__(self, obj): try: return obj._label == self._label except AttributeError: return text_type(obj) == self._label
def __unicode__(self): return text_type(self._labels)
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, ))
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
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