Moved some code around, fixed some POD, added checking of existing
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator / Schema / Table.pm
index e38f67b..196b159 100644 (file)
@@ -1,7 +1,7 @@
 package SQL::Translator::Schema::Table;
 
 # ----------------------------------------------------------------------
-# $Id: Table.pm,v 1.4 2003-05-07 20:42:34 kycl4rk Exp $
+# $Id: Table.pm,v 1.6 2003-06-06 00:10:32 kycl4rk Exp $
 # ----------------------------------------------------------------------
 # Copyright (C) 2003 Ken Y. Clark <kclark@cpan.org>
 #
@@ -41,6 +41,7 @@ C<SQL::Translator::Schema::Table> is the table object.
 
 use strict;
 use Class::Base;
+use SQL::Translator::Utils 'parse_list_arg';
 use SQL::Translator::Schema::Constants;
 use SQL::Translator::Schema::Constraint;
 use SQL::Translator::Schema::Field;
@@ -78,35 +79,6 @@ Object constructor.
 }
 
 # ----------------------------------------------------------------------
-sub name {
-
-=pod
-
-=head2 name
-
-Get or set the table's name.
-
-If provided an argument, checks the schema object for a table of 
-that name and disallows the change if one exists.
-
-  my $table_name = $table->name('foo');
-
-=cut
-
-    my $self = shift;
-
-    if ( my $arg = shift ) {
-        if ( my $schema = $self->schema ) {
-            return $self->error( qq[Can't use table name "$arg": table exists] )
-                if $schema->get_table( $arg );
-        }
-        $self->{'name'} = $arg;
-    }
-
-    return $self->{'name'} || '';
-}
-
-# ----------------------------------------------------------------------
 sub add_constraint {
 
 =pod
@@ -116,14 +88,14 @@ sub add_constraint {
 Add a constraint to the table.  Returns the newly created 
 C<SQL::Translator::Schema::Constraint> object.
 
-  my $constraint1 = $table->add_constraint(
+  my $c1 = $table->add_constraint(
       name        => 'pk',
       type        => PRIMARY_KEY,
       fields      => [ 'foo_id' ],
   );
 
-  my $constraint2 = SQL::Translator::Schema::Constraint->new( name => 'uniq' );
-  $constraint2    = $table->add_constraint( $constraint );
+  my $c2 = SQL::Translator::Schema::Constraint->new( name => 'uniq' );
+  $c2    = $table->add_constraint( $constraint );
 
 =cut
 
@@ -142,7 +114,40 @@ C<SQL::Translator::Schema::Constraint> object.
             return $self->error( $constraint_class->error );
     }
 
-    push @{ $self->{'constraints'} }, $constraint;
+    #
+    # If we're trying to add a PK when one is already defined,
+    # then just add the fields to the existing definition.
+    #
+    my $ok = 0;
+    my $pk = $self->primary_key;
+    if ( $pk && $constraint->type eq PRIMARY_KEY ) {
+        $self->primary_key( $constraint->fields );
+        $constraint = $pk;
+    }
+    else {
+        my @field_names = $constraint->fields;
+        $ok = 1;
+
+        for my $c ( 
+            grep { $_->type eq $constraint->type } 
+            $self->get_constraints 
+        ) {
+            my %fields = map { $_, 1 } $c->fields;
+            for my $field_name ( @field_names ) {
+                if ( $fields{ $field_name } ) {
+                    $constraint = $c;
+                    $ok = 0; 
+                    last;
+                }
+            }
+            last unless $ok;
+        }
+    }
+
+    if ( $ok ) {
+        push @{ $self->{'constraints'} }, $constraint;
+    }
+
     return $constraint;
 }
 
@@ -156,14 +161,14 @@ sub add_index {
 Add an index to the table.  Returns the newly created
 C<SQL::Translator::Schema::Index> object.
 
-  my $index1 = $table->add_index(
+  my $i1 = $table->add_index(
       name   => 'name',
       fields => [ 'name' ],
       type   => 'normal',
   );
 
-  my $index2 = SQL::Translator::Schema::Index->new( name => 'id' );
-  $index2    = $table->add_index( $index );
+  my $i2 = SQL::Translator::Schema::Index->new( name => 'id' );
+  $i2    = $table->add_index( $index );
 
 =cut
 
@@ -198,21 +203,21 @@ C<SQL::Translator::Schema::Field> object.  The "name" parameter is
 required.  If you try to create a field with the same name as an 
 existing field, you will get an error and the field will not be created.
 
-  my $field1    =  $table->add_field(
+  my $f1    =  $table->add_field(
       name      => 'foo_id',
       data_type => 'integer',
       size      => 11,
   );
 
-  my $field2 =  SQL::Translator::Schema::Field->new( 
+  my $f2 =  SQL::Translator::Schema::Field->new( 
       name   => 'name', 
       table  => $table,
   );
-  $field2    = $table->add_field( $field2 ) or die $table->error;
+  $f2    = $table->add_field( $field2 ) or die $table->error;
 
 =cut
 
-    my $self  = shift;
+    my $self        = shift;
     my $field_class = 'SQL::Translator::Schema::Field';
     my $field;
 
@@ -227,6 +232,7 @@ existing field, you will get an error and the field will not be created.
             $self->error( $field_class->error );
     }
 
+    $field->order( ++$FIELD_ORDER );
     my $field_name = $field->name or return $self->error('No name');
 
     if ( exists $self->{'fields'}{ $field_name } ) { 
@@ -234,7 +240,6 @@ existing field, you will get an error and the field will not be created.
     }
     else {
         $self->{'fields'}{ $field_name } = $field;
-        $self->{'fields'}{ $field_name }{'order'} = ++$FIELD_ORDER;
     }
 
     return $field;
@@ -326,7 +331,9 @@ Returns all the field objects as an array or array reference.
 
     my $self = shift;
     my @fields = 
-        sort { $a->{'order'} <=> $b->{'order'} }
+        map  { $_->[1] }
+        sort { $a->[0] <=> $b->[0] }
+        map  { [ $_->order, $_ ] }
         values %{ $self->{'fields'} || {} };
 
     if ( @fields ) {
@@ -365,6 +372,35 @@ Determine whether the view is valid or not.
 }
 
 # ----------------------------------------------------------------------
+sub name {
+
+=pod
+
+=head2 name
+
+Get or set the table's name.
+
+If provided an argument, checks the schema object for a table of 
+that name and disallows the change if one exists.
+
+  my $table_name = $table->name('foo');
+
+=cut
+
+    my $self = shift;
+
+    if ( my $arg = shift ) {
+        if ( my $schema = $self->schema ) {
+            return $self->error( qq[Can't use table name "$arg": table exists] )
+                if $schema->get_table( $arg );
+        }
+        $self->{'name'} = $arg;
+    }
+
+    return $self->{'name'} || '';
+}
+
+# ----------------------------------------------------------------------
 sub schema {
 
 =pod
@@ -414,9 +450,8 @@ These are eqivalent:
 
 =cut
 
-    my $self = shift;
-    my $fields = UNIVERSAL::isa( $_[0], 'ARRAY' ) 
-        ? shift : [ map { s/^\s+|\s+$//g; $_ } map { split /,/ } @_ ];
+    my $self   = shift;
+    my $fields = parse_list_arg( @_ );
 
     my $constraint;
     if ( @$fields ) {
@@ -451,7 +486,7 @@ These are eqivalent:
         }
     }
 
-    return $self->error('No primary key');
+    return;
 }
 
 # ----------------------------------------------------------------------
@@ -469,8 +504,7 @@ an array or array reference.
 =cut
 
     my $self    = shift;
-    my $options = UNIVERSAL::isa( $_[0], 'ARRAY' ) 
-        ? shift : [ map { s/^\s+|\s+$//g; $_ } map { split /,/ } @_ ];
+    my $options = parse_list_arg( @_ );
 
     push @{ $self->{'options'} }, @$options;
 
@@ -482,6 +516,37 @@ an array or array reference.
     }
 }
 
+# ----------------------------------------------------------------------
+sub order {
+
+=pod
+
+=head2 order
+
+Get or set the table's order.
+
+  my $order = $table->order(3);
+
+=cut
+
+    my ( $self, $arg ) = @_;
+
+    if ( defined $arg && $arg =~ /^\d+$/ ) {
+        $self->{'order'} = $arg;
+    }
+
+    return $self->{'order'} || 0;
+}
+
+# ----------------------------------------------------------------------
+sub DESTROY {
+    my $self = shift;
+    undef $self->{'schema'}; # destroy cyclical reference
+    undef $_ for @{ $self->{'constraints'} };
+    undef $_ for @{ $self->{'indices'} };
+    undef $_ for values %{ $self->{'fields'} };
+}
+
 1;
 
 # ----------------------------------------------------------------------