Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added more cypher support for traversal methods, e.g. outgoing(:foo).…

…query
  • Loading branch information...
commit 75dff34200edac429a3f9321607e1cfc85f3f99c 1 parent 9596a0a
@andreasronge andreasronge authored
View
10 lib/neo4j-core/cypher/cypher.rb
@@ -172,13 +172,19 @@ def >>(other)
def outgoing(rel_type)
node = NodeVar.new(@expressions, @variables)
- MatchRelLeft.new(self, ":#{rel_type}", expressions, :outgoing) > node
+ MatchRelLeft.new(self, ":`#{rel_type}`", expressions, :outgoing) > node
node
end
def incoming(rel_type)
node = NodeVar.new(@expressions, @variables)
- MatchRelLeft.new(self, ":#{rel_type}", expressions, :incoming) < node
+ MatchRelLeft.new(self, ":`#{rel_type}`", expressions, :incoming) < node
+ node
+ end
+
+ def both(rel_type)
+ node = NodeVar.new(@expressions, @variables)
+ MatchRelLeft.new(self, ":`#{rel_type}`", expressions, :both) < node
node
end
View
84 lib/neo4j-core/traversal/traverser.rb
@@ -2,6 +2,50 @@ module Neo4j
module Core
module Traversal
+ class CypherQuery
+ include Enumerable
+ attr_accessor :query, :return_variable
+
+ def initialize(start_id, dir, types, query_hash=nil, &block)
+ this = self
+
+ rel_type = ":#{types.map{|x| "`#{x}`"}.join('|')}"
+
+ @query = Neo4j::Cypher.new do
+ default_ret = node(:default_ret)
+ n = node(start_id)
+ case dir
+ when :outgoing then
+ n > rel_type > default_ret
+ when :incoming then
+ n < rel_type < default_ret
+ when :both then
+ n - rel_type - default_ret
+ end
+
+ # where statement
+ ret_maybe = block && self.instance_exec(default_ret, &block)
+ ret = ret_maybe.respond_to?(:var_name) ? ret_maybe : default_ret
+ if query_hash
+ expr = []
+ query_hash.each{|pair| expr << (ret[pair[0]] == pair[1])}.to_a
+ expr.each_with_index do |obj, i|
+ Neo4j::Core::Cypher::ExprOp.new(obj, expr[i+1], "and") if i < expr.size - 1
+ end
+ end
+
+ this.return_variable = ret.var_name.to_sym
+ ret
+ end.to_s
+ end
+
+ def each
+ Neo4j._query(query).each do |r|
+ yield r[return_variable]
+ end
+ end
+ end
+
# By using this class you can both specify traversals and create new relationships.
# This object is return from the Neo4j::Core::Traversal methods.
# @see Neo4j::Core::Traversal#outgoing
@@ -29,42 +73,13 @@ def initialize(from, dir=:both, type=nil)
end
- class CypherQuery
- include Enumerable
- attr_accessor :query, :return_variable
-
- def initialize(start_id, dir, types, &block)
- this = self
-
- rel_type = ":#{types.first}"
-
- @query = Neo4j::Cypher.new do
- default_ret = node(:default_ret)
- n = node(start_id)
- n > rel_type > default_ret
- # where statement
- ret_maybe = block && self.instance_exec(default_ret, &block)
- # puts "ret_maybe=#{ret_maybe}/#{ret_maybe.class} respond? "
- ret = ret_maybe.respond_to?(:var_name) ? ret_maybe : default_ret
- this.return_variable = ret.var_name.to_sym
- ret
- end.to_s
- puts "QUERY = '#{query}'"
- end
-
- def each
- Neo4j._query(query).each do |r|
- yield r[return_variable]
- end
- end
- end
-
def query(&block)
# only one direction is supported
rel_types = [@outgoing_rel_types, @incoming_rel_types, @both_rel_types].find_all { |x| !x.nil? }
raise "Only one direction is allowed, outgoing:#{@outgoing_rel_types}, incoming:#{@incoming_rel_types}, @both:#{@both_rel_types}" if rel_types.count != 1
start_id = @from.neo_id
- CypherQuery.new(start_id, :outgoing, rel_types.first, &block)
+ dir = (@outgoing_rel_types && :outgoing) || (@incoming_rel_types && :incoming) || (@both_rel_types && :both)
+ CypherQuery.new(start_id, dir, rel_types.first, &block)
end
# Sets traversing depth first.
@@ -196,9 +211,9 @@ def to_ary
# @param [Hash] props properties of new relationship
# @return [Neo4j::Relationship] the created relationship
def new(other_node, props = {})
- @outgoing_rel_types && @outgoing_rel_types.each {|type| _new_out(other_node, type, props)}
- @incoming_rel_types && @incoming_rel_types.each {|type| _new_in(other_node, type, props)}
- @both_rel_types && @both_rel_types.each {|type| _new_both(other_node, type, props)}
+ @outgoing_rel_types && @outgoing_rel_types.each { |type| _new_out(other_node, type, props) }
+ @incoming_rel_types && @incoming_rel_types.each { |type| _new_in(other_node, type, props) }
+ @both_rel_types && @both_rel_types.each { |type| _new_both(other_node, type, props) }
end
# @private
@@ -370,6 +385,7 @@ def iterator
end
end
+
end
end
end
View
36 spec/neo4j/traversal_cypher_integration_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe "Neo4j Cypher Traversal", :type => :integration do
+describe "Neo4j Traversal query method", :type => :integration do
before(:all) do
new_tx
@a = Neo4j::Node.new(:name => 'a', :val => 1)
@@ -25,29 +25,33 @@
describe "b.outgoing(:foo).outgoing(:bar).query" do
it "returns all outgoing nodes of rel type foo and bar" do
- pending "TODO"
@b.outgoing(:foo).outgoing(:bar).query.to_a.size.should == 3
@b.outgoing(:foo).outgoing(:bar).query.should include(@c, @d, @e)
end
end
- it "Some Tests" do
- @a.outgoing(:foo).to_a.should include(@b,@c)
- #result = a.outgoing(:foo).query{|x| x[:val] == 2}.to_a#.should include(b,c)
- #result.size.should == 1
- #result.should include(b)
- #
- #result = a.outgoing(:foo).query{|x| b=node(:b); x > ':bar' > b; b}
- result = @a.outgoing(:foo).query{|x| b=node(:b); x > ':bar' > b; b}
- result.each do |x|
- puts "X=#{x.props.inspect}"
+
+ describe "a match clause in the query block" do
+
+ it "allows > match clause" do
+ result = @a.outgoing(:foo).query { |x| b=node(:b); x > ':bar' > b; b }
+ result.count.should == 3
end
- result = @a.outgoing(:foo).query{|x| f = x.outgoing(:bar); f2 = f.incoming(:bar); where f[:val] < 123123; f.distinct}
- result.each do |x|
- puts "X=#{x.props.inspect}"
+ it "allows a outgoing/incoming clause in the query block" do
+ result = @a.outgoing(:foo).query { |x| f = x.outgoing(:bar); f2 = f.incoming(:bar); f.distinct }
+ result.count.should == 1
end
- end
+ it "allows a both clause in the query block" do
+ result = @a.outgoing(:foo).query { |x| f = x.both(:bar); f.distinct }
+ result.count.should == 2
+ end
+ it "allows a where clause in the query block" do
+ result = @a.outgoing(:foo).query { |x| x[:val] == 2 }.to_a
+ result.count.should == 1
+ result.first[:val].should == 2
+ end
+ end
end
Please sign in to comment.
Something went wrong with that request. Please try again.