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__ |