Re: Better handling of constraint failures?
[prev]
[thread]
[next]
[Date index for 2004/08/12]
On Thu, 2004-08-12 at 16:04, Clayton L. Scott wrote:
> On Thu, 12 Aug 2004, Daniel Collis Puro wrote:
>
> > Folks,
> >
> > Here's the solution I came up with: Is this something that can make it
> > into Class::DBI proper?
>
> [snip]
>
> This looks interesting but I don't understand it without the docs to go
> with it. can you create an example as a part of the Album/Artist
> schema?
>
>
> Clayton
Here you go. The only change I'm asking to go into Class::DBI is
putting more information into croak() when an exception is thrown
related to constraints. If you don't override _croak() the only
difference will be that %info gets populated behind your back.
I'm assuming below that Class::DBI includes the changes to
add_constraint that I enumerated in my previous email.
This is how I would like to use the more informational exceptions, which
will essentially allow a programmer to use CDBI constraint failure as
triggers to redisplay the entry method (HTML in my case) with specific
messages.
package Music::DBI;
use base 'Class::DBI';
Music::DBI->connection('dbi:mysql:dbname', 'username', 'password');
################################################################################
#Special, super-duper overridden croak to catch these
#"special" exceptions.
sub _croak {
my ($self, $message, %info) = @_;
Carp::croak(@_) if(not %info);
if ($info{exception_type} eq 'constraint_failure') {
$self->{__constraint_errors}->{$info{column}}=\%info;
} else {
Carp::croak(@_);
}
}
########################################
package Music::Artist;
use base 'Music::DBI';
Music::Artist->table('artist');
Music::Artist->columns(All => qw/artistid name/);
Music::Artist->has_many(cds => 'Music::CD');
package Music::CD;
use base 'Music::DBI';
Music::CD->table('cd');
Music::CD->columns(All => qw/cdid artist title year/);
Music::CD->has_many(tracks => 'Music::Track');
Music::CD->has_a(artist => 'Music::Artist');
Music::CD->has_a(reldate => 'Time::Piece',
inflate => sub { Time::Piece->strptime(shift, "%Y-%m-%d") },
deflate => 'ymd',
);
################################################################################
#Contrived. It doesn't matter for this example, really.
Music::CD->add_constraint('valid title',title=>
sub{
return 1 if (! $_[0]);
});
########################################
Music::CD->might_have(liner_notes => LinerNotes => qw/notes/);
package Music::Track;
use base 'Music::DBI';
Music::Track->table('track');
Music::Track->columns(All => qw/trackid cd position title/);
#-- Meanwhile, in a nearby piece of code! --#
my $artist = Music::Artist->create({ artistid => 1, name => 'U2' });
my $cd = $artist->add_to_cds({
cdid => 1,
title => 'October',
year => 1980,
});
# Oops, got it wrong.
$cd->year(1981);
################################################################################
#Get the hash of errors we created in the overridden _croak().
#If there aren't errors, update. If there are,
#use the more specific information to redisplay the form
#with more "intelligent" error messages.
#It would be better to get the constraint errors via a method. . .
my $constraint_errors=$cd->{__constraint_errors};
my @columns=$cd->columns();
if (not %$constraint_errors) {
$cd->update;
} else {
my @columns=$cd->columns();
foreach my $column(@columns) {
if ($constraint_errors->{$column}) {
print "$column had an error. Please correct it!\n";
#And redisplay HTML form, or set a variable to cause the
#form to be redisplayed.
}
}
}
########################################
# etc.
foreach my $track ($cd->tracks) {
print $track->position, $track->title
}
$cd->delete; # also deletes the tracks
my $cd = Music::CD->retrieve(1);
my @cds = Music::CD->retrieve_all;
my @cds = Music::CD->search(year => 1980);
my @cds = Music::CD->search_like(title => 'October%');
--
Dan Collis Puro
Chief Engineer
GeekUprising Internet Consultants
http://www.geekuprising.com
dan@xxxxxxxxxxxx.xxx
781-775-3942