File Coverage

blib/lib/DBIx/QuickORM/SQLBuilder/SQLAbstract.pm
Criterion Covered Total %
statement 101 115 87.8
branch 17 32 53.1
condition 6 13 46.1
subroutine 21 24 87.5
pod 1 9 11.1
total 146 193 75.6


line stmt bran cond sub pod time code
1             package DBIx::QuickORM::SQLBuilder::SQLAbstract;
2 23     23   183 use strict;
  23         57  
  23         1063  
3 23     23   302 use warnings;
  23         57  
  23         2347  
4              
5             our $VERSION = '0.000019';
6              
7 23     23   4033 use Carp qw/croak confess/;
  23         54  
  23         2138  
8 23     23   220 use Sub::Util qw/set_subname/;
  23         54  
  23         1551  
9 23     23   198 use Scalar::Util qw/blessed/;
  23         63  
  23         1545  
10 23     23   161 use parent 'SQL::Abstract';
  23         63  
  23         250  
11              
12 23     23   947209 use Role::Tiny::With qw/with/;
  23         70  
  23         18295  
13             with 'DBIx::QuickORM::Role::SQLBuilder';
14              
15             sub new {
16 23     23 1 75 my $class = shift;
17 23         289 return $class->SUPER::new(bindtype => 'columns', @_);
18             }
19              
20             BEGIN {
21 23     23   127 for my $meth (qw/insert update select delete where/) {
22 115         264 my $arg_meth = "_${meth}_args";
23 115         462 my $new_meth = "qorm_${meth}";
24              
25             my $code = sub {
26 162     162 0 442 my $self = shift;
        162 0    
        162 0    
        162 0    
        162 0    
27 162         1100 my %params = @_;
28              
29 162 50       875 my $source = delete $params{source} or croak "No source provided";
30              
31 162         5874 my @args = $self->$arg_meth(\%params);
32              
33 162         437 my ($stmt, @bind);
34 162 50       584 if (blessed($source)) {
35 162 50       819 croak "'$source' does not implement the 'DBIx::QuickORM::Role::Source' role" unless $source->DOES('DBIx::QuickORM::Role::Source');
36 162         18199 my $moniker = $source->source_db_moniker;
37 162         1637 ($stmt, @bind) = $self->$meth($moniker, @args);
38             }
39             else {
40 0         0 ($stmt, @bind) = $self->$meth($source, @args);
41             }
42              
43 162         835675 my $param = 1;
44 162         544 @bind = map { my ($f, $v) = @{$_}; +{param => $param++, value => $v, type => 'field', field => $f} } @bind;
  190         397  
  190         554  
  190         1776  
45              
46 162 50       882 if (my $limit = $params{limit}) {
47 0         0 $stmt .= " LIMIT ?";
48 0         0 push @bind => {param => $param++, value => $limit, type => 'limit'};
49             }
50              
51 162         2051 return {statement => $stmt, bind => \@bind, source => $source};
52 115         914 };
53              
54 23     23   229 no strict 'refs';
  23         66  
  23         2381  
55 115         32325 *$new_meth = set_subname $new_meth => $code;
56             }
57             }
58              
59             sub qorm_upsert {
60 2     2 0 6 my $self = shift;
61 2         11 my %params = @_;
62              
63 2   33     10 my $data = delete $params{insert} // delete $params{update};
64              
65 2         14 my $sql = $self->qorm_insert(%params, insert => $data);
66              
67 2         25 my $pk = $params{source}->primary_key;
68 2 50 33     15 confess "upsert cannot be used on a table without a primary key" unless $pk && @$pk;
69              
70 2         11 my $changes = { %$data };
71 2         7 my $where = { map {$_ => delete $changes->{$_}} @$pk };
  2         11  
72              
73 2   50     9 my $binds = $sql->{bind} //= [];
74 2         5 my $counter = @$binds + 1;
75              
76 2         7 my $returning = "";
77 2         5 my $statement = $sql->{statement};
78 2 50       39 $returning = $1 if $statement =~ s/\s+(returning.*)$//is;
79              
80 2         27 my $conf = $params{dialect}->upsert_statement($pk);
81 2         4 my @inject;
82 2         11 for my $field (sort keys %$changes) {
83 3         7 push @inject => "$field = ?";
84             push @$binds => {
85             field => $field,
86 3         20 value => $changes->{$field},
87             type => 'field',
88             param => $counter++,
89             };
90             }
91 2 50       13 $conf .= " " . join(', ' => @inject) if @inject;
92              
93 2         7 $sql->{statement} = "$statement $conf $returning";
94              
95 2         16 return $sql;
96             }
97              
98             sub _insert_args {
99 80     80   192 my $self = shift;
100 80         284 my ($params) = @_;
101              
102 80 50       329 confess "insert() with a 'limit' clause is not currently supported" if $params->{limit};
103 80 50       303 confess "insert() with an 'order_by' clause is not currently supported" if $params->{order_by};
104              
105 80   33     342 my $values = $params->{insert} // croak "'insert' is required";
106 80         204 my $returning = $params->{returning};
107              
108 80         363 $values = $self->_format_insert_and_update_data($values);
109              
110 80 100       561 return ($values, $returning ? {returning => $returning} : ());
111             }
112              
113             sub _delete_args {
114 4     4   11 my $self = shift;
115 4         13 my ($params) = @_;
116              
117 4 50       22 confess "delete() with a 'limit' clause is not currently supported" if $params->{limit};
118 4 50       39 confess "delete() with an 'order_by' clause is not currently supported" if $params->{order_by};
119              
120 4   100     22 my $where = $params->{where} // undef;
121 4         9 my $returning = $params->{returning};
122              
123 4 50       30 return ($where, $returning ? {returning => $returning} : ());
124             }
125              
126             sub _update_args {
127 12     12   25 my $self = shift;
128 12         39 my ($params) = @_;
129              
130 12 50       48 my $values = $params->{update} or croak "'update' is required";
131 12         29 my $returning = $params->{returning};
132              
133 12         48 $values = $self->_format_insert_and_update_data($values);
134              
135 12 50       57 return ($values, $params->{where}, $returning ? {returning => $returning} : ());
136             }
137              
138             sub _select_args {
139 66     66   156 my $self = shift;
140 66         198 my ($params) = @_;
141              
142 66 50       314 my $fields = $params->{fields} or croak "'fields' is required";
143 66         180 my $where = $params->{where};
144 66         171 my $order = $params->{order_by};
145              
146 66         318 return ($fields, $where, $order);
147             }
148              
149             sub _where_args {
150 0     0   0 my $self = shift;
151 0         0 my ($params) = @_;
152              
153 0         0 my $where = $params->{where};
154 0         0 my $order = $params->{order_by};
155              
156 0         0 return ($where, $order);
157             }
158              
159             sub qorm_and {
160 0     0 0 0 my $self = shift;
161 0         0 my ($a, $b) = @_;
162 0         0 return +{'-and' => [$a, $b]}
163             }
164              
165             sub qorm_or {
166 0     0 0 0 my $self = shift;
167 0         0 my ($a, $b) = @_;
168 0         0 return +{'-or' => [$a, $b]}
169             }
170              
171             sub _format_insert_and_update_data {
172 92     92   218 my $self = shift;
173 92         242 my ($data) = @_;
174              
175 92         394 $data = { map { $_ => {'-value' => $data->{$_}} } keys %$data };
  119         843  
176              
177 92         292 return $data;
178             }
179              
180             1;
181              
182             __END__
183              
184             our $IN_TARGET = 0;
185             sub _render_insert_clause_target {
186             my $self = shift;
187              
188             local $IN_TARGET = 1;
189              
190             $self->SUPER::_render_insert_clause_target(@_);
191             }
192              
193             sub _render_ident {
194             my $self = shift;
195             my (undef, $ident) = @_;
196              
197             unless ($IN_TARGET) {
198             if (my $s = $self->{source}) {
199             if (my $db_name = $s->field_db_name($ident->[0])) {
200             $ident->[0] = $db_name;
201             }
202             }
203             }
204              
205             $self->SUPER::_render_ident(@_);
206             }
207              
208             -value => HASH should work, no need for this
209             sub _expand_insert_value {
210             my ($self, $v) = @_;
211              
212             my $k = $SQL::Abstract::Cur_Col_Meta;
213              
214             if (my $s = $self->{source}) {
215             my $r = ref($v);
216             if ($r eq 'HASH' || $r eq 'ARRAY') {
217             if (my $type = $s->field_type($k)) {
218             return +{-bind => [$k, $v]};
219             }
220             }
221             }
222              
223             return $self->SUPER::_expand_insert_value($v);
224             }