Alzabo
view release on metacpan or search on metacpan
lib/Alzabo/Runtime/RowState/Live.pm view on Meta::CPAN
package Alzabo::Runtime::RowState::Live;
use strict;
use Alzabo::Exceptions;
use Alzabo::Runtime;
use Alzabo::Utils;
sub _where
{
my $class = shift;
my $row = shift;
my $sql = shift;
my ($pk1, @pk) = $row->table->primary_key;
$sql->where( $pk1, '=', $row->{pk}{ $pk1->name } );
$sql->and( $_, '=', $row->{pk}{ $_->name } ) foreach @pk;
}
sub _init
{
my $class = shift;
my $row = shift;
my %p = @_;
$row->{pk} = $row->_make_id_hash(%p);
while ( my ($k, $v) = each %{ $row->{pk} } )
{
$row->{data}{$k} = $v;
}
if ( $p{prefetch} )
{
while ( my ($k, $v) = each %{ $p{prefetch} } )
{
$row->{data}{$k} = $v;
}
}
else
{
eval { $class->_get_prefetch_data($row) };
if ( my $e = $@ )
{
return if isa_alzabo_exception( $e, 'Alzabo::Exception::NoSuchRow' );
rethrow_exception $e;
}
}
unless ( keys %{ $row->{data} } > keys %{ $row->{pk} } )
{
# Need to try to fetch something to confirm that this row exists!
my $sql = ( $row->schema->sqlmaker->
select( ($row->table->primary_key)[0] )->
from( $row->table ) );
$class->_where($row, $sql);
$sql->debug(\*STDERR) if Alzabo::Debug::SQL;
print STDERR Devel::StackTrace->new if Alzabo::Debug::TRACE;
return
unless defined $row->schema->driver->one_row( sql => $sql->sql,
bind => $sql->bind );
}
return 1;
}
sub _get_prefetch_data
{
my $class = shift;
my $row = shift;
my @pre = $row->table->prefetch;
return unless @pre;
$class->_get_data( $row, @pre );
}
sub _get_data
{
my $class = shift;
my $row = shift;
my %data;
my @select;
foreach my $col (@_)
{
if ( exists $row->{data}{$col} )
{
$data{$col} = $row->{data}{$col};
}
else
{
push @select, $col;
}
}
return %data unless @select;
my $sql = ( $row->schema->sqlmaker->
select( $row->table->columns(@select) )->
from( $row->table ) );
$class->_where($row, $sql);
$sql->debug(\*STDERR) if Alzabo::Debug::SQL;
print STDERR Devel::StackTrace->new if Alzabo::Debug::TRACE;
my %d;
@d{@select} =
$row->schema->driver->one_row( sql => $sql->sql,
bind => $sql->bind )
or $row->_no_such_row_error;
while ( my( $k, $v ) = each %d )
{
$row->{data}{$k} = $data{$k} = $v;
}
return %data;
}
sub id_as_string
{
my $class = shift;
my $row = shift;
my %p = @_;
return $row->{id_string} if exists $row->{id_string};
$row->{id_string} = $row->id_as_string_ext( pk => $row->{pk},
table => $row->table );
return $row->{id_string};
}
sub select
{
my $class = shift;
my $row = shift;
my @cols = @_ ? @_ : map { $_->name } $row->table->columns;
my %data = $class->_get_data( $row, @cols );
return wantarray ? @data{@cols} : $data{ $cols[0] };
}
sub select_hash
{
my $class = shift;
my $row = shift;
my @cols = @_ ? @_ : map { $_->name } $row->table->columns;
return $class->_get_data( $row, @cols );
}
sub update
{
my $class = shift;
my $row = shift;
my %data = @_;
my $schema = $row->schema;
my @fk; # this never gets populated unless referential integrity
# checking is on
my @set;
my $includes_pk = 0;
foreach my $k ( sort keys %data )
{
# This will throw an exception if the column doesn't exist.
my $c = $row->table->column($k);
if ( $row->_cached_data_is_same( $k, $data{$k} ) )
{
delete $data{$k};
next;
}
$includes_pk = 1 if $c->is_primary_key;
Alzabo::Exception::NotNullable->throw
( error => $c->name . " column in " . $row->table->name . " table cannot be null.",
column_name => $c->name,
table_name => $c->table->name,
schema_name => $schema->name,
)
unless defined $data{$k} || $c->nullable || defined $c->default;
push @fk, $row->table->foreign_keys_by_column($c)
if $schema->referential_integrity;
push @set, $c => $data{$k};
}
return 0 unless keys %data;
my $sql = ( $schema->sqlmaker->update( $row->table ) );
$sql->set(@set);
$class->_where( $row, $sql );
# If we have foreign keys we'd like all the fiddling to be atomic.
$schema->begin_work if @fk;
( run in 1.464 second using v1.01-cache-2.11-cpan-ceb78f64989 )