implement editing of an existing sequencing info record.
[sgn.git] / lib / CXGN / Stock / SequencingInfo.pm
blob8db7e2d22d00324f92d6108e04ec7b5c97cb13c3
2 =head1 NAME
4 CXGN::Stock::SequencingInfo - a class to match keys to a standardized JSON structure
6 =head1 DESCRIPTION
8 The stockprop of type "sequencing_project_info" is stored as JSON. This class maps keys to the JSON structure and retrieves and saves the stockprop.
10 =head1 EXAMPLE
12 my $si = CXGN::Stock::SequencingInfo->new( { schema => $schema, $stockprop_id });
14 =head1 AUTHOR
16 Lukas Mueller <lam87@cornell.edu>
18 =cut
20 package CXGN::Stock::SequencingInfo;
22 use Moose;
23 use JSON::Any;
24 use Data::Dumper;
25 use SGN::Model::Cvterm;
27 =head1 ACCESSORS
29 =head2 schema
31 =head2 stock_id
33 =head2 stockprop_id
35 =head2 organization
37 =head2 website
39 =head2 genbank_accession
41 =head2 funded_by
43 =head2 funder_project_id
45 =head2 contact_email
47 =head2 sequencing_year
49 =head2 publication
51 =head2 jbrowse_link
53 =head2 blast_db_id
55 =cut
57 has 'schema' => (isa => 'Ref', is => 'rw', required => 1);
59 has 'stockprop_id' => (isa => 'Maybe[Int]', is => 'rw');
61 has 'stock_id' => (isa => 'Int', is => 'rw');
63 has 'type_id' => (isa => 'Int', is => 'rw');
65 has 'type' => (isa => 'Str', is => 'ro', default => "sequencing_project_info" );
67 has 'organization' => (isa => 'Maybe[Str]', is => 'rw');
69 has 'website' => (isa => 'Maybe[Str]', is => 'rw');
71 has 'genbank_accession' => (isa => 'Maybe[Str]', is => 'rw');
73 has 'funded_by' => (isa => 'Maybe[Str]', is => 'rw');
75 has 'funder_project_id' => (isa => 'Maybe[Str]', is => 'rw');
77 has 'contact_email' => (isa => 'Maybe[Str]', is => 'rw');
79 has 'sequencing_year' => (isa => 'Maybe[Str]', is => 'rw');
81 has 'publication' => (isa => 'Maybe[Str]', is => 'rw');
83 has 'jbrowse_link' => (isa => 'Maybe[Str]', is => 'rw');
85 has 'blast_db_id' => (isa => 'Maybe[Int]', is => 'rw');
87 has 'allowed_fields' => (isa => 'Ref', is => 'ro', default => sub { [ qw | organization website genbank_accession funded_by funder_project_id contact_email sequencing_year publication jbrowse_link blast_db_id stockprop_id stock_id | ] } );
90 sub BUILD {
91 my $self = shift;
92 my $args = shift;
94 if ($args->{stockprop_id} eq "undefined") { $args->{stockprop_id} = undef; }
96 print STDtERR "STOCKPROPID: ".$self->stockprop_id.", TYPE: ".$self->type()."\n";
97 my $type_id = SGN::Model::Cvterm->get_cvterm_row($self->schema(), $self->type(), 'stock_property')->cvterm_id();
99 $self->type_id($type_id);
101 $self->_load_object();
103 $self->stockprop_id($args->{stockprop_id});
107 =head2 Class methods
110 =head2 get_sequencing_project_infos($schema, $stock_id)
112 Usage: my @seq_projects = $se_info->get_sequencing_project_infos($schema, $stock_id);
113 Desc:
114 Ret:
115 Args:
116 Side Effects:
117 Example:
119 =cut
121 sub get_sequencing_project_infos {
122 my $class = shift;
123 my $schema = shift;
124 my $stock_id = shift;
126 my @stockprops = $class->_retrieve_stockprops($schema, $stock_id, "sequencing_project_info");
128 print STDERR "Stockprops = ".Dumper(\@stockprops);
130 my @infos = ();
131 foreach my $sp (@stockprops) {
132 my $hash;
134 my $json = $sp->[1];
136 eval {
137 $hash = JSON::Any->jsonToObj($json);
139 $hash->{stockprop_id} = $sp->[0];
140 $hash->{uniquename} = $schema->resultset("Stock::Stock")->find( { stock_id => $stock_id })->uniquename();
141 if ($@) {
142 print STDERR "Warning: $json is not valid json in stockprop ".$sp->[0].".!\n";
144 push @infos, $hash;
147 print STDERR "Hashes = ".Dumper(\@infos);
148 return \@infos;
151 =head2 all_sequenced_stocks()
153 Usage: @sequenced_stocks = CXGN::Stock->sequenced_stocks();
154 Desc:
155 Ret:
156 Args:
157 Side Effects:
158 Example:
160 =cut
162 sub all_sequenced_stocks {
163 my $class = shift;
164 my $schema = shift;
166 print STDERR "all_sequenced_stocks with ".ref($schema)." as parameter...\n";
167 my $type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'sequencing_project_info', 'stock_property')->cvterm_id();
168 print STDERR "type_id = $type_id\n";
170 my $sp_rs = $schema->resultset("Stock::Stockprop")->search({ type_id => $type_id });
172 my @sequenced_stocks = ();
173 while (my $row = $sp_rs->next()) {
174 print STDERR "found stock with stock_id ".$row->stock_id()."\n";
175 push @sequenced_stocks, $row->stock_id();
178 return @sequenced_stocks;
182 =head2 OBJECT METHODS
184 =head2 method store()
186 Usage: $s->set_sequencing_project_info($si, $stockprop_id)
187 Desc: creates a sequencing project info in the stockprop
188 Ret:
189 Args: a CXGN::Stock::SequencingInfo object, and an optional
190 stockprop_id (which will trigger an update instead
191 of insert)
192 Side Effects:
193 Example:
195 =cut
197 sub store {
198 my $self = shift;
200 if (!$self->stock_id()) {
201 die "Need a stock_id to save SequencingInfo object.";
204 if ($self->stockprop_id()) {
205 # update
206 print STDERR "updating stockprop...\n";
207 my $row = $self->schema()->resultset("Stock::Stockprop")->find( { stockprop_id => $self->stockprop_id() } );
208 if ($row) {
209 $row->value($self->to_json());
210 $row->update();
213 else {
214 # insert
215 print STDERR "inserting stockprop...\n";
216 my $row = $self->schema()->resultset("Stock::Stockprop")->create(
218 stock_id => $self->stock_id(),
219 type_id => $self->type_id(),
220 value => $self->to_json()
223 $self->stockprop_id($row->stockprop_id());
224 $self->stock_id($row->stock_id());
225 return $row->stockprop_id();
230 =head2 method delete()
232 Usage:
233 Desc:
234 Ret:
235 Args:
236 Side Effects:
237 Example:
239 =cut
241 sub delete {
242 my $self = shift;
244 print STDERR "CXGN::Stock::SequencingInfo: Deleting sequencing info object ".$self->stockprop_id()."\n";
245 my $stockprop;
247 print STDERR "stock_id = ".$self->stock_id().", stockprop_id = ".$self->stockprop_id()."\n";
249 eval {
250 $stockprop = $self->schema()->resultset("Stock::Stockprop")->find({ type_id=>$self->type_id(), stock_id => $self->stock_id(), stockprop_id=>$self->stockprop_id() });
253 if ($@) {
254 die "Delete failed!\n";
257 if (!$stockprop) {
258 print STDERR "No such stockprop associated with such type or stock. Not deleting.\n";
259 return 0;
261 else {
262 print STDERR "Deleting stcokprop now.\n";
263 $stockprop->delete();
264 print STDERR "SequencingInfo successfully deleted.\n";
265 return 1;
269 =head2 _load_object
271 Desc:
272 Ret:
273 Args:
274 Side Effects: requires stockprop_id and schema to be set
275 Example:
277 =cut
279 sub _load_object {
280 my $self= shift;
282 print STDERR "_load_object...\n";
284 print STDERR "Stockprop_id is now ".$self->stockprop_id()."\n";
285 if ($self->stockprop_id()) {
286 print STDERR "configuring object...\n";
287 my $stockprop_type_id = SGN::Model::Cvterm->get_cvterm_row($self->schema, $self->type(), 'stock_property')->cvterm_id();
288 my $rs = $self->schema->resultset("Stock::Stockprop")->search({ stockprop_id => $self->stockprop_id(), type_id => $stockprop_type_id } );
290 if ($rs->count() == 0) { die "No stockprops could be retrieved." }
292 my $row = $rs->next(); # should only be one
294 $self->type_id($stockprop_type_id);
295 $self->stock_id($row->stock_id());
296 $self->from_json($row->value());
303 =head2 _retrieve_stockprops
305 Usage:
306 Desc: Retrieves stockprop as a list of [stockprop_id, value]
307 Ret:
308 Args:
309 Side Effects:
310 Example:
312 =cut
314 sub _retrieve_stockprops {
315 my $class = shift;
316 my $schema = shift;
317 my $stock_id = shift;
318 my $type = shift;
320 my @results;
322 print STDERR "_retrieve_stockprops...\n";
324 eval {
325 my $stockprop_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, $type, 'stock_property')->cvterm_id();
326 my $rs = $schema->resultset("Stock::Stockprop")->search({ stock_id => $stock_id, type_id => $stockprop_type_id }, { order_by => {-asc => 'stockprop_id'} });
328 while (my $r = $rs->next()){
329 push @results, [ $r->stockprop_id(), $r->value() ];
333 if ($@) {
334 print STDERR "Cvterm $type does not exist in this database\n";
337 return @results;
340 =head2 from_json
342 Usage:
343 Desc:
344 Ret:
345 Args:
346 Side Effects:
347 Example:
349 =cut
351 sub from_json {
352 my $self = shift;
353 my $json = shift;
355 my $data = JSON::Any->decode($json);
357 $self->from_hash($data);
360 =head2 from_hash
362 Usage:
363 Desc:
364 Ret:
365 Args:
366 Side Effects:
367 Example:
369 =cut
371 sub from_hash {
372 my $self = shift;
373 my $hash = shift;
375 my $allowed_fields = $self->allowed_fields();
377 print STDERR Dumper($hash);
379 foreach my $f (@$allowed_fields) {
380 print STDERR "Processing $f ($hash->{$f})...\n";
381 if ($hash->{$f} eq "undefined") { $hash->{$f} = undef; }
382 $self->$f($hash->{$f});
386 =head2 to_json
388 Usage:
389 Desc:
390 Ret:
391 Args:
392 Side Effects:
393 Example:
395 =cut
397 sub to_json {
398 my $self = shift;
400 my $allowed_fields = $self->allowed_fields();
402 print STDERR Dumper($allowed_fields);
403 my $data;
405 foreach my $f (@$allowed_fields) {
406 if (defined($self->$f())) {
407 $data->{$f} = $self->$f();
411 my $json = JSON::Any->encode($data);
412 return $json;
415 =head2 to_hash
417 Usage:
418 Desc:
419 Ret:
420 Args:
421 Side Effects:
422 Example:
424 =cut
426 sub to_hashref {
427 my $self = shift;
429 my $hashref;
430 foreach my $f (@{$self->allowed_fields()}) {
431 $hashref->{$f} = $self->$f;
433 return $hashref;
436 =head2 validate
438 Usage:
439 Desc:
440 Ret:
441 Args:
442 Side Effects:
443 Example:
445 =cut
447 sub validate {
448 my $self = shift;
450 my @errors = ();
451 my @warnings = ();
453 # check keys in the info hash...
454 if (!defined($self->sequencing_year())) {
455 push @errors, "Need year for sequencing project";
457 if (!defined($self->organization())) {
458 push @errors, "Need organization for sequencing project";
460 if (!defined($self->website())) {
461 push @errors, "Need website for sequencing project";
463 if (!defined($self->publication())) {
464 push @warnings, "Need publication for sequencing project";
466 if (!defined($self->website())) {
467 push @warnings, "Need project url for sequencing project";
469 if (!defined($self->jbrowse_link())) {
470 push @warnings, "Need jbrowse link for sequencing project";
473 if (@errors) {
474 die join("\n", @errors);