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 )