Alzabo

 view release on metacpan or  search on metacpan

lib/Alzabo/Create/Column.pm  view on Meta::CPAN

package Alzabo::Create::Column;

use strict;
use vars qw($VERSION);

use Alzabo::Create;
use Alzabo::Exceptions ( abbr => 'params_exception' );

use Params::Validate qw( :all );
Params::Validate::validation_options
    ( on_fail => sub { params_exception join '', @_ } );

use base qw(Alzabo::Column);

$VERSION = 2.0;

1;

sub new
{
    my $proto = shift;
    my $class = ref $proto || $proto;

    my $self = bless {}, $class;

    $self->_init(@_);

    return $self;
}

sub _init
{
    my $self = shift;

    my %p =
        validate( @_, { table => { isa => 'Alzabo::Table' },
                        name  => { type => SCALAR },
                        null  => { optional => 1 },
                        nullable => { optional => 1 },
                        type  => { type => SCALAR,
                                   optional => 1 },
                        attributes => { type => ARRAYREF,
                                        default => [] },
                        default    => { type => BOOLEAN,
                                        optional => 1 },
                        default_is_raw => { type => BOOLEAN,
                                            default => 0 },
                        sequenced  => { optional => 1 },
                        length => { type => BOOLEAN,
                                    optional => 1 },
                        precision  => { type => BOOLEAN,
                                        optional => 1 },
                        definition => { isa => 'Alzabo::Create::ColumnDefinition',
                                        optional => 1 },
                        comment => { type => BOOLEAN,
                                     default => '' },
                  } );

    $self->set_table( $p{table} );

    $self->set_name( $p{name} );

    $self->{nullable} = $p{nullable} || $p{null} || 0;

    if ($p{definition})
    {
        $self->set_definition( $p{definition} );
    }
    else
    {
        $self->set_definition
            ( Alzabo::Create::ColumnDefinition->new
                  ( owner => $self,
                    type => $p{type},
                  )
            );
    }

    my %attr;
    tie %{ $self->{attributes} }, 'Tie::IxHash';

    $self->set_attributes( @{ $p{attributes} } );

    $self->set_sequenced( $p{sequenced} || 0 );

    $self->set_default( $p{default} )
        if exists $p{default};
    $self->set_default_is_raw( $p{default_is_raw} );

    # We always set length, since not giving a length at all may be an
    # error for some column types, unless we got a definition object,
    # in which case it should contain the length & precision.
    $self->set_length( length => $p{length}, precision => $p{precision} )
        unless $p{definition};

    $self->set_comment( $p{comment} );
}

sub set_table
{
    my $self = shift;

    validate_pos( @_, { isa => 'Alzabo::Create::Table' } );
    $self->{table} = shift;
}

sub set_name
{
    my $self = shift;

    validate_pos( @_, { type => SCALAR } );
    my $name = shift;

    params_exception "Column $name already exists in table"
        if $self->table->has_column($name);

    my $old_name = $self->{name};
    $self->{name} = $name;

    eval
    {
        $self->table->schema->rules->validate_column_name($self);
    };
    if ($@)
    {
        $self->{name} = $old_name;

        rethrow_exception($@);
    }

    $self->table->register_column_name_change( column => $self,
                                               old_name => $old_name )
        if $old_name;
}

sub set_nullable
{
    my $self = shift;

    validate_pos( @_, { type => SCALAR } );
    my $n = shift;

    params_exception "Invalid value for nullable attribute: $n"
        unless $n eq '1' || $n eq '0';

    params_exception "Primary key column cannot be nullable"
        if $n eq '1' && $self->is_primary_key;

    $self->{nullable} = $n;
}

sub set_default
{
    my $self = shift;

    validate_pos( @_, { type => BOOLEAN } );
    $self->{default} = shift;
}

sub set_default_is_raw
{
    my $self = shift;

    validate_pos( @_, { type => BOOLEAN } );
    $self->{default_is_raw} = shift;
}

sub set_length
{
    my $self = shift;

    $self->{definition}->set_length(@_);
}

sub set_attributes
{
    my $self = shift;

    validate_pos( @_, ( { type => SCALAR } ) x @_ );

    %{ $self->{attributes} } = ();

    foreach (@_)
    {
        $self->add_attribute($_);
    }
}

sub add_attribute
{
    my $self = shift;

    validate_pos( @_, { type => SCALAR } );
    my $attr = shift;

    $attr =~ s/^\s+//;
    $attr =~ s/\s+$//;

    $self->table->schema->rules->validate_column_attribute( column => $self,
                                                            attribute => $attr );

    $self->{attributes}{$attr} = 1;
}

sub delete_attribute
{
    my $self = shift;

    validate_pos( @_, { type => SCALAR } );
    my $attr = shift;

    params_exception "Column " . $self->name . " doesn't have attribute $attr"
        unless exists $self->{attributes}{$attr};

    delete $self->{attributes}{$attr};
}

sub alter
{
    my $self = shift;
    $self->{definition}->alter(@_);

    # this will force them to go through the rules code again.
    # Attributes that don't work with the new type are silently
    # discarded.
    foreach ( $self->attributes )
    {
        $self->delete_attribute($_);
        eval { $self->add_attribute($_) };
    }
}

sub set_type
{
    my $self = shift;

    validate_pos( @_, { type => SCALAR } );
    my $t = shift;

    $self->{definition}->set_type($t);

    # this will force them to go through the rules code again.
    # Attributes that don't work with the new type are silently
    # discarded.
    foreach ( $self->attributes )
    {
        $self->delete_attribute($_);
        eval { $self->add_attribute($_) };
    }

    if ( $self->length )
    {
        eval { $self->set_length( length => $self->length,
                                  precision => $self->precision ) };
        if ($@)
        {
            eval { $self->set_length( length => $self->length, precision => undef ) };
            if ($@)
            {
                $self->set_length( length => undef,
                                   precision => undef );
            }
        }
    }
}

sub set_sequenced
{
    my $self = shift;

    validate_pos( @_, { type => SCALAR } );
    my $s = shift;

    params_exception "Invalid value for sequenced attribute: $s"
        unless $s eq '1' || $s eq '0';

    $self->table->schema->rules->validate_sequenced_attribute($self)
        if $s eq '1';

    $self->{sequenced} = $s;
}

sub set_definition
{
    my $self = shift;

    validate_pos( @_, { isa => 'Alzabo::Create::ColumnDefinition' } );
    my $d = shift;

    $self->{definition} = $d;
}

sub set_comment { $_[0]->{comment} = defined $_[1] ? $_[1] : '' }

sub save_current_name
{
    my $self = shift;

    $self->{last_instantiated_name} = $self->name;
}

sub former_name { $_[0]->{last_instantiated_name} }

__END__

=head1 NAME

Alzabo::Create::Column - Column objects for use in schema creation

=head1 SYNOPSIS

  use Alzabo::Create::Column;

=head1 DESCRIPTION

This object represents a column.  It holds data specific to a column.
Additional data is held in a
L<C<Alzabo::Create::ColumnDefinition>|Alzabo::Create::ColumnDefinition>
object, which is used to allow two columns to share a type (which is
good when two columns in different tables are related as it means that
if the type of one is changed, the other is also.)

=head1 INHERITS FROM

C<Alzabo::Column>

=for pod_merge merged

=head1 METHODS

=head2 new

The constructor accepts the following parameters:

=over 4

=item * table => C<Alzabo::Create::Table> object

=item * name => $name

=item * nullable => 0 or 1 (optional)

Defaults to false.

=item * sequenced => 0 or 1 (optional)

Defaults to false.



( run in 1.133 second using v1.01-cache-2.11-cpan-5a3173703d6 )