DBIx-TNDBO

 view release on metacpan or  search on metacpan

lib/DBIx/TNDBO.pm  view on Meta::CPAN

    my %config = (
        dbh    => $Dbh_For{$database},
        table  => "$database.$table",
        schema => $Schema_Hr->{"$database.$table"},
    );
    return DBIx::TNDBO::iter->_new( $sth, \%config );
}

sub count {
    my ( $database, $table, $where_hr, $option_hr ) = @_;

    printf "%s::%s::list(%s)\n", $Class_Base, ucfirst $table,
        _dumper($where_hr)
        if $Debug;

    my ( $sql, $param_ar )
        = _build_sql( "$database.$table", $where_hr, 'count' );

    my $dbh = _get_dbh( $database, $table );

    my $sth = $dbh->prepare($sql);

    croak $DBI::errstr
        if $DBI::errstr;

    $sth->execute( @{$param_ar} );

    my ($n) = $sth->fetchrow();

    $sth->finish();

    return $n;
}

# Called by Perl on use

sub import {
    my ( $class, @databases ) = @_;

    SYMBOL:
    for my $symbol ( keys %:: ) {

        next SYMBOL
            if $symbol !~ m{ :: \z}xms;

        next SYMBOL
            if !defined $::{$symbol}->{ISA};

        if ( grep { $_ eq __PACKAGE__ } @{ $::{$symbol}->{ISA} } ) {

            $Class_Base = substr $symbol, 0, -2;
            last SYMBOL;
        }
    }

    die 'unable to determine the class using ', __PACKAGE__, ' as its base'
        if !$Class_Base;

    {
        no strict 'refs';
        *{ __PACKAGE__ . '::credentials' }
            = *{ $Class_Base . '::credentials' };
    }

    croak sprintf 'You must define %s::credentials( $dbname ) ', $Class_Base
        if !defined &credentials;

    my $creds_key;

    NAME:
    for my $dbname (@databases) {

        if ( $dbname =~ m{\A : ( \w+ ) \z}xms ) {

            $creds_key = $1;
            last NAME;
        }
    }

    if ($creds_key) {

        @databases = grep { $_ ne ":$creds_key" } @databases;

        my $cred_hr = credentials();

        if ( ref $cred_hr->{$creds_key} eq 'ARRAY' ) {

            push @databases, @{ $cred_hr->{$creds_key} };
        }
        elsif ( ref $cred_hr->{$creds_key} eq 'HASH' ) {

            push @databases, keys %{ $cred_hr->{$creds_key} };
        }
        elsif ( $cred_hr->{$creds_key} ) {

            push @databases, $cred_hr->{$creds_key};
        }
    }

    return
        if !@databases;

    if ( !$Schema_Hr ) {

        $Schema_Hr = _read_schema( \@databases );
    }

    my @tables = keys %{ $Schema_Hr };

    for my $database_table (@tables) {

        my ( $database, $table ) = split /[.]/, $database_table;

        for my $method (qw( new list iterator count )) {

            my $class = sprintf '%s::%s', $Class_Base, ucfirst lc $table;
            {
                no strict 'refs';

                *{"${class}::${method}"} = sub {

                    croak 'call constructors with arrow operator:',
                        sprintf ' %s->%s(...)', $class, $method
                        if $_[0] ne $class;

                    shift @_;

                    return *{$method}->( $database, $table, @_ );
                };
            }
        }
    }

    return;
}

# Internal

sub _read_schema {
    my ($database_ar) = @_;

    if ( !$Schema_Cache_Filename ) {

        my $tmpdir = File::Spec->tmpdir();

lib/DBIx/TNDBO.pm  view on Meta::CPAN

                        delete $desc_hr->{$name};
                    }
                }

                push @columns, $desc_hr;
            }

            $Schema_Hr->{"$database.$table"} = \@columns;
        }
    }

    croak sprintf 'failed to read schema from any of (%s)', join ',',
        @{$database_ar}
        if !%{$Schema_Hr};

    Storable::store( $Schema_Hr, $Schema_Cache_Filename );

    return $Schema_Hr;
}

sub _build_sql {
    my ( $from, $where_hr, $operation ) = @_;

    $operation ||= 'select';

    my $sql = SQL::Abstract->new();

    my @fields;

    if ( $operation eq 'count' ) {

        $operation = 'select';
        @fields = qw/ count(*) /;
    }
    else {

        @fields = map { $_->{field} } @{ $Schema_Hr->{$from} };
    }

    my ( $stmt, @bind ) = $sql->$operation( $from, \@fields, $where_hr );

    # TODO error condition handling

    return ( $stmt, \@bind );
}

sub _get_dbh {
    my ($database) = @_;

    my $dbh;

    if ( $database && exists $Dbh_For{$database} ) {

        $dbh = $Dbh_For{$database};
    }

    if ( !$dbh || !$dbh->ping() ) {

        my ( $user, $pass, $driver, $host, $port );
        {
            my $cred_hr = credentials($database);

            my @keys = qw( user pass driver host port );

            my @creds = grep {$_} @{$cred_hr}{@keys};

            croak sprintf 'credentials() should include (%s)', join ',', @keys
                if @creds != @keys;

            ( $user, $pass, $driver, $host, $port ) = @creds;
        }

        my $dsn
            = sprintf 'DBI:%s:database=%s;host=%s;port=%s',
            $driver, $database, $host, $port;

        $dbh = DBI->connect( $dsn, $user, $pass );

        croak $DBI::errstr
            if $DBI::errstr;

        $Dbh_For{$database} = $dbh;
    }

    return $dbh;
}

sub _dumper {
    my ($ref) = @_;

    my $text;
    {
        require Data::Dumper;

        no warnings 'once';
        local $Data::Dumper::Terse  = 1;
        local $Data::Dumper::Indent = 0;

        $text = Data::Dumper::Dumper($ref);
    }

    $text =~ s{ ;? \s* \z}{}xms;

    return $text;
}

# Secluded Iterator Package
{
    package DBIx::TNDBO::iter;

    use strict;
    use warnings;
    {
        use Carp;
    }

    my $Index = 0;
    my ( @Sths, @Configs, @Counts );

    sub _new {
        my ( $class, $sth, $config_hr ) = @_;

        my $self = $Index++;
        {
            $Sths[$self]    = $sth;
            $Counts[$self]  = $sth->rows();
            $Configs[$self] = $config_hr;



( run in 2.093 seconds using v1.01-cache-2.11-cpan-364913b4093 )