Bot-IRC

 view release on metacpan or  search on metacpan

lib/Bot/IRC/Store/SQLite.pm  view on Meta::CPAN

sub new {
    my ( $class, $bot ) = @_;

    my $conf = $bot->vars('store') || 'store.sqlite';
    $conf = { file => $conf } unless ( ref $conf eq 'HASH' );

    my $self = bless( $conf, $class );
    $self->{json} = JSON::XS->new->ascii;

    return $self;
}

sub _dbh {
    my ($self) = @_;
    my $pre_exists = ( -f $self->{file} ) ? 1 : 0;

    my $dbh = DBI->connect(
        'dbi:SQLite:dbname=' . $self->{file},
        undef,
        undef,
        {
            PrintError                   => 0,
            RaiseError                   => 1,
            sqlite_see_if_its_a_number   => 1,
            sqlite_defensive             => 1,
            sqlite_extended_result_codes => 1,
            sqlite_string_mode           => 6,
                # 4 = DBD_SQLITE_STRING_MODE_UNICODE_NAIVE
                # 5 = DBD_SQLITE_STRING_MODE_UNICODE_FALLBACK
                # 6 = DBD_SQLITE_STRING_MODE_UNICODE_STRICT
            %{ $self->{attr} // {} },
        },
    ) or die "$@\n";

    my $pragma = {
        encoding           => '"UTF-8"',
        foreign_keys       => 'ON',
        journal_mode       => 'DELETE',
        recursive_triggers => 'ON',
        synchronous        => 'FULL',
        temp_store         => 'MEMORY',
        %{ $self->{pragma} // {} },
    };
    $dbh->do( 'PRAGMA ' . $_ . ' = ' . $pragma->{$_} ) for ( keys %$pragma );

    $dbh->do(q{
        CREATE TABLE IF NOT EXISTS bot_store (
            bot_store_id INTEGER PRIMARY KEY,
            namespace    TEXT,
            key          TEXT,
            value        TEXT,
            created      TEXT NOT NULL DEFAULT ( STRFTIME( '%Y-%m-%d %H:%M:%f', 'NOW', 'LOCALTIME' ) )
        )
    }) unless ($pre_exists);

    return $dbh;
}

sub get {
    my ( $self, $key ) = @_;
    my $namespace = ( caller() )[0];
    my $value;

    $self->{dbh} //= $self->_dbh;

    try {
        my $sth = $self->{dbh}->prepare_cached(q{
            SELECT value FROM bot_store WHERE namespace = ? AND key = ?
        });
        $sth->execute( $namespace, $key ) or die $self->{dbh}->errstr;
        $value = $sth->fetchrow_array;
        $sth->finish;
    }
    catch ($e) {
        warn "Store get error with $namespace (likely an IRC::Store::SQLite issue); key = $key; error = $e\n";
    }

    if ($value) {
        $value = $self->{json}->decode($value) || undef;
        $value = $value->{value} if ( ref $value eq 'HASH' and exists $value->{value} );
    }

    return $value;
}

sub set {
    my ( $self, $key, $value ) = @_;
    my $namespace = ( caller() )[0];

    $self->{dbh} //= $self->_dbh;

    try {
        $self->{dbh}->begin_work;

        $self->{dbh}->prepare_cached(q{
            DELETE FROM bot_store WHERE namespace = ? AND key = ?
        })->execute( $namespace, $key ) or die $self->{dbh}->errstr;

        $self->{dbh}->prepare_cached(q{
            INSERT INTO bot_store ( namespace, key, value ) VALUES ( ?, ?, ? )
        })->execute(
            $namespace,
            $key,
            $self->{json}->encode( { value => $value } ),
        ) or die $self->{dbh}->errstr;

        $self->{dbh}->commit;
    }
    catch ($e) {
        $self->{dbh}->rollback;
        warn "Store set error with $namespace (likely an IRC::Store::SQLite issue); key = $key; error = $e\n";
    }

    return $self;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Bot::IRC::Store::SQLite - Bot::IRC persistent data storage with SQLite

=head1 VERSION

version 1.48

=head1 SYNOPSIS

    use Bot::IRC;

    Bot::IRC->new(
        connect => { server => 'irc.perl.org' },
        plugins => ['Store::SQLite'],
        vars    => {
            store => {
                file => 'store.sqlite',
                attr => {
                    PrintError                   => 0,
                    RaiseError                   => 1,
                    sqlite_see_if_its_a_number   => 1,
                    sqlite_defensive             => 1,
                    sqlite_extended_result_codes => 1,



( run in 1.222 second using v1.01-cache-2.11-cpan-75ffa21a3d4 )