package Pcore::Handle::SQLite;

use Pcore -class;
use DBD::SQLite;

# NOTE http://habrahabr.ru/post/149635/
# SQLite может вставлять и до 50 тыс записей в секунду, но фиксировать транзакций он не может больше, чем ~ 50 в секунду
# для вставки данных в цикле надо использовать h->begin_work ... h->commit

with qw[Pcore::DBD];

has '+h_disconnect_on' => ( isa => Enum [ 'PID_CHANGE', 'BEFORE_FORK', 'REQ_FINISH' ], default => 'PID_CHANGE' );

has addr => ( is => 'ro', isa => Str, required => 1 );    # file://<path>, memory:// and temp:// schemes allowed, memory:// and temp:// not shared between processes
has mode => ( is => 'ro', isa => Enum [qw[R RW RWC]], default => 'RWC' );    # READONLY, READWRITE, READWRITE + CREATE
has busy_timeout => ( is => 'ro', isa => Int, default => 30 * 1_000 );       # milliseconds, set to 0 to disable timeout

# SQLITE PRAGMAS
has temp_store   => ( is => 'ro', isa => Enum [qw[FILE MEMORY]],                            default => 'MEMORY' );
has journal_mode => ( is => 'ro', isa => Enum [qw[DELETE TRUNCATE PERSIST MEMORY WAL OFF]], default => 'WAL' );      # WAL is the best
has synchronous  => ( is => 'ro', isa => Enum [qw[FULL NORMAL OFF]],                        default => 'OFF' );      # OFF - data integrity on app failure, NORMAL - data integrity on app and OS failures, FULL - full data integrity on app or OS failures, slower
has cache_size   => ( is => 'ro', isa => Int,  default => 20_000 );                                                  # 0+ - pages,  -kilobytes
has foreign_keys => ( is => 'ro', isa => Bool, default => 1 );

# H
around h_connect => sub ( $orig, $self ) {
    my $h = $self->$orig;

    $h->do('PRAGMA encoding = "UTF-8"');
    $h->do( 'PRAGMA temp_store = ' . $self->temp_store );
    $h->do( 'PRAGMA journal_mode = ' . $self->journal_mode );
    $h->do( 'PRAGMA synchronous = ' . $self->synchronous );
    $h->do( 'PRAGMA cache_size = ' . $self->cache_size );
    $h->do( 'PRAGMA foreign_keys = ' . $self->foreign_keys );

    $h->sqlite_busy_timeout( $self->busy_timeout );

    return $h;
};

# DBD
sub _build__connection ($self) {
    my $attr = P->hash->merge(
        $self->_default_attr,
        {   sqlite_open_flags => $self->mode eq 'R' ? DBD::SQLite::OPEN_READONLY : $self->mode eq 'RW' ? DBD::SQLite::OPEN_READWRITE : DBD::SQLite::OPEN_READWRITE | DBD::SQLite::OPEN_CREATE,
            sqlite_unicode => 1,
            sqlite_allow_multiple_statements => 1,
            sqlite_use_immediate_transaction => 1,
            sqlite_see_if_its_a_number       => 1,
        }
    );

    my $dbfile;

    my $addr = P->uri( $self->addr );

    if ( $addr->scheme eq 'file' ) {
        $dbfile = $addr->path->to_string;
    }
    elsif ( $addr->scheme eq 'memory' ) {
        $dbfile = q[:memory:];
    }
    elsif ( $addr->scheme eq 'temp' ) {
        $dbfile = q[];
    }
    else {
        die q[Unsupported addr scheme];
    }

    return [ qq[dbi:SQLite:dbname=$dbfile], q[], q[], $attr ];
}

sub version ($self) {
    return $self->h->{sqlite_version};
}

1;
__END__
=pod

=encoding utf8

=head1 NAME

Pcore::Handle::SQLite

=head1 SYNOPSIS

=head1 DESCRIPTION

=cut
