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 )