Alzabo
view release on metacpan or search on metacpan
lib/Alzabo/Runtime/Table.pm view on Meta::CPAN
package Alzabo::Runtime::Table;
use strict;
use vars qw($VERSION);
use Alzabo::Exceptions ( abbr => [ qw( logic_exception not_nullable_exception
params_exception ) ] );
use Alzabo::Runtime;
use Alzabo::Utils;
use Params::Validate qw( :all );
Params::Validate::validation_options( on_fail => sub { params_exception join '', @_ } );
use Scalar::Util ();
use Tie::IxHash;
use base qw(Alzabo::Table);
$VERSION = 2.0;
sub insert
{
my $self = shift;
logic_exception "Can't make rows for tables without a primary key"
unless $self->primary_key;
my %p = @_;
%p = validate( @_,
{ ( map { $_ => { optional => 1 } } keys %p ),
values => { type => HASHREF, optional => 1 },
quote_identifiers => { type => BOOLEAN,
optional => 1 },
},
);
my $vals = delete $p{values} || {};
my $schema = $self->schema;
my @pk = $self->primary_key;
foreach my $pk (@pk)
{
unless ( exists $vals->{ $pk->name } )
{
if ($pk->sequenced)
{
$vals->{ $pk->name } = $schema->driver->next_sequence_number($pk);
}
else
{
params_exception
( "No value provided for primary key (" .
$pk->name . ") and no sequence is available." );
}
}
}
foreach my $c ($self->columns)
{
next if $c->is_primary_key;
unless ( defined $vals->{ $c->name } || $c->nullable || defined $c->default )
{
not_nullable_exception
( error => $c->name . " column in " . $self->name . " table cannot be null.",
column_name => $c->name,
table_name => $c->table->name,
schema_name => $c->table->schema->name,
);
}
delete $vals->{ $c->name }
if ! defined $vals->{ $c->name } && defined $c->default;
}
my @fk;
@fk = $self->all_foreign_keys
if $schema->referential_integrity;
my $sql = ( Alzabo::Runtime::sqlmaker( $self->schema, \%p )->
insert->
into($self, $self->columns( sort keys %$vals ) )->
values( map { $self->column($_) => $vals->{$_} } sort keys %$vals ) );
my %id;
$schema->begin_work if @fk;
eval
{
foreach my $fk (@fk)
{
$fk->register_insert( map { $_->name => $vals->{ $_->name } } $fk->columns_from );
}
$sql->debug(\*STDERR) if Alzabo::Debug::SQL;
print STDERR Devel::StackTrace->new if Alzabo::Debug::TRACE;
$self->schema->driver->do( sql => $sql->sql,
bind => $sql->bind );
foreach my $pk (@pk)
{
$id{ $pk->name } = ( defined $vals->{ $pk->name } ?
$vals->{ $pk->name } :
$schema->driver->get_last_id($self) );
}
# must come after call to ->get_last_id for MySQL because the
# id will no longer be available after the transaction ends.
$schema->commit if @fk;
};
if (my $e = $@)
{
eval { $schema->rollback };
rethrow_exception $e;
}
return unless defined wantarray || $p{potential_row};
return $self->row_by_pk( pk => \%id, %p );
}
sub insert_handle
lib/Alzabo/Runtime/Table.pm view on Meta::CPAN
my %p = @_;
%p = validate( @_,
{ ( map { $_ => { optional => 1 } } keys %p ),
columns => { type => ARRAYREF, default => [] },
values => { type => HASHREF, default => {} },
quote_identifiers => { type => BOOLEAN,
optional => 1 },
},
);
my %func_vals;
my %static_vals;
if ( $p{values} )
{
my $v = delete $p{values};
while ( my ( $name, $val ) = each %$v )
{
if ( Alzabo::Utils::safe_isa( $val, 'Alzabo::SQLMaker::Function' ) )
{
$func_vals{$name} = $val;
}
else
{
$static_vals{$name} = $val
}
}
}
my $placeholder = $self->schema->sqlmaker->placeholder;
my %cols;
my %vals;
# Get the unique set of columns and associated values
foreach my $col ( @{ $p{columns} }, $self->primary_key )
{
$vals{ $col->name } = $placeholder;
$cols{ $col->name } = 1;
}
foreach my $name ( keys %static_vals )
{
$vals{$name} = $placeholder;
$cols{$name} = 1;
}
%vals = ( %vals, %func_vals );
# At this point, %vals has each column's name and associated
# value. The value may be a placeholder or SQL function.
$cols{$_} = 1 foreach keys %func_vals;
foreach my $c ( $self->columns )
{
next if $c->is_primary_key || $c->nullable || defined $c->default;
unless ( $cols{ $c->name } )
{
not_nullable_exception
( error => $c->name . " column in " . $self->name . " table cannot be null.",
column_name => $c->name,
table_name => $c->table->name,
schema_name => $c->table->schema->name,
);
}
}
my @columns = $self->columns( keys %vals );
my $sql = ( Alzabo::Runtime::sqlmaker( $self->schema, \%p )->
insert->
into( $self, @columns )->
values( map { $_ => $vals{ $_->name } } @columns ),
);
return Alzabo::Runtime::InsertHandle->new( table => $self,
sql => $sql,
values => \%static_vals,
columns => \@columns,
%p,
);
}
sub row_by_pk
{
my $self = shift;
logic_exception "Can't make rows for tables without a primary key"
unless $self->primary_key;
my %p = @_;
my $pk_val = $p{pk};
my @pk = $self->primary_key;
params_exception
'Incorrect number of pk values provided. ' . scalar @pk . ' are needed.'
if ref $pk_val && @pk != scalar keys %$pk_val;
if (@pk > 1)
{
params_exception
( 'Primary key for ' . $self->name . ' is more than one column.' .
' Please provide multiple key values as a hashref.' )
unless ref $pk_val;
foreach my $pk (@pk)
{
params_exception 'No value provided for primary key ' . $pk->name . '.'
unless defined $pk_val->{ $pk->name };
}
}
return $self->_make_row( %p,
table => $self,
);
}
( run in 0.474 second using v1.01-cache-2.11-cpan-ceb78f64989 )