File Coverage

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