File Coverage

blib/lib/MySQL/Explain/Parser.pm
Criterion Covered Total %
statement 71 71 100.0
branch 13 14 92.8
condition n/a
subroutine 9 9 100.0
pod 2 2 100.0
total 95 96 98.9


line stmt bran cond sub pod time code
1             package MySQL::Explain::Parser;
2 3     3   4199 use 5.008005;
  3         10  
  3         109  
3 3     3   15 use strict;
  3         6  
  3         85  
4 3     3   21 use warnings;
  3         5  
  3         72  
5 3     3   938 use utf8;
  3         15  
  3         12  
6 3     3   2303 use parent "Exporter";
  3         907  
  3         14  
7 3     3   2383 use Text::VisualWidth::PP qw/vtrim/;
  3         69465  
  3         2278  
8              
9             our $VERSION = "0.02";
10             our @EXPORT_OK = qw/parse parse_vertical/;
11              
12             sub parse {
13 4     4 1 31575 my ($explain) = @_;
14              
15 4         71 my @rows = grep {$_} split /\r?\n/, $explain;
  25         38  
16              
17 4         8 shift @rows; # Skip the top of outline
18              
19             # Skip bottom unnecessary line(s)
20 4 100       20 if (pop(@rows) =~ /\A\d+\s+rows/) {
21 1         2 pop @rows;
22             }
23              
24 4         11 my $index_row = shift @rows;
25 4         26 my @indexes = grep {$_} split /\|/, $index_row;
  47         109  
26 4         9 my @indexes_length = map {length $_} @indexes;
  43         65  
27 4         8 map {s/\s//g} @indexes; ## no critic
  43         161  
28              
29 4         6 shift @rows; # Skip the separator between header and body
30              
31 4         7 my @parsed;
32 4         7 my $num_of_indexes = scalar @indexes;
33 4         8 for my $row (@rows) {
34 7         8 my %parsed;
35 7         8 my $begin_pos = 0;
36 7         19 for (my $i = 0; $i < $num_of_indexes; $i++) {
37 76         106 my $length = $indexes_length[$i];
38 76         217 my $item = vtrim($row, $length + 1);
39 76         13799 $row =~ s/\A\Q$item\E//;
40 76         383 ($item) = $item =~ /\A\|\s*(.*?)\s*\Z/;
41              
42 76 100       432 $parsed{$indexes[$i]} = $item eq 'NULL' ? undef : $item;
43             }
44 7         25 push @parsed, \%parsed;
45             }
46              
47 4         26 return \@parsed;
48             }
49              
50             sub parse_vertical {
51 4     4 1 41574 my ($explain) = @_;
52              
53 4         8 my @parsed;
54             my @explains;
55 4         132 my @rows = grep {$_} split /\r?\n/, $explain;
  85         120  
56 4         12 for my $row (@rows) {
57 84 100       185 if ($row =~ /\A\*+\s\d/) {
58 7 100       22 if (@explains) {
59 3         11 push @parsed, _parse_yaml_like(\@explains);
60             }
61 7         13 @explains = ();
62 7         14 next;
63             }
64              
65 77         235 $row =~ s/\A\s*//;
66 77         147 push @explains, $row;
67             }
68              
69 4 50       11 if (@explains) {
70 4         12 push @parsed, _parse_yaml_like(\@explains);
71             }
72              
73 4         24 return \@parsed;
74             }
75              
76             sub _parse_yaml_like {
77 7     7   11 my ($explains) = @_;
78              
79 7 100       30 if ($explains->[-1] =~ /\A\d+\s+rows/) {
80 1         2 pop @$explains;
81             }
82              
83 7         10 my %parsed;
84 7         15 for my $explain (@$explains) {
85 76         329 (my $v = $explain) =~ s/\s*?([^:]*):\s*//;
86 76         157 my $k = $1;
87 76 100       145 if ($v eq 'NULL') {
88 11         17 $v = undef;
89             }
90 76         222 $parsed{$k} = $v;
91             }
92 7         25 return \%parsed;
93             }
94              
95             1;
96             __END__