File Coverage

blib/lib/Class/DBI/Sweet/More.pm
Criterion Covered Total %
statement 109 117 93.1
branch 29 38 76.3
condition 12 15 80.0
subroutine 7 7 100.0
pod n/a
total 157 177 88.7


line stmt bran cond sub pod time code
1             package Class::DBI::Sweet::More;
2 7     7   256852 use warnings;
  7         16  
  7         257  
3 7     7   35 use strict;
  7         15  
  7         1034  
4            
5             our $VERSION = '0.01';
6 7     7   47 use base qw/Class::DBI::Sweet/;
  7         14  
  7         46463  
7            
8             sub _search {
9 29     29   6467943 my $proto = shift;
10 29         70 my $criteria = shift;
11 29         60 my $attributes = shift;
12 29   66     311 my $class = ref($proto) || $proto;
13            
14             # Valid SQL::Abstract params
15 29         91 my %params = map { $_ => $attributes->{$_} } qw(case cmp convert logic);
  116         356  
16            
17 29         101 $params{cdbi_class} = $class;
18 29         68 $params{cdbi_me_alias} = 'me';
19            
20             # Overide bindtype, we need all columns and values for deflating
21 29         494 my $abstract =
22             Class::DBI::Sweet::More::SQL::Abstract->new( %params, bindtype => 'columns' );
23            
24 29         8421 my ( $sql, $from, $classes, @bind ) =
25             $abstract->where( $criteria, '', $attributes->{prefetch} );
26            
27 29         70 my ( @columns, @values, %cache );
28            
29 29         61 foreach my $bind (@bind) {
30 28         57 push( @columns, $bind->[0] );
31 28         55 push( @values, @{$bind}[ 1 .. $#$bind ] );
  28         82  
32             }
33            
34 29 100       183 unless ( $sql =~ /^\s*WHERE/i )
35             { # huh? This is either WHERE.. or empty string.
36 3         5 $sql = "WHERE 1=1 $sql";
37             }
38            
39 29         137 $sql =~ s/^\s*(WHERE)\s*//i;
40            
41 29         303 my %sql_parts = (
42             where => $sql,
43             from => $from,
44             limit => '',
45             order_by => '',
46             );
47            
48 29 100       205 $sql_parts{order_by} = $abstract->_order_by( $attributes->{order_by} )
49             if $attributes->{order_by};
50            
51 29 100 100     1212 if ( $attributes->{rows} && !$attributes->{disable_sql_paging} ) {
52            
53 6         15 my $rows = $attributes->{rows};
54 6   50     30 my $offset = $attributes->{offset} || 0;
55 6         27 my $driver = lc $class->db_Main->{Driver}->{Name};
56            
57 6 50       576 if ( $driver =~ /^(maxdb|mysql|mysqlpp)$/ ) {
    50          
    0          
58 0         0 $sql_parts{limit} = ' LIMIT ?, ?';
59 0         0 push( @columns, '__OFFSET', '__ROWS' );
60 0         0 push( @values, $offset, $rows );
61             }
62            
63             elsif ( $driver =~ /^(pg|pgpp|sqlite|sqlite2)$/ ) {
64 6         13 $sql_parts{limit} = ' LIMIT ? OFFSET ?';
65 6         13 push( @columns, '__ROWS', '__OFFSET' );
66 6         15 push( @values, $rows, $offset );
67             }
68            
69             elsif ( $driver =~ /^(interbase)$/ ) {
70 0         0 $sql_parts{limit} = ' ROWS ? TO ?';
71 0         0 push( @columns, '__ROWS', '__OFFSET' );
72 0         0 push( @values, $rows, $offset + $rows );
73             }
74             }
75            
76 29         250 return ( \%sql_parts, $classes, \@columns, \@values );
77             }
78            
79            
80             package Class::DBI::Sweet::More::SQL::Abstract;
81 7     7   728353 use base qw/Class::DBI::Sweet::SQL::Abstract/;
  7         19  
  7         15137  
82            
83             sub where {
84 29     29   98 my ($self, $where, $order, $must_join) = @_;
85 29         177 my $me = $self->{cdbi_me_alias};
86 29         225 $self->{cdbi_table_aliases} = { $me => $self->{cdbi_class} };
87 29         77 $self->{cdbi_join_info} = { };
88 29         68 $self->{cdbi_column_cache} = { };
89              
90 29 100       496 foreach my $join (@{$must_join || []}) {
  29         327  
91 2         9 $self->_resolve_join($me => $join);
92             }
93            
94             ## add
95             {
96 29         47 my $l_alias = $me;
  29         55  
97 29         201 my $l_class = $self->{cdbi_class};
98 29         147 my $meta = $l_class->meta_info;
99 29         538 foreach my $colum (keys %$where) {
100 30         58 my $val = $where->{ $colum };
101 30 100       147 next unless ref $val eq 'HASH';
102 8 100 66     45 next unless exists $val->{'-and'} and ref $val->{'-and'} eq 'ARRAY';
103            
104 1         8 my ($f_alias, $match_col) = $colum =~ m/^(.+?)\.(.+)$/x;
105 1 50       7 next unless $meta->{has_many}{$f_alias};
106            
107 1         2 my $match_list = delete $val->{'-and'};
108 1         2 my $match_count = scalar @$match_list;
109            
110 1         4 for my $i (1 .. $match_count) {
111 2         4 my $new_f_alias = "${f_alias}__$i";
112            
113 2         5 my $new_match_col = $match_col;
114 2 50       5 if ($match_col =~ m/^(.+?)\.(.+)$/x) {
115 0         0 $new_match_col = "$1__$i.$2";
116             }
117 2         23 $where->{"$new_f_alias.$new_match_col"} = shift @$match_list;
118             }
119             }
120             }
121             ## end
122            
123 29         71 my $sql = '';
124 29         176 my (@ret) = $self->_recurse_where($where);
125            
126 29 50       10479 if (@ret) {
127 29         56 my $wh = shift @ret;
128 29 100       133 $sql .= $self->_sqlcase(' where ') . $wh if $wh;
129             }
130              
131 29         244 $sql =~ s/(\S+)( IS(?: NOT)? NULL)/$self->_default_tables($1).$2/ge;
  5         28  
132              
133 29         280 my $joins = delete $self->{cdbi_join_info};
134 29         73 my $tables = delete $self->{cdbi_table_aliases};
135              
136 29         159 my $from = $self->{cdbi_class}->table." ${me}";
137            
138             ## add
139 29         547 foreach my $join ( keys %{$joins} ) {
  29         107  
140 20 100       86 next unless $joins->{$join}{join_type};
141            
142 3         13 my $table = $tables->{$join}->table;
143 3         43 my $join_data = delete $joins->{$join};
144 3         10 my ( $l_alias, $l_key, $f_key, $join_type ) =
145 3         7 @{$join_data}{qw/l_alias l_key f_key join_type/};
146            
147 3         16 $from .= " ${join_type} JOIN ${table} ${join} ON ${l_alias}.${l_key} = ${join}.${f_key}";
148             }
149             # end
150            
151 29         175 foreach my $join (keys %{$joins}) {
  29         79  
152 17         372 my $table = $tables->{$join}->table;
153            
154 17         546 $from .= ", ${table} ${join}";
155 17         60 my ($l_alias, $l_key, $f_key) =
156 17         32 @{$joins->{$join}}{qw/l_alias l_key f_key/};
157 17         79 $sql .= " AND ${l_alias}.${l_key} = ${join}.${f_key}";
158             }
159              
160             # order by?
161             #if ($order) {
162             # $sql .= $self->_order_by($order);
163             #}
164              
165 29         411 delete $self->{cdbi_column_cache};
166            
167 29 50       212 return wantarray ? ($sql, $from, $tables, @ret) : $sql;
168             }
169            
170             sub _resolve_join {
171 20     20   2497 my $self = shift;
172 20         41 my ($l_alias, $f_alias) = @_;
173            
174 20         56 my $l_class = $self->{cdbi_table_aliases}->{$l_alias};
175 20         69 my $meta = $l_class->meta_info;
176            
177             ## add
178 20         326 my $org_f_alias = $f_alias;
179 20 100       82 if ($f_alias =~ /^(.+?)__\d+$/) {
180 2         7 $f_alias = $1;
181             }
182            
183 20         31 my ($rel, $f_class);
184 20 100       172 if ($rel = $meta->{has_a}{$f_alias}) {
    100          
    50          
185 2         8 $f_class = $rel->foreign_class;
186             #$self->{cdbi_join_info}{$f_alias} = {
187 2         20 $self->{cdbi_join_info}{$org_f_alias} = { # modify
188             l_alias => $l_alias,
189             l_key => $f_alias,
190             f_key => ($f_class->columns('Primary'))[0]
191             };
192             }
193             elsif ($rel = $meta->{has_many}{$f_alias}) {
194 10         52 $f_class = $rel->foreign_class;
195             #$self->{cdbi_join_info}{$f_alias} = {
196 10   100     95 $self->{cdbi_join_info}{$org_f_alias} = { # modify
197             l_alias => $l_alias,
198             l_key => ($l_class->columns('Primary'))[0],
199             f_key => $rel->args->{foreign_key},
200             join_type => $rel->args->{join_type} || '', # add
201             };
202             }
203             elsif ($rel = $meta->{might_have}{$f_alias}) {
204 8         349 $f_class = $rel->foreign_class;
205             #$self->{cdbi_join_info}{$f_alias} = {
206 8   100     297 $self->{cdbi_join_info}{$org_f_alias} = { # modify
207             l_alias => $l_alias,
208             l_key => ($l_class->columns('Primary'))[0],
209             f_key => ($f_class->columns('Primary'))[0],
210             join_type => $rel->args->{join_type} || '', # add
211             };
212             }
213             else {
214 0         0 croak("Unable to find join info for ${f_alias} from ${l_class}");
215             }
216              
217             #$self->{cdbi_table_aliases}{$f_alias} = $f_class;
218 20         2016 $self->{cdbi_table_aliases}{$org_f_alias} = $f_class; # modify
219             }
220            
221             1; # End of Class::DBI::Sweet::More
222             __END__