File Coverage

blib/lib/PomBase/Chobo/Role/ChadoStore.pm
Criterion Covered Total %
statement 55 60 91.6
branch 8 14 57.1
condition n/a
subroutine 9 9 100.0
pod 0 1 0.0
total 72 84 85.7


line stmt bran cond sub pod time code
1             package PomBase::Chobo::Role::ChadoStore;
2              
3             =head1 NAME
4              
5             PomBase::Chobo::Role::ChadoStore - Code for storing terms in Chado
6              
7             =head1 SYNOPSIS
8              
9             =head1 AUTHOR
10              
11             Kim Rutherford C<< >>
12              
13             =head1 BUGS
14              
15             Please report any bugs or feature requests to C.
16              
17             =head1 SUPPORT
18              
19             You can find documentation for this module with the perldoc command.
20              
21             perldoc PomBase::Chobo::Role::ChadoStore
22              
23             =over 4
24              
25             =back
26              
27             =head1 COPYRIGHT & LICENSE
28              
29             Copyright 2012 Kim Rutherford, all rights reserved.
30              
31             This program is free software; you can redistribute it and/or modify it
32             under the same terms as Perl itself.
33              
34             =head1 FUNCTIONS
35              
36             =cut
37              
38             our $VERSION = '0.041'; # VERSION
39              
40 1     1   1505 use Mouse::Role;
  1         1664  
  1         5  
41 1     1   1054 use Text::CSV::Encoded;
  1         2906  
  1         5  
42 1     1   42 use Carp;
  1         2  
  1         94  
43              
44             requires 'dbh';
45             requires 'ontology_data';
46              
47 1     1   7 use PomBase::Chobo::ChadoData;
  1         2  
  1         26  
48 1     1   6 use PomBase::Chobo::OntologyConf;
  1         2  
  1         52  
49              
50             our @relationship_cv_names;
51              
52             BEGIN {
53 1     1   3357 @relationship_cv_names = @PomBase::Chobo::OntologyConf::relationship_cv_names;
54             }
55              
56             sub _copy_to_table
57             {
58 18     18   37 my $self = shift;
59 18         33 my $table_name = shift;
60 18         28 my $column_names_ref = shift;
61 18         59 my @column_names = @$column_names_ref;
62 18         31 my $data_ref = shift;
63 18         37 my @data = @$data_ref;
64              
65 18         60 my $dbh = $self->dbh();
66              
67 18         65 my $column_names = join ',', @column_names;
68              
69 18 50       94 $dbh->do("COPY $table_name($column_names) FROM STDIN CSV")
70             or die "failed to COPY into $table_name: ", $dbh->errstr, "\n";
71              
72 18         2179 my $csv = Text::CSV::Encoded->new({ encoding => "utf8" });
73              
74 18         8327 for my $row (@data) {
75 67         19817 $csv->combine(@$row);
76              
77 67 50       9485 if (!$dbh->pg_putcopydata($csv->string() . "\n")) {
78 0         0 die $dbh->errstr();
79             }
80             }
81              
82 18 50       6547 if (!$dbh->pg_putcopyend()) {
83 0         0 die $dbh->errstr();
84             }
85             }
86              
87             sub _get_relationship_terms
88             {
89 2     2   4 my $chado_data = shift;
90              
91 2         9 my @cvterm_data = $chado_data->get_all_cvterms();
92              
93             my @rel_terms =
94             sort {
95 2 100       12 if ($a->{id} =~ /:/) {
96 1 50       2 if ($b->{id} =~ /:/) {
97 1         5 $a->{id} cmp $b->{id};
98             } else {
99 0         0 -1;
100             }
101             } else {
102 1 50       31 if ($b->{id} =~ /:/) {
103 1         8 1;
104             } else {
105 0         0 $a->{id} cmp $b->{id};
106             }
107             }
108             }
109             grep {
110 2         6 $_->is_relationshiptype();
  21         52  
111             } @cvterm_data;
112              
113 2         4 my %terms_by_name = ();
114 2         5 my %terms_by_termid = ();
115              
116             map {
117 2 50       6 if (exists $terms_by_name{$_->name()}) {
  4         14  
118             warn 'two relationship terms with the same name ("' .
119             $_->id() . '" and "' . $terms_by_name{$_->name()}->id() . '") - ' .
120 0         0 'using: ' . $terms_by_name{$_->name()}->id(), "\n";
121             } else {
122 4         11 $terms_by_name{$_->name()} = $_;
123 4         14 $terms_by_name{$_->name() =~ s/\s+/_/gr} = $_;
124 4         15 $terms_by_termid{$_->id()} = $_;
125             }
126             } @rel_terms;
127              
128 2         11 return (\%terms_by_name, \%terms_by_termid);
129             }
130              
131              
132             my %row_makers = (
133             db => sub {
134             my $ontology_data = shift;
135             my $chado_data = shift;
136              
137             my %chado_db_names = ();
138              
139             map {
140             $chado_db_names{$_} = 1;
141             } $chado_data->get_db_names();
142              
143             return map {
144             [$_];
145             } grep {
146             !$chado_db_names{$_};
147             } $ontology_data->get_db_names();
148             },
149             dbxref => sub {
150             my $ontology_data = shift;
151             my $chado_data = shift;
152              
153             map {
154             my $db_name = $_;
155             my $db_id = $chado_data->get_db_by_name($db_name)->{db_id};
156              
157             my %chado_termids = ();
158              
159             map {
160             $chado_termids{$_} = 1;
161             } $chado_data->get_all_termids();
162              
163             my @ont_db_termids = grep {
164             !$chado_termids{"$db_name:$_"};
165             } $ontology_data->accessions_by_db_name($db_name);
166              
167             map {
168             my $accession = $_;
169             if (!defined $accession) {
170             die "accession is null for accession in db: $db_name\n";
171             }
172             [$db_id, $accession];
173             } @ont_db_termids;
174             } $ontology_data->get_db_names();
175             },
176             cv => sub {
177             my $ontology_data = shift;
178             my $chado_data = shift;
179              
180             my %chado_cv_names = ();
181              
182             map {
183             $chado_cv_names{$_} = 1;
184             } $chado_data->get_cv_names();
185              
186             return map {
187             [$_];
188             } grep {
189             !$chado_cv_names{$_};
190             } $ontology_data->get_cv_names();
191             },
192             cvterm => sub {
193             my $ontology_data = shift;
194             my $chado_data = shift;
195              
196             map {
197             my $term = $_;
198              
199             my $cv = $chado_data->get_cv_by_name($term->{namespace});
200             my $cv_id = $cv->{cv_id};
201              
202             my $dbxref = $chado_data->get_dbxref_by_termid($term->id());
203              
204             if (!$dbxref) {
205             die "dbxref not found for:\n", $term->to_string(), "\n";
206             }
207              
208             my $name = $term->name();
209              
210             if ($term->is_obsolete()) {
211             $name .= ' (obsolete ' . $term->id() . ')';
212             }
213              
214             my $definition = undef;
215             if (defined $term->def()) {
216             $definition = $term->def()->{definition};
217             }
218             my $dbxref_id = $dbxref->{dbxref_id};
219             my $is_relationshiptype = $term->{is_relationshiptype};
220             my $is_obsolete = $term->{is_obsolete} ? 1 : 0;
221              
222             [$name, $definition, $cv_id, $dbxref_id, $is_relationshiptype, $is_obsolete];
223             } $ontology_data->get_terms();
224             },
225             cvtermprop => sub {
226             my $ontology_data = shift;
227             my $chado_data = shift;
228              
229             my $prop_type_cv =
230             $chado_data->get_cv_by_name('cvterm_property_type');
231              
232             if (!defined $prop_type_cv) {
233             die qq|no "cvterm_property_type" CV in database\n|;
234             }
235              
236             my %prop_types =
237             %{$chado_data->get_cvterms_by_cv_id($prop_type_cv->{cv_id})};
238              
239             map {
240             my $term = $_;
241              
242             my $replaced_by = $term->replaced_by();
243              
244             my @res = ();
245              
246             if (defined $replaced_by) {
247             my $cvterm_id =
248             $chado_data->get_cvterm_by_termid($term->id())->cvterm_id();
249             push @res, [$cvterm_id, $prop_types{replaced_by}->cvterm_id(), $replaced_by];
250             }
251              
252             my $consider = $term->consider();
253              
254             if (defined $consider) {
255             my $cvterm_id =
256             $chado_data->get_cvterm_by_termid($term->id())->cvterm_id();
257             push @res, [$cvterm_id, $prop_types{consider}->cvterm_id(), $consider];
258             }
259              
260             my @property_values = $term->property_values();
261              
262             for my $prop_value (@property_values) {
263             my $cvterm_id =
264             $chado_data->get_cvterm_by_termid($term->id())->cvterm_id();
265             my $prop_value_name = $prop_value->[0];
266             my $prop_value_value = $prop_value->[1];
267             if (defined $prop_types{$prop_value_name}) {
268             push @res, [$cvterm_id, $prop_types{$prop_value_name}->cvterm_id(), $prop_value_value];
269             }
270             }
271              
272             @res;
273             } $ontology_data->get_terms();
274             },
275             cvtermsynonym => sub {
276             my $ontology_data = shift;
277             my $chado_data = shift;
278              
279             my $synonym_type_cv =
280             $chado_data->get_cv_by_name('synonym_type');
281             my %synonym_types =
282             %{$chado_data->get_cvterms_by_cv_id($synonym_type_cv->{cv_id})};
283              
284             map {
285             my $term = $_;
286              
287             map {
288             my $synonym_type_name = $_->{scope};
289             my $synonym_type_term =
290             $synonym_types{lc $synonym_type_name} //
291             $synonym_types{uc $synonym_type_name};
292              
293             if (!defined $synonym_type_term) {
294             die "unknown synonym scope: $synonym_type_name";
295             }
296              
297             my $cvterm_id = $chado_data->get_cvterm_by_termid($term->id())->cvterm_id();
298              
299             [$cvterm_id, $_->{synonym}, $synonym_type_term->{cvterm_id}];
300             } $term->synonyms();
301             } $ontology_data->get_terms();
302             },
303             cvterm_dbxref => sub {
304             my $ontology_data = shift;
305             my $chado_data = shift;
306              
307             my %seen_cvterm_dbxrefs = ();
308              
309             map {
310             my $term = $_;
311              
312             my $helper = sub {
313             my $id = shift;
314              
315             my $is_for_definition = shift;
316              
317             my $cvterm_id = $chado_data->get_cvterm_by_termid($term->id())->cvterm_id();
318             my $dbxref_details = $chado_data->get_dbxref_by_termid($id);
319              
320             if (!defined $dbxref_details) {
321             die "no dbxref details for $id ", $term->name(), "\n";
322             }
323              
324             my $dbxref_id = $dbxref_details->{dbxref_id};
325              
326             my $key = "$cvterm_id - $dbxref_id";
327             if (exists $seen_cvterm_dbxrefs{$key}) {
328             ()
329             } else {
330             $seen_cvterm_dbxrefs{$key} = 1;
331             [$cvterm_id, $dbxref_id, $is_for_definition]
332             }
333             };
334              
335             my @ret = ();
336              
337             if ($term->def()) {
338             push @ret, map { $helper->($_, 1) } @{$term->def()->{dbxrefs}}
339             }
340              
341             push @ret, map { $helper->($_->{id}, 0) } $term->alt_ids();
342             push @ret, map { $helper->($_, 0) } $term->xrefs();
343              
344             @ret;
345             } $ontology_data->get_terms();
346             },
347             cvterm_relationship => sub {
348             my $ontology_data = shift;
349             my $chado_data = shift;
350              
351             my ($terms_by_name, $terms_by_termid) = _get_relationship_terms($chado_data);
352              
353             map {
354             my ($subject_termid, $rel_name_or_id, $object_termid) = @$_;
355              
356             my $subject_term = $chado_data->get_cvterm_by_termid($subject_termid);
357             if (defined $subject_term) {
358             my $subject_id = $subject_term->{cvterm_id};
359             my $rel_term = $terms_by_name->{$rel_name_or_id} ||
360             $terms_by_termid->{$rel_name_or_id};
361             if (!defined $rel_term) {
362             die "can't find relation term $rel_name_or_id for relation:\n" .
363             " $subject_termid <-$rel_name_or_id-> $object_termid\n";
364             }
365              
366             my $rel_id = $rel_term->cvterm_id();
367              
368             my $object_term = $chado_data->get_cvterm_by_termid($object_termid);
369             if (defined $object_term) {
370             my $object_id = $object_term->{cvterm_id};
371              
372             [$subject_id, $rel_id, $object_id]
373             } else {
374             warn "no Chado cvterm for $object_termid - ignoring relation:\n" .
375             " $subject_termid <-$rel_name_or_id-> $object_termid\n";
376             ();
377             }
378             } else {
379             warn "no Chado cvterm for $subject_termid - ignoring relation:\n" .
380             " $subject_termid <-$rel_name_or_id-> $object_termid\n";
381             ();
382             }
383             } $ontology_data->relationships();
384             },
385             cvprop => sub {
386             my $ontology_data = shift;
387             my $chado_data = shift;
388              
389             my @namespaces = $ontology_data->get_namespaces();
390              
391             my $cv_version_term = $chado_data->get_cvterm_by_name('cv_property_type', 'cv_version');
392              
393             map {
394             my $namespace = $_;
395              
396             my $metadata = $ontology_data->get_metadata_by_namespace($namespace);
397             my $cv_version = $metadata->{'data-version'} || $metadata->{'date'};;
398              
399             if ($cv_version) {
400             my $cv = $chado_data->get_cv_by_name($namespace);
401             my $cv_id = $cv->{cv_id};
402              
403             [$cv_id, $cv_version_term->{cvterm_id}, $cv_version];
404             } else {
405             ();
406             }
407             } @namespaces
408             },
409              
410             );
411              
412             my %table_column_names = (
413             db => [qw(name)],
414             dbxref => [qw(db_id accession)],
415             cv => [qw(name)],
416             cvterm => [qw(name definition cv_id dbxref_id is_relationshiptype is_obsolete)],
417             cvtermprop => [qw(cvterm_id type_id value)],
418             cvtermsynonym => [qw(cvterm_id synonym type_id)],
419             cvterm_dbxref => [qw(cvterm_id dbxref_id is_for_definition)],
420             cvterm_relationship => [qw(subject_id type_id object_id)],
421             cvprop => [qw(cv_id type_id value)],
422             );
423              
424             sub chado_store
425             {
426 2     2 0 5 my $self = shift;
427              
428 2         13 $self->ontology_data()->finish();
429              
430 2         12 my @cvterm_column_names =
431             @PomBase::Chobo::ChadoData::cvterm_column_names;
432              
433 2         8 my @tables_to_store = qw(db dbxref cv cvterm cvtermprop cvtermsynonym cvterm_dbxref cvterm_relationship cvprop);
434              
435 2         6 for my $table_to_store (@tables_to_store) {
436 18         1416 my $chado_data = PomBase::Chobo::ChadoData->new(dbh => $self->dbh());
437              
438 18         220 my @rows = $row_makers{$table_to_store}->($self->ontology_data(),
439             $chado_data);
440              
441 18         108 $self->_copy_to_table($table_to_store, $table_column_names{$table_to_store},
442             \@rows);
443             }
444              
445             }
446              
447             1;