File Coverage

blib/lib/SQL/Abstract/Plugin/InsertMulti.pm
Criterion Covered Total %
statement 88 98 89.8
branch 10 12 83.3
condition 5 8 62.5
subroutine 15 18 83.3
pod 2 2 100.0
total 120 138 86.9


line stmt bran cond sub pod time code
1             package SQL::Abstract::Plugin::InsertMulti;
2              
3 3     3   119778 use strict;
  3         8  
  3         118  
4 3     3   18 use warnings;
  3         4  
  3         144  
5              
6             our $VERSION = '0.04';
7              
8 3     3   19 use Carp ();
  3         9  
  3         156  
9 3         53 use Sub::Exporter -setup => +{
10             into => 'SQL::Abstract',
11             exports => [
12             qw/insert_multi update_multi _insert_multi _insert_multi_HASHREF _insert_multi_ARRAYREF _insert_multi_values _insert_multi_process_args/
13             ],
14             groups => +{
15             default => [
16             qw/insert_multi update_multi _insert_multi _insert_multi_HASHREF _insert_multi_ARRAYREF _insert_multi_values _insert_multi_process_args/
17             ]
18             },
19 3     3   4670 };
  3         46233  
20              
21             sub insert_multi {
22 5     5 1 11273 my $self = shift;
23 5         18 my $table = $self->_table(shift);
24 5         299 my ( $data, $opts, $fields ) = $self->_insert_multi_process_args(@_);
25 5         14 my ( $sql, @bind ) = $self->_insert_multi( $table, $data, $opts );
26 4 50       32 return wantarray ? ( $sql, @bind ) : $sql;
27             }
28              
29             sub _insert_multi {
30 8     8   14 my ( $self, $table, $data, $opts ) = @_;
31              
32 8         30 my $method = $self->_METHOD_FOR_refkind( '_insert_multi', $data->[0] );
33 8         207 my ( $sql, @bind ) = $self->$method( $data, $opts );
34 36         358 $sql = '( '
35 6         11 . join( ', ', ( map { $self->_quote($_) } @{ $opts->{fields} } ) ) . ' ) '
  6         16  
36             . $sql;
37              
38 6 100       87 $sql = join ' ' => grep { defined $_ } (
  30         113  
39             $self->_sqlcase('insert'),
40             $opts->{option},
41             $self->_sqlcase( ( $opts->{ignore} ) ? 'ignore' : 'into' ),
42             $table, $sql,
43             );
44              
45 6         34 return ( $sql, @bind );
46             }
47              
48             sub _insert_multi_HASHREF {
49 7     7   10 my ( $self, $data, $opts ) = @_;
50 7         15 my ( $sql, @bind ) = $self->_insert_multi_values( $data, $opts );
51 5         30 return ( $sql, @bind );
52             }
53              
54             sub _insert_multi_ARRAYREF {
55 1     1   2 my ( $self, $data, $opts ) = @_;
56 4         17 my ( $sql, @bind ) = $self->_insert_multi_values(
57             [
58             map {
59 1         3 my %h;
60 4         5 @h{ @{ $opts->{fields} } } = @$_;
  4         14  
61 4         11 \%h;
62             } @$data
63             ],
64             $opts
65             );
66 1         8 return ( $sql, @bind );
67             }
68              
69             sub _insert_multi_values {
70 8     8   25 my ( $self, $data, $opts ) = @_;
71              
72 8         9 my ( @value_sqls, @all_bind );
73              
74 8         16 for my $d (@$data) {
75 26         28 my @values;
76 26         22 for my $column ( @{$opts->{fields}} ) {
  26         53  
77 146         839 my $v = $d->{$column};
78              
79             $self->_SWITCH_refkind(
80             $v,
81             {
82             ARRAYREFREF => sub { # literal SQL with bind
83 0     0   0 my ( $sql, @bind ) = @${$v};
  0         0  
84              
85             # $self->_assert_bindval_matches_bindtype(@bind);
86 0         0 push @values, $sql;
87 0         0 push @all_bind, @bind;
88             },
89              
90             # THINK : anything useful to do with a HASHREF ?
91             HASHREF => sub { # (nothing, but old SQLA passed it through)
92             #TODO in SQLA >= 2.0 it will die instead
93 0     0   0 push @values, '?';
94 0         0 push @all_bind, $self->_bindtype( $column, $v );
95             },
96             SCALARREF => sub { # literal SQL without bind
97 54     54   1295 push @values, $$v;
98             },
99             SCALAR_or_UNDEF => sub {
100 90     90   1546 push @values, '?';
101 90         202 push @all_bind, $self->_bindtype( $column, $v );
102             },
103             }
104 146         1162 );
105             }
106 24         223 push( @value_sqls, '( ' . join( ', ' => @values ) . ' )' );
107             }
108              
109 6         18 my $sql = $self->_sqlcase('values') . ' ' . join( ', ' => @value_sqls );
110              
111 6 100       47 if ( $opts->{update} ) {
112 3         4 my @set;
113              
114 3         4 for my $k ( sort keys %{ $opts->{update} } ) {
  3         12  
115 9         13 my $v = $opts->{update}{$k};
116 9         11 my $r = ref $v;
117 9         20 my $label = $self->_quote($k);
118              
119             $self->_SWITCH_refkind(
120             $v,
121             {
122             ARRAYREFREF => sub { # literal SQL with bind
123 0     0   0 my ( $sql, @bind ) = @${$v};
  0         0  
124 0         0 push @set, "$label = $sql";
125 0         0 push @all_bind, @bind;
126             },
127             SCALARREF => sub { # literal SQL without bind
128 8     8   224 push @set, "$label = $$v";
129             },
130             SCALAR_or_UNDEF => sub {
131 1     1   20 push @set, "$label = ?";
132 1         3 push @all_bind, $self->_bindtype( $k, $v );
133             },
134             }
135 9         160 );
136             }
137              
138             $sql .=
139 3         23 $self->_sqlcase(' on duplicate key update ') . join( ', ', @set );
140             }
141              
142 6         59 return ( $sql, @all_bind );
143             }
144              
145             sub _insert_multi_process_args {
146 8     8   12 my $self = shift;
147 8         10 my ( $data, $opts, $fields );
148              
149 8 100 66     46 if ( ref $_[0] eq 'ARRAY' && !ref $_[0]->[0] ) {
150 1         3 $fields = shift;
151             }
152             else {
153 7         14 $fields = [ sort keys %{ $_[0]->[0] } ];
  7         43  
154             }
155              
156 8         16 ( $data, $opts ) = @_;
157              
158 8   100     23 $opts ||= +{};
159 8   33     35 $opts->{fields} ||= $fields;
160              
161 8         15 return ( $data, $opts );
162             }
163              
164             sub update_multi {
165 3     3 1 7567 my $self = shift;
166 3         10 my $table = $self->_table(shift);
167 3         132 my ( $data, $opts ) = $self->_insert_multi_process_args(@_);
168              
169 3         4 my %ignore;
170 3 100       9 if ($opts->{update_ignore_fields}) {
171 1         1 @ignore{@{$opts->{update_ignore_fields}}} = map { 1 } @{$opts->{update_ignore_fields}};
  1         4  
  4         6  
  1         3  
172             }
173            
174 9         25 $opts->{update} = +{
175             map {
176 13         20 my ( $k, $v ) = ( $_, $self->_sqlcase('values( ') . $_ . ' )' );
177 9         54 ( $k, \$v );
178             }
179 3         5 grep { !exists $ignore{$_} }
180 3         4 @{ $opts->{fields} }
181             };
182              
183 3         8 my ( $sql, @bind ) = $self->_insert_multi( $table, $data, $opts );
184 2 50       23 return wantarray ? ( $sql, @bind ) : $sql;
185             }
186              
187             1;
188             __END__