File Coverage

blib/lib/SQL/Wizard/Expr.pm
Criterion Covered Total %
statement 67 68 98.5
branch 8 10 80.0
condition 5 9 55.5
subroutine 26 27 96.3
pod 0 8 0.0
total 106 122 86.8


line stmt bran cond sub pod time code
1             package SQL::Wizard::Expr;
2              
3 14     14   5089 use strict;
  14         27  
  14         512  
4 14     14   70 use warnings;
  14         22  
  14         536  
5 14     14   1607 use Carp;
  14         1647  
  14         7873  
6 14     14   82 use Scalar::Util qw(blessed);
  14         1590  
  14         5322  
7 14     14   10303 use SQL::Wizard::Expr::Alias;
  14         58  
  14         375  
8 14     14   4627 use SQL::Wizard::Expr::Order;
  14         31  
  14         400  
9 14     14   4397 use SQL::Wizard::Expr::Window;
  14         47  
  14         374  
10 14     14   4919 use SQL::Wizard::Expr::BinaryOp;
  14         32  
  14         373  
11 14     14   4803 use SQL::Wizard::Expr::Value;
  14         34  
  14         2031  
12              
13             use overload
14 3     3   12 '+' => sub { _binop('+', @_) },
15 1     1   3 '-' => sub { _binop('-', @_) },
16 6     6   17 '*' => sub { _binop('*', @_) },
17 2     2   6 '/' => sub { _binop('/', @_) },
18 1     1   4 '%' => sub { _binop('%', @_) },
19 0     0   0 '""' => sub { croak "Cannot stringify SQL::Wizard::Expr directly; use ->to_sql" },
20 57     57   128 'bool' => sub { 1 },
21 14     14   7454 fallback => 1;
  14         21335  
  14         164  
22              
23             sub new {
24 410     410 0 894 my ($class, %args) = @_;
25 410         2187 bless \%args, $class;
26             }
27              
28             sub to_sql {
29 177     177 0 5432 my ($self, $renderer) = @_;
30 177   33     1436 $renderer ||= $self->{_renderer};
31 177 50       315 croak "No renderer available" unless $renderer;
32 177         567 $renderer->render($self);
33             }
34              
35             sub as {
36 28     28 0 59 my ($self, $alias) = @_;
37 28 50       119 croak "alias must be a word (\\w+), got '$alias'" unless $alias =~ /^\w+$/;
38             SQL::Wizard::Expr::Alias->new(
39             expr => $self,
40             alias => $alias,
41             _renderer => $self->{_renderer},
42 28         324 );
43             }
44              
45             sub asc {
46 2     2 0 5 my ($self) = @_;
47             SQL::Wizard::Expr::Order->new(
48             expr => $self,
49             direction => 'ASC',
50             _renderer => $self->{_renderer},
51 2         40 );
52             }
53              
54             sub desc {
55 2     2 0 3 my ($self) = @_;
56             SQL::Wizard::Expr::Order->new(
57             expr => $self,
58             direction => 'DESC',
59             _renderer => $self->{_renderer},
60 2         10 );
61             }
62              
63             sub asc_nulls_first {
64 1     1 0 4 my ($self) = @_;
65             SQL::Wizard::Expr::Order->new(
66             expr => $self,
67             direction => 'ASC',
68             nulls => 'FIRST',
69             _renderer => $self->{_renderer},
70 1         7 );
71             }
72              
73             sub desc_nulls_last {
74 1     1 0 3 my ($self) = @_;
75             SQL::Wizard::Expr::Order->new(
76             expr => $self,
77             direction => 'DESC',
78             nulls => 'LAST',
79             _renderer => $self->{_renderer},
80 1         7 );
81             }
82              
83             sub over {
84 9     9 0 19 my ($self, @args) = @_;
85             # over('window_name') or over(-partition_by => ..., -order_by => ...)
86 9         11 my $spec;
87 9 100 66     33 if (@args == 1 && !ref $args[0]) {
88 4         8 $spec = { name => $args[0] };
89             } else {
90 5         12 my %opts = @args;
91 5         8 $spec = \%opts;
92             }
93             SQL::Wizard::Expr::Window->new(
94             expr => $self,
95             spec => $spec,
96             _renderer => $self->{_renderer},
97 9         64 );
98             }
99              
100             sub _binop {
101 13     13   26 my ($op, $left, $right, $swap) = @_;
102             # Coerce plain values to Value nodes
103 13         20 $right = _coerce($right, $left);
104 13 100       38 ($left, $right) = ($right, $left) if $swap;
105             SQL::Wizard::Expr::BinaryOp->new(
106             op => $op,
107             left => $left,
108             right => $right,
109             _renderer => $left->{_renderer},
110 13         61 );
111             }
112              
113             sub _coerce {
114 13     13   20 my ($thing, $ref_expr) = @_;
115 13 100 66     69 return $thing if blessed($thing) && $thing->isa('SQL::Wizard::Expr');
116             SQL::Wizard::Expr::Value->new(
117             value => $thing,
118             _renderer => $ref_expr->{_renderer},
119 3         9 );
120             }
121              
122             1;