Commit | Line | Data |
b3b54441 |
1 | package SQL::Abstract::Formatter; |
2 | |
3 | require SQL::Abstract::Parts; # it loads us too, don't cross the streams |
4 | |
5 | use Moo; |
6 | |
7 | has indent_by => (is => 'ro', default => ' '); |
8 | has max_width => (is => 'ro', default => 78); |
9 | |
10 | sub _join { |
11 | shift; |
4ebfbfc1 |
12 | return SQL::Abstract::Parts::stringify(\@_); |
b3b54441 |
13 | } |
14 | |
15 | sub format { |
16 | my ($self, $join, @parts) = @_; |
07070f1a |
17 | $self->_fold_sql('', '', @{$self->_simplify($join, @parts)}); |
18 | } |
19 | |
20 | sub _simplify { |
21 | my ($self, $join, @parts) = @_; |
22 | return '' unless @parts; |
23 | return $parts[0] if @parts == 1 and !ref($parts[0]); |
24 | return $self->_simplify(@{$parts[0]}) if @parts == 1; |
25 | return [ $join, map ref() ? $self->_simplify(@$_) : $_, @parts ]; |
26 | } |
27 | |
28 | sub _fold_sql { |
07070f1a |
29 | my ($self, $indent0, $indent, $join, @parts) = @_; |
30 | my @res; |
31 | my $w = $self->max_width; |
32 | my $join_len = 0; |
33 | (s/, \Z/,\n/ and $join_len = 1) |
34 | or s/\A /\n/ |
35 | or $_ = "\n" |
36 | for my $line_join = $join; |
37 | my ($nl_pre, $nl_post) = split "\n", $line_join; |
38 | my $line = $indent0; |
39 | my $next_indent = $indent.$self->indent_by; |
40 | PART: foreach my $idx (0..$#parts) { |
07070f1a |
41 | my $p = $parts[$idx]; |
42 | my $pre = $idx ? $join : ''; |
43 | my $j_part = $pre.(my $j = ref($p) ? $self->_join(@$p) : $p); |
44 | if (length($j_part) + length($line) + $join_len <= $w) { |
45 | $line .= $j_part; |
46 | } else { |
1f2d8ba1 |
47 | if (ref($p) and $p->[1] eq '(' and $p->[-1] eq ')') { |
0655a7af |
48 | push @res, $line.$join.'('."\n"; |
4ebfbfc1 |
49 | my (undef, undef, $inner) = @$p; |
50 | my $folded = $self->_fold_sql($indent, $indent, @$inner); |
51 | push @res, $nl_post.$folded."\n"; |
52 | $line = $indent0.')'; |
53 | next PART; |
54 | } |
4a9ad1af |
55 | push @res, $line.$nl_pre."\n" if $line =~ /\S/; |
07070f1a |
56 | if (length($line = $indent.$nl_post.$j) <= $w) { |
57 | next PART; |
58 | } |
e7d3a4e5 |
59 | my $folded = $self->_fold_sql($indent.$nl_post, $next_indent, @$p); |
4a9ad1af |
60 | $folded =~ s/\n\Z//; |
e7d3a4e5 |
61 | push @res, $folded.$nl_pre."\n"; |
4a9ad1af |
62 | $line = $idx == $#parts ? '' : $indent.$nl_post; |
07070f1a |
63 | } |
07070f1a |
64 | } |
4ebfbfc1 |
65 | return join '', @res, $line; |
b3b54441 |
66 | } |
67 | |
68 | 1; |