App-DBBrowser
view release on metacpan or search on metacpan
lib/App/DBBrowser/Auxil.pm view on Meta::CPAN
package # hide from PAUSE
App::DBBrowser::Auxil;
use warnings;
use strict;
use 5.016;
use Encode qw( decode );
use Scalar::Util qw( looks_like_number );
#use Storable qw(); # required
use DBI::Const::GetInfoType;
use JSON::MaybeXS qw( decode_json );
use List::MoreUtils qw( none );
use Term::Choose qw();
use Term::Choose::Constants qw( EXTRA_W );
use Term::Choose::LineFold qw( line_fold );
use Term::Choose::Screen qw( clear_screen );
use Term::Choose::Util qw( insert_sep get_term_width get_term_height unicode_sprintf );
use Term::Form::ReadLine qw();
sub new {
my ( $class, $info, $options, $d ) = @_;
bless {
i => $info,
o => $options,
d => $d
}, $class;
}
sub reset_sql {
my ( $sf, $sql ) = @_;
# preserve base data: table name, column names and data types:
my $backup = {
table => $sql->{table} // '',
columns => $sql->{columns} // [],
data_types => $sql->{data_types} // {},
};
# reset:
delete @{$sql}{ keys %$sql }; # not "$sql = {}" so $sql is still pointing to the outer $sql
# initialize:
my @string = qw( distinct_stmt set_stmt where_stmt having_stmt order_by_stmt limit_stmt offset_stmt );
my @array = qw( group_by_cols selected_cols set_args order_by_cols
ct_column_definitions ct_table_constraints ct_table_options
insert_col_names insert_args );
my @hash = qw( alias );
@{$sql}{@string} = ( '' ) x @string;
@{$sql}{@array} = map{ [] } @array;
@{$sql}{@hash} = map{ {} } @hash;
for my $y ( keys %$backup ) {
$sql->{$y} = $backup->{$y};
}
}
sub __stmt_fold {
my ( $sf, $term_w, $used_for, $stmt, $indent ) = @_;
if ( $used_for eq 'print' ) {
my $in = ' ' x $sf->{o}{G}{base_indent};
my %tabs = ( init_tab => $in x $indent, subseq_tab => $in x ( $indent + 1 ) );
return line_fold( $stmt, { width => $term_w, %tabs, join => 0 } );
}
else {
return $stmt;
}
}
sub __select_cols {
my ( $sf, $sql ) = @_;
my @cols;
if ( @{$sql->{selected_cols}} ) {
@cols = @{$sql->{selected_cols}};
}
elsif ( keys %{$sql->{alias}} && ! $sql->{aggregate_mode} ) {
@cols = @{$sql->{columns}};
# use column names and not * if columns have aliases (join)
lib/App/DBBrowser/Auxil.pm view on Meta::CPAN
my $term_h = get_term_height();
my $term_w = get_term_width() + EXTRA_W;
my $row_count = @{$sql->{insert_args}};
if ( $row_count == 0 ) {
return [];
}
my $col_count = 0; ##
if ( $sf->{d}{stmt_types}[0] && $sf->{d}{stmt_types}[0] eq 'Create_Table' ) {
$col_count = @{$sql->{insert_args}[0]//[]};
#$col_count = @{$sql->{ct_column_definitions//[]}};
$col_count += 1 + $sf->{o}{create}{table_constraint_rows} if $sf->{o}{create}{table_constraint_rows};
$col_count += 1 + $sf->{o}{create}{table_option_rows} if $sf->{o}{create}{table_option_rows};
$col_count += 12;
if ( $col_count < 22 ) {
$col_count = 22;
}
}
else {
$col_count = 22;
}
my $avail_h = $term_h - $col_count;
if ( $avail_h < $term_h / 3.5 ) {
$avail_h = int $term_h / 3.5;
}
if ( $avail_h < 5) {
$avail_h = 5;
}
my $tmp = [];
if ( $row_count > $avail_h ) {
$avail_h -= 2; # for "[...]" + "[count rows]"
my $count_part_1 = int( $avail_h / 1.5 );
my $count_part_2 = $avail_h - $count_part_1;
my $begin_idx_part_1 = 0;
my $end___idx_part_1 = $count_part_1 - 1;
my $begin_idx_part_2 = $row_count - $count_part_2;
my $end___idx_part_2 = $row_count - 1;
for my $row ( @{$sql->{insert_args}}[ $begin_idx_part_1 .. $end___idx_part_1 ] ) {
push @$tmp, $sf->__prepare_data_row( $row, $indent, $term_w );
}
push @$tmp, $indent . '[...]';
for my $row ( @{$sql->{insert_args}}[ $begin_idx_part_2 .. $end___idx_part_2 ] ) {
push @$tmp, $sf->__prepare_data_row( $row, $indent, $term_w );
}
my $row_count = scalar( @{$sql->{insert_args}} );
push @$tmp, $indent . '[' . insert_sep( $row_count, $sf->{i}{info_thsd_sep} ) . ' rows]';
}
else {
for my $row ( @{$sql->{insert_args}} ) {
push @$tmp, $sf->__prepare_data_row( $row, $indent, $term_w );
}
}
return $tmp;
}
sub __prepare_data_row {
my ( $sf, $row, $indent, $term_w ) = @_;
my $list_sep = ', ';
no warnings 'uninitialized';
my $row_str = join( $list_sep, map { s/\t/ /g; s/\n/\\n/g; s/\v/\\v/g; $_ } @$row );
return unicode_sprintf( $indent . $row_str, $term_w, { suffix_on_truncate => $sf->{i}{dots} } );
}
sub print_sql_info {
my ( $sf, $info, $waiting ) = @_;
if ( ! defined $info ) {
return;
}
print clear_screen();
print $info, "\n";
if ( defined $waiting ) {
print $waiting . "\r";
}
}
sub get_sql_info {
my ( $sf, $sql ) = @_;
my $stmt = '';
for my $stmt_type ( @{$sf->{d}{stmt_types}} ) {
$stmt .= $sf->get_stmt( $sql, $stmt_type, 'print' );
}
return $stmt;
}
sub sql_limit {
my ( $sf, $rows ) = @_;
my $driver = $sf->{i}{driver}; # Use driver so that dbms remains optional.
if ( $driver =~ /^(?:SQLite|mysql|MariaDB|Pg|DuckDB)\z/ ) {
return " LIMIT $rows";
}
elsif ( $driver =~ /^(?:Firebird|DB2|Oracle)\z/ ) {
return " FETCH NEXT $rows ROWS ONLY"
}
else {
return "";
}
}
#sub sql_limit {
# my ( $sf, $rows ) = @_;
# my $dbms = $sf->{i}{dbms};
# if ( $dbms =~ /^(?:SQLite|mysql|MariaDB|Pg|DuckDB)\z/ ) {
# return " LIMIT $rows";
# }
# elsif ( $dbms =~ /^(?:Firebird|DB2|Oracle)\z/ ) {
# return " FETCH NEXT $rows ROWS ONLY"
# }
# elsif ( $dbms eq 'MSSQL' ) {
# return " OFFSET 0 ROWS FETCH NEXT $rows ROWS ONLY"
# }
# else {
# return "";
# }
#}
sub column_names_and_types {
my ( $sf, $table ) = @_;
( run in 0.601 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )