File Coverage

blib/lib/ObjectDB/Util.pm
Criterion Covered Total %
statement 69 94 73.4
branch 31 44 70.4
condition 7 9 77.7
subroutine 9 11 81.8
pod 0 6 0.0
total 116 164 70.7


line stmt bran cond sub pod time code
1             package ObjectDB::Util;
2              
3 7     7   135677 use strict;
  7         39  
  7         197  
4 7     7   40 use warnings;
  7         11  
  7         215  
5              
6 7     7   40 use base 'Exporter';
  7         15  
  7         2228  
7              
8             our $VERSION = '3.28';
9             our @EXPORT_OK = qw(load_class execute to_array merge_rows filter_columns);
10              
11             require Carp;
12             require Storable;
13              
14             sub load_class {
15 5     5 0 9 my ($class) = @_;
16              
17 5 50       22 Carp::croak('class name is required') unless $class;
18              
19 5 50       37 Carp::croak("Invalid class name '$class'")
20             unless $class =~ m/^[[:lower:]\d:]+$/smxi;
21              
22 5         9 my $path = $class;
23 5         24 $path =~ s{::}{/}smxg;
24 5         9 $path .= '.pm';
25              
26 5 100 66     26 return 1 if exists $INC{$path} && defined $INC{$path};
27              
28             {
29 7     7   56 no strict 'refs';
  7         11  
  7         744  
  2         3  
30              
31 2         5 for (keys %{"$class\::"}) {
  2         17  
32 0 0       0 return 1 if defined &{$_};
  0         0  
33             }
34             }
35              
36             eval {
37 2         1146 require $path;
38              
39 2         11 1;
40 2 50       5 } or do {
41 0         0 my $e = $@;
42              
43 0         0 delete $INC{$path};
44              
45             {
46 7     7   49 no strict 'refs';
  7         12  
  7         5580  
  0         0  
47 0         0 %{"$class\::"} = ();
  0         0  
48             }
49              
50 0         0 Carp::croak($e);
51             };
52             }
53              
54             sub execute {
55 0     0 0 0 my ($dbh, $stmt) = @_;
56              
57 0         0 my $sql = $stmt->to_sql;
58 0         0 my @bind = $stmt->to_bind;
59              
60 0         0 my $sth = $dbh->prepare($sql);
61 0         0 my $rv = $sth->execute(@bind);
62              
63 0 0       0 return wantarray ? ($rv, $sth) : $rv;
64             }
65              
66             sub force_arrayrefs {
67 0     0 0 0 my ($data, $defaults) = @_;
68              
69 0         0 my $clone = Storable::dclone($data);
70              
71 0         0 foreach my $key (keys %$defaults) {
72 0 0       0 if (!exists $clone->{$key}) {
    0          
73 0         0 $clone->{$key} = [ @{ $defaults->{$key} } ];
  0         0  
74             }
75             elsif (!ref $clone->{$key}) {
76 0         0 $clone->{$key} = [ $clone->{$key} ];
77             }
78              
79 0         0 push @{ $clone->{$key} }, @{ $defaults->{$key} };
  0         0  
  0         0  
80              
81             }
82              
83 0         0 return $clone;
84             }
85              
86             sub to_array {
87 7     7 0 1476 my ($data) = @_;
88              
89 7 100       33 return () unless defined $data;
90              
91 6 100       28 return @$data if ref $data eq 'ARRAY';
92              
93 1         8 return ($data);
94             }
95              
96             sub merge_rows {
97 14     14 0 24649 my $rows = shift;
98              
99 14         24 my $merged = [];
100              
101 14         22 my %order;
102 14         33 NEXT_MERGE: while (@$rows) {
103 30         45 my $row = shift @$rows;
104              
105 30         39 my $row_sign = '';
106 30         86 foreach my $key (sort keys %$row) {
107 42         64 my $value = $row->{$key};
108 42 100 66     137 $value = \'join' if ref $value eq 'HASH' || ref $value eq 'ARRAY';
109              
110 42 100       70 $value = \undef unless defined $value;
111 42         85 $row_sign .= "$key=$value";
112             }
113              
114 30 100       64 if (!exists $order{$row_sign}) {
115 23         44 $order{$row_sign} = $row;
116              
117 23         39 push @$merged, $row;
118 23         53 next NEXT_MERGE;
119             }
120              
121 7         14 my $prev = $order{$row_sign};
122              
123 7         39 foreach my $key (keys %$row) {
124             next
125             unless ref $prev->{$key} eq 'HASH'
126 12 100 100     51 || ref $prev->{$key} eq 'ARRAY';
127              
128             my $prev_row =
129             ref $prev->{$key} eq 'ARRAY'
130             ? $prev->{$key}->[-1]
131 5 100       17 : $prev->{$key};
132              
133 5         17 my $merged_rows = merge_rows([ $prev_row, $row->{$key} ]);
134 5 100       15 if (@$merged_rows > 1) {
135             my $prev_rows =
136             ref $prev->{$key} eq 'ARRAY'
137             ? $prev->{$key}
138 4 100       13 : [ $prev->{$key} ];
139 4         7 pop @$prev_rows;
140 4         12 $prev->{$key} = [ @$prev_rows, @$merged_rows ];
141             }
142             }
143             }
144              
145 14         40 return $merged;
146             }
147              
148             sub filter_columns {
149 4     4 0 2804 my ($meta_columns, $params) = @_;
150              
151 4         7 my @columns;
152 4 100       13 if ($params->{columns}) {
153 1 50       5 push @columns, to_array($params->{columns}) if $params->{columns};
154             }
155             else {
156 3         8 push @columns, @$meta_columns;
157             }
158              
159 4 100       13 push @columns, to_array($params->{'+columns'}) if $params->{'+columns'};
160 4 100       11 if ($params->{'-columns'}) {
161 1         5 my $minus_columns = { map { $_ => 1 } to_array($params->{'-columns'}) };
  1         6  
162              
163 1 50       3 @columns = grep { !exists $minus_columns->{ ref($_) ? $_->{'-col'} : $_ } } @columns;
  2         11  
164             }
165              
166 4         32 return \@columns;
167             }
168              
169             1;