also add multicat while we are at it...
[sgn.git] / lib / CXGN / BrAPI / v2 / Scales.pm
blobb3b0eb30dec594b9a75fc16ff8bd7a47fefb0870
1 package CXGN::BrAPI::v2::Scales;
3 use Moose;
4 use Data::Dumper;
5 use Try::Tiny;
6 use List::Util 'max';
8 has 'bcs_schema' => (
9 isa => 'Bio::Chado::Schema',
10 is => 'rw',
11 required => 1,
14 has 'scale' => (
15 is => 'ro',
16 isa => 'HashRef[Any]',
19 has 'cvterm_id' => (
20 isa => 'Int',
21 is => 'rw',
22 required => 0,
25 has 'cv_id' => (
26 isa => 'Int',
27 is => 'ro',
28 lazy => 1,
29 default => sub {
30 my $self = shift;
31 my $cv_id = $self->bcs_schema->resultset("Cv::Cv")->find(
33 name => 'trait_property'
35 { key => 'cv_c1' }
36 )->get_column('cv_id');
37 return $cv_id;
41 has 'scale_categories_id' => (
42 isa => 'Int',
43 is => 'ro',
44 lazy => 1,
45 default => sub {
46 my $self = shift;
47 my $scale_categories_id = $self->bcs_schema->resultset("Cv::Cvterm")->find(
49 name => 'trait_categories',
50 cv_id => $self->cv_id,
51 is_obsolete => 0
53 { key => 'cvterm_c1' }
54 )->get_column('cvterm_id');
55 return $scale_categories_id;
59 has 'scale_categories_label_id' => (
60 isa => 'Int',
61 is => 'ro',
62 lazy => 1,
63 default => sub {
64 my $self = shift;
65 my $scale_categories_label_id = $self->bcs_schema->resultset("Cv::Cvterm")->find(
67 name => 'trait_categories_label',
68 cv_id => $self->cv_id,
69 is_obsolete => 0
71 { key => 'cvterm_c1' }
72 )->get_column('cvterm_id');
73 return $scale_categories_label_id;
77 has 'scale_categories_value_id' => (
78 isa => 'Int',
79 is => 'ro',
80 lazy => 1,
81 default => sub {
82 my $self = shift;
83 my $scale_categories_value_id = $self->bcs_schema->resultset("Cv::Cvterm")->find(
85 name => 'trait_categories_value',
86 cv_id => $self->cv_id,
87 is_obsolete => 0
89 { key => 'cvterm_c1' }
90 )->get_column('cvterm_id');
91 return $scale_categories_value_id;
97 has 'scale_format_id' => (
98 isa => 'Int',
99 is => 'ro',
100 lazy => 1,
101 default => sub {
102 my $self = shift;
103 my $scale_format_id = $self->bcs_schema->resultset("Cv::Cvterm")->find(
105 name => 'trait_format',
106 cv_id => $self->cv_id,
107 is_obsolete => 0
109 { key => 'cvterm_c1' }
110 )->get_column('cvterm_id');
111 return $scale_format_id;
115 has 'scale_maximum_id' => (
116 isa => 'Int',
117 is => 'ro',
118 lazy => 1,
119 default => sub {
120 my $self = shift;
121 my $scale_maximum_id = $self->bcs_schema->resultset("Cv::Cvterm")->find(
123 name => 'trait_maximum',
124 cv_id => $self->cv_id,
125 is_obsolete => 0
127 { key => 'cvterm_c1' }
128 )->get_column('cvterm_id');
129 return $scale_maximum_id;
133 has 'scale_minimum_id' => (
134 isa => 'Int',
135 is => 'ro',
136 lazy => 1,
137 default => sub {
138 my $self = shift;
139 my $scale_minimum_id = $self->bcs_schema->resultset("Cv::Cvterm")->find(
141 name => 'trait_minimum',
142 cv_id => $self->cv_id,
143 is_obsolete => 0
145 { key => 'cvterm_c1' }
146 )->get_column('cvterm_id');
147 return $scale_minimum_id;
151 has 'scale_decimal_places_id' => (
152 isa => 'Int',
153 is => 'ro',
154 lazy => 1,
155 default => sub {
156 my $self = shift;
157 my $scale_decimal_places_id = $self->bcs_schema->resultset("Cv::Cvterm")->find(
159 name => 'trait_decimal_places',
160 cv_id => $self->cv_id,
161 is_obsolete => 0
163 { key => 'cvterm_c1' }
164 )->get_column('cvterm_id');
165 return $scale_decimal_places_id;
169 has 'scale_db' => (
170 isa => 'HashRef[Any]',
171 is => 'ro',
172 lazy => 1,
173 default => sub {
174 my $self = shift;
176 my %scale;
177 my %categories;
179 my $props = $self->bcs_schema()->resultset("Cv::Cvtermprop")->search(
181 cvterm_id => $self->cvterm_id()
183 {order_by => { -asc => 'rank' }}
186 my $scale_ref = \%scale;
187 my $data_type;
188 my $decimal_places;
189 my $trait_categories;
190 my $valid_values_max;
191 my $valid_values_min;
192 my $additional_info;
193 my $external_references;
194 my $ontology_reference;
195 my $scale_id;
196 my $scale_name;
197 my $scale_PUI;
198 my $units;
199 $scale_ref->{'validValues'}{'categories'} =undef;
201 while (my $prop = $props->next()){
202 my $category = $categories{$prop->get_column('rank')};
204 if ($prop->get_column('type_id') == $self->scale_categories_id) {
205 $trait_categories = $prop->get_column('value');
208 if ($prop->get_column('type_id') == $self->scale_categories_label_id) {
209 $category->{'label'} = $prop->get_column('value');
210 $categories{$prop->get_column('rank')}=$category;
213 if ($prop->get_column('type_id') == $self->scale_categories_value_id) {
214 $category->{'value'} = $prop->get_column('value');
215 $categories{$prop->get_column('rank')}=$category;
218 if ($prop->get_column('type_id') == $self->scale_format_id) {
219 $data_type = $prop->get_column('value');
221 if ($prop->get_column('type_id') == $self->scale_decimal_places_id) {
222 $decimal_places = $prop->get_column('value')+0;
225 if ($prop->get_column('type_id') == $self->scale_maximum_id) {
226 $valid_values_max = $prop->get_column('value')+0;
228 if ($prop->get_column('type_id') == $self->scale_minimum_id) {
229 $valid_values_min = $prop->get_column('value')+0;
233 if ($trait_categories){ #Breedbase categories
234 my @categories = split(/\//, $trait_categories);
235 foreach (@categories){
236 push @{$scale_ref->{'validValues'}{'categories'}}, {
237 'label' => qq|$_|,
238 'value' => qq|$_|
241 } elsif (%categories) { #Implemented by BI
242 my $ref = \%categories;
243 my $maxkey = max keys %$ref;
244 my @array = @{$ref}{0 .. $maxkey};
245 $scale_ref->{'validValues'}{'categories'} = \@array;
247 $scale_ref->{'additionalInfo'} = $additional_info;
248 $scale_ref->{'dataType'} = $self-> _format_data_type($data_type);
249 $scale_ref->{'decimalPlaces'} = $decimal_places;
250 $scale_ref->{'validValues'}{'maximumValue'} = $valid_values_max;
251 $scale_ref->{'validValues'}{'minimumValue'} = $valid_values_min;
252 $scale_ref->{'externalReferences'} = $external_references;
253 $scale_ref->{'ontologyReference'} = $ontology_reference;
254 $scale_ref->{'scaleDbId'} = $scale_id;
255 $scale_ref->{'scaleName'} = $scale_name;
256 $scale_ref->{'scalePUI'} = $scale_PUI;
257 $scale_ref->{'units'} = $units;
259 return $scale_ref;
263 sub store {
264 my $self = shift;
265 my $schema = $self->bcs_schema();
266 my $cvterm_id = $self->cvterm_id();
267 my $scale = $self->scale();
268 my @scale_categories;
270 if (!defined($cvterm_id)) {
271 CXGN::BrAPI::Exceptions::ServerException->throw({message => "Error: Scale cvterm_id not specified, cannot store"});
274 # Clear out old scale
275 $self->delete();
277 if ($self->scale->{'validValues'}{'categories'}) {
278 @scale_categories = @{$self->scale->{'validValues'}{'categories'}};
281 my $scale_format_id = $self->scale_format_id;
282 my $scale_decimal_places_id = $self->scale_decimal_places_id;
283 my $scale_categories_id = $self->scale_categories_id;
284 my $scale_categories_label_id = $self->scale_categories_label_id;
285 my $scale_categories_value_id = $self->scale_categories_value_id;
286 my $scale_maximum_id = $self->scale_maximum_id;
287 my $scale_minimum_id = $self->scale_minimum_id;
289 my $scale_format = $scale->{'dataType'};
290 my $scale_decimal_places = $scale->{'decimalPlaces'};
291 my $scale_categories = $scale->{'validValues'}{'categories'};
292 my $scale_maximum = $scale->{'validValues'}{'max'};
293 my $scale_minimum = $scale->{'validValues'}{'min'};
295 my $rank = 0;
296 my $categories_v1 = "";
298 my $coderef = sub {
300 # write category values for v2
301 foreach my $category (@scale_categories) {
302 my $label = $category->{'label'};
303 my $value = $category->{'value'};
305 # write external reference info to dbxrefprop
306 my $prop_id = $schema->resultset("Cv::Cvtermprop")->create(
308 cvterm_id => $cvterm_id,
309 type_id => $scale_categories_label_id,
310 value => defined $label && $label ne "" ? $label : $value,
311 rank => $rank
315 my $prop_source = $schema->resultset("Cv::Cvtermprop")->create(
317 cvterm_id => $cvterm_id,
318 type_id => $scale_categories_value_id,
319 value => $value,
320 rank => $rank
324 $rank++;
326 # form categories string for v1 call
327 # For brapi v1, label = meaning, in brapi v2 terms, value = label.
328 $categories_v1=$categories_v1.$value."=".$label."/";
331 my $format = $schema->resultset("Cv::Cvtermprop")->create(
333 cvterm_id => $cvterm_id,
334 type_id => $scale_format_id,
335 value => $scale_format,
336 rank => 0
340 if (defined($scale_decimal_places) && length($scale_decimal_places)) {
341 my $decimal_places = $schema->resultset("Cv::Cvtermprop")->create(
343 cvterm_id => $cvterm_id,
344 type_id => $scale_decimal_places_id,
345 value => $scale_decimal_places,
346 rank => 0
351 # write in format used by v1 calls
352 if ($scale_categories) {
353 my $categories = $schema->resultset("Cv::Cvtermprop")->create(
355 cvterm_id => $cvterm_id,
356 type_id => $scale_categories_id,
357 value => $categories_v1,
358 rank => 0
363 if (defined($scale_maximum) && length($scale_maximum)) {
364 my $maximum = $schema->resultset("Cv::Cvtermprop")->create(
366 cvterm_id => $cvterm_id,
367 type_id => $scale_maximum_id,
368 value => $scale_maximum,
369 rank => 0
374 if (defined($scale_minimum) && length($scale_minimum)) {
375 my $minimum = $schema->resultset("Cv::Cvtermprop")->create(
377 cvterm_id => $cvterm_id,
378 type_id => $scale_minimum_id,
379 value => $scale_minimum,
380 rank => 0
387 my $transaction_error;
389 try {
390 $schema->txn_do($coderef);
391 } catch {
392 $transaction_error = $_;
395 if ($transaction_error) {
396 return {error => "Scale transaction error trying to write to db"}
399 return { success => "Scale added successfully" };
403 sub delete {
405 my $self = shift;
406 my $schema = $self->bcs_schema();
407 my $cvterm_id = $self->cvterm_id();
409 $schema->resultset("Cv::Cvtermprop")->search(
410 { cvterm_id => $cvterm_id,
411 type_id => { -in =>
413 $self->scale_format_id,
414 $self->scale_decimal_places_id,
415 $self->scale_categories_id,
416 $self->scale_categories_label_id,
417 $self->scale_categories_value_id,
418 $self->scale_maximum_id,
419 $self->scale_minimum_id
423 )->delete;
426 sub _format_data_type {
427 my $self = shift;
428 my $value = shift;
429 my $dataType = "Text"; #Text is the default trait_format for phenotypes in breedbase
430 $value =~ s/^\s+|\s+$//g;
432 if ($value) {
433 my %formats = (
434 "categorical" => "Ordinal",
435 "numeric" => "Numerical",
436 "qualitative" => "Nominal",
437 "numerical" => "Numerical",
438 "nominal" => "Nominal",
439 "code" => "Code",
440 "date" => "Date" ,
441 "duration" => "Duration",
442 "ordinal" => "Ordinal",
443 "text" => "Text",
444 "photo" => "Photo",
445 "multicat" => "Multicat",
448 $dataType = $formats{lc $value} ? $formats{lc $value} : $dataType;
450 return $dataType;