[Catalyst] Adjacency list "trees" and DBIC (recursion fun)

Jess Robinson castaway at desert-island.demon.co.uk
Fri Dec 15 18:04:29 GMT 2006



On Thu, 14 Dec 2006, Dylan Vanderhoof wrote:

> Hello all,
> 	I have a bit of a niche question, but maybe somebody has run
> into this.
> My environment is Catalyst (latest stable), DBIx::Class and TT.  Below
> is a table description and some chunk of code I'm actually using with
> altered names.
>
> I'm wanting to traverse the tree and just have debug statements to tell
> me what node I found and what order the node is.
> However, when running, it seems to recurse endlessly, which isn't
> happening in my pure-perl/DBI version.  I'm guessing there's something
> about DBIC I'm running into that's making this not work and there should
> be a better approach.  Anybody have any suggestions?  =)
>
> (I put this on the Cat list because I'll almost certainly follow up with
> some Catalyst/TT questions, but I can punt it to the DBIC list if that
> makes more sens.)
>
> Thanks,
> Dylan
>
> ---------------------------------------
> Table structure and code follows
>
> I have a self-referencing table that forms a tree using an adjacency
> list, more or less of the format:
>
>
> Table Foo:
>
> id int not null pk
> parent int fk referencing self.id
> is_leaf boolean
> [data columns]
>
>
> A null parent is a root, and any node where is_leaf is true is the end
> of a branch.
>
>
> My DBIC config has (among other things):
>
> __PACKAGE__->has_many(
>  "foo",
>  "MyApp::Schema::Foo",
>  { "foreign.parent" => "self.id" },
> );
>
>
> My thought was that I should be able to do:
>
>
>
> sub someroutine : Whatever {
>
> $rs = $schema->resultset('Foo')->search( { parent => undef } ); # root
> nodes
>
> while( $root_node = $rs->next ) {
>   if( $root_node->leaf_node == 0 ) {
>       $c->log->debug("Root is a left, stopping");
>   } else {
>       while ( $child = $root_node->foo->next ) {
>           traverse_tree( $c, $root_node, $child, 2);
>       }
>   }
> }

What's happening here is that everytime you call ->foo->next, it's 
creating your a NEW resultset, and next returns the first item in it, 
always. DBIx::Class doesnt keep track of the resultsets it creates for 
you, you need to do that yourself (i.r. assign ->foo to a variable, and 
call next on that). This is basically to lessen the problem of references 
hanging around in DBIC and not getting garbage collected properly.

>
> sub traverse_tree {
>    my $c = shift;
>    my $parent = shift;
>    my $child = shift;
>    my $order = shift;
>    my $next_child;
>
>    if( $child->leaf_node == 0 )
>    {
>        $c->log->debug( "Got order $order child: " . $child->description
> );
>        while( $next_child = $child->foo->next ) {
>            build_tree( $c, $child, $next_child, $order + 1 );
>        }
>    } else {
>        $c->log->debug( "Got order $order child (leaf): " .
> $child->description );
>    }
> }
>
> _______________________________________________
> List: Catalyst at lists.rawmode.org
> Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
> Searchable archive: http://www.mail-archive.com/catalyst@lists.rawmode.org/
> Dev site: http://dev.catalyst.perl.org/
>
>

Jess



More information about the Catalyst mailing list