Acrux-DBI

 view release on metacpan or  search on metacpan

lib/Acrux/DBI.pm  view on Meta::CPAN

    my $dsn = $dbi->dsn('DBI:SQLite::memory:');

This method generates the connection DSN and returns it or
returns already generated earley.

=head2 dump

    my $dump = $dbi->dump;
    my $dump = $dbi->dump(name => 'schema');

This method returns instance of L<Acrux::DBI::Dump> class that you
can use to change your database schema more easily

    # Load SQL dump file and import schema to database
    $dbi->dump->from_file('/tmp/schema.sql')->poke('foo');

See L<Acrux::DBI::Dump> for details

=head2 err

    my $err = $dbi->err;

This method just returns C<$DBI::err> value

=head2 errstr

    my $errstr = $dbi->errstr;

This method just returns C<$DBI::errstr> value

=head2 error

    my $error = $dbi->error;

Returns error string if occurred any errors while working with database

    $dbi = $dbi->error( "error text" );

Sets new error message and returns object

=head2 host

    my $host = $dbi->host;

This is the L<Mojo::URL/host> that will be used for generating the connection DSN

Default: C<localhost>

=head2 options

    my $options = $dbi->options;

This method returns options that will be used for generating the connection DSN

Default: all passed options to constructor merged with system defaults:

    RaiseError  => 0,
    PrintError  => 0,
    PrintWarn   => 0,

=head2 password

    my $password = $dbi->password;

This is the L<Mojo::URL/password> that will be used for generating the connection DSN

default: none

=head2 ping

    $dbi->ping ? 'OK' : 'Database session is expired';

Checks the connection to database

=head2 port

    my $port = $dbi->port;

This is the L<Mojo::URL/port> that will be used for generating the connection DSN

Default: none

=head2 query

    my $res = $dbi->query('select * from test');
    my $res = $dbi->query('insert into test values (?, ?)', @values);

Execute a blocking statement and return a L<Acrux::DBI::Res> object with the results.
You can also append a 'bind_callback' to perform binding value manually:

    my $res = $dbi->query('insert into test values (?, ?)', {
        bind_callback => sub {
            my $sth = shift;
            $sth->bind_param( ... );
          }
      });

=head2 rollback

    $dbi->begin;
    # ...
    $dbi->rollback;

This is a transaction method!

This method discards all changes to the database and marks the end
point for the transaction to complete

See also L</begin>, L</commit>

=head2 transaction

    my $tx = $dbi->transaction;

Begin transaction and return L<Acrux::DBI::Tx> object, which will automatically
roll back the transaction unless L<Acrux::DBI::Tx/commit> has been called before
it is destroyed

    # Insert rows in a transaction
    eval {
      my $tx = $dbi->transaction;
      $dbi->query( ... );
      $dbi->query( ... );
      $tx->commit;
    };

lib/Acrux/DBI.pm  view on Meta::CPAN

       croak 'Invalid DBI URL' unless $url;
    my $opts = scalar(@_) ? scalar(@_) > 1 ? {@_} : {%{$_[0]}} : {};
    my $uri = Mojo::URL->new($url);

    # Default attributes
    my %_opts = (%{(DEFAULT_DBI_OPTS)}, %$opts);
    my $autoclean = delete $_opts{autoclean};

    my $self  = bless {
            url     => $url,
            uri     => $uri,
            dsn     => '',
            cachekey=> '',
            driver  => '',
            dbh     => undef,
            error   => "", # Ok
            autoclean => $autoclean ? 1 : 0,
            opts    => {%_opts},
            cache   => Mojo::Cache->new,
        }, $class;
    return $self;
}

# Attributes
sub url {
    my $self = shift;
    if (scalar(@_) >= 1) {
        $self->{url} = shift;
        $self->{uri}->parse($self->{url});
        $self->{dsn} = '';
        $self->{cachekey} = '';
        $self->{driver} = '';
        return $self;
    }
    return $self->{url};
}
sub driver { # scheme
    my $self = shift;
    $self->{driver} ||= $self->{uri}->protocol;
}
sub host {
    my $self = shift;
    return $self->{uri}->host || 'localhost';
}
sub port {
    my $self = shift;
    return $self->{uri}->port // '';
}
sub options {
    my $self = shift;
    my $opts = $self->{opts}; # defaults
    my $query = $self->{uri}->query;
    my %params = ();
       $params{$_} = $query->param($_) for @{$query->names};
    return { (%$opts, %params) } ; # merge defaults and URL params
}
sub username {
    my $self = shift;
    return $self->{uri}->username // '';
}
sub password {
    my $self = shift;
    return $self->{uri}->password // '';
}
sub userinfo {
    my $self = shift;
    return $self->{uri}->userinfo // '';
}
sub database {
    my $self = shift;
    my $u = $self->{uri};
    my $dr = $self->driver;
    my $db = '';
    if ($dr eq 'sqlite' or $dr eq 'file') {
        $db = $u->path->leading_slash(1)->trailing_slash(0)->to_string // '';
        $db =~ s/^\/+\.\///;
    } else {
        $db = $u->path->leading_slash(0)->trailing_slash(0)->to_string // '';
    }
    return $db;
}
sub dsn {
    my $self = shift;
    $self->{dsn} = shift if scalar(@_) >= 1;
    return $self->{dsn} if $self->{dsn};
    my $dr = $self->driver;

    # Set DSN
    my @params = ();
    my $dsn = '';
    my $db = $self->database;
    if ($dr eq 'sqlite' or $dr eq 'file') {
        $dsn = sprintf('DBI:SQLite:dbname=%s', $db);
    } elsif ($dr eq 'mysql') {
        push @params, sprintf("%s=%s", "database", $db) if length $db;
        push @params, sprintf("%s=%s", "host", $self->host);
        push @params, sprintf("%s=%s", "port", $self->port) if $self->port;
        $dsn = sprintf('DBI:mysql:%s', join(";", @params) || '');
    } elsif ($dr eq 'maria' or $dr eq 'mariadb') {
        push @params, sprintf("%s=%s", "database", $db) if length $db;
        push @params, sprintf("%s=%s", "host", $self->host);
        push @params, sprintf("%s=%s", "port", $self->port) if $self->port;
        $dsn = sprintf('DBI:MariaDB:%s', join(";", @params) || '');
    } elsif ($dr eq 'pg' or $dr eq 'pgsql' or $dr eq 'postgres' or $dr eq 'postgresql') {
        push @params, sprintf("%s=%s", "dbname", $db) if length $db;
        push @params, sprintf("%s=%s", "host", $self->host);
        push @params, sprintf("%s=%s", "port", $self->port) if $self->port;
        $dsn = sprintf('DBI:Pg:%s', join(";", @params) || '');
    } elsif ($dr eq 'oracle') {
        push @params, sprintf("%s=%s", "host", $self->host);
        push @params, sprintf("%s=%s", "sid", $db) if length $db;
        push @params, sprintf("%s=%s", "port", $self->port) if $self->port;
        $dsn = sprintf('DBI:Oracle:%s', join(";", @params) || '');
    } else {
        $dsn = DEFAULT_DBI_DSN;
    }

    $self->{dsn} = $dsn;
}
sub cache { shift->{cache} }
sub cachekey {
    my $self = shift;
    return $self->{cachekey} if $self->{cachekey};

    # Generate cachekey data
    my $opts = $self->{opts}; # defaults
    my @pairs = ();
    foreach my $k (sort { $a cmp $b } keys %$opts) {
        push @pairs, "$k=" . ($opts->{$k} // '');
    }
    my $sfx = join ";", @pairs;
    $self->{cachekey} = md5_sum($self->{url} . $sfx);
}
sub dbh { shift->{dbh} }

# Methods
sub error {
    my $self = shift;
    if (scalar(@_) >= 1) {
        $self->{error} = shift;
        return $self;
    }
    return $self->{error};
}
sub err {
    my $self = shift;
    return $self->dbh->err // $DBI::err if defined($self->dbh) && $self->dbh->can('err');
    return $DBI::err;
}
sub errstr {
    my $self = shift;
    return $self->dbh->errstr // $DBI::errstr if defined($self->dbh) && $self->dbh->can('errstr');
    return $DBI::errstr;
}

# Database methods
sub connect {
    my $self = shift;
    $self->{error} = '';
    my $dbh = DBI->connect($self->dsn, $self->username, $self->password, $self->options);
    if ($dbh) {
        $self->{dbh} = $dbh;
        printf STDERR "Connected to '%s'\n", $self->dsn if DEBUG;
    } else {
        $self->{error} = $DBI::errstr || "DBI->connect failed";
        $self->{dbh} = undef;
    }
    return $self;
}
sub connect_cached {
    my $self = shift;
    $self->{error} = '';
    my %opts = %{($self->options)};
       $opts{private_cachekey} = $self->cachekey;
    my $dbh = DBI->connect_cached($self->dsn, $self->username, $self->password, {%opts});
    if ($dbh) {
        $self->{dbh} = $dbh;
        printf STDERR "Connected (cached) to '%s'\n", $self->dsn if DEBUG;
    } else {
        $self->{error} = $DBI::errstr || "DBI->connect failed";
        $self->{dbh} = undef;
    }
    return $self;
}
sub disconnect {
    my $self = shift;
    return unless my $dbh = $self->dbh;
    $dbh->disconnect;
    printf STDERR "Disconnected from '%s'\n", $self->dsn if DEBUG;
    $self->cleanup;
}
sub ping {
    my $self = shift;
    return 0 unless $self->{dsn};
    return 0 unless my $dbh = $self->dbh;
    return 0 unless $dbh->can('ping');
    return $dbh->ping();
}

# Transaction methods
sub transaction {
    my $tx = Acrux::DBI::Tx->new(dbi => shift);
    weaken $tx->{dbi};
    return $tx;
}
sub begin {
    my $self = shift;
    return unless my $dbh = $self->dbh;
    $dbh->begin_work;
    return $self;
}
sub commit {
    my $self = shift;
    return unless my $dbh = $self->dbh;
    $dbh->commit;
    return $self;
}
sub rollback {
    my $self = shift;
    return unless my $dbh = $self->dbh;
    $dbh->rollback;
    return $self;
}

# Request methods
sub query { # SQL, { args }
    my $self = shift;
    my $sql = shift // '';
    my $args = @_
      ? @_ > 1
        ? {bind_values => [@_]}
        : ref($_[0]) eq 'HASH'
          ? {%{$_[0]}}
          : {bind_values => [@_]}
      : {};



( run in 1.146 second using v1.01-cache-2.11-cpan-140bd7fdf52 )