1 package SGN
::Controller
::Sequence
;
5 SGN::Controller::Sequence - Catalyst controller for dealing with sequences
9 Right now, only knows how to fetch sequences from BCS features.
14 use namespace
::autoclean
;
18 BEGIN { extends
'Catalyst::Controller' }
22 =head2 gmodrpc_fetch_seq
24 Public path: /gmodrpc/v1.1/fetch/seq/<name or id>.fasta?start..end
26 Just forwards to api_v1_single_sequence
30 sub gmodrpc_fetch_seq
:Path
('/gmodrpc/v1.1/fetch/seq') :Args
(1) {
31 my ( $self, $c, $name ) = @_;
32 $c->forward( 'api_v1_single_sequence', [ $name ] );
35 =head2 api_v1_single_sequence
37 Public path: /api/v1/sequence/<name or id>.fasta?start..end
39 ?start..end is optional. If start E<gt> end, does reverse complement.
43 sub api_v1_single_sequence
:Path
('/api/v1/sequence/download/single') :Args
(1) {
44 my ( $self, $c, $name ) = @_;
46 if( $name =~ s/\.([^\.]+)$// ) {
47 $c->stash->{seqio_format
} = $1;
50 if( my $kw = $c->request->query_keywords ) {
54 $c->stash->{sequence_identifiers
} = [ $name ];
55 $c->forward( 'fetch_sequences' );
56 $c->forward( 'download_sequences' );
59 =head2 api_v1_multi_sequence
61 Public path: /api/v1/sequence/download/multi
65 s: multi-valued, holds identifiers to download. Each
66 identifier may have a :start..end appended to take a
67 subsequence. (Reverse complement if start > end).
71 sub api_v1_multi_sequence
:Path
('/api/v1/sequence/download/multi') :Args
(0) {
72 my ( $self, $c ) = @_;
74 $c->stash->{sequence_identifiers
} = $c->req->parameters->{'s'};
75 $c->stash->{seqio_format
} = $c->req->parameters->{'format'};
77 $c->forward( 'fetch_sequences' );
78 $c->forward( 'download_sequences' );
81 =head1 PRIVATE ACTIONS
83 =head2 download_sequences
87 sub download_sequences
:Private
{
88 my ( $self, $c ) = @_;
90 # set an appropriate download filename, and the appropriate
91 # headers to trigger a file download
92 $c->stash->{download_filename
} = $c->stash->{sequences
} && @
{$c->stash->{sequences
}} == 1
93 ?
$c->stash->{sequences
}->[0]->id.'.fasta'
94 : 'SGN_sequence_download.fasta';
95 $c->forward('/download/set_download_headers');
97 $c->forward( 'View::SeqIO' );
100 =head2 fetch_sequences
104 sub fetch_sequences
:Private
{
105 my ( $self, $c ) = @_;
106 my $sequence_idents = $c->stash->{sequence_identifiers
};
107 $sequence_idents = [ $sequence_idents ] unless ref $sequence_idents;
109 # parse out region descriptions in any of the sequence idents
110 for my $id (@
$sequence_idents) {
111 # full format looks like myseqID1123:455..43255. if start is
112 # greater than end, means revcom
113 if( $id =~ s/ : ([\d,]+) \.\. ([\d,]+) $ //x ) {
114 my ( $start, $end ) = ( $1, $2 );
115 s/,//g for $start, $end;
117 if( $start > $end ) {
118 ( $start, $end ) = ( $end, $start );
121 $id = [ $id, $strand, $start, $end ];
123 $id = [ $id, undef, undef, undef ];
127 # find the feature(s) for each ID and convert them to
130 for ( @
$sequence_idents ) {
131 my ( $id, $strand, $start, $end ) = @
$_;
132 my $rs = $self->_feature_rs( $c, $id );
135 while( my $feature = $rs->next ) {
136 push @sequences, $self->_feature_to_primaryseq( $feature, $strand, $start, $end );
139 # if there is only one sequence identifier, not finding it should throw a 404
140 # otherwise, ignore it so bulk downloads via the multi api still work
141 # Bulk queries always ignore all invalid identifiers
142 if( @
$sequence_idents == 1 and !$c->stash->{bulk_query
} ){
143 $found or $c->throw_404( sprintf('No sequence found with id "%s"', encode_entities
( $id )) );
147 $c->stash->{sequences
} = \
@sequences;
152 # searches for features given a name or ID. Assumes it's a feature ID
155 my ( $self, $c, $id ) = @_;
158 $c->dbic_schema('Bio::Chado::Schema','sgn_chado')
159 ->resultset('Sequence::Feature');
162 $features_rs = $features_rs->search({ name
=> $id });
164 $features_rs = $features_rs->search({ feature_id
=> $id });
170 # converts a feature to a Bio::PrimarySeq, applying a subsequence and
171 # revcom if necessary
172 sub _feature_to_primaryseq
{
173 my ( $self, $feature, $strand, $start, $end ) = @_;
175 my $seq_id = $feature->name || 'feature_'.$feature->feature_id;
176 if( $start && $end ) {
177 $seq_id .= $strand && $strand eq '-' ?
":$end..$start" : ":$start..$end";
180 my $seq = Bio
::PrimarySeq
->new(
182 ( $feature->desc ?
( -desc
=> $feature->desc ) : () ),
183 -seq
=> $feature->subseq( ($start || 1), ($end || $feature->length) ),
185 $seq = $seq->revcom if $strand && $strand eq '-';
190 __PACKAGE__
->meta->make_immutable;