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 => \¬_active );
*is_done = subname( is_done => \¬_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 )