my $position_column = $self->position_column;
$self->set_column( $position_column => $self->result_source->resultset->search( {$self->_collection_clause()} )->count()+1 )
if (!$self->get_column($position_column));
- $self->next::method( @_ );
+ return $self->next::method( @_ );
}
=head2 delete
sub delete {
my $self = shift;
$self->move_last;
- $self->next::method( @_ );
+ return $self->next::method( @_ );
}
=head1 PRIVATE METHODS
Declares the name of the column that contains the self-referential
ID which defines the parent row. Defaults to "parent_id".
+If you are useing the Positioned component then this parent_column
+will automatically be used as the collection_column.
+
=cut
__PACKAGE__->mk_classdata( 'parent_column' => 'parent_id' );
$new_parent = $new_parent->id() || 0;
}
return 0 if ($new_parent == ($self->get_column($parent_column)||0));
- my $positioned = $self->can('position_column');
- $self->move_last if ($positioned);
+ my $is_positioned = $self->isa('DBIx::Class::Positioned');
+ $self->move_last() if ($is_positioned);
$self->set_column( $parent_column => $new_parent );
- if ($positioned) {
+ if ($is_positioned) {
$self->set_column(
- $self->position_column() => $self->search( {$self->_parent_clause()} )->count() + 1
+ $self->position_column() => $self->search( {$self->_collection_clause()} )->count() + 1
);
}
$self->update();
my( $self ) = @_;
my $rs = $self->search(
{ $self->parent_column()=>$self->id() },
- ( $self->can('position_column') ? {order_by=>$self->position_column()} : () )
+ ( $self->isa('DBIx::Class::Position') ? {order_by=>$self->position_column()} : () )
);
return $rs->all() if (wantarray());
return $rs;
}
-=head2 descendents
-
-Same as children. Declared so that this module is
-compatible with the Tree::NestedSet module.
-
-=cut
-
-#*descendants = \&children;
-
=head1 PRIVATE METHODS
These methods are used internally. You should never have the
need to use them.
-=head2 _parent_clause
+=head2 _collection_clause
This method is provided as an override of the method in
-DBIC::Positioned. This way Positioned and Tree::AdjacencyList
+DBIx::Class::Positioned. This way Positioned and Tree::AdjacencyList
may be used together without conflict. Make sure that in
-you component list that you load Tree::AdjacencyList before you
+your component list that you load Tree::AdjacencyList before you
load Positioned.
-This method assumes a parent ID of 0 if none is defined. This
-usually comes in to play if you are just createing the object
-and it has not yet been assigned a parent.
-
=cut
-sub _parent_clause {
+sub _collection_clause {
my( $self ) = @_;
return (
$self->parent_column() =>
=head1 AUTHOR
-Aran Deltac <bluefeet@cpan.org>
+Aran Clary Deltac <bluefeet@cpan.org>
=head1 LICENSE
--- /dev/null
+use Test::More;
+use lib qw(t/lib);
+use DBICTest;
+use DBICTest::HelperRels;
+
+require "t/run/27adjacency_list.tl";
+run_tests(DBICTest->schema);
Artist
Employee::Positioned
Employee::AdjacencyList
- Employee::PositionedAdjacencyList
CD
#dummy
Track
__PACKAGE__->load_components(qw(
Tree::AdjacencyList
+ Positioned
PK::Auto
Core
));
},
parent_id => {
data_type => 'integer',
+ },
+ position => {
+ data_type => 'integer',
is_nullable => 1,
},
name => {
__PACKAGE__->set_primary_key('employee_id');
__PACKAGE__->parent_column('parent_id');
+__PACKAGE__->position_column('position');
__PACKAGE__->mk_classdata('field_name_for', {
employee_id => 'primary key',
parent_id => 'parent id',
+ position => 'list order',
name => 'employee name',
});
+++ /dev/null
-package # hide from PAUSE
- DBICTest::Schema::Employee::PositionedAdjacencyList;
-
-use base 'DBIx::Class';
-
-__PACKAGE__->load_components(qw(
- Tree::AdjacencyList
- Positioned
- PK::Auto
- Core
-));
-
-__PACKAGE__->table('employees_positioned_adjacencylist');
-
-__PACKAGE__->add_columns(
- employee_id => {
- data_type => 'integer',
- is_auto_increment => 1
- },
- parent_id => {
- data_type => 'integer',
- is_nullable => 1,
- },
- position => {
- data_type => 'integer',
- },
- name => {
- data_type => 'varchar',
- size => 100,
- is_nullable => 1,
- },
-);
-
-__PACKAGE__->set_primary_key('employee_id');
-__PACKAGE__->position_column('position');
-__PACKAGE__->parent_column('parent_id');
-
-__PACKAGE__->mk_classdata('field_name_for', {
- employee_id => 'primary key',
- parent_id => 'parent id',
- position => 'list position',
- name => 'employee name',
-});
-
-1;
--
-- Created by SQL::Translator::Producer::SQLite
--- Created on Thu Mar 23 11:13:18 2006
+-- Created on Thu Mar 23 19:41:26 2006
--
BEGIN TRANSACTION;
--
+-- Table: serialized
+--
+CREATE TABLE serialized (
+ id INTEGER PRIMARY KEY NOT NULL,
+ serialized text NOT NULL
+);
+
+--
-- Table: employees_positioned
--
CREATE TABLE employees_positioned (
);
--
--- Table: serialized
---
-CREATE TABLE serialized (
- id INTEGER PRIMARY KEY NOT NULL,
- serialized text NOT NULL
-);
-
---
--- Table: cd_to_producer
+-- Table: employees_adjacencylist
--
-CREATE TABLE cd_to_producer (
- cd integer NOT NULL,
- producer integer NOT NULL,
- PRIMARY KEY (cd, producer)
+CREATE TABLE employees_adjacencylist (
+ employee_id INTEGER PRIMARY KEY NOT NULL,
+ parent_id integer NOT NULL,
+ position integer,
+ name varchar(100)
);
--
);
--
--- Table: employees_adjacencylist
+-- Table: cd_to_producer
--
-CREATE TABLE employees_adjacencylist (
- employee_id INTEGER PRIMARY KEY NOT NULL,
- parent_id integer,
- name varchar(100)
+CREATE TABLE cd_to_producer (
+ cd integer NOT NULL,
+ producer integer NOT NULL,
+ PRIMARY KEY (cd, producer)
);
--
);
--
--- Table: employees_positioned_adjacencylist
---
-CREATE TABLE employees_positioned_adjacencylist (
- employee_id INTEGER PRIMARY KEY NOT NULL,
- parent_id integer,
- position integer NOT NULL,
- name varchar(100)
-);
-
---
-- Table: self_ref_alias
--
CREATE TABLE self_ref_alias (
);
--
--- Table: treelike
+-- Table: self_ref
--
-CREATE TABLE treelike (
+CREATE TABLE self_ref (
id INTEGER PRIMARY KEY NOT NULL,
- parent integer NOT NULL,
name varchar(100) NOT NULL
);
);
--
--- Table: self_ref
+-- Table: treelike
--
-CREATE TABLE self_ref (
+CREATE TABLE treelike (
id INTEGER PRIMARY KEY NOT NULL,
+ parent integer NOT NULL,
name varchar(100) NOT NULL
);
);
--
+-- Table: producer
+--
+CREATE TABLE producer (
+ producerid INTEGER PRIMARY KEY NOT NULL,
+ name varchar(100) NOT NULL
+);
+
+--
-- Table: onekey
--
CREATE TABLE onekey (
cd integer NOT NULL
);
---
--- Table: producer
---
-CREATE TABLE producer (
- producerid INTEGER PRIMARY KEY NOT NULL,
- name varchar(100) NOT NULL
-);
-
COMMIT;
--- /dev/null
+# vim: filetype=perl
+
+sub run_tests {
+
+ plan tests => 5;
+ my $schema = shift;
+
+ my $employees = $schema->resultset('Employee::AdjacencyList');
+ $employees->delete();
+
+ my $grandma = $employees->create({ name=>'grandma', parent_id=>0 });
+ foreach (1..15) {
+ $employees->create({ name=>'temp', parent_id=>$grandma->id() });
+ }
+ ok( ($grandma->children->count()==15), 'grandma children' );
+
+ my $mom = ($grandma->children->search(undef,{rows=>1})->all())[0];
+ foreach (1..5) {
+ ($grandma->children->search(undef,{rows=>1})->all())[0]->parent( $mom );
+ }
+ ok( ($mom->children->count()==5), 'mom children' );
+ ok( ($grandma->children->count()==10), 'grandma children' );
+
+ $mom = ($grandma->children->search(undef,{rows=>2})->all())[0];
+ foreach (1..4) {
+ ($grandma->children->search(undef,{rows=>1})->all())[0]->parent( $mom );
+ }
+ ok( ($mom->children->count()==4), 'mom children' );
+ ok( ($grandma->children->count()==6), 'grandma children' );
+
+ ok( check_rs( scalar $grandma->children() ), 'correct positions' );
+}
+
+sub check_rs {
+ my( $rs ) = @_;
+ $rs->reset();
+ my $position_column = $rs->result_class->position_column();
+ my $expected_position = 0;
+ while (my $row = $rs->next()) {
+ $expected_position ++;
+ if ($row->get_column($position_column)!=$expected_position) {
+ return 0;
+ }
+ my $children = $row->children();
+ while (my $child = $children->next()) {
+ return 0 if (!check_rs( scalar $child->children() ));
+ }
+ }
+ return 1;
+}
+
+1;