File Coverage

blib/lib/DBIx/Class/Smooth/FilterItem.pm
Criterion Covered Total %
statement 23 125 18.4
branch 0 58 0.0
condition 0 21 0.0
subroutine 8 15 53.3
pod 0 7 0.0
total 31 226 13.7


line stmt bran cond sub pod time code
1 2     2   25 use 5.20.0;
  2         7  
2 2     2   13 use strict;
  2         4  
  2         43  
3 2     2   10 use warnings;
  2         5  
  2         127  
4              
5             package DBIx::Class::Smooth::FilterItem;
6              
7             # ABSTRACT: Short intro
8             our $AUTHORITY = 'cpan:CSSON'; # AUTHORITY
9             our $VERSION = '0.0101';
10              
11 2     2   11 use Carp qw/croak confess/;
  2         4  
  2         103  
12 2     2   11 use Safe::Isa qw/$_isa/;
  2         7  
  2         181  
13 2     2   14 use Scalar::Util qw/blessed/;
  2         4  
  2         86  
14 2     2   13 use Moo;
  2         4  
  2         21  
15              
16 2     2   728 use experimental qw/signatures postderef/;
  2         5  
  2         16  
17              
18             # parts, resultset and value (and nothing else) are constructor args
19             has parts => (
20             is => 'rw',
21             required => 1,
22             default => sub { [] },
23             );
24             has resultset => (
25             is => 'rw',
26             required => 1,
27             default => sub { undef },
28             );
29             has value => (
30             is => 'rw',
31             required => 1,
32             );
33              
34             # so these are *not* constructor args
35             for my $scalar_arg (qw/left_hand_prefix operator sql_operator column_name/) {
36             has $scalar_arg => (
37             is => 'rw',
38             default => sub { undef },
39             );
40             }
41             has left_hand_functions => (
42             is => 'rw',
43             default => sub { [] },
44             );
45             has quote_value => (
46             # it's a boolean!
47             is => 'rw',
48             default => sub { 1 },
49             );
50              
51             around BUILDARGS => sub ($orig, $class, %args) {
52             if(exists $args{'resultset'} && exists $args{'value'}) {
53             if(blessed $args{'value'}) {
54             my $flatten_method = sprintf 'smooth__flatten__%s', blessed $args{'value'};
55             if($args{'resultset'}->can($flatten_method)) {
56             $args{'value'} = $args{'resultset'}->$flatten_method($args{'value'});
57             }
58             }
59             }
60             $class->$orig(%args);
61             };
62              
63 0     0 0   sub get_part($self, $index) {
  0            
  0            
  0            
64 0           return $self->parts->[$index];
65             }
66 0     0 0   sub get_all_parts($self) {
  0            
  0            
67 0           return $self->parts->@*;
68             }
69 0     0 0   sub shift_parts($self, $repeats = 1) {
  0            
  0            
  0            
70 0 0         if($repeats == 1) {
    0          
71 0           return shift $self->parts->@*;
72             }
73             elsif($repeats > 1) {
74 0           return splice $self->parts->@*, 0, $repeats;
75             }
76             }
77              
78 0     0 0   sub set_left_hand_prefix($self, $prefix) {
  0            
  0            
  0            
79 0 0         if(defined $self->left_hand_prefix) {
80 0           die "Trying to set left hand prefix ($prefix), but it is already set to (@{[ $self->left_hand_prefix ]})";
  0            
81             }
82 0           $self->left_hand_prefix($prefix);
83             }
84              
85 0     0 0   sub add_left_hand_function($self, $data) {
  0            
  0            
  0            
86 0           push $self->left_hand_functions->@* => $data;
87             }
88 0     0 0   sub left_hand_functions_get_all($self) {
  0            
  0            
89 0 0         if(!$self->left_hand_functions) {
90 0           return ();
91             }
92 0           return $self->left_hand_functions->@*;
93             }
94              
95 0     0 0   sub parse($self) {
  0            
  0            
96             # Ordinary column name, like 'me.first_name' or 'that_relation.whatever', then we keep that as the column name
97 0 0         if($self->get_part(0) =~ m/\./) {
    0          
98 0           $self->column_name($self->shift_parts);
99             }
100             # Otherwise we make it into an ordinary column name
101             elsif($self->resultset->result_source->has_column($self->get_part(0))) {
102 0           $self->column_name(sprintf '%s.%s', $self->resultset->current_source_alias, $self->shift_parts);
103             }
104             else {
105 0           my $possible_relation = $self->get_part(0);
106 0           my $possible_column = $self->get_part(1);
107              
108 0           my $has_relationship = $self->resultset->result_source->has_relationship($possible_relation);
109              
110 0 0 0       if($has_relationship && defined $possible_column && $self->resultset->result_source->relationship_info($possible_relation)->{'class'}->has_column($possible_column)) {
    0 0        
      0        
111 0 0         if($self->value->$_isa('DBIx::Class::Row')) {
112 0           confess "Don't pass a row object to a column";
113             }
114 0           $self->column_name(sprintf '%s.%s', $self->shift_parts(2));
115             }
116             elsif($has_relationship && $self->value->$_isa('DBIx::Class::Row')) {
117 0           $self->column_name(sprintf '%s.id', $possible_relation);
118 0           $self->value($self->value->id);
119 0           $self->shift_parts;
120             }
121             else {
122 0           confess "Has no relation <$possible_relation> or that has no column <$possible_column>";
123             }
124             }
125              
126 0           for my $part ($self->get_all_parts) {
127 0           my @params = ();
128 0 0         if($part =~ m{^ (\w+) \( ([^)]+) \) $}x) {
129 0           $part = $1;
130 0           @params = split /\s*,\s*/ => $2;
131             }
132 0           my $method = "smooth__lookup__$part";
133              
134 0           my $lookup_result;
135 0 0         if($self->resultset->can($method)) {
136 0           $lookup_result = $self->resultset->$method($self->column_name, $self->value, \@params);
137             }
138             else {
139 0           confess "Can't do <$method>, find suitable Lookup and add it to load_components";
140             }
141              
142 0 0         if(!exists $lookup_result->{'value'}) {
143 0           confess "Lookup for <$part> is expected to return { value => ... }, can't proceed";
144             }
145 0           $self->value(delete $lookup_result->{'value'});
146 0 0         if(exists $lookup_result->{'left_hand_function'}) {
147 0           $self->add_left_hand_function(delete $lookup_result->{'left_hand_function'});
148             }
149 0 0         if(exists $lookup_result->{'left_hand_prefix'}) {
150 0           $self->set_left_hand_prefix(delete $lookup_result->{'left_hand_prefix'});
151             }
152 0 0         if(exists $lookup_result->{'sql_operator'}) {
153 0           $self->sql_operator(delete $lookup_result->{'sql_operator'});
154             }
155 0 0         if(exists $lookup_result->{'operator'}) {
156 0           $self->operator(delete $lookup_result->{'operator'});
157             }
158 0 0         if(exists $lookup_result->{'quote_value'}) {
159 0           $self->quote_value(delete $lookup_result->{'quote_value'});
160             }
161             else {
162 0           $self->quote_value(1);
163             }
164 0 0         if(scalar keys $lookup_result->%*) {
165 0           die sprintf "Unexpected keys returned from lookup for <$part>: %s", join(', ' => sort keys $lookup_result->%*);
166             }
167             }
168              
169             # Happy case
170 0 0 0       if((!defined $self->left_hand_functions || !scalar $self->left_hand_functions->@*) && !defined $self->left_hand_prefix && $self->quote_value) {
      0        
171 0           my $column_name = $self->column_name;
172              
173 0 0 0       if($self->operator && $self->operator ne '=') {
174 0           return ($self->column_name, { $self->operator => $self->value });
175             }
176             else {
177 0           return ($self->column_name, $self->value);
178             }
179             }
180             else {
181 0           my @left_hand = ();
182 0 0         if($self->left_hand_prefix) {
183 0           push @left_hand => $self->left_hand_prefix;
184             }
185 0           my $function_call_string = $self->column_name;
186 0           for my $lhf ($self->left_hand_functions_get_all) {
187 0 0 0       if(exists $lhf->{'complete'}) {
    0          
    0          
188 0           $function_call_string = delete $lhf->{'complete'};
189             }
190             elsif(exists $lhf->{'name'}) {
191 0           $function_call_string = sprintf '%s(%s)', delete ($lhf->{'name'}), $function_call_string;
192             }
193             elsif(exists $lhf->{'start'} && exists $lhf->{'end'}) {
194 0           $function_call_string = sprintf '%s%s%s', delete ($lhf->{'start'}), $function_call_string, delete ($lhf->{'end'});
195             }
196             }
197 0           push @left_hand => $function_call_string;
198 0 0         push @left_hand => $self->sql_operator ? $self->sql_operator : $self->operator ? $self->operator : '=';
    0          
199              
200 0 0         if($self->quote_value) {
201             # Either ? or (?, ?, ...., ?)
202 0 0         my $placeholders = ref $self->value eq 'ARRAY' ? '(' . join(', ', split (//, ('?' x scalar $self->value->@*))) . ')' : ' ? ';
203 0           push @left_hand => $placeholders;
204              
205 0           my $left_hand = join ' ' => @left_hand;
206 0 0         return (undef, \[$left_hand, (ref $self->value eq 'ARRAY' ? $self->value->@* : $self->value)]);
207             }
208             else {
209 0           push @left_hand => $self->value;
210 0           my $left_hand = join ' ' => @left_hand;
211 0           return (undef, \[$left_hand]);
212             }
213             }
214             }
215              
216             1;
217              
218             __END__
219              
220             =pod
221              
222             =encoding UTF-8
223              
224             =head1 NAME
225              
226             DBIx::Class::Smooth::FilterItem - Short intro
227              
228             =head1 VERSION
229              
230             Version 0.0101, released 2018-11-29.
231              
232             =head1 SOURCE
233              
234             L<https://github.com/Csson/p5-DBIx-Class-Smooth>
235              
236             =head1 HOMEPAGE
237              
238             L<https://metacpan.org/release/DBIx-Class-Smooth>
239              
240             =head1 AUTHOR
241              
242             Erik Carlsson <info@code301.com>
243              
244             =head1 COPYRIGHT AND LICENSE
245              
246             This software is copyright (c) 2018 by Erik Carlsson.
247              
248             This is free software; you can redistribute it and/or modify it under
249             the same terms as the Perl 5 programming language system itself.
250              
251             =cut