From: Matt S Trout Date: Mon, 1 Aug 2005 02:22:45 +0000 (+0000) Subject: Slice support for iterators X-Git-Tag: v0.03001~111 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=525035fb51a62462fc675dcb2f25900dcb46f412;p=dbsrgits%2FDBIx-Class.git Slice support for iterators --- diff --git a/lib/DBIx/Class/Cursor.pm b/lib/DBIx/Class/Cursor.pm index 83baa7d..753b6bc 100644 --- a/lib/DBIx/Class/Cursor.pm +++ b/lib/DBIx/Class/Cursor.pm @@ -8,26 +8,53 @@ use overload sub new { my ($it_class, $db_class, $sth, $args, $cols, $attrs) = @_; - $sth->execute(@{$args || []}) unless $sth->{Active}; + #use Data::Dumper; warn Dumper(@_); + $it_class = ref $it_class if ref $it_class; + unless ($sth) { + $sth = $db_class->_get_sth('select', $cols, + $db_class->_table_name, $attrs->{where}); + } my $new = { class => $db_class, sth => $sth, cols => $cols, args => $args, + pos => 0, attrs => $attrs }; return bless ($new, $it_class); } +sub slice { + my ($self, $min, $max) = @_; + my $attrs = { %{ $self->{attrs} || {} } }; + $self->{class}->throw("Can't slice without where") unless $attrs->{where}; + $attrs->{offset} = $min; + $attrs->{rows} = ($max ? ($max - $min + 1) : 1); + my $slice = $self->new($self->{class}, undef, $self->{args}, + $self->{cols}, $attrs); + return (wantarray ? $slice->all : $slice); +} + sub next { my ($self) = @_; + return if $self->{attrs}{rows} + && $self->{pos} >= $self->{attrs}{rows}; # + $self->{attrs}{offset}); + unless ($self->{live_sth}) { + $self->{sth}->execute(@{$self->{args} || []}); + if (my $offset = $self->{attrs}{offset}) { + $self->{sth}->fetchrow_array for 1 .. $offset; + } + $self->{live_sth} = 1; + } my @row = $self->{sth}->fetchrow_array; return unless @row; - #unless (@row) { $self->{sth}->finish; return; } + $self->{pos}++; return $self->{class}->_row_to_object($self->{cols}, \@row); } sub count { my ($self) = @_; + return $self->{attrs}{rows} if $self->{attrs}{rows}; if (my $cond = $self->{attrs}->{where}) { my $class = $self->{class}; my $sth = $class->_get_sth( 'select', [ 'COUNT(*)' ], @@ -52,13 +79,21 @@ sub all { } sub reset { - $_[0]->{sth}->finish if $_[0]->{sth}->{Active}; - $_[0]->{sth}->execute(@{$_[0]->{args} || []}); - return $_[0]; + my ($self) = @_; + $self->{sth}->finish if $self->{sth}->{Active}; + $self->{pos} = 0; + $self->{live_sth} = 0; + return $self; } sub first { return $_[0]->reset->next; } +sub delete_all { + my ($self) = @_; + $_->delete for $self->all; + return 1; +} + 1; diff --git a/lib/DBIx/Class/Table.pm b/lib/DBIx/Class/Table.pm index ed2e86e..e6ba457 100644 --- a/lib/DBIx/Class/Table.pm +++ b/lib/DBIx/Class/Table.pm @@ -15,6 +15,8 @@ __PACKAGE__->mk_classdata('table_alias'); # FIXME: Doesn't actually do anything __PACKAGE__->mk_classdata('_cursor_class' => 'DBIx::Class::Cursor'); +sub iterator_class { shift->_cursor_class(@_) } + =head1 NAME DBIx::Class::Table - Basic table methods diff --git a/t/cdbi-t/12-filter.t b/t/cdbi-t/12-filter.t index bce6e6f..7132a54 100644 --- a/t/cdbi-t/12-filter.t +++ b/t/cdbi-t/12-filter.t @@ -125,7 +125,7 @@ test_normal_iterator; test_normal_iterator; SKIP: { - skip "dbic iterators don't support slice yet", 12; + #skip "dbic iterators don't support slice yet", 12; { @@ -149,7 +149,9 @@ SKIP: { package Class::DBI::My::Iterator; -use base 'Class::DBI::Iterator'; +use vars qw/@ISA/; + +@ISA = ($it_class); sub slice { qw/fred barney/ } diff --git a/t/cdbi-t/13-constraint.t b/t/cdbi-t/13-constraint.t new file mode 100644 index 0000000..c25227a --- /dev/null +++ b/t/cdbi-t/13-constraint.t @@ -0,0 +1,113 @@ +use strict; +use Test::More; + +BEGIN { + eval "use DBD::SQLite"; + plan $@ ? (skip_all => 'needs DBD::SQLite for testing') : (tests => 23); +} + +use lib 't/testlib'; +use Film; + +sub valid_rating { + my $value = shift; + my $ok = grep $value eq $_, qw/U Uc PG 12 15 18/; + return $ok; +} + +Film->add_constraint('valid rating', Rating => \&valid_rating); + +my %info = ( + Title => 'La Double Vie De Veronique', + Director => 'Kryzstof Kieslowski', + Rating => '18', +); + +{ + local $info{Title} = "nonsense"; + local $info{Rating} = 19; + eval { Film->create({%info}) }; + ok $@, $@; + ok !Film->retrieve($info{Title}), "No film created"; + is(Film->retrieve_all, 0, "So no films"); +} + +ok(my $ver = Film->create({%info}), "Can create with valid rating"); +is $ver->Rating, 18, "Rating 18"; + +ok $ver->Rating(12), "Change to 12"; +ok $ver->update, "And update"; +is $ver->Rating, 12, "Rating now 12"; + +eval { + $ver->Rating(13); + $ver->update; +}; +ok $@, $@; +is $ver->Rating, 12, "Rating still 12"; +ok $ver->delete, "Delete"; + +# this threw an infinite loop in old versions +Film->add_constraint('valid director', Director => sub { 1 }); +my $fred = Film->create({ Rating => '12' }); + +# this test is a bit problematical because we don't supply a primary key +# to the create() and the table doesn't use auto_increment or a sequence. +ok $fred, "Got fred"; + +{ + ok +Film->constrain_column(rating => [qw/U PG 12 15 19/]), + "constraint_column"; + my $narrower = eval { Film->create({ Rating => 'Uc' }) }; + like $@, qr/fails.*constraint/, "Fails listref constraint"; + my $ok = eval { Film->create({ Rating => 'U' }) }; + is $@, '', "Can create with rating U"; + SKIP: { + skip "No column objects", 2; + ok +Film->find_column('rating')->is_constrained, "Rating is constrained"; + ok +Film->find_column('director')->is_constrained, "Director is not"; + } +} + +{ + ok +Film->constrain_column(title => qr/The/), "constraint_column"; + my $inferno = eval { Film->create({ Title => 'Towering Infero' }) }; + like $@, qr/fails.*constraint/, "Can't create towering inferno"; + my $the_inferno = eval { Film->create({ Title => 'The Towering Infero' }) }; + is $@, '', "But can create THE towering inferno"; +} + +{ + + sub Film::_constrain_by_untaint { + my ($class, $col, $string, $type) = @_; + $class->add_constraint( + untaint => $col => sub { + my ($value, $self, $column_name, $changing) = @_; + $value eq "today" ? $changing->{$column_name} = "2001-03-03" : 0; + } + ); + } + eval { Film->constrain_column(codirector => Untaint => 'date') }; + is $@, '', 'Can constrain with untaint'; + my $freeaa = + eval { Film->create({ title => "The Freaa", codirector => 'today' }) }; + is $@, '', "Can create codirector"; + is $freeaa->codirector, '2001-03-03', "Set the codirector"; +} + +__DATA__ + +use CGI::Untaint; + +sub _constrain_by_untaint { + my ($class, $col, $string, $type) = @_; + $class->add_constraint(untaint => $col => sub { + my ($value, $self, $column_name, $changing) = @_; + my $h = CGI::Untaint->new({ %$changing }); + return unless my $val = $h->extract("-as_$type" => $column_name); + $changing->{$column_name} = $val; + return 1; + }); +} + diff --git a/t/cdbi-t/21-iterator.t b/t/cdbi-t/21-iterator.t index 7a88f43..d029bab 100644 --- a/t/cdbi-t/21-iterator.t +++ b/t/cdbi-t/21-iterator.t @@ -45,7 +45,7 @@ my @film = ( } SKIP: { - skip "Iterator doesn't yet have slice support", 19; + #skip "Iterator doesn't yet have slice support", 19; { my $it = Film->retrieve_all;