Commit b1c97544 authored by Marek Szuba's avatar Marek Szuba
Browse files

RNAProduct: implement synchronise_attributes()

Properties of specific types of mature RNA products such as microRNAs
are stored in the database as attributes (so that we needn't add
type-specific columns to the rnaproduct table) but have shorthand
accessors such as MicroRNA::arm() backed by cache member variables
in the API (for convenience and speed). In order for this to work
properly we have to push possible changes to the cache variables back
to attributes before they are stored in the database - which is what
this method does.

The synchronisation code itself is generic and has been implemented
in the superclass. Specialisation is handled by class-specific mappings
between member names and respective Attribute codes, provided
by RNAProductTypeMapper.

Limitations:
 - at present there can only be either zero or one target attribute;
   having many attributes with the same code results in an exception
   because we do not know which one(s) to update. In the future we might
   have to extend the mapping syntax to support multiple attributes, for
   now however (i.e. for microRNA arms) we do not need it;
 - chances are things will break badly if we fetch a MicroRNA object
   from the database, change the arm and push it back. Right now this is
   not a problem because RNAProducts do not support database updates at
   all, then again should we want to support them we will have to check
   how AttributeAdaptor handles updates of existing objects (as well as
   the same for DBEntryAdaptor, as a matter of fact).
parent 8b4b7967
......@@ -753,6 +753,65 @@ sub summary_as_hash {
}
=head2 synchronise_attributes
Example : $rnaproduct->synchronise_attributes();
Description : Some RNAProduct attributes, e.g. stem-loop arm in case
of MicroRNA, use a local cache of their value for
convenience. Unless the corresponding setters update both
the cache value and the attribute (which would defeat
the convenience thing), we have to make sure the former
get propagated to the latter before storing the object
in the database:
- if no corresponding attribute exists, create one;
- if there is one, update its value.
Class-specific maps of attributes to synchronise are
provided by
RNAProductTypeMapper::class_attribute_cache_map() .
Returntype : none
Exceptions : throws if the object contains multiple attributes with the
given code and the choice which one to update is
ambiguous.
Caller : RNAProductAdaptor
Status : At Risk (In Development)
=cut
sub synchronise_attributes {
my ($self) = @_;
my $attribute_cache_map = Bio::EnsEMBL::Utils::RNAProductTypeMapper::mapper()
->class_attribute_cache_map(ref($self));
while (my ($cache_key, $attr_code) = each %{$attribute_cache_map}) {
my $existing_attributes = $self->get_all_Attributes($attr_code);
my $n_existing_attrs = scalar @{$existing_attributes};
if ($n_existing_attrs > 0) {
# At the moment we do not support multiple occurrences of target
# attributes at all
if ($n_existing_attrs > 1) {
throw("Object has multiple '$attr_code' attributes and we do not know"
. " which one to update");
}
else {
$existing_attributes->[0]->value($self->{$cache_key});
}
}
else {
# No corresponding attribute exists, most likely because we are
# dealing with a newly created object which has never been pushed
# to the database.
$self->add_Attributes(Bio::EnsEMBL::Attribute->new(
-CODE => $attr_code,
-VALUE => $self->{$cache_key},
));
}
}
return;
}
=head2 transcript
Arg [1] : Transcript object (optional)
......
......@@ -111,19 +111,51 @@ sub new {
# Declare this here rather than in the package scope so that the map
# cannot be modified (we do not presently use Readonly in the Core
# API code), accidentally or otherwise.
my $class_attribute_cache_map = {
'Bio::EnsEMBL::RNAProduct' => { },
'Bio::EnsEMBL::MicroRNA' => {
'arm' => 'mirna_arm',
},
};
my $type_to_class_map = {
'generic' => 'Bio::EnsEMBL::RNAProduct',
'miRNA' => 'Bio::EnsEMBL::MicroRNA',
'miRNA' => 'Bio::EnsEMBL::MicroRNA',
};
my $self = bless {
'type_to_class_map' => $type_to_class_map,
'class_to_type_map' => undef,
'class_attribute_cache_map' => $class_attribute_cache_map,
'type_to_class_map' => $type_to_class_map,
'class_to_type_map' => undef,
}, $class;
return $self;
}
=head2 class_attribute_cache_map
Arg [1] : string $class_name - fully qualified rnaproduct class name
Example : my $attr_cache_map
= $mapper->class_attribute_cache_map( 'Bio::EnsEMBL::MicroRNA' );
Description: For the given name of a class representing a mature RNA
product, returns the map indicating which local members variables
should be synchronised with which Attributes.
Returntype : hashref
Exceptions : throw if the class does not represent known RNA-product type
Caller : internal
Status : Stable
=cut
sub class_attribute_cache_map {
my ( $self, $class_name ) = @_;
my %map = %{ $self->{'class_attribute_cache_map'} };
if ( !exists $map{$class_name} ) {
throw( "Unknown RNA-product class name " . $class_name );
}
return $map{$class_name};
}
=head2 class_to_type_code
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment