NAME
    DBIx::Class::MaterializedPath - efficiently retrieve and search trees
    with DBIx::Class

VERSION
    version 0.001001

SYNOPSIS
     package A::Schema::Result::Category;

     use strict;
     use warnings;

     use base 'DBIx::Class::Core';

     __PACKAGE__->table('category');

     __PACKAGE__->load_components('MaterializedPath');

     __PACKAGE__->add_columns(
        id => {
           data_type => 'int',
           is_auto_increment => 1,
        },

        parent_id => {
           data_type => 'int',
           is_nullable => 1, # root
        },

        parent_path => {
           data_type => 'varchar',
           size      => 256,
           is_nullable => 1,
        },

        name => {
           data_type => 'varchar',
           size      => 256,
        },
     );

     __PACKAGE__->set_primary_key('id');

     __PACKAGE__->belongs_to(
       parent_category => 'A::Schema::Result::Category', 'parent_id'
     );

     __PACKAGE__->has_many(
       child_categories => 'A::Schema::Result::Category', 'parent_id'
     );

     sub materialized_path_columns {
        return {
           parent => {
              parent_column                => 'parent_id',
              parent_fk_column             => 'id',
              materialized_path_column     => 'parent_path',
              include_self_in_path         => 1,
              include_self_in_reverse_path => 1,
              separator                    => '/',
              parent_relationship          => 'parent_category',
              children_relationship        => 'child_categories',
              full_path                    => 'ancestors',
              reverse_full_path            => 'descendants',
           },
        }
     }

     1;

    Elsewhere...

     my $child_rows = $row->descendants;

    or better yet

     my $awesome_kids = $rs->search({ awesome => 1 })
       ->related_resultset('descendants');

DESCRIPTION
    Materialized path
    <https://communities.bmc.com/communities/docs/DOC-9902> is a way to
    store trees in relational databases that results in very efficient
    retrieval, at the expense of space and more write-time queries.

    This module makes using matpaths easy. The interface is somewhat
    unusual, but the benefit is that it creates actual relationships for the
    both directions of the tree, allowing you to use the powerful querying
    DBIx::Class already gives you.

    The first strange part of the interface is that the call to
    "load_components" must come after the call to "table". The next strange
    bit is that the way you define all of the metadata about your matpath is
    by defining a subroutine called "materialized_path_columns". The
    subroutine must return a hashref where the key is name of your path
    (currently unused) and the value is the metadata for the path. Here are
    the parts that need to be defined in the metadata:

    * "parent_column" - the column that points directly to the parent row,
      for example "parent_id".

    * "parent_fk_column" - the column that "parent_column" points to, for
      example "id".

    * "materialized_path_column" - the column that contains the materialized
      path. One thing to note here is that the width of the column defines
      how deep your tree can be. For example if the number of digits for
      most of your "id"'s is three, and your materialized path column is 255
      characters wide, you can support a depth of something like 63 levels,
      because each level in the tree is "q(/) . "$id"", so "255/4 ~~ 63". An
      example for this might be "parent_materialized_path".

    * "parent_relationship" - the direct relationship to your parent row

    * "children_relationship" - the direct relationship to your child rows

    * "full_path" - the name of the relationship that this materialized path
      will define for all parents. For example, "ancestry".

    * "reverse_full_path" - the name of the relationship that this
      materialized path will define for all children. For example,
      "descendants".

    * "include_self_in_path" - (optional) I've found that it's often helpful
      to include the current row in the full ancestry. For example if your
      path is a for categorization system you probably want to turn this on.

    * "include_self_in_reverse_path" - (optional) see above, but for chilren
      instead of parents

    * "separator" - (optional) defaults to "/". If you don't know what this
      is for just ignore it.

AUTHOR
    Arthur Axel "fREW" Schmidt <frioux+cpan@gmail.com>

COPYRIGHT AND LICENSE
    This software is copyright (c) 2012 by Arthur Axel "fREW" Schmidt.

    This is free software; you can redistribute it and/or modify it under
    the same terms as the Perl 5 programming language system itself.

