1 package SQL::Translator::Schema::Table;
7 SQL::Translator::Schema::Table - SQL::Translator table object
11 use SQL::Translator::Schema::Table;
12 my $table = SQL::Translator::Schema::Table->new( name => 'foo' );
16 C<SQL::Translator::Schema::Table> is the table object.
23 use SQL::Translator::Utils qw(parse_list_arg ex2err throw carp_ro);
24 use SQL::Translator::Types qw(schema_obj);
25 use SQL::Translator::Role::ListAttr;
26 use SQL::Translator::Schema::Constants;
27 use SQL::Translator::Schema::Constraint;
28 use SQL::Translator::Schema::Field;
29 use SQL::Translator::Schema::Index;
31 use Carp::Clan '^SQL::Translator';
33 use Sub::Quote qw(quote_sub);
35 extends 'SQL::Translator::Schema::Object';
37 our $VERSION = '1.59';
39 # Stringify to our name, being careful not to pass any args through so we don't
40 # accidentally set it to undef. We also have to tweak bool so the object is
41 # still true when it doesn't have a name (which shouldn't happen!).
43 '""' => sub { shift->name },
44 'bool' => sub { $_[0]->name || $_[0] },
54 my $table = SQL::Translator::Schema::Table->new(
61 Add a constraint to the table. Returns the newly created
62 C<SQL::Translator::Schema::Constraint> object.
64 my $c1 = $table->add_constraint(
67 fields => [ 'foo_id' ],
70 my $c2 = SQL::Translator::Schema::Constraint->new( name => 'uniq' );
71 $c2 = $table->add_constraint( $constraint );
78 default => quote_sub(q{ +[] }),
85 my $constraint_class = 'SQL::Translator::Schema::Constraint';
88 if ( UNIVERSAL::isa( $_[0], $constraint_class ) ) {
90 $constraint->table( $self );
94 $args{'table'} = $self;
95 $constraint = $constraint_class->new( \%args ) or
96 return $self->error( $constraint_class->error );
100 # If we're trying to add a PK when one is already defined,
101 # then just add the fields to the existing definition.
104 my $pk = $self->primary_key;
105 if ( $pk && $constraint->type eq PRIMARY_KEY ) {
106 $self->primary_key( $constraint->fields );
107 $pk->name($constraint->name) if $constraint->name;
108 my %extra = $constraint->extra;
109 $pk->extra(%extra) if keys %extra;
113 elsif ( $constraint->type eq PRIMARY_KEY ) {
114 for my $fname ( $constraint->fields ) {
115 if ( my $f = $self->get_field( $fname ) ) {
116 $f->is_primary_key( 1 );
121 # See if another constraint of the same type
122 # covers the same fields. -- This doesn't work! ky
124 # elsif ( $constraint->type ne CHECK_C ) {
125 # my @field_names = $constraint->fields;
127 # grep { $_->type eq $constraint->type }
128 # $self->get_constraints
130 # my %fields = map { $_, 1 } $c->fields;
131 # for my $field_name ( @field_names ) {
132 # if ( $fields{ $field_name } ) {
143 push @{ $self->_constraints }, $constraint;
149 =head2 drop_constraint
151 Remove a constraint from the table. Returns the constraint object if the index
152 was found and removed, an error otherwise. The single parameter can be either
153 an index name or an C<SQL::Translator::Schema::Constraint> object.
155 $table->drop_constraint('myconstraint');
159 sub drop_constraint {
161 my $constraint_class = 'SQL::Translator::Schema::Constraint';
164 if ( UNIVERSAL::isa( $_[0], $constraint_class ) ) {
165 $constraint_name = shift->name;
168 $constraint_name = shift;
171 if ( ! ($self->_has_constraints && grep { $_->name eq $constraint_name } @ { $self->_constraints }) ) {
172 return $self->error(qq[Can't drop constraint: "$constraint_name" doesn't exist]);
175 my @cs = @{ $self->_constraints };
176 my ($constraint_id) = grep { $cs[$_]->name eq $constraint_name } (0..$#cs);
177 my $constraint = splice(@{$self->_constraints}, $constraint_id, 1);
184 Add an index to the table. Returns the newly created
185 C<SQL::Translator::Schema::Index> object.
187 my $i1 = $table->add_index(
189 fields => [ 'name' ],
193 my $i2 = SQL::Translator::Schema::Index->new( name => 'id' );
194 $i2 = $table->add_index( $index );
201 default => quote_sub(q{ [] }),
208 my $index_class = 'SQL::Translator::Schema::Index';
211 if ( UNIVERSAL::isa( $_[0], $index_class ) ) {
213 $index->table( $self );
217 $args{'table'} = $self;
218 $index = $index_class->new( \%args ) or return
219 $self->error( $index_class->error );
221 foreach my $ex_index ($self->get_indices) {
222 return if ($ex_index->equals($index));
224 push @{ $self->_indices }, $index;
230 Remove an index from the table. Returns the index object if the index was
231 found and removed, an error otherwise. The single parameter can be either
232 an index name of an C<SQL::Translator::Schema::Index> object.
234 $table->drop_index('myindex');
240 my $index_class = 'SQL::Translator::Schema::Index';
243 if ( UNIVERSAL::isa( $_[0], $index_class ) ) {
244 $index_name = shift->name;
250 if ( ! ($self->_has_indices && grep { $_->name eq $index_name } @{ $self->_indices }) ) {
251 return $self->error(qq[Can't drop index: "$index_name" doesn't exist]);
254 my @is = @{ $self->_indices };
255 my ($index_id) = grep { $is[$_]->name eq $index_name } (0..$#is);
256 my $index = splice(@{$self->_indices}, $index_id, 1);
263 Add an field to the table. Returns the newly created
264 C<SQL::Translator::Schema::Field> object. The "name" parameter is
265 required. If you try to create a field with the same name as an
266 existing field, you will get an error and the field will not be created.
268 my $f1 = $table->add_field(
270 data_type => 'integer',
274 my $f2 = SQL::Translator::Schema::Field->new(
278 $f2 = $table->add_field( $field2 ) or die $table->error;
285 default => quote_sub(q{ +{} }),
292 my $field_class = 'SQL::Translator::Schema::Field';
295 if ( UNIVERSAL::isa( $_[0], $field_class ) ) {
297 $field->table( $self );
301 $args{'table'} = $self;
302 $field = $field_class->new( \%args ) or return
303 $self->error( $field_class->error );
306 my $existing_order = { map { $_->order => $_->name } $self->get_fields };
308 # supplied order, possible unordered assembly
309 if ( $field->order ) {
310 if($existing_order->{$field->order}) {
312 "Requested order '%d' for column '%s' conflicts with already existing column '%s'",
315 $existing_order->{$field->order},
320 my $last_field_no = max(keys %$existing_order) || 0;
321 if ( $last_field_no != scalar keys %$existing_order ) {
323 "Table '%s' field order incomplete - unable to auto-determine order for newly added field",
328 $field->order( $last_field_no + 1 );
331 # We know we have a name as the Field->new above errors if none given.
332 my $field_name = $field->name;
334 if ( $self->get_field($field_name) ) {
335 return $self->error(qq[Can't use field name "$field_name": field exists]);
338 $self->_fields->{ $field_name } = $field;
346 Remove a field from the table. Returns the field object if the field was
347 found and removed, an error otherwise. The single parameter can be either
348 a field name or an C<SQL::Translator::Schema::Field> object.
350 $table->drop_field('myfield');
356 my $field_class = 'SQL::Translator::Schema::Field';
359 if ( UNIVERSAL::isa( $_[0], $field_class ) ) {
360 $field_name = shift->name;
366 my $cascade = $args{'cascade'};
368 if ( ! ($self->_has_fields && exists $self->_fields->{ $field_name } ) ) {
369 return $self->error(qq[Can't drop field: "$field_name" doesn't exists]);
372 my $field = delete $self->_fields->{ $field_name };
375 # Remove this field from all indices using it
376 foreach my $i ($self->get_indices()) {
377 my @fs = $i->fields();
378 @fs = grep { $_ ne $field->name } @fs;
382 # Remove this field from all constraints using it
383 foreach my $c ($self->get_constraints()) {
384 my @cs = $c->fields();
385 @cs = grep { $_ ne $field->name } @cs;
395 Get or set the comments on a table. May be called several times to
396 set and it will accumulate the comments. Called in an array context,
397 returns each comment individually; called in a scalar context, returns
398 all the comments joined on newlines.
400 $table->comments('foo');
401 $table->comments('bar');
402 print join( ', ', $table->comments ); # prints "foo, bar"
408 coerce => quote_sub(q{ ref($_[0]) eq 'ARRAY' ? $_[0] : [$_[0]] }),
409 default => quote_sub(q{ [] }),
412 around comments => sub {
415 my @comments = ref $_[0] ? @{ $_[0] } : @_;
417 for my $arg ( @comments ) {
418 $arg = $arg->[0] if ref $arg;
419 push @{ $self->$orig }, $arg if defined $arg && $arg;
422 @comments = @{$self->$orig};
423 return wantarray ? @comments
424 : @comments ? join( "\n", @comments )
428 =head2 get_constraints
430 Returns all the constraint objects as an array or array reference.
432 my @constraints = $table->get_constraints;
436 sub get_constraints {
439 if ( $self->_has_constraints ) {
441 ? @{ $self->_constraints } : $self->_constraints;
444 $self->error('No constraints');
451 Returns all the index objects as an array or array reference.
453 my @indices = $table->get_indices;
460 if ( $self->_has_indices ) {
462 ? @{ $self->_indices }
466 $self->error('No indices');
473 Returns a field by the name provided.
475 my $field = $table->get_field('foo');
481 my $field_name = shift or return $self->error('No field name');
482 my $case_insensitive = shift;
483 return $self->error(qq[Field "$field_name" does not exist])
484 unless $self->_has_fields;
485 if ( $case_insensitive ) {
486 $field_name = uc($field_name);
487 foreach my $field ( keys %{$self->_fields} ) {
488 return $self->_fields->{$field} if $field_name eq uc($field);
490 return $self->error(qq[Field "$field_name" does not exist]);
492 return $self->error( qq[Field "$field_name" does not exist] ) unless
493 exists $self->_fields->{ $field_name };
494 return $self->_fields->{ $field_name };
499 Returns all the field objects as an array or array reference.
501 my @fields = $table->get_fields;
509 sort { $a->[0] <=> $b->[0] }
510 map { [ $_->order, $_ ] }
511 values %{ $self->_has_fields ? $self->_fields : {} };
514 return wantarray ? @fields : \@fields;
517 $self->error('No fields');
524 Determine whether the view is valid or not.
526 my $ok = $view->is_valid;
532 return $self->error('No name') unless $self->name;
533 return $self->error('No fields') unless $self->get_fields;
536 $self->get_fields, $self->get_indices, $self->get_constraints
538 return $object->error unless $object->is_valid;
544 =head2 is_trivial_link
546 True if table has no data (non-key) fields and only uses single key joins.
550 has is_trivial_link => ( is => 'lazy', init_arg => undef );
552 around is_trivial_link => carp_ro('is_trivial_link');
554 sub _build_is_trivial_link {
556 return 0 if $self->is_data;
560 foreach my $field ( $self->get_fields ) {
561 next unless $field->is_foreign_key;
562 $fk{$field->foreign_key_reference->reference_table}++;
565 foreach my $referenced (keys %fk){
566 if($fk{$referenced} > 1){
576 Returns true if the table has some non-key fields.
580 has is_data => ( is => 'lazy', init_arg => undef );
582 around is_data => carp_ro('is_data');
587 foreach my $field ( $self->get_fields ) {
588 if ( !$field->is_primary_key and !$field->is_foreign_key ) {
598 Determine whether the table can link two arg tables via many-to-many.
600 my $ok = $table->can_link($table1,$table2);
604 has _can_link => ( is => 'ro', init_arg => undef, default => quote_sub(q{ +{} }) );
607 my ( $self, $table1, $table2 ) = @_;
609 return $self->_can_link->{ $table1->name }{ $table2->name }
610 if defined $self->_can_link->{ $table1->name }{ $table2->name };
612 if ( $self->is_data == 1 ) {
613 $self->_can_link->{ $table1->name }{ $table2->name } = [0];
614 $self->_can_link->{ $table2->name }{ $table1->name } = [0];
615 return $self->_can_link->{ $table1->name }{ $table2->name };
620 foreach my $field ( $self->get_fields ) {
621 if ( $field->is_foreign_key ) {
622 push @{ $fk{ $field->foreign_key_reference->reference_table } },
623 $field->foreign_key_reference;
627 if ( !defined( $fk{ $table1->name } ) or !defined( $fk{ $table2->name } ) )
629 $self->_can_link->{ $table1->name }{ $table2->name } = [0];
630 $self->_can_link->{ $table2->name }{ $table1->name } = [0];
631 return $self->_can_link->{ $table1->name }{ $table2->name };
634 # trivial traversal, only one way to link the two tables
635 if ( scalar( @{ $fk{ $table1->name } } == 1 )
636 and scalar( @{ $fk{ $table2->name } } == 1 ) )
638 $self->_can_link->{ $table1->name }{ $table2->name } =
639 [ 'one2one', $fk{ $table1->name }, $fk{ $table2->name } ];
640 $self->_can_link->{ $table1->name }{ $table2->name } =
641 [ 'one2one', $fk{ $table2->name }, $fk{ $table1->name } ];
643 # non-trivial traversal. one way to link table2,
644 # many ways to link table1
646 elsif ( scalar( @{ $fk{ $table1->name } } > 1 )
647 and scalar( @{ $fk{ $table2->name } } == 1 ) )
649 $self->_can_link->{ $table1->name }{ $table2->name } =
650 [ 'many2one', $fk{ $table1->name }, $fk{ $table2->name } ];
651 $self->_can_link->{ $table2->name }{ $table1->name } =
652 [ 'one2many', $fk{ $table2->name }, $fk{ $table1->name } ];
654 # non-trivial traversal. one way to link table1,
655 # many ways to link table2
657 elsif ( scalar( @{ $fk{ $table1->name } } == 1 )
658 and scalar( @{ $fk{ $table2->name } } > 1 ) )
660 $self->_can_link->{ $table1->name }{ $table2->name } =
661 [ 'one2many', $fk{ $table1->name }, $fk{ $table2->name } ];
662 $self->_can_link->{ $table2->name }{ $table1->name } =
663 [ 'many2one', $fk{ $table2->name }, $fk{ $table1->name } ];
665 # non-trivial traversal. many ways to link table1 and table2
667 elsif ( scalar( @{ $fk{ $table1->name } } > 1 )
668 and scalar( @{ $fk{ $table2->name } } > 1 ) )
670 $self->_can_link->{ $table1->name }{ $table2->name } =
671 [ 'many2many', $fk{ $table1->name }, $fk{ $table2->name } ];
672 $self->_can_link->{ $table2->name }{ $table1->name } =
673 [ 'many2many', $fk{ $table2->name }, $fk{ $table1->name } ];
675 # one of the tables didn't export a key
676 # to this table, no linking possible
679 $self->_can_link->{ $table1->name }{ $table2->name } = [0];
680 $self->_can_link->{ $table2->name }{ $table1->name } = [0];
683 return $self->_can_link->{ $table1->name }{ $table2->name };
688 Get or set the table's name.
690 Errors ("No table name") if you try to set a blank name.
692 If provided an argument, checks the schema object for a table of
693 that name and disallows the change if one exists (setting the error to
694 "Can't use table name "%s": table exists").
696 my $table_name = $table->name('foo');
702 isa => sub { throw("No table name") unless $_[0] },
709 if ( my ($arg) = @_ ) {
710 if ( my $schema = $self->schema ) {
711 return $self->error( qq[Can't use table name "$arg": table exists] )
712 if $schema->get_table( $arg );
716 return ex2err($orig, $self, @_);
721 Get or set the table's schema object.
723 my $schema = $table->schema;
727 has schema => ( is => 'rw', isa => schema_obj('Schema'), weak_ref => 1 );
729 around schema => \&ex2err;
737 Gets or sets the table's primary key(s). Takes one or more field
738 names (as a string, list or array[ref]) as an argument. If the field
739 names are present, it will create a new PK if none exists, or it will
740 add to the fields of an existing PK (and will unique the field names).
741 Returns the C<SQL::Translator::Schema::Constraint> object representing
744 These are equivalent:
746 $table->primary_key('id');
747 $table->primary_key(['name']);
748 $table->primary_key('id','name']);
749 $table->primary_key(['id','name']);
750 $table->primary_key('id,name');
751 $table->primary_key(qw[ id name ]);
753 my $pk = $table->primary_key;
758 my $fields = parse_list_arg( @_ );
762 for my $f ( @$fields ) {
763 return $self->error(qq[Invalid field "$f"]) unless
764 $self->get_field($f);
768 for my $c ( $self->get_constraints ) {
769 if ( $c->type eq PRIMARY_KEY ) {
771 $c->fields( @{ $c->fields }, @$fields );
777 $constraint = $self->add_constraint(
788 for my $c ( $self->get_constraints ) {
789 return $c if $c->type eq PRIMARY_KEY;
798 Get or append to the table's options (e.g., table types for MySQL).
799 Returns an array or array reference.
801 my @options = $table->options;
805 with ListAttr options => ( append => 1 );
809 Get or set the table's order.
811 my $order = $table->order(3);
815 has order => ( is => 'rw', default => quote_sub(q{ 0 }) );
817 around order => sub {
818 my ( $orig, $self, $arg ) = @_;
820 if ( defined $arg && $arg =~ /^\d+$/ ) {
821 return $self->$orig($arg);
829 Read-only method to return a list or array ref of the field names. Returns undef
830 or an empty list if the table has no fields set. Useful if you want to
831 avoid the overload magic of the Field objects returned by the get_fields method.
833 my @names = $constraint->field_names;
844 return wantarray ? @fields : \@fields;
847 $self->error('No fields');
858 Determines if this table is the same as another
860 my $isIdentical = $table1->equals( $table2 );
866 my $case_insensitive = shift;
868 return 0 unless $self->SUPER::equals($other);
869 return 0 unless $case_insensitive ? uc($self->name) eq uc($other->name) : $self->name eq $other->name;
870 return 0 unless $self->_compare_objects(scalar $self->options, scalar $other->options);
871 return 0 unless $self->_compare_objects(scalar $self->extra, scalar $other->extra);
874 # Go through our fields
876 foreach my $field ( $self->get_fields ) {
877 my $otherField = $other->get_field($field->name, $case_insensitive);
878 return 0 unless $field->equals($otherField, $case_insensitive);
879 $checkedFields{$field->name} = 1;
881 # Go through the other table's fields
882 foreach my $otherField ( $other->get_fields ) {
883 next if $checkedFields{$otherField->name};
888 # Go through our constraints
889 my %checkedConstraints;
891 foreach my $constraint ( $self->get_constraints ) {
892 foreach my $otherConstraint ( $other->get_constraints ) {
893 if ( $constraint->equals($otherConstraint, $case_insensitive) ) {
894 $checkedConstraints{$otherConstraint} = 1;
900 # Go through the other table's constraints
902 foreach my $otherConstraint ( $other->get_constraints ) {
903 next if $checkedFields{$otherConstraint};
904 foreach my $constraint ( $self->get_constraints ) {
905 if ( $otherConstraint->equals($constraint, $case_insensitive) ) {
913 # Go through our indices
916 foreach my $index ( $self->get_indices ) {
917 foreach my $otherIndex ( $other->get_indices ) {
918 if ( $index->equals($otherIndex, $case_insensitive) ) {
919 $checkedIndices{$otherIndex} = 1;
925 # Go through the other table's indices
927 foreach my $otherIndex ( $other->get_indices ) {
928 next if $checkedIndices{$otherIndex};
929 foreach my $index ( $self->get_indices ) {
930 if ( $otherIndex->equals($index, $case_insensitive) ) {
940 =head1 LOOKUP METHODS
942 The following are a set of shortcut methods for getting commonly used lists of
943 fields and constraints. They all return lists or array refs of Field or
950 The primary key fields.
954 All foreign key fields.
958 All the fields except the primary key.
966 All fields with unique constraints.
968 =item unique_constraints
970 All this tables unique constraints.
972 =item fkey_constraints
974 All this tables foreign key constraints. (See primary_key method to get the
975 primary key constraint)
983 my @fields = grep { $_->is_primary_key } $me->get_fields;
984 return wantarray ? @fields : \@fields;
990 push @fields, $_->fields foreach $me->fkey_constraints;
991 return wantarray ? @fields : \@fields;
996 my @fields = grep { !$_->is_primary_key } $me->get_fields;
997 return wantarray ? @fields : \@fields;
1003 grep { !$_->is_foreign_key and !$_->is_primary_key } $me->get_fields;
1004 return wantarray ? @fields : \@fields;
1010 push @fields, $_->fields foreach $me->unique_constraints;
1011 return wantarray ? @fields : \@fields;
1014 sub unique_constraints {
1016 my @cons = grep { $_->type eq UNIQUE } $me->get_constraints;
1017 return wantarray ? @cons : \@cons;
1020 sub fkey_constraints {
1022 my @cons = grep { $_->type eq FOREIGN_KEY } $me->get_constraints;
1023 return wantarray ? @cons : \@cons;
1026 # Must come after all 'has' declarations
1027 around new => \&ex2err;
1035 Ken Youens-Clark E<lt>kclark@cpan.orgE<gt>,
1036 Allen Day E<lt>allenday@ucla.eduE<gt>.