Class-DBI

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN


  - constrain_column can now take subref constraint
  - Document DBD::AnyData and FreeTDS issues (Matt Trout)
  - Factor out database error handling to _db_error()
  - Switch to Class::Accessor::Fast in Column and Relationship 

3.0.5 Sep 14 2005

  - has_many can take compile time constraints (Cees Hek)
  - has_many can take a cascading delete strategy (deprecating the old,
    undocumented, 'no_cascade_delete' option)
  - columns() can take Class::DBI::Column objects directly
    which can now in turn take options, thus allowing things like:
      __PACKAGE__->columns(dates => Class::DBI::Column->new(
        tdate => { placeholder => 'IF(1, CURDATE(), ?)' }
      )

3.0.4 Sep 13 2005

  Pre-Reqs
    - Note requirement for Scalar::Util 1.08+ (for refaddr)

Changes  view on Meta::CPAN

      off caching if required) [gfalck]
    - We now warn about column names clashing with any inherited methods,
      not just ones defined in Class::DBI itself [Dan Thill]
    - Silence some test warnings reported by Paul Makepeace

0.94  Wed Aug 27 2003

  New Functionality
    - allow has_a() columns to hold NULL values (Dominic Mitchell)
    - cascading deletions can be turned off by passing argument to
      has_many setup: no_cascade_delete => 1 (undocumented/untested)
      [now implemented as a trigger]
    - classes and objects can be marked as read_only (experimental and
      undocumented, although tested)

  Documentation
    - no longer refer to Class::DBI::Join, which is dead
    - warn about inflating a primary key using has_a
    - rewrite of docs on transactions
    - numerous small tweaks from Jay Strauss, Alexander Karelas and Brad
      Bowman

Changes  view on Meta::CPAN


0.34  Sat Oct  6 2001
    - Don't die if a value is a reference. (Ima::DBI does this for us,
       and better in case of overloaded objects)
    - fix minor problem with mutual hasa / hasa_list referencing
    - better diagnostics if hasa_list is miscalled

0.33  Sat Sep 15 2001
    + Added create_filter(), and with it retrieve_all()
    + added docs on how to set-up many-to-many relationships
    + _cascade delete now split out to allow overriding
    + copy() and move() can now take multiple arguments to change
       (thanks to Jonathan Swartz)

0.32  Sun Sep  9 2001
    + delete() now removes any foreign elements, to avoid orphans

0.31  Sun Sep  9 2001
    + split out _column_placeholder (thanks to Jonathan Swartz)
    + added hasa() checks for orphaned rows

MANIFEST  view on Meta::CPAN

t/12-filter.t
t/13-constraint.t
t/14-might_have.t
t/15-accessor.t
t/16-reserved.t
t/17-data_type.t
t/18-has_a.t
t/19-set_sql.t
t/21-iterator.t
t/22-deflate_order.t
t/23-cascade.t
t/24-meta_info.t
t/25-closures_in_meta.t
t/26-mutator.t
t/27-mutator-old.t
t/97-pod.t
t/98-failure.t
t/99-misc.t
t/testlib/Actor.pm
t/testlib/Binary.pm
t/testlib/Blurb.pm

README  view on Meta::CPAN

    Deletes this object from the database and from memory. If you have set
    up any relationships using "has_many" or "might_have", this will delete
    the foreign elements also, recursively (cascading delete). $obj is no
    longer usable after this call.

    Multiple objects can be deleted by calling delete_all on the Iterator
    returned from a search. Each object found will be deleted in turn, so
    cascading delete and other triggers will be honoured.

    The "before_delete" trigger is when an object instance is about to be
    deleted. It is invoked before any cascaded deletes. The "after_delete"
    trigger is invoked after the record has been deleted from the database
    and just before the contents in memory are discarded.

RETRIEVING OBJECTS
    Class::DBI provides a few very simple search methods.

    It is not the goal of Class::DBI to replace the need for using SQL.
    Users are expected to write their own searches for more complex cases.

    Class::DBI::AbstractSearch, available on CPAN, provides a much more

README  view on Meta::CPAN


      sub styles { 
        my $self = shift;
        return map $_->style, $self->_style_refs;
      }

    For an example of where this is useful see "MANY TO MANY RELATIONSHIPS"
    below.

   Cascading Delete
      Music::Artist->has_many(cds => 'Music::CD', { cascade => 'Fail' });

    It is also possible to control what happens to the 'child' objects when
    the 'parent' object is deleted. By default this is set to 'Delete' - so,
    for example, when you delete an artist, you also delete all their CDs,
    leaving no orphaned records. However you could also set this to 'None',
    which would leave all those orphaned records (although this generally
    isn't a good idea), or 'Fail', which will throw an exception when you
    try to delete an artist that still has any CDs.

    You can also write your own Cascade strategies by supplying a Class Name
    here.

    For example you could write a Class::DBI::Cascade::Plugin::Nullify which
    would set all related foreign keys to be NULL, and plug it into your
    relationship:

      Music::Artist->has_many(cds => 'Music::CD', { 
        cascade => 'Class::DBI::Cascade::Plugin::Nullify' 
      });

  might_have
      Music::CD->might_have(method_name => Class => (@fields_to_import));

      Music::CD->might_have(liner_notes => LinerNotes => qw/notes/);

      my $liner_notes_object = $cd->liner_notes;
      my $notes = $cd->notes; # equivalent to $cd->liner_notes->notes;

lib/Class/DBI.pm  view on Meta::CPAN

Deletes this object from the database and from memory. If you have set up
any relationships using C<has_many> or C<might_have>, this will delete
the foreign elements also, recursively (cascading delete).  $obj is no
longer usable after this call.

Multiple objects can be deleted by calling delete_all on the Iterator
returned from a search. Each object found will be deleted in turn,
so cascading delete and other triggers will be honoured.

The C<before_delete> trigger is when an object instance is about to be
deleted. It is invoked before any cascaded deletes.  The C<after_delete>
trigger is invoked after the record has been deleted from the database
and just before the contents in memory are discarded.

=head1 RETRIEVING OBJECTS

Class::DBI provides a few very simple search methods. 

It is not the goal of Class::DBI to replace the need for using SQL. Users
are expected to write their own searches for more complex cases.

lib/Class/DBI.pm  view on Meta::CPAN

  sub styles { 
    my $self = shift;
    return map $_->style, $self->_style_refs;
  }

For an example of where this is useful see L<"MANY TO MANY RELATIONSHIPS">
below.

=head3 Cascading Delete
    
  Music::Artist->has_many(cds => 'Music::CD', { cascade => 'Fail' });

It is also possible to control what happens to the 'child' objects when
the 'parent' object is deleted. By default this is set to 'Delete' - so,
for example, when you delete an artist, you also delete all their CDs,
leaving no orphaned records. However you could also set this to 'None',
which would leave all those orphaned records (although this generally
isn't a good idea), or 'Fail', which will throw an exception when you
try to delete an artist that still has any CDs.

You can also write your own Cascade strategies by supplying a Class
Name here.

For example you could write a Class::DBI::Cascade::Plugin::Nullify
which would set all related foreign keys to be NULL, and plug it into
your relationship:

  Music::Artist->has_many(cds => 'Music::CD', { 
    cascade => 'Class::DBI::Cascade::Plugin::Nullify' 
  });

=head2 might_have

  Music::CD->might_have(method_name => Class => (@fields_to_import));

  Music::CD->might_have(liner_notes => LinerNotes => qw/notes/);

  my $liner_notes_object = $cd->liner_notes;
  my $notes = $cd->notes; # equivalent to $cd->liner_notes->notes;

lib/Class/DBI/Cascade/Delete.pm  view on Meta::CPAN

This is a Cascading Delete strategy that will delete any related
objects.

=cut

use strict;
use warnings;

use base 'Class::DBI::Cascade::None';

sub cascade {
	my ($self, $obj) = @_;
	$self->foreign_for($obj)->delete_all;
}

1;

lib/Class/DBI/Cascade/Fail.pm  view on Meta::CPAN

package Class::DBI::Cascade::Fail;

=head1 NAME

Class::DBI::Cascade::Fail - Do not cascade if foreign objects exist

=head1 DESCRIPTION

This is a Cascading Delete strategy that will throw an error if any
object about to be deleted still has any other objects pointing at it.

=cut

use strict;
use warnings;

use base 'Class::DBI::Cascade::None';

sub cascade {
	my ($self, $obj) = @_;
	my $refs = $self->foreign_for($obj)->count or return;
	$self->{_rel}->foreign_class->_croak(
		"$refs objects still refer to $obj. Deletion failed");
}

1;

lib/Class/DBI/Cascade/None.pm  view on Meta::CPAN

=head1 METHODS

=head2 foreign_for

	my $iterator = $strategy->foreign_for($obj);

This will return all the objects which are foreign to $obj across the
relationship. It's a normal Class::DBI search you can get the results
either as a list or as an iterator.

=head2 cascade

	$strategy->cascade($obj);

Cascade across the related objects to $obj.

=head1 WRITING NEW STRATEGIES

Creating a Cascade strategy should be fairly simple. You usually just
need to inherit from here, and then supply a cascade() method that does
the required thing with the results from foreign_for().

So, for example, Cascade::Delete is implemented simply as:

	package Class::DBI::Cascade::Delete;

	use base 'Class::DBI::Cascade::None';

	sub cascade {
		my ($self, $obj) = @_;
		$self->foreign_for($obj)->delete_all;
	}

=cut

use strict;
use warnings;

sub new {
	my ($class, $rel) = @_;
	bless { _rel => $rel } => $class;
}

sub foreign_for {
	my ($self, $obj) = @_;
	return $self->{_rel}
		->foreign_class->search($self->{_rel}->args->{foreign_key} => $obj->id);
}

sub cascade { return; }

1;

lib/Class/DBI/Relationship/HasMany.pm  view on Meta::CPAN


sub _set_up_class_data {
	my $self = shift;
	$self->class->_extend_class_data(
		__hasa_list => $self->foreign_class => $self->args->{foreign_key});
	$self->SUPER::_set_up_class_data;
}

sub triggers {
	my $self = shift;
	if ($self->args->{no_cascade_delete}) {    # old undocumented way
		warn "no_cascade_delete deprecated in favour of cascade => None";
		return;
	}
	my $strategy = $self->args->{cascade} || "Delete";
	$strategy = "Class::DBI::Cascade::$strategy" unless $strategy =~ /::/;

	$self->foreign_class->_require_class($strategy);
	$strategy->can('cascade')
		or return $self->_croak("$strategy is not a valid Cascade Strategy");
	my $strat_obj = $strategy->new($self);
	return (before_delete => sub { $strat_obj->cascade(@_) });
}

sub methods {
	my $self     = shift;
	my $accessor = $self->accessor;
	return (
		$accessor          => $self->_has_many_method,
		"add_to_$accessor" => $self->_method_add_to,
	);
}

t/10-mysql.t  view on Meta::CPAN

	ok MyStar->has_many(filmids => [ MyStarLink => 'film', 'id' ]),
		"**** Multi-map";
	my @filmid = $s1->filmids;
	ok !ref $filmid[0], "Film-id is not a reference";

	my $first = $s1->filmids->first;
	ok !ref $first, "First is not a reference";
	is $first, $filmid[0], "But it's the same as filmid[0]";
}

{    # cascades correctly
	my $lenin  = MyFilm->insert({ title    => "Leningrad Cowboys Go America" });
	my $pimme  = MyStar->insert({ name     => "Pimme Korhonen" });
	my $cowboy = MyStarLink->insert({ film => $lenin, star => $pimme });
	$lenin->delete;
	is MyStar->search(name => 'Pimme Korhonen')->count, 1, "Pimme still exists";
	is MyStarLink->search(star => $pimme->id)->count, 0, "But in no films";
}

{
	ok MyStar->has_many(filmids_mcpk => [ MyStarLinkMCPK => 'film', 'id' ]),

t/14-might_have.t  view on Meta::CPAN

	is $bt->blurb, $info->blurb, "Blurb is the same as fetching the long way";
	ok $bt->blurb("New blurb"), "We can set the blurb";
	$bt->update;
	is $bt->blurb, $info->blurb, "Blurb has been set";

	$bt->rating(18);
	eval { $bt->update };
	is $@, '', "No problems updating when do have";
	is $bt->rating, 18, "Updated OK";

	# cascade delete?
	{
		my $blurb = Blurb->retrieve('Bad Taste');
		isa_ok $blurb => "Blurb";
		$bt->delete;
		$blurb = Blurb->retrieve('Bad Taste');
		is $blurb, undef, "Blurb has gone";
	}
		
}

t/23-cascade.t  view on Meta::CPAN

BEGIN {
	eval "use DBD::SQLite";
	plan $@ ? (skip_all => 'needs DBD::SQLite for testing') : (tests => 5);
}

use lib 't/testlib';
use Film;
use Director;

{ # Cascade Strategies
	Director->has_many(nasties => Film => { cascade => 'Fail' });

	my $dir = Director->insert({ name => "Nasty Noddy" });
	my $kk = $dir->add_to_nasties({ Title => 'Killer Killers' });
	is $kk->director, $dir, "Director set OK";
	is $dir->nasties, 1, "We have one nasty";
	eval { $dir->delete };
	like $@, qr/1/, "Can't delete while films exist";
	my $rr = $dir->add_to_nasties({ Title => 'Revenge of the Revengers' });
	eval { $dir->delete };
	like $@, qr/2/, "Still can't delete";



( run in 0.576 second using v1.01-cache-2.11-cpan-49f99fa48dc )