diff --git a/README.rdoc b/README.rdoc index 73a097b93..d61a12c64 100644 --- a/README.rdoc +++ b/README.rdoc @@ -142,6 +142,10 @@ Traversing using a filter person.friends{ salary == 10000 }.each {|n| ...} +Traversing with a specific depth (depth 1 is default) + + person.friends{ salary == 10000}.depth(3).each { ... } + Deleting a relationship person.relations[person2].delete @@ -661,10 +665,19 @@ Each type of relationship has a method that returns an Enumerable object that en to traverse that type of relationship. For example the Person example above declares one relationship of type friends. -You can traverse all Person's friend by doing: +You can traverse all Person's friend by doing of depth 1: f.friends.each { |n| puts n } +Traversing friends of a specific depth. +Example finding all friends and friends friends. + + f.friends.depth(2).each { ...} + +Traversing to the end of the graph + + f.friends.depth(:all).each { ...} + === Filtering nodes in a relationship If you want to find one node in a relationship you can use a filter. diff --git a/lib/neo4j/relations/has_n_relations.rb b/lib/neo4j/relations/has_n_relations.rb index e40c639e4..4038114d3 100644 --- a/lib/neo4j/relations/has_n_relations.rb +++ b/lib/neo4j/relations/has_n_relations.rb @@ -14,7 +14,7 @@ def initialize(node, type, &filter) @node = node @type = RelationshipType.instance(type) @filter = filter - @depth = 1 + @stop_evaluator = DepthStopEvaluator.new(1) @info = node.class.relations_info[type.to_sym] if @info[:outgoing] @@ -41,14 +41,17 @@ def initialize(node, type, &filter) # # :api: public def depth(d) - @depth = d + if d == :all + @stop_evaluator = org.neo4j.api.core.StopEvaluator::END_OF_GRAPH + else + @stop_evaluator = DepthStopEvaluator.new(d) + end self end def each - stop = DepthStopEvaluator.new(@depth) traverser = @node.internal_node.traverse(org.neo4j.api.core.Traverser::Order::BREADTH_FIRST, - stop, + @stop_evaluator, org.neo4j.api.core.ReturnableEvaluator::ALL_BUT_START_NODE, @type, @direction) @@ -65,7 +68,7 @@ def each end end - # + # Creates a relationship instance between this and the other node. # If a class for the relationship has not been specified it will be of type DynamicRelation. # To set a relationship type see #Neo4j::relations @@ -81,10 +84,10 @@ def new(other) end - # # Creates a relationship between this and the other node. - # Returns self so that we can add several nodes like this: # + # ==== Example + # # n1 = Node.new # Node has declared having a friend type of relationship # n2 = Node.new # n3 = NodeMixin.new @@ -96,6 +99,10 @@ def new(other) # n1.friends.new(n2) # n1.friends.new(n3) # + # ==== Returns + # self + # + # :api: public def <<(other) from, to = @node, other from,to = to,from unless @info[:outgoing] @@ -108,23 +115,15 @@ def <<(other) end - # # Private class # + # :api: private class DepthStopEvaluator include org.neo4j.api.core.StopEvaluator def initialize(depth) -# puts "DEPTH = #{depth} #{depth.class.to_s}" @depth = depth end - -# def self.new(depth) -# if depth.to_sym == :all -# return org.neo4j.api.core.StopEvaluator::END_OF_GRAPH -# end -# super depth -# end def isStopNode(pos) pos.depth >= @depth diff --git a/test/neo4j/relation_spec.rb b/test/neo4j/relation_spec.rb index f8c94bb22..be407b643 100644 --- a/test/neo4j/relation_spec.rb +++ b/test/neo4j/relation_spec.rb @@ -192,13 +192,14 @@ class TestNode end end - describe "traversing nodes of any depth" do + describe "#relations, traversing nodes of a specific depth" do before(:all) do undefine_class :PersonNode class PersonNode include Neo4j::NodeMixin property :name has_n :friends + has_n(:known_by).from(PersonNode, :friends) end @n0 = PersonNode.new @@ -214,28 +215,42 @@ class PersonNode @n112.friends << @n1121 end - it "should be possible with node.friends.depth(2).each" do + it "should be possible with outgoing nodes of depth 2" do nodes = @n1.friends.depth(2) nodes.should include(@n11,@n12,@n112) nodes.should_not include(@n0,@n1,@n1121) end - it "should be possible with node.friends.depth(3).each" do + it "should be possible with outgoing nodes of depth 3" do nodes = @n1.friends.depth(3) nodes.should include(@n11,@n12,@n112, @n1121) nodes.should_not include(@n0,@n1) end - it "should be possible with node.friends.depth(:all).each" do - pending + it "should be possible with outgoing nodes to the end of graph" do nodes = @n1.friends.depth(:all) nodes.should include(@n11,@n12,@n112, @n1121) nodes.should_not include(@n0,@n1) end - it "should get all nodes two levels deep (for levels(2))" do + it "should be possible with incoming nodes of depth 2" do + nodes = @n1.known_by.depth(2) + nodes.should include(@n0) + nodes.to_a.size.should == 1 + + nodes = @n11.known_by.depth(2) + nodes.should include(@n0, @n1) + nodes.to_a.size.should == 2 + + nodes = @n112.known_by.depth(2) + nodes.should include(@n1, @n11) + nodes.to_a.size.should == 2 + end + + + it "should get all nodes two levels deep (for depth(2))" do pending - nodes = @n1.relations.outgoing(:friends).levels(2) + nodes = @n1.relations.outgoing(:friends).depth(2) @n1.friends.levels nodes.should include(@n11,@n12,@n112) nodes.should_not include(@n0,@n1,@n1121) @@ -243,7 +258,7 @@ class PersonNode it "should get all nodes (for levels(:all))" do pending - nodes = @n1.relations.outgoing(:friends).levels(:all) + nodes = @n1.relations.outgoing(:friends).depth(:all) nodes.should include(@n11,@n12,@n112,@n1121) nodes.should_not include(@n0,@n1) end