RSS Git Download  Clone
Raw Blame History
package Local::DB;

=begin # README ================================================================
wrapper around DBIx::Simple providing overloaded query() and _replace_omniholder()
methods to:
* dump query statements to output
* allow omniplaceholders (??) in same query as placeholders (?)
usage: my $o = Local::DB->dbix('db_name'), then call DBIx::Simple methods on $o
=cut #==========================================================================

use parent 'DBIx::Simple';

use Data::Dump qw(dump);
use Data::Dumper;
use Modern::Perl;

sub dbix { # provides overloaded query() & _mysql_connection_params()
    my ($class, $args) = @_;
	return $class->SUPER::connect( _mysql_connection_params($args) );
}

#==============================================================================
# !!! don't use this method - it's wrong !!!!
sub _dbix { # does NOT use overloaded methods, returns a DBIx::Simple object:
    my ($class, $args) = @_;
	return DBIx::Simple->connect( _mysql_connection_params($args) );
}
#==============================================================================

sub query {
    my $self  = shift;
    my $query = shift; # warn $query;
    my @bind  = @_; # warn Dumper \@bind;
    
    # try to emulate output of Rose::DB::Object::QueryBuilder :
    {
        my $key_words = join '|',
            qw(select from where join date_sub curdate interval show columns);
    
        $query =~ s/\b($key_words)\b/uc $1/eg;
        
        $query =~ s/(SELECT)(?!\n)/$1\n  /;
    
        $query =~ s/(FROM)(?!\n)/\n$1\n  /g; 
        
        $query =~ s/(WHERE)(?!\n)/\n$1\n  /g; # SORT|(GROUP BY)/
        
        $query =~ s/\t/  /g; # leading tab -> 2 spaces        
    }
    
    if ( $ENV{RDBO_DEBUG} ) {
        no warnings 'uninitialized'; # common for @bind params to be undef
        warn "$query (", join(', ', @bind), ")\n"; # modified from RDBO  
    }
    
    $self->SUPER::query($query, @bind);
}

sub _replace_omniholder {
    my ($self, $query, $binds) = @_; # say dump [$query, $binds]; # scalarref, arrayref
    return if $$query !~ /\(\?\?\)/;

#-------------------------------------------------------------------------------
    # count how many individual placeholders in query for subtraction from @$binds:
    my $re = qr{\s\?}; # ie individual placeholders - WHERE foo = ? AND bar = ? 

	# $placeholders_count++ while $$query =~ /$re/g; # warn $placeholders_count;
	my $placeholders_count = () = $$query =~ /$re/g; # warn $placeholders_count; # perlfaq4
	my $omniholders_count = scalar(@$binds) - $placeholders_count;
#-------------------------------------------------------------------------------

    my $omniholders = 0;

#-------------------------------------------------------------------------------
    # global vars copied from DBIx::Simple - only used in this sub anyway:
    my $quoted         = qr/(?:'[^']*'|"[^"]*")*/;  # 'foo''bar' simply matches the (?:) twice
    my $quoted_mysql   = qr/(?:(?:[^\\']*(?:\\.[^\\']*)*)'|"(?:[^\\"]*(?:\\.[^\\"]*)*)")*/;
#-------------------------------------------------------------------------------

    my $q = $self->{dbd} =~ /mysql/ ? $quoted_mysql : $quoted; # warn $q;
    $$query =~ s[($q|\(\?\?\))] {
        $1 eq '(??)'
        ? do {
            Carp::croak('There can be only one omniholder') if $omniholders++; # warn $1;
#-------------------------------------------------------------------------------
#           '(' . join(', ', ('?') x @$binds) . ')'
            '(' . join(', ', ('?') x $omniholders_count) . ')' # adjusted bind count
#-------------------------------------------------------------------------------
        }
        : $1
    }eg; # warn dump $query;
}

sub _mysql_connection_params {
    my $args = shift; # can be db name (str) or href eg dsn => dbi:SQLite:dbname=<db>
    
	my $cnf = '/home/raj/.local/mysql.cnf';

    return ( ref $args eq 'HASH' && $args->{dsn} )
		? $args->{dsn} # just return dsn if configured (eg SQLite doesn't need username/pwd)
		: "dbi:mysql:host=localhost;database=$args;mysql_read_default_file=$cnf", 
			undef, undef, { PrintError => 0, RaiseError => 1 };    
}

1;