| 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 |