Add patch for nebulous
Arthur Axel "fREW" Schmidt [Fri, 20 Aug 2010 20:35:00 +0000 (20:35 +0000)]
Changes
lib/DBIx/Class/Tree/AdjacencyList.pm
t/lib/TreeTest.pm

diff --git a/Changes b/Changes
index cf049ba..441e145 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,6 +1,8 @@
 
 Revision history for DBIx::Class::Tree
 
+    - Added ordered ancesors (nebulous)
+
 0.03001 2010-04-25
     - Fixed the parents (note the plural) relationship to
       not have cascade_copy set by default
index 285d5de..d913113 100644 (file)
@@ -21,7 +21,7 @@ Create a table for your tree data.
     name TEXT NOT NULL
   );
 
-In your Schema or DB class add Tree::AdjacencyList to the top 
+In your Schema or DB class add Tree::AdjacencyList to the top
 of the component list.
 
   __PACKAGE__->load_components(qw( Tree::AdjacencyList ... ));
@@ -39,24 +39,24 @@ Thats it, now you can modify and analyze the tree.
 
   #!/usr/bin/perl
   use My::Employee;
-  
+
   my $employee = My::Employee->create({ name=>'Matt S. Trout' });
-  
+
   my $rs = $employee->children();
   my @siblings = $employee->children();
-  
+
   my $parent = $employee->parent();
   $employee->parent( 7 );
 
 =head1 DESCRIPTION
 
-This module provides methods for working with adjacency lists.  The 
-adjacency list model is a very common way of representing a tree structure.  
-In this model each row in a table has a prent ID column that references the 
-primary key of another row in the same table.  Because of this the primary 
-key must only be one column and is usually some sort of integer.  The row 
-with a parent ID of 0 is the root node and is usually the parent of all 
-other rows.  Although, there is no limitation in this module that would 
+This module provides methods for working with adjacency lists.  The
+adjacency list model is a very common way of representing a tree structure.
+In this model each row in a table has a prent ID column that references the
+primary key of another row in the same table.  Because of this the primary
+key must only be one column and is usually some sort of integer.  The row
+with a parent ID of 0 is the root node and is usually the parent of all
+other rows.  Although, there is no limitation in this module that would
 stop you from having multiple root nodes.
 
 =head1 METHODS
@@ -65,13 +65,13 @@ stop you from having multiple root nodes.
 
   __PACKAGE__->parent_column('parent_id');
 
-Declares the name of the column that contains the self-referential 
-ID which defines the parent row.  Defaults to "parent_id".  This 
-will create a has_many (children) and belongs_to (parent) 
+Declares the name of the column that contains the self-referential
+ID which defines the parent row.  Defaults to "parent_id".  This
+will create a has_many (children) and belongs_to (parent)
 relationship.
 
-This method also setups an additional has_many relationship called 
-parents which is useful when you want to treat an adjacency list 
+This method also setups an additional has_many relationship called
+parents which is useful when you want to treat an adjacency list
 as a DAG.
 
 =cut
@@ -134,12 +134,12 @@ __PACKAGE__->mk_classdata( 'repair_tree' => 0 );
   $employee->parent( $parent_obj );
   $employee->parent( $parent_id );
 
-Retrieves the object's parent object, or changes the object's 
-parent to the specified parent or parent ID.  If you would like 
+Retrieves the object's parent object, or changes the object's
+parent to the specified parent or parent ID.  If you would like
 to make the object the root node, just set the parent to 0.
 
-If you are setting the parent then 0 will be returned if the 
-specified parent is already the object's parent and 1 on 
+If you are setting the parent then 0 will be returned if the
+specified parent is already the object's parent and 1 on
 success.
 
 =cut
@@ -171,6 +171,25 @@ sub parent {
     }
     return $self->_parent();
 }
+=head2 ancestors
+
+  @list = $employee->ancestors();
+
+Returns a list of ancestors starting with a record's
+parent and moving toward the tree root.
+
+=cut
+
+sub ancestors {
+    my $self = shift;
+    my @ancestors = ();
+    my $rec = $self;
+    while ($rec = $rec->parent) {
+      push(@ancestors, $rec);
+    }
+    return @ancestors;
+}
+
 
 =head2 has_descendant
 
@@ -200,10 +219,10 @@ sub has_descendant {
   my $parents = $node->parents();
   my @parents = $node->parents();
 
-This has_many relationship is not that useful as it will 
-never return more than one parent due to the one-to-many 
-structure of adjacency lists.  The reason this relationship 
-is defined is so that this tree type may be treated as if 
+This has_many relationship is not that useful as it will
+never return more than one parent due to the one-to-many
+structure of adjacency lists.  The reason this relationship
+is defined is so that this tree type may be treated as if
 it was a DAG.
 
 =head2 children
@@ -211,9 +230,9 @@ it was a DAG.
   my $children_rs = $employee->children();
   my @children = $employee->children();
 
-Returns a list or record set, depending on context, of all 
-the objects one level below the current one.  This method 
-is created when parent_column() is called, which sets up a 
+Returns a list or record set, depending on context, of all
+the objects one level below the current one.  This method
+is created when parent_column() is called, which sets up a
 has_many relationship called children.
 
 =head2 attach_child
@@ -221,8 +240,8 @@ has_many relationship called children.
   $parent->attach_child( $child );
   $parent->attach_child( $child, $child, ... );
 
-Sets the child, or children, to the new parent.  Returns 1 
-on success and returns 0 if the parent object already has 
+Sets the child, or children, to the new parent.  Returns 1
+on success and returns 0 if the parent object already has
 the child.
 
 =cut
@@ -241,7 +260,7 @@ sub attach_child {
   my $rs = $node->siblings();
   my @siblings = $node->siblings();
 
-Returns either a result set or an array of all other objects 
+Returns either a result set or an array of all other objects
 with the same parent as the calling object.
 
 =cut
@@ -265,8 +284,8 @@ sub siblings {
   $obj->attach_sibling( $sibling );
   $obj->attach_sibling( $sibling, $sibling, ... );
 
-Sets the passed in object(s) to have the same parent 
-as the calling object.  Returns 1 on success and 
+Sets the passed in object(s) to have the same parent
+as the calling object.  Returns 1 on success and
 0 if the sibling already has the same parent.
 
 =cut
@@ -316,7 +335,7 @@ sub is_root {
 
   if ($obj->is_branch()) { ... }
 
-Returns 1 if the object has a parent and has children.  
+Returns 1 if the object has a parent and has children.
 Returns 0 otherwise.
 
 =cut
@@ -328,10 +347,10 @@ sub is_branch {
 
 =head2 set_primary_key
 
-This method is an override of DBIx::Class' method for setting the 
-class' primary key column(s).  This method passes control right on 
-to the normal method after first validating that only one column is 
-being selected as a primary key.  If more than one column is then 
+This method is an override of DBIx::Class' method for setting the
+class' primary key column(s).  This method passes control right on
+to the normal method after first validating that only one column is
+being selected as a primary key.  If more than one column is then
 an error will be thrown.
 
 =cut
index 0e66aa6..7af89b3 100644 (file)
@@ -9,7 +9,7 @@ use TreeTest::Schema;
 our $NODE_COUNT = 80;
 
 sub count_tests {
-    my $count = 14;
+    my $count = 17;
     if( TreeTest::Schema::Node->can('position_column') ){
         $count ++;
     }
@@ -51,6 +51,11 @@ sub run_tests {
     ok( ($nodes->find(22)->parents->count()==1), 'node 22 has correct number of parents' );
     ok( (($nodes->find(22)->parents->all())[0]->id()==$nodes->find(22)->parent->id()), 'node 22 parent matches parents' );
 
+    my @ancestors = $nodes->find(44)->ancestors();
+    ok( scalar(@ancestors)==8, 'node 44 has correct number of ancestors' );
+    ok( $ancestors[0]->id == $nodes->find(44)->parent_id, 'node 44\'s first ancestor is its parent' );
+    ok( $ancestors[-1]->name eq 'root', 'node 44\'s last ancestor is root' );
+
     if( TreeTest::Schema::Node->can('position_column') ){
         ok( check_positions(scalar $root->children()), 'positions are correct' );
     }