File Coverage

lib/UR/BoolExpr/Template/Or.pm
Criterion Covered Total %
statement 71 99 71.7
branch 7 22 31.8
condition 0 3 0.0
subroutine 9 11 81.8
pod 0 5 0.0
total 87 140 62.1


line stmt bran cond sub pod time code
1             package UR::BoolExpr::Template::Or;
2              
3 266     266   1078 use warnings;
  266         339  
  266         8347  
4 266     266   928 use strict;
  266         319  
  266         222705  
5             our $VERSION = "0.46"; # UR $VERSION;;
6              
7             require UR;
8              
9             UR::Object::Type->define(
10             class_name => __PACKAGE__,
11             is => ['UR::BoolExpr::Template::Composite'],
12             );
13              
14             sub _flatten_bx {
15 1     1   3 my ($class, $bx) = @_;
16 1         5 my @old = $bx->underlying_rules;
17 1         1 my @new;
18 1         3 for my $old (@old) {
19 2         4 my $new = $old->flatten;
20 2         7 push @new, [ $new->_params_list ];
21             }
22 1         4 my $flattened_bx = $class->_compose($bx->subject_class_name,\@new);
23 1         3 return $flattened_bx;
24             }
25              
26             sub _reframe_bx {
27 1     1   2 my ($class, $bx, $in_terms_of) = @_;
28 1         4 my @old = $bx->underlying_rules;
29 1         3 my @new;
30 1         4 for my $old (@old) {
31 2         9 my $new = $old->reframe($in_terms_of);
32 2         7 push @new, [ $new->_params_list ];
33             }
34 1         5 my @meta = $bx->subject_class_name->__meta__->property_meta_for_name($in_terms_of);
35 1         5 my @joins = $meta[-1]->_resolve_join_chain($in_terms_of);
36 1         5 my $reframed_bx = $class->_compose($joins[-1]{foreign_class},\@new);
37 1         5 return $reframed_bx;
38             }
39              
40             sub _compose {
41 33     33   45 my $self = shift;
42 33         39 my $subject_class = shift;
43 33         40 my $sub_queries = shift;
44 33         39 my $meta_params = shift;
45              
46 33         42 my @underlying_rules;
47             my @expressions;
48 0         0 my @values;
49 33         75 while (@$sub_queries) {
50 78         65 my $underlying_query;
51 78 50       176 if (ref($sub_queries->[0]) eq 'ARRAY') {
    0          
52 78         83 $underlying_query = UR::BoolExpr->resolve($subject_class, @{$sub_queries->[0]}, @$meta_params);
  78         270  
53 78         104 shift @$sub_queries;
54             }
55             elsif (ref($sub_queries->[0]) eq 'UR::BoolExpr::And') {
56 0         0 $underlying_query = shift @$sub_queries;
57             }
58             else {
59 0         0 $underlying_query = UR::BoolExpr->resolve($subject_class, @$sub_queries[0,1], @$meta_params);
60 0         0 shift @$sub_queries;
61 0         0 shift @$sub_queries;
62             }
63              
64 78 50       169 if ($underlying_query->{'_constant_values'}) {
65 0         0 Carp::confess("cannot use -* expressions in subordinate clauses of a logical ");
66             }
67            
68 78 50       206 unless ($underlying_query->template->isa("UR::BoolExpr::Template::And")) {
69 0         0 Carp::confess("$underlying_query is not an AND template");
70             }
71 78         99 push @underlying_rules, $underlying_query;
72              
73 78         140 push @expressions, $underlying_query->template->logic_detail;
74 78         199 push @values, $underlying_query->values;
75             }
76 33         222 my $bxt = UR::BoolExpr::Template::Or->get_by_subject_class_name_logic_type_and_logic_detail($subject_class,'Or',join('|',@expressions));
77 33         124 my $bx = $bxt->get_rule_for_values(@values);
78             # This (and accompanying "caching" in UR::BoolExpr::underlying_rules())
79             # is a giant hack to allow composite rules to have -order and -group
80             # The real fix is to coax the above combination of
81             # get_by_subject_class_name_logic_type_and_logic_detail() and get_rule_for_values() to
82             # properly encode these constant/template values into the rule and template IDs,
83             # and subsequently reconsitiute them when you call $template->order_by
84 33         69 $bx->{'_underlying_rules'} = \@underlying_rules;
85 33         116 for (my $i = 0; $i < @$meta_params; $i += 2) {
86 3         7 my $method = $meta_params->[$i];
87 3         7 substr($method, 0, 1, ''); # remove the -
88 3 50       15 if ($method eq 'recurse') {
    100          
89 0         0 $bx->template->recursion_desc($meta_params->[$i + 1]);
90             } elsif ($method eq 'order') {
91 2         7 $bx->template->order_by($meta_params->[$i + 1]);
92             } else {
93 1         3 $bx->template->$method($meta_params->[$i + 1]);
94             }
95             }
96              
97 33         99 return $bx;
98             }
99              
100             sub _underlying_keys {
101 3     3   22 my $self = shift;
102 3         13 my $logic_detail = $self->logic_detail;
103 3 50       7 return unless $logic_detail;
104 3         11 my @underlying_keys = split('\|',$logic_detail);
105 3         8 return @underlying_keys;
106             }
107              
108             # sub get_underlying_rules_for_values
109              
110             sub get_underlying_rule_templates {
111 3     3 0 5 my $self = shift;
112 3         8 my @underlying_keys = $self->_underlying_keys();
113 3         11 my $subject_class_name = $self->subject_class_name;
114             return map {
115 3         4 UR::BoolExpr::Template::And
  6         26  
116             ->_get_for_subject_class_name_and_logic_detail(
117             $subject_class_name,
118             $_
119             );
120             } @underlying_keys;
121             }
122              
123             sub specifies_value_for {
124 0     0 0 0 my ($self, $property_name) = @_;
125 0 0       0 Carp::confess() if not defined $property_name;
126 0         0 my @underlying_templates = $self->get_underlying_rule_templates();
127 0         0 my @all_specified;
128 0         0 for my $template (@underlying_templates) {
129 0         0 my @specified = $template->specifies_value_for($property_name);
130 0 0       0 if (@specified) {
131 0         0 push @all_specified, @specified;
132             }
133             else {
134 0         0 return;
135             }
136             }
137 0         0 return @all_specified;
138             }
139              
140             sub evaluate_subject_and_values {
141 0     0 0 0 my $self = shift;
142 0         0 my $subject = shift;
143 0 0 0     0 return unless (ref($subject) && $subject->isa($self->subject_class_name));
144 0         0 my @underlying = $self->get_underlying_rule_templates;
145 0         0 while (my $underlying = shift (@underlying)) {
146 0         0 my $n = $underlying->_variable_value_count;
147 0         0 my @next_values = splice(@_,0,$n);
148 0 0       0 if ($underlying->evaluate_subject_and_values($subject,@_)) {
149 0         0 return 1;
150             }
151             }
152 0         0 return;
153             }
154              
155             sub params_list_for_values {
156 1     1 0 2 my $self = shift;
157 1         2 my @values_sorted = @_;
158 1         2 my @list;
159 1         4 my @t = $self->get_underlying_rule_templates;
160 1         3 for my $t (@t) {
161 2         6 my $c = $t->_variable_value_count;
162 2         7 my @l = $t->params_list_for_values(splice(@values_sorted,0,$c));
163 2         5 push @list, \@l;
164             }
165 1         5 return -or => \@list;
166             }
167              
168             sub get_normalized_rule_for_values {
169 9     9 0 15 my $self = shift;
170 9         22 return $self->get_rule_for_values(@_);
171             }
172              
173             1;
174              
175             =pod
176              
177             =head1 NAME
178              
179             UR::BoolExpr::Or - a rule which is true if ANY of the underlying conditions are true
180              
181             =head1 SEE ALSO
182              
183             UR::BoolExpr;(3)
184              
185             =cut