File Coverage

lib/SQL/Abstract/Builder.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package SQL::Abstract::Builder;
2              
3 1     1   2461 use v5.14;
  1         4  
  1         42  
4 1     1   983 use DBIx::Simple;
  1         32580  
  1         45  
5 1     1   2027 use SQL::Abstract::More;
  0            
  0            
6             use List::Util qw(reduce);
7             use Hash::Merge qw(merge);
8             Hash::Merge::set_behavior('RETAINMENT_PRECEDENT');
9              
10             use Exporter qw(import);
11             our @EXPORT_OK = qw(query build include);
12              
13             # ABSTRACT: Quickly build & query relational data
14             our $VERSION = 'v0.1.1'; # VERSION
15              
16             sub _refp {
17             return unless defined $_[0];
18             return @{$_[0]} if ref $_[0] eq ref [];
19             return @_;
20             }
21              
22             sub _rollup {
23             my %row = @_;
24             my @fields = grep {m/\w+:\w+/} keys %row;
25             for (@fields) {
26             my ($t,$c) = split ':';
27             $row{$t}{$c} = delete $row{$_};
28             }
29             %row;
30             }
31              
32             sub _smerge {
33             my ($a,$b) = @_;
34             for (keys $b) {
35             $a->{$_} = $b->{$_} unless defined $a->{$_};
36             next if $a->{$_} eq $b->{$_};
37             $a->{$_} = [_refp $a->{$_}] unless ref $a->{$_} eq ref [];
38             push @{$a->{$_}}, _refp $b->{$_};
39             }
40             return $a;
41             }
42              
43             sub query (&;@) {
44             my @db = (shift)->();
45             my $dbh = ref $db[0] eq 'DBIx::Simple' ? $db[0] : DBIx::Simple->connect(@db);
46             my ($key,%row);
47             $row{$_->{$key}} = _smerge $row{$_->{$key}}, $_ for map {{_rollup %$_}}
48             map {my @q;($key,@q) = $_->(); $dbh->query(@q)->hashes} @_;
49             values %row;
50             }
51              
52             sub build (&;@) {
53             my ($fn,@includes) = @_;
54             my %params = $fn->();
55             my $table = $params{'-from'};
56             $params{'-columns'} = [map {"$table.$_"} _refp $params{'-columns'}];
57             my $key = delete $params{'-key'};
58             my $a = SQL::Abstract::More->new;
59             map {
60             my %p = %{merge \%params, {$_->()}};
61             $p{'-from'} = [-join =>
62             map {ref $_ eq ref sub {} ? ($_->($table,$key)) : $_ } _refp $p{'-from'}
63             ];
64             sub {$key, $a->select(%p)};
65             } @includes;
66             }
67              
68             sub include (&;@) {
69             my ($fn,@rest) = @_;
70             my %params = $fn->();
71             my ($jtable,$jfield) = @params{qw(-from -key)};
72             $params{'-columns'} = [
73             map {"$jtable.$_|'$jtable:$_'"}
74             _refp $params{'-columns'}
75             ];
76             $params{'-from'} = sub {"=>{$_[0].$_[1]=$jtable.$jfield}",$jtable};
77             delete $params{'-key'};
78             return sub {%params}, @rest;
79             }
80              
81             1;
82              
83             __END__