File Coverage

blib/lib/ObjectDB/Table.pm
Criterion Covered Total %
statement 36 203 17.7
branch 0 58 0.0
condition 0 39 0.0
subroutine 12 24 50.0
pod 6 9 66.6
total 54 333 16.2


line stmt bran cond sub pod time code
1             package ObjectDB::Table;
2              
3 5     5   27 use strict;
  5         7  
  5         115  
4 5     5   21 use warnings;
  5         8  
  5         177  
5              
6             our $VERSION = '3.26';
7              
8 5     5   22 use constant DEFAULT_PAGE_SIZE => 10;
  5         14  
  5         365  
9              
10             require Carp;
11 5     5   26 use SQL::Composer;
  5         8  
  5         168  
12 5     5   24 use SQL::Composer::Expression;
  5         22  
  5         102  
13 5     5   18 use ObjectDB;
  5         9  
  5         153  
14 5     5   1766 use ObjectDB::Stmt;
  5         11  
  5         112  
15 5     5   1651 use ObjectDB::Iterator;
  5         11  
  5         113  
16 5     5   25 use ObjectDB::Quoter;
  5         9  
  5         76  
17 5     5   1454 use ObjectDB::With;
  5         12  
  5         106  
18 5     5   24 use ObjectDB::Meta;
  5         8  
  5         88  
19 5     5   19 use ObjectDB::Util qw(execute to_array filter_columns);
  5         8  
  5         9059  
20              
21             sub new {
22 0     0 0   my $class = shift;
23 0 0         $class = ref $class if ref $class;
24 0           my (%params) = @_;
25              
26 0           my $self = {};
27 0           bless $self, $class;
28              
29 0           $self->{class} = $params{class};
30 0           $self->{dbh} = $params{dbh};
31              
32 0           return $self;
33             }
34              
35             sub meta {
36 0     0 0   my $self = shift;
37              
38 0           return $self->{class}->meta;
39             }
40              
41             sub dbh {
42 0     0 0   my $self = shift;
43              
44 0           return $self->{dbh};
45             }
46              
47             sub find {
48 0     0 1   my $self = shift;
49 0           my (%params) = @_;
50              
51 0   0       my $single = $params{single} || $params{first};
52              
53 0           my $offset = $params{offset};
54 0           my $limit = $params{limit};
55              
56 0 0         if ($single) {
    0          
57 0           $limit = 1;
58             }
59             elsif (my $page = $params{page}) {
60 0           my $page_size = $params{page_size};
61              
62 0 0 0       $page = 1 unless $page && $page =~ m/^[0-9]+$/;
63 0 0 0       $page_size = DEFAULT_PAGE_SIZE unless $page_size && $page_size =~ m/^[0-9]+$/;
64              
65 0           $offset = ($page - 1) * $page_size;
66 0           $limit = $page_size;
67             }
68              
69 0           my $table = $self->meta->table;
70              
71             my $quoter = ObjectDB::Quoter->new(
72             meta => $self->meta,
73             driver => $self->dbh->{Driver}->{Name},
74 0           );
75             my $where = SQL::Composer::Expression->new(
76             quoter => $quoter,
77             expr => $params{where},
78 0           default_prefix => $table
79             );
80             my $having = SQL::Composer::Expression->new(
81             quoter => $quoter,
82             expr => $params{having},
83 0           default_prefix => $table
84             );
85             my $with = ObjectDB::With->new(
86             meta => $self->meta,
87 0           with => [ to_array($params{with}), $quoter->with ]
88             );
89              
90 0           my $columns = filter_columns([ $self->meta->columns ], {%params});
91              
92 0           my $join = $with->to_joins;
93 0 0         push @$join, to_array($params{join}) if $params{join};
94              
95             my $select = SQL::Composer->build(
96             'select',
97             driver => $self->dbh->{Driver}->{Name},
98             from => $table,
99             columns => $columns,
100             join => $join,
101             where => $where,
102             limit => $limit,
103             offset => $offset,
104             order_by => $params{order_by},
105             group_by => $params{group_by},
106             having => $having,
107             for_update => $params{for_update},
108 0           );
109              
110 0           my ($rv, $sth) = execute($self->dbh, $select);
111              
112 0           return $self->_finalize_results($select, $sth, %params, meta => $self->meta, wantarray => wantarray);
113             }
114              
115             sub find_by_compose {
116 0     0 1   my $self = shift;
117 0           my (%params) = @_;
118              
119 0   0       my $single = $params{single} || $params{first};
120              
121 0           my $offset = $params{offset};
122 0           my $limit = $params{limit};
123              
124 0 0         if ($single) {
    0          
125 0           $limit = 1;
126             }
127             elsif (my $page = $params{page}) {
128 0           my $page_size = $params{page_size};
129              
130 0 0 0       $page = 1 unless $page && $page =~ m/^[0-9]$/;
131 0 0 0       $page_size = DEFAULT_PAGE_SIZE unless $page_size && $page_size =~ m/^[0-9]$/;
132              
133 0           $offset = ($page - 1) * $page_size;
134 0           $limit = $page_size;
135             }
136              
137 0           my $table = $params{table};
138              
139             my $select = SQL::Composer->build(
140             'select',
141             driver => $self->dbh->{Driver}->{Name},
142             from => $table,
143             columns => $params{columns},
144             join => $params{join},
145             where => $params{where},
146             limit => $params{limit},
147             offset => $params{offset},
148             order_by => $params{order_by},
149             group_by => $params{group_by},
150             having => $params{heaving},
151             for_update => $params{for_update},
152 0           );
153              
154 0           my ($rv, $sth) = execute($self->dbh, $select);
155              
156 0           my $meta;
157 0 0         if (!$params{rows_as_hashes}) {
158 0           $meta = ObjectDB::Meta->find_by_table($table);
159 0 0         die qq{Can't find meta for table '$table'} unless $meta;
160             }
161              
162 0           return $self->_finalize_results($select, $sth, %params, meta => $meta, wantarray => wantarray);
163             }
164              
165             sub find_by_sql {
166 0     0 1   my $self = shift;
167 0           my ($sql, $bind, %params) = @_;
168              
169 0   0       my $single = $params{single} || $params{first};
170              
171 0           my @bind;
172 0 0         if (ref $bind eq 'HASH') {
173 0           while ($sql =~ s{:([[:alnum:]]+)}{?}) {
174 0           push @bind, $bind->{$1};
175             }
176             }
177             else {
178 0 0 0       @bind = @$bind if $bind && ref $bind eq 'ARRAY';
179             }
180              
181 0           my $stmt = ObjectDB::Stmt->new(sql => $sql, bind => \@bind);
182              
183 0           my ($rv, $sth) = execute($self->dbh, $stmt);
184              
185 0           my @column_names = @{ $sth->{NAME_lc} };
  0            
186              
187 0 0 0       if (my $cb = $params{each}) {
    0          
188 0           while (my $row = $sth->fetchrow_arrayref) {
189 0           my $row_copy = [@$row];
190 0           my %values;
191 0           foreach my $column (@column_names) {
192 0           $values{$column} = shift @$row_copy;
193             }
194              
195 0           my $object = $self->meta->class->new(%values);
196 0           $object->is_in_db(1);
197              
198 0           $cb->($object);
199             }
200              
201 0           return $self;
202             }
203             elsif ($single || wantarray) {
204 0           my $rows = $sth->fetchall_arrayref;
205 0 0 0       return () unless $rows && @$rows;
206              
207 0           my $i = 0;
208 0           my @results;
209 0           foreach my $row (@$rows) {
210 0           my %values;
211 0           foreach my $column (@column_names) {
212 0           $values{$column} = $row->[ $i++ ];
213             }
214              
215 0 0         if ($params{rows_as_hashes}) {
216 0           push @results, \%values;
217             }
218             else {
219 0           push @results, $self->meta->class->new(%values)->is_in_db(1);
220             }
221             }
222              
223 0           return @results;
224             }
225             else {
226 0           my $i = 0;
227             my $walker = sub {
228 0     0     my $row = $sth->fetchrow_arrayref;
229 0 0         return unless defined $row;
230              
231 0           my %values;
232 0           foreach my $column (@column_names) {
233 0           $values{$column} = $row->[ $i++ ];
234             }
235              
236 0           my $result;
237 0 0         if ($params{rows_as_hashes}) {
238 0           $result = \%values;
239             }
240             else {
241 0           $result = $self->meta->class->new(%values);
242 0           $result->is_in_db(1);
243             }
244              
245 0           return $result;
246 0           };
247              
248 0           return ObjectDB::Iterator->new(walker => $walker);
249             }
250             }
251              
252             sub _finalize_results {
253 0     0     my $self = shift;
254 0           my ($select, $sth, %params) = @_;
255              
256 0           my $meta = $params{meta};
257 0   0       my $single = $params{single} || $params{first};
258              
259 0 0 0       if (my $cb = $params{each}) {
    0          
260 0           while (my $row = $sth->fetchrow_arrayref) {
261 0           my $rows = [ [@$row] ];
262 0           $rows = $select->from_rows($rows);
263              
264 0           my $result;
265 0 0         if ($params{rows_as_hashes}) {
266 0           $result = $rows->[0];
267             }
268             else {
269 0           $result = $meta->class->new(%{ $rows->[0] });
  0            
270 0           $result = $result->is_in_db(1);
271             }
272              
273 0           $cb->($result);
274             }
275              
276 0           return $self;
277             }
278             elsif ($single || $params{wantarray}) {
279 0           my $rows = $sth->fetchall_arrayref;
280 0 0 0       return unless $rows && @$rows;
281              
282 0           $rows = $select->from_rows($rows);
283              
284 0           my @results;
285              
286 0 0         if ($params{rows_as_hashes}) {
287 0           @results = @$rows;
288             }
289             else {
290             @results =
291 0           map { $_->is_in_db(1) }
292 0           map { $meta->class->new->set_columns(%{$_}) } @$rows;
  0            
  0            
293             }
294              
295 0 0         return $single ? $results[0] : @results;
296             }
297             else {
298             my $walker = sub {
299 0     0     my $row = $sth->fetchrow_arrayref;
300 0 0         return unless defined $row;
301              
302 0           my $rows = [ [@$row] ];
303 0           $rows = $select->from_rows($rows);
304              
305 0           my $result;
306 0 0         if ($params{rows_as_hashes}) {
307 0           $result = $rows->[0];
308             }
309             else {
310 0           $result = $meta->class->new(%{ $rows->[0] });
  0            
311 0           $result->is_in_db(1);
312             }
313              
314 0           return $result;
315 0           };
316              
317 0           return ObjectDB::Iterator->new(walker => $walker);
318             }
319             }
320              
321             sub update {
322 0     0 1   my $self = shift;
323 0           my (%params) = @_;
324              
325             my $sql = SQL::Composer->build(
326             'update',
327             driver => $self->dbh->{Driver}->{Name},
328             table => $self->meta->table,
329             set => $params{set},
330             where => $params{where},
331 0           );
332              
333 0           my $rv = execute($self->dbh, $sql);
334 0           return $rv;
335             }
336              
337             sub delete : method {
338 0     0 1   my $self = shift;
339 0           my (%params) = @_;
340              
341             my $sql = SQL::Composer->build(
342             'delete',
343             driver => $self->dbh->{Driver}->{Name},
344             from => $self->meta->table,
345             where => $params{where},
346 0           );
347              
348 0           my $rv = execute($self->dbh, $sql);
349 0           return $rv;
350             }
351              
352             sub count {
353 0     0 1   my $self = shift;
354 0           my (%params) = @_;
355              
356             my $quoter = ObjectDB::Quoter->new(
357             driver => $self->dbh->{Driver}->{Name},
358 0           meta => $self->meta
359             );
360             my $where = SQL::Composer::Expression->new(
361             quoter => $quoter,
362             expr => $params{where},
363 0           default_prefix => $self->meta->table
364             );
365 0           my $with = ObjectDB::With->new(meta => $self->meta, with => [ $quoter->with ]);
366              
367 0           my $joins = $with->to_joins;
368 0 0         push @$joins, @{ $params{join} } if $params{join};
  0            
369              
370             # We have to remove columns, because:
371             # 1) we don't need them
372             # 2) PostgreSQL complains
373 0           delete $_->{columns} for @$joins;
374              
375             my $select = SQL::Composer->build(
376             'select',
377             driver => $self->dbh->{Driver}->{Name},
378             from => $self->meta->table,
379             columns => [ { -col => \'COUNT(*)', -as => 'count' } ],
380             where => $where,
381             join => $joins,
382             group_by => $params{group_by},
383 0           );
384              
385 0           my ($rv, $sth) = execute($self->dbh, $select);
386              
387 0           my $results = $sth->fetchall_arrayref;
388 0           my $row_object = $select->from_rows($results);
389              
390 0           return $row_object->[0]->{count};
391             }
392              
393             1;
394             __END__