BioPerl-DB
view release on metacpan or search on metacpan
lib/Bio/DB/BioSQL/BasePersistenceAdaptor.pm view on Meta::CPAN
=head2 create
Title : create
Usage : $objectstoreadp->create($obj, @params)
Function: Creates the object as a persistent object in the datastore. This
is equivalent to an insert.
Example :
Returns : A Bio::DB::PersistentObjectI implementing object wrapping the
inserted object.
Args : The object to be inserted, and optionally additional (named)
parameters. A common parameter will
be -fkobjs, with a reference to an array of foreign key objects
that are not retrievable from the persistent object itself.
=cut
sub create{
my ($self,$obj,@args) = @_;
my $skip_children; # at some point we may want to introduce an
# argument that allows you to supply this
# If the object wasn't a PersistentObjectI already it needs to become
# one now. We do this always to make sure the children etc are persistent,
# too. Note that Bio::DB::PersistentObjectI objects remain the same
# reference.
$obj = $self->create_persistent($obj);
# obtain foreign key objects either from arguments or from object
my @fkobjs = $self->get_foreign_key_objects($obj, @args);
# make sure the foreign key objects are all persistent objects and have
# been stored already
foreach (@fkobjs) {
next unless ref($_);
if(! $_->isa("Bio::DB::PersistentObjectI")) {
$self->throw("All foreign key objects must implement ".
"Bio::DB::PersistentObjectI. This one doesn't: ".
ref($_));
}
# no cascading updates of FK objects through create()
$_->create() unless $_->primary_key();
}
# The object may already exist, and we don't want to duplicate it.
# We'll rely on the RDBMS to catch UK violations unless this adaptor
# caches objects, in which case we'll do a query by UK first. The idea
# is that this will save many failing INSERTs for objects of a finite
# number (as the adaptors for those will have caching enabled hopefully),
# and save many unnecessary UK look-ups for objects of unlimited number,
# because those will be new in most cases.
#
# Note that since foreign keys may be part of the unique key, we can
# do this only now (i.e., after having stored the parent rows).
my $foundobj;
if($self->caching_mode() &&
($foundobj = $self->find_by_unique_key($obj, @args))) {
$obj->primary_key($foundobj->primary_key);
# Should we return right here instead of storing children? Not sure.
#
# My take is that we shouldn't store the children for found objects,
# because it essentially would amount to updating dependent
# information, which is inconsistent with the fact that we don't
# update the object itself. So, leave it to the caller to physically
# trigger an update (which will cascade through to the children)
# instead of doing possibly unwanted magic here.
#
$skip_children = 1 unless defined($skip_children);
} else {
# either caching disabled or not found in cache
#
# insert and obtain primary key
my $pk = $self->dbd()->insert_object($self, $obj, \@fkobjs);
# if no primary key, it may be due to a UK violation (provided that
# caching is disabled)
if(! (defined($pk) || $self->caching_mode())) {
$foundobj = $self->find_by_unique_key($obj, @args);
$pk = $foundobj->primary_key() if $foundobj;
}
if(! defined($pk)) {
$self->throw("create: object (". ref($obj->obj) .
") failed to insert or to be found by unique key");
}
# store primary key
$obj->primary_key($pk);
}
# insert child records if any
my $ok = $skip_children ? 1 : $self->store_children($obj, \@fkobjs);
if((! defined($ok)) || ($ok <= 0)) {
$self->warn("failed to store ".
($ok ? -$ok : "one or more").
" child objects for an instance of class ".
ref($obj->obj()). " (PK=".$obj->primary_key().")");
} else {
# mark it as clean - it's fresh from the press
$obj->is_dirty(0);
}
# done
return $obj;
}
=head2 store
Title : store
Usage : $objectstoreadp->store($persistent_obj,@params)
Function: Updates the given persistent object in the datastore.
Example :
Returns : TRUE on success and FALSE otherwise
Args : The object to be updated, and optionally additional (named)
parameters. A common parameter will
be -fkobjs, with a reference to an array of foreign key objects
that are not retrievable from the persistent object itself.
=cut
sub store{
my ($self,$obj,@args) = @_;
$self->throw("Object of class ".ref($obj)." does not implement ".
"Bio::DB::PersistentObjectI. Bad, cannot store.")
if ! $obj->isa("Bio::DB::PersistentObjectI");
# if there's no primary key, we need to create() the record(s) instead
# of update
return $self->create($obj, @args) if(! $obj->primary_key());
lib/Bio/DB/BioSQL/BasePersistenceAdaptor.pm view on Meta::CPAN
$self->throw("All foreign key objects must implement ".
"Bio::DB::PersistentObjectI. This one doesn't: ".
ref($_));
}
# no cascading updates of FK objects - only create()
$_->create() unless $_->primary_key();
}
# update (if necessary)
my $rv = $obj->is_dirty() > 0 ?
$self->dbd()->update_object($self, $obj, \@fkobjs) : 1;
# update children
$rv = $self->store_children($obj, \@fkobjs);
if((! defined($rv)) || ($rv <= 0)) {
$self->warn("failed to store ".
($rv ? -$rv : "one or more").
" child objects for an instance of class ".
ref($obj->obj()). " (PK=".$obj->primary_key().")");
}
# done
return $rv;
}
=head2 remove
Title : remove
Usage : $objectstoreadp->remove($persistent_obj, @params)
Function: Removes the persistent object from the datastore.
Example :
Returns : TRUE on success and FALSE otherwise
Args : The object to be removed, and optionally additional (named)
parameters.
=cut
sub remove{
my ($self,$obj,@args) = @_;
$self->throw("Object of class ".ref($obj)." does not implement ".
"Bio::DB::PersistentObjectI. Bad, cannot remove.")
unless $obj->isa("Bio::DB::PersistentObjectI");
# first off, delete from cache
$self->_remove_from_obj_cache($obj);
# obtain primary key
my $pk = $obj->primary_key();
$self->throw("Object of class ".ref($obj)." does not have ".
"a primary key. Have you used \$pobj->create()?") if !defined $pk;
# prepared delete statement cached?
my $cache_key = 'DELETE '.ref($obj->obj());
my $sth = $self->sth($cache_key);
if(! $sth) {
# need to create one
$sth = $self->dbd()->prepare_delete_sth($self, @args);
# and cache
$self->sth($cache_key, $sth);
}
# execute
my ($rv, $rv2);
$self->debug("DELETING ".ref($obj->obj())." object (pk=$pk)\n");
$rv = $sth->execute($pk);
# we may need to cascade in software -- ugly
$rv2 = $self->dbd()->cascade_delete($self->dbcontext(), $obj) if $rv;
# the caller should commit if necessary
#
# take care of the children (do this before undefining the primary key
# as something might have children that need this to locate them)
$rv = $self->remove_children($obj,@args) ? $rv : 0;
# undefine the objects primary key - it doesn't exist in the datastore any
# longer
$obj->primary_key(undef);
# done
return $rv;
}
=head2 add_association
Title : add_assocation
Usage :
Function: Stores the association between given objects in the datastore.
Example :
Returns : TRUE on success and FALSE otherwise
Args : Named parameters. At least the following must be recognized:
-objs a reference to an array of objects to be
associated with each other
-values a reference to a hash the keys of which are
abstract column names and the values are values
of those columns. These columns are generally
those other than the ones for foreign keys to
the entities to be associated
-contexts optional; if given it denotes a reference
to an array of context keys (strings), which
allow the foreign key name to be determined
through the slot-to-column map rather than through
foreign_key_name(). This may be necessary if
more than one object of the same type takes
part in the association. The array must be in
the same order as -objs, and have the same
number of elements. Put undef for objects
for which there are no multiple contexts.
Caveats: Make sure you *always* give the objects to be associated in the
same order.
=cut
sub add_association{
my ($self,@args) = @_;
my ($i);
# get arguments
my ($objs, $values) =
$self->_rearrange([qw(OBJS VALUES)], @args);
# have we been called in error? If so, be graceful and return an error.
return undef unless $objs && @$objs;
# construct key for cached statement
my $cache_key = "INSERT ASSOC [" .
($values ? scalar(keys %$values) : 0) . "] " .
join(";", map {
$_->isa("Bio::DB::PersistentObjectI") ? ref($_->obj) : ref($_);
} @$objs);
# statement cached?
my $sth = $self->sth($cache_key);
lib/Bio/DB/BioSQL/BasePersistenceAdaptor.pm view on Meta::CPAN
Usually, those child objects will reference the given object as
a foreign key.
The implementation can assume that all of the child objects
are already Bio::DB::PersistentObjectI.
While obtaining and looping over all child objects could have been
implemented as a generic business logic method, supplying the right
foreign key objects is hard to accomplish in a generic fashion.
The implementation here assumes there are no children and hence
just returns TRUE. You MUST override it in order to have any
children taken care of.
Example :
Returns : TRUE on success, and FALSE otherwise
Args : The Bio::DB::PersistentObjectI implementing object for which the
child objects shall be made persistent.
A reference to an array of foreign key values, in the order of
foreign keys returned by get_foreign_key_objects().
=cut
sub store_children{
return 1;
}
=head2 attach_children
Title : attach_children
Usage :
Function: Possibly retrieve and attach child objects of the given object.
This is needed when whole object trees are supposed to be built
when a base object is queried for and returned. An example would
be Bio::SeqI objects and all the annotation objects that hang off
of it.
This is called by the find_by_XXXX() methods once the base object
has been built.
This implementation will do nothing unless it is overridden. Whether
to override it or not will depend on which of the children shall be
loaded instantly instead of lazily.
Example :
Returns : TRUE on success, and FALSE otherwise.
Args : The object for which to find and to which to attach the child
objects.
=cut
sub attach_children{
return 1;
}
=head2 remove_children
Title : remove_children
Usage :
Function: This method is to cascade deletes in maintained objects.
Child records in the database will usually be cascaded by
the RDBMS. In order to cascade removals to persistent child
objects, you must override this method. Usually you will
need to undefine the primary key of child objects, and
possibly remove them from caches if they are cached.
Because failure to do so may result in serious and often
non-obvious bugs, there is no default provided here. You
*must* override this method in a derived adaptor as
evidence that you know what you are doing, even if all you
do is just return TRUE.
Example :
Returns : TRUE on success and FALSE otherwise
Args : The persistent object that was just removed from the database.
Additional (named) parameter, as passed to remove().
=cut
sub remove_children{
shift->throw_not_implemented();
}
=head2 instantiate_from_row
Title : instantiate_from_row
Usage :
Function: Instantiates the class this object is an adaptor for, and populates
it with values from columns of the row.
Usually a derived class will instantiate the proper class and pass
it on to populate_from_row().
This implementation assumes that the object factory is provided,
uses it to instantiate a new object, and then passes on to
populate_from_row(). If this is not appropriate the method must be
overridden by a derived object.
Example :
Returns : An object, or undef, if the row contains no values
Args : A reference to an array of column values. The first column is the
primary key, the other columns are expected to be in the order
returned by get_persistent_slots().
Optionally, the object factory to be used for instantiating the
proper class. The adaptor must be able to instantiate a default
class if this value is undef.
=cut
sub instantiate_from_row{
my ($self,$row,$fact) = @_;
my $obj;
if($row && @$row) {
if(! $fact) {
$self->throw("No object factory provided. Override this method ".
"in ".ref($self).
" if you know a good default way to go.");
}
$obj = $fact->create_object();
$self->populate_from_row($obj, $row);
( run in 0.771 second using v1.01-cache-2.11-cpan-39bf76dae61 )