DBIx-Squirrel

 view release on metacpan or  search on metacpan

lib/DBIx/Squirrel/it.pm  view on Meta::CPAN

use strict;
use warnings;
use 5.010_001;

package    # hide from PAUSE
    DBIx::Squirrel::it;

=head1 NAME

DBIx::Squirrel::it - Statement iterator iterator base class

=head1 SYNOPSIS


=head1 DESCRIPTION

This module provides a base class for statement iterators. It is usable as
is, but is also subclassed by the L<DBIx::Squirrel::rs> (Results) class.

=cut

use Exporter     ();
use Scalar::Util qw(
    looks_like_number
    weaken
);
use Sub::Name 'subname';
use DBIx::Squirrel::util qw(
    cluckf
    confessf
    callbacks_args
);
use namespace::clean;

use constant E_BAD_STH   => 'Expected a statement handle object';
use constant E_BAD_SLICE => 'Slice must be a reference to an ARRAY or HASH';
use constant E_BAD_CACHE_SIZE =>
    'Maximum row count must be an integer greater than zero';
use constant W_MORE_ROWS     => 'Query would yield more than one result';
use constant E_EXP_ARRAY_REF => 'Expected an ARRAY-REF';

BEGIN {
    require DBIx::Squirrel
        unless keys %DBIx::Squirrel::;
    *DBIx::Squirrel::it::VERSION     = *DBIx::Squirrel::VERSION;
    @DBIx::Squirrel::it::ISA         = 'Exporter';
    %DBIx::Squirrel::it::EXPORT_TAGS = ( all => [
        @DBIx::Squirrel::it::EXPORT_OK = qw(
            database
            iterator
            result
            result_current
            result_first
            result_number
            result_offset
            result_original
            result_prev
            result_previous
            result_transform
            statement
        )
    ] );
    $DBIx::Squirrel::it::DEFAULT_SLICE      = [];    # Faster!
    $DBIx::Squirrel::it::DEFAULT_CACHE_SIZE = 2;     # Initial buffer size and autoscaling increment
    $DBIx::Squirrel::it::CACHE_SIZE_LIMIT   = 64;    # Absolute maximum buffersize
}

our $_DATABASE;
our $_ITERATOR;
our $_RESULT;
our $_RESULT_FIRST;
our $_RESULT_NUMBER;
our $_RESULT_OFFSET;
our $_RESULT_ORIGINAL;
our $_RESULT_PREV;
our $_STATEMENT;

sub _cache_charge {
    my( $attr, $self ) = shift->_private_state;
    my $sth = $attr->{sth};
    unless ( $sth->{Executed} ) {
        return unless defined $self->start;
    }
    return unless $sth->{Active};
    my( $slice, $cache_size ) = @{$attr}{qw(slice cache_size)};
    my $rows = $sth->fetchall_arrayref( $slice, $cache_size );
    return 0 unless $rows;
    unless ( $attr->{cache_size_fixed} ) {
        if ( $attr->{cache_size} < CACHE_SIZE_LIMIT() ) {
            $self->_cache_size_auto_adjust if @{$rows} >= $attr->{cache_size};
        }

lib/DBIx/Squirrel/it.pm  view on Meta::CPAN

    }
    if ( exists $attr->{results_first} ) {
        return $_ = $attr->{results_first};
    }
    else {
        return $_ = $self->_result_fetch;
    }
}

sub is_active {
    my( $attr, $self ) = shift->_private_state;
    return $attr->{sth}->{Active} || !$self->_cache_empty;
}

BEGIN {
    *active   = subname( active   => \&is_active );
    *not_done = subname( not_done => \&is_active );
}

sub iterate {
    my $self = shift;
    return unless defined $self->start(@_);
    return $_ = $self;
}

sub last {
    my( $attr, $self ) = shift->_private_state;
    unless ( $attr->{sth}->{Executed} ) {
        return unless defined $self->start;
        while ( defined $self->_result_fetch ) { ; }
    }
    return $_ = $attr->{results_last};
}

sub last_fetched {
    my( $attr, $self ) = shift->_private_state;
    unless ( $attr->{sth}->{Executed} ) {
        $self->start;
        return $_ = undef;
    }
    return $_ = $attr->{results_last};
}


=head3 C<new>

    my $it = DBIx::Squirrel::it->new($sth);
    my $it = DBIx::Squirrel::it->new($sth, @bind_values);
    my $it = DBIx::Squirrel::it->new($sth, @bind_values, @transforms);

Creates a new iterator object.

This method is not intended to be called directly, but rather indirectly
via the C<iterate> or C<results> methods of L<DBIx::Squirrel::st> and
L<DBIx::Squirrel::db> packages.

=cut

sub new {
    my $class = ref $_[0] ? ref shift : shift;
    my( $transforms, $sth, @bind_values ) = callbacks_args(@_);
    confessf E_BAD_STH unless UNIVERSAL::isa( $sth, 'DBIx::Squirrel::st' );
    my $self = bless {}, $class;
    $self->_private_state( {
        sth                 => $sth,
        bind_values_initial => [@bind_values],
        transforms_initial  => $transforms,
    } );
    return $self;
}


sub next {
    my $self = shift;
    my $sth  = $self->sth;
    unless ( $sth->{Executed} ) {
        return unless defined $self->start;
    }
    return $_ = $self->_result_fetch;
}

sub not_active {
    my( $attr, $self ) = shift->_private_state;
    return !$attr->{sth}->{Active} && $self->_cache_empty;
}

BEGIN {
    *inactive = subname( inactive => \&not_active );
    *is_done  = subname( is_done  => \&not_active );
}

sub remaining {
    my $self = shift;
    my $sth  = $self->sth;
    unless ( $sth->{Executed} ) {
        return unless defined $self->start;
    }
    my @rows;
    while ( $self->not_done ) {
        push @rows, $self->_result_fetch;
    }
    return wantarray ? @rows : \@rows;
}

sub reset {
    my $self = shift;
    if (@_) {
        if ( ref( $_[0] ) ) {
            $self->slice(shift);
            $self->cache_size(shift) if @_;
        }
        else {
            $self->cache_size(shift);
            $self->slice(shift) if @_;
        }
    }
    $self->start;
    return $self;
}


lib/DBIx/Squirrel/it.pm  view on Meta::CPAN

    return @results;
}

sub rows {
    return shift->sth->rows;
}

sub single {
    my( $attr, $self ) = shift->_private_state;
    return unless defined $self->start;
    return unless defined $self->_result_fetch;
    cluckf W_MORE_ROWS if @{ $attr->{buffer} };
    return $_ = exists $attr->{results_first} ? $attr->{results_first} : ();
}

BEGIN {
    *one = subname( one => \&single );
}

sub slice {
    my( $attr, $self ) = shift->_private_state;
    if (@_) {
        if ( ref $_[0] ) {
            if ( UNIVERSAL::isa( $_[0], 'ARRAY' ) ) {
                $attr->{slice} = shift;
                return $self;
            }
            if ( UNIVERSAL::isa( $_[0], 'HASH' ) ) {
                $attr->{slice} = shift;
                return $self;
            }
        }
        confessf E_BAD_SLICE;
    }
    else {
        $attr->{slice} = DEFAULT_SLICE unless $attr->{slice};
        return $attr->{slice};
    }
}

sub slice_cache_size {
    my $self = shift;
    return $self->slice, $self->cache_size unless @_;
    if ( ref $_[0] ) {
        $self->slice(shift);
        $self->cache_size(shift) if @_;
    }
    else {
        $self->cache_size(shift);
        $self->slice(shift) if @_;
    }
    return $self;
}

BEGIN {
    *slice_buffer_size = subname( slice_buffer_size => \&slice_cache_size );
}

sub start {
    my( $attr,       $self )        = shift->_private_state;
    my( $transforms, @bind_values ) = callbacks_args(@_);
    if ( @{$transforms} ) {
        $attr->{transforms} = [ @{ $attr->{transforms_initial} }, @{$transforms} ];
    }
    else {
        unless ( defined $attr->{transforms} && @{ $attr->{transforms} } ) {
            $attr->{transforms} = [ @{ $attr->{transforms_initial} } ];
        }
    }
    if (@bind_values) {
        $attr->{bind_values} = [@bind_values];
    }
    else {
        unless ( defined $attr->{bind_values} && @{ $attr->{bind_values} } ) {
            $attr->{bind_values} = [ @{ $attr->{bind_values_initial} } ];
        }
    }
    my $sth = $attr->{sth};
    $self->_private_state_reset;
    $attr->{execute_returned} = $sth->execute( @{ $attr->{bind_values} } );
    return $_ = $attr->{execute_returned};
}

BEGIN {
    *execute = subname( execute => \&start );
}

sub statement {
    return $_STATEMENT;
}

sub sth {
    return shift->_private_state->{sth};
}

=head1 AUTHORS

Iain Campbell E<lt>cpanic@cpan.orgE<gt>

=head1 COPYRIGHT AND LICENSE

The DBIx::Squirrel module is Copyright (c) 2020-2025 Iain Campbell.
All rights reserved.

You may distribute under the terms of either the GNU General Public
License or the Artistic License, as specified in the Perl 5.10.0 README file.

=head1 SUPPORT / WARRANTY

DBIx::Squirrel is free Open Source software. IT COMES WITHOUT WARRANTY OF ANY
KIND.

=cut

1;



( run in 2.534 seconds using v1.01-cache-2.11-cpan-140bd7fdf52 )