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