File Coverage

blib/lib/SQL/Translator/Schema/Table.pm
Criterion Covered Total %
statement 281 344 81.6
branch 112 162 69.1
condition 24 31 77.4
subroutine 37 38 97.3
pod 22 22 100.0
total 476 597 79.7


line stmt bran cond sub pod time code
1             package SQL::Translator::Schema::Table;
2              
3             =pod
4              
5             =head1 NAME
6              
7             SQL::Translator::Schema::Table - SQL::Translator table object
8              
9             =head1 SYNOPSIS
10              
11             use SQL::Translator::Schema::Table;
12             my $table = SQL::Translator::Schema::Table->new( name => 'foo' );
13              
14             =head1 DESCRIPTION
15              
16             C is the table object.
17              
18             =head1 METHODS
19              
20             =cut
21              
22 73     73   2831 use Moo;
  73         23596  
  73         486  
23 73     73   28600 use SQL::Translator::Utils qw(parse_list_arg ex2err throw carp_ro);
  73         193  
  73         5863  
24 73     73   1373 use SQL::Translator::Types qw(schema_obj);
  73         176  
  73         3819  
25 73     73   1809 use SQL::Translator::Role::ListAttr;
  73         179  
  73         624  
26 73     73   4515 use SQL::Translator::Schema::Constants;
  73         198  
  73         5577  
27 73     73   35262 use SQL::Translator::Schema::Constraint;
  73         268  
  73         2839  
28 73     73   41273 use SQL::Translator::Schema::Field;
  73         302  
  73         3365  
29 73     73   43747 use SQL::Translator::Schema::Index;
  73         280  
  73         2823  
30              
31 73     73   39706 use Carp::Clan '^SQL::Translator';
  73         125493  
  73         583  
32 73     73   8991 use List::Util 'max';
  73         195  
  73         8361  
33 73     73   699 use Sub::Quote qw(quote_sub);
  73         204  
  73         10694  
34              
35             extends 'SQL::Translator::Schema::Object';
36              
37             our $VERSION = '1.62';
38              
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!).
42             use overload
43 429     429   59696 '""' => sub { shift->name },
44 6223 50   6223   236505 'bool' => sub { $_[0]->name || $_[0] },
45 73         2407 fallback => 1,
46 73     73   595 ;
  73         184  
47              
48             =pod
49              
50             =head2 new
51              
52             Object constructor.
53              
54             my $table = SQL::Translator::Schema::Table->new(
55             schema => $schema,
56             name => 'foo',
57             );
58              
59             =head2 add_constraint
60              
61             Add a constraint to the table. Returns the newly created
62             C object.
63              
64             my $c1 = $table->add_constraint(
65             name => 'pk',
66             type => PRIMARY_KEY,
67             fields => [ 'foo_id' ],
68             );
69              
70             my $c2 = SQL::Translator::Schema::Constraint->new( name => 'uniq' );
71             $c2 = $table->add_constraint( $constraint );
72              
73             =cut
74              
75             has _constraints => (
76             is => 'ro',
77             init_arg => undef,
78             default => quote_sub(q{ +[] }),
79             predicate => 1,
80             lazy => 1,
81             );
82              
83             sub add_constraint {
84 550     550 1 5402 my $self = shift;
85 550         1161 my $constraint_class = 'SQL::Translator::Schema::Constraint';
86 550         954 my $constraint;
87              
88 550 100       3383 if ( UNIVERSAL::isa( $_[0], $constraint_class ) ) {
89 3         4 $constraint = shift;
90 3         75 $constraint->table( $self );
91             }
92             else {
93 547         3954 my %args = @_;
94 547         1365 $args{'table'} = $self;
95 547 50       12765 $constraint = $constraint_class->new( \%args ) or
96             return $self->error( $constraint_class->error );
97             }
98              
99             #
100             # If we're trying to add a PK when one is already defined,
101             # then just add the fields to the existing definition.
102             #
103 550         15282 my $ok = 1;
104 550         2117 my $pk = $self->primary_key;
105 550 100 100     17446 if ( $pk && $constraint->type eq PRIMARY_KEY ) {
    100          
106 78         1868 $self->primary_key( $constraint->fields );
107 78 50       1932 $pk->name($constraint->name) if $constraint->name;
108 78         1920 my %extra = $constraint->extra;
109 78 100       689 $pk->extra(%extra) if keys %extra;
110 78         655 $constraint = $pk;
111 78         252 $ok = 0;
112             }
113             elsif ( $constraint->type eq PRIMARY_KEY ) {
114 207         5369 for my $fname ( $constraint->fields ) {
115 231 50       1372 if ( my $f = $self->get_field( $fname ) ) {
116 231         8757 $f->is_primary_key( 1 );
117             }
118             }
119             }
120             #
121             # See if another constraint of the same type
122             # covers the same fields. -- This doesn't work! ky
123             #
124             # elsif ( $constraint->type ne CHECK_C ) {
125             # my @field_names = $constraint->fields;
126             # for my $c (
127             # grep { $_->type eq $constraint->type }
128             # $self->get_constraints
129             # ) {
130             # my %fields = map { $_, 1 } $c->fields;
131             # for my $field_name ( @field_names ) {
132             # if ( $fields{ $field_name } ) {
133             # $constraint = $c;
134             # $ok = 0;
135             # last;
136             # }
137             # }
138             # last unless $ok;
139             # }
140             # }
141              
142 550 100       11541 if ( $ok ) {
143 472         915 push @{ $self->_constraints }, $constraint;
  472         8501  
144             }
145              
146 550         7204 return $constraint;
147             }
148              
149             =head2 drop_constraint
150              
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 object.
154              
155             $table->drop_constraint('myconstraint');
156              
157             =cut
158              
159             sub drop_constraint {
160 3     3 1 14 my $self = shift;
161 3         6 my $constraint_class = 'SQL::Translator::Schema::Constraint';
162 3         4 my $constraint_name;
163              
164 3 100       29 if ( UNIVERSAL::isa( $_[0], $constraint_class ) ) {
165 1         35 $constraint_name = shift->name;
166             }
167             else {
168 2         5 $constraint_name = shift;
169             }
170              
171 3 100 66     15 if ( ! ($self->_has_constraints && grep { $_->name eq $constraint_name } @ { $self->_constraints }) ) {
  8         166  
  3         79  
172 1         39 return $self->error(qq[Can't drop constraint: "$constraint_name" doesn't exist]);
173             }
174              
175 2         6 my @cs = @{ $self->_constraints };
  2         35  
176 2         40 my ($constraint_id) = grep { $cs[$_]->name eq $constraint_name } (0..$#cs);
  6         106  
177 2         10 my $constraint = splice(@{$self->_constraints}, $constraint_id, 1);
  2         32  
178              
179 2         19 return $constraint;
180             }
181              
182             =head2 add_index
183              
184             Add an index to the table. Returns the newly created
185             C object.
186              
187             my $i1 = $table->add_index(
188             name => 'name',
189             fields => [ 'name' ],
190             type => 'normal',
191             );
192              
193             my $i2 = SQL::Translator::Schema::Index->new( name => 'id' );
194             $i2 = $table->add_index( $index );
195              
196             =cut
197              
198             has _indices => (
199             is => 'ro',
200             init_arg => undef,
201             default => quote_sub(q{ [] }),
202             predicate => 1,
203             lazy => 1,
204             );
205              
206             sub add_index {
207 125     125 1 3824 my $self = shift;
208 125         340 my $index_class = 'SQL::Translator::Schema::Index';
209 125         225 my $index;
210              
211 125 100       1126 if ( UNIVERSAL::isa( $_[0], $index_class ) ) {
212 3         7 $index = shift;
213 3         76 $index->table( $self );
214             }
215             else {
216 122         689 my %args = @_;
217 122         343 $args{'table'} = $self;
218 122 50       3184 $index = $index_class->new( \%args ) or return
219             $self->error( $index_class->error );
220             }
221 125         3808 foreach my $ex_index ($self->get_indices) {
222 56 50       1578 return if ($ex_index->equals($index));
223             }
224 125         728 push @{ $self->_indices }, $index;
  125         2331  
225 125         2203 return $index;
226             }
227              
228             =head2 drop_index
229              
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 object.
233              
234             $table->drop_index('myindex');
235              
236             =cut
237              
238             sub drop_index {
239 3     3 1 3198 my $self = shift;
240 3         6 my $index_class = 'SQL::Translator::Schema::Index';
241 3         6 my $index_name;
242              
243 3 100       26 if ( UNIVERSAL::isa( $_[0], $index_class ) ) {
244 1         17 $index_name = shift->name;
245             }
246             else {
247 2         5 $index_name = shift;
248             }
249              
250 3 100 66     19 if ( ! ($self->_has_indices && grep { $_->name eq $index_name } @{ $self->_indices }) ) {
  5         103  
  3         49  
251 1         36 return $self->error(qq[Can't drop index: "$index_name" doesn't exist]);
252             }
253              
254 2         29 my @is = @{ $self->_indices };
  2         199  
255 2         28 my ($index_id) = grep { $is[$_]->name eq $index_name } (0..$#is);
  4         177  
256 2         27 my $index = splice(@{$self->_indices}, $index_id, 1);
  2         50  
257              
258 2         20 return $index;
259             }
260              
261             =head2 add_field
262              
263             Add an field to the table. Returns the newly created
264             C 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.
267              
268             my $f1 = $table->add_field(
269             name => 'foo_id',
270             data_type => 'integer',
271             size => 11,
272             );
273              
274             my $f2 = SQL::Translator::Schema::Field->new(
275             name => 'name',
276             table => $table,
277             );
278             $f2 = $table->add_field( $field2 ) or die $table->error;
279              
280             =cut
281              
282             has _fields => (
283             is => 'ro',
284             init_arg => undef,
285             default => quote_sub(q{ +{} }),
286             predicate => 1,
287             lazy => 1
288             );
289              
290             sub add_field {
291 1369     1369 1 9001 my $self = shift;
292 1369         2454 my $field_class = 'SQL::Translator::Schema::Field';
293 1369         2187 my $field;
294              
295 1369 100       7545 if ( UNIVERSAL::isa( $_[0], $field_class ) ) {
296 7         17 $field = shift;
297 7         174 $field->table( $self );
298             }
299             else {
300 1362         9589 my %args = @_;
301 1362         4056 $args{'table'} = $self;
302 1362 100       31919 $field = $field_class->new( \%args ) or return
303             $self->error( $field_class->error );
304             }
305              
306 1368         31939 my $existing_order = { map { $_->order => $_->name } $self->get_fields };
  4854         154121  
307              
308             # supplied order, possible unordered assembly
309 1368 100       49114 if ( $field->order ) {
310 181 100       3286 if($existing_order->{$field->order}) {
311             croak sprintf
312             "Requested order '%d' for column '%s' conflicts with already existing column '%s'",
313             $field->order,
314             $field->name,
315 1         21 $existing_order->{$field->order},
316             ;
317             }
318             }
319             else {
320 1187   100     9344 my $last_field_no = max(keys %$existing_order) || 0;
321 1187 100       4330 if ( $last_field_no != scalar keys %$existing_order ) {
322 1         23 croak sprintf
323             "Table '%s' field order incomplete - unable to auto-determine order for newly added field",
324             $self->name,
325             ;
326             }
327              
328 1186         23164 $field->order( $last_field_no + 1 );
329             }
330              
331             # We know we have a name as the Field->new above errors if none given.
332 1366         25396 my $field_name = $field->name;
333              
334 1366 100       27344 if ( $self->get_field($field_name) ) {
335 2         81 return $self->error(qq[Can't use field name "$field_name": field exists]);
336             }
337             else {
338 1364         22266 $self->_fields->{ $field_name } = $field;
339             }
340              
341 1364         17828 return $field;
342             }
343              
344             =head2 drop_field
345              
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 object.
349              
350             $table->drop_field('myfield');
351              
352             =cut
353              
354             sub drop_field {
355 3     3 1 50 my $self = shift;
356 3         7 my $field_class = 'SQL::Translator::Schema::Field';
357 3         4 my $field_name;
358              
359 3 100       22 if ( UNIVERSAL::isa( $_[0], $field_class ) ) {
360 1         21 $field_name = shift->name;
361             }
362             else {
363 2         4 $field_name = shift;
364             }
365 3         26 my %args = @_;
366 3         7 my $cascade = $args{'cascade'};
367              
368 3 100 66     66 if ( ! ($self->_has_fields && exists $self->_fields->{ $field_name } ) ) {
369 1         50 return $self->error(qq[Can't drop field: "$field_name" doesn't exists]);
370             }
371              
372 2         52 my $field = delete $self->_fields->{ $field_name };
373              
374 2 50       19 if ( $cascade ) {
375             # Remove this field from all indices using it
376 2         7 foreach my $i ($self->get_indices()) {
377 0         0 my @fs = $i->fields();
378 0         0 @fs = grep { $_ ne $field->name } @fs;
  0         0  
379 0         0 $i->fields(@fs);
380             }
381              
382             # Remove this field from all constraints using it
383 2         88 foreach my $c ($self->get_constraints()) {
384 0         0 my @cs = $c->fields();
385 0         0 @cs = grep { $_ ne $field->name } @cs;
  0         0  
386 0         0 $c->fields(@cs);
387             }
388             }
389              
390 2         12 return $field;
391             }
392              
393             =head2 comments
394              
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.
399              
400             $table->comments('foo');
401             $table->comments('bar');
402             print join( ', ', $table->comments ); # prints "foo, bar"
403              
404             =cut
405              
406             has comments => (
407             is => 'rw',
408             coerce => quote_sub(q{ ref($_[0]) eq 'ARRAY' ? $_[0] : [$_[0]] }),
409             default => quote_sub(q{ [] }),
410             );
411              
412             around comments => sub {
413             my $orig = shift;
414             my $self = shift;
415             my @comments = ref $_[0] ? @{ $_[0] } : @_;
416              
417             for my $arg ( @comments ) {
418             $arg = $arg->[0] if ref $arg;
419             push @{ $self->$orig }, $arg if defined $arg && $arg;
420             }
421              
422             @comments = @{$self->$orig};
423             return wantarray ? @comments
424             : @comments ? join( "\n", @comments )
425             : undef;
426             };
427              
428             =head2 get_constraints
429              
430             Returns all the constraint objects as an array or array reference.
431              
432             my @constraints = $table->get_constraints;
433              
434             =cut
435              
436             sub get_constraints {
437 2506     2506 1 16579 my $self = shift;
438              
439 2506 100       7782 if ( $self->_has_constraints ) {
440             return wantarray
441 1873 100       4272 ? @{ $self->_constraints } : $self->_constraints;
  1871         34305  
442             }
443             else {
444 633         13583 $self->error('No constraints');
445 633         1929 return;
446             }
447             }
448              
449             =head2 get_indices
450              
451             Returns all the index objects as an array or array reference.
452              
453             my @indices = $table->get_indices;
454              
455             =cut
456              
457             sub get_indices {
458 552     552 1 11606 my $self = shift;
459              
460 552 100       2354 if ( $self->_has_indices ) {
461             return wantarray
462 188 100       607 ? @{ $self->_indices }
  187         3667  
463             : $self->_indices;
464             }
465             else {
466 364         8168 $self->error('No indices');
467 364         1471 return;
468             }
469             }
470              
471             =head2 get_field
472              
473             Returns a field by the name provided.
474              
475             my $field = $table->get_field('foo');
476              
477             =cut
478              
479             sub get_field {
480 4856     4856 1 8414 my $self = shift;
481 4856 50       13328 my $field_name = shift or return $self->error('No field name');
482 4856         25490 my $case_insensitive = shift;
483 4856 100       21873 return $self->error(qq[Field "$field_name" does not exist])
484             unless $self->_has_fields;
485 4519 100       9739 if ( $case_insensitive ) {
486 1         4 $field_name = uc($field_name);
487 1         2 foreach my $field ( keys %{$self->_fields} ) {
  1         25  
488 2 100       34 return $self->_fields->{$field} if $field_name eq uc($field);
489             }
490 0         0 return $self->error(qq[Field "$field_name" does not exist]);
491             }
492             return $self->error( qq[Field "$field_name" does not exist] ) unless
493 4518 100       77206 exists $self->_fields->{ $field_name };
494 3402         87760 return $self->_fields->{ $field_name };
495             }
496              
497             =head2 get_fields
498              
499             Returns all the field objects as an array or array reference.
500              
501             my @fields = $table->get_fields;
502              
503             =cut
504              
505             sub get_fields {
506 2223     2223 1 23781 my $self = shift;
507             my @fields =
508 8235         14349 map { $_->[1] }
509 14460         22786 sort { $a->[0] <=> $b->[0] }
510 8235         158100 map { [ $_->order, $_ ] }
511 2223 100       3683 values %{ $self->_has_fields ? $self->_fields : {} };
  2223         39891  
512              
513 2223 100       7532 if ( @fields ) {
514 1903 100       7692 return wantarray ? @fields : \@fields;
515             }
516             else {
517 320         7546 $self->error('No fields');
518 320         1180 return;
519             }
520             }
521              
522             =head2 is_valid
523              
524             Determine whether the view is valid or not.
525              
526             my $ok = $view->is_valid;
527              
528             =cut
529              
530             sub is_valid {
531 59     59 1 1531 my $self = shift;
532 59 50       1603 return $self->error('No name') unless $self->name;
533 59 100       1422 return $self->error('No fields') unless $self->get_fields;
534              
535 57         200 for my $object (
536             $self->get_fields, $self->get_indices, $self->get_constraints
537             ) {
538 327 100       1191 return $object->error unless $object->is_valid;
539             }
540              
541 54         247 return 1;
542             }
543              
544             =head2 is_trivial_link
545              
546             True if table has no data (non-key) fields and only uses single key joins.
547              
548             =cut
549              
550             has is_trivial_link => ( is => 'lazy', init_arg => undef );
551              
552             around is_trivial_link => carp_ro('is_trivial_link');
553              
554             sub _build_is_trivial_link {
555 3     3   33 my $self = shift;
556 3 100       58 return 0 if $self->is_data;
557              
558 2         18 my %fk = ();
559              
560 2         8 foreach my $field ( $self->get_fields ) {
561 5 100       136 next unless $field->is_foreign_key;
562 4         94 $fk{$field->foreign_key_reference->reference_table}++;
563             }
564              
565 2         43 foreach my $referenced (keys %fk){
566 3 100       33 if($fk{$referenced} > 1){
567 1         10 return 0;
568             }
569             }
570              
571 1         13 return 1;
572             }
573              
574             =head2 is_data
575              
576             Returns true if the table has some non-key fields.
577              
578             =cut
579              
580             has is_data => ( is => 'lazy', init_arg => undef );
581              
582             around is_data => carp_ro('is_data');
583              
584             sub _build_is_data {
585 4     4   38 my $self = shift;
586              
587 4         14 foreach my $field ( $self->get_fields ) {
588 9 100 100     245 if ( !$field->is_primary_key and !$field->is_foreign_key ) {
589 2         51 return 1;
590             }
591             }
592              
593 2         91 return 0;
594             }
595              
596             =head2 can_link
597              
598             Determine whether the table can link two arg tables via many-to-many.
599              
600             my $ok = $table->can_link($table1,$table2);
601              
602             =cut
603              
604             has _can_link => ( is => 'ro', init_arg => undef, default => quote_sub(q{ +{} }) );
605              
606             sub can_link {
607 3     3 1 775 my ( $self, $table1, $table2 ) = @_;
608              
609             return $self->_can_link->{ $table1->name }{ $table2->name }
610 3 50       87 if defined $self->_can_link->{ $table1->name }{ $table2->name };
611              
612 3 50       119 if ( $self->is_data == 1 ) {
613 0         0 $self->_can_link->{ $table1->name }{ $table2->name } = [0];
614 0         0 $self->_can_link->{ $table2->name }{ $table1->name } = [0];
615 0         0 return $self->_can_link->{ $table1->name }{ $table2->name };
616             }
617              
618 3         32 my %fk = ();
619              
620 3         9 foreach my $field ( $self->get_fields ) {
621 7 100       140 if ( $field->is_foreign_key ) {
622 6         41 push @{ $fk{ $field->foreign_key_reference->reference_table } },
  6         110  
623             $field->foreign_key_reference;
624             }
625             }
626              
627 3 100 66     74 if ( !defined( $fk{ $table1->name } ) or !defined( $fk{ $table2->name } ) )
628             {
629 1         45 $self->_can_link->{ $table1->name }{ $table2->name } = [0];
630 1         41 $self->_can_link->{ $table2->name }{ $table1->name } = [0];
631 1         41 return $self->_can_link->{ $table1->name }{ $table2->name };
632             }
633              
634             # trivial traversal, only one way to link the two tables
635 2 100 100     44 if ( scalar( @{ $fk{ $table1->name } } == 1 )
  2 50 50     57  
    50 50        
    50 50        
636 1         43 and scalar( @{ $fk{ $table2->name } } == 1 ) )
637             {
638             $self->_can_link->{ $table1->name }{ $table2->name } =
639 1         42 [ 'one2one', $fk{ $table1->name }, $fk{ $table2->name } ];
640             $self->_can_link->{ $table1->name }{ $table2->name } =
641 1         38 [ 'one2one', $fk{ $table2->name }, $fk{ $table1->name } ];
642              
643             # non-trivial traversal. one way to link table2,
644             # many ways to link table1
645             }
646 1         52 elsif ( scalar( @{ $fk{ $table1->name } } > 1 )
647 1         43 and scalar( @{ $fk{ $table2->name } } == 1 ) )
648             {
649             $self->_can_link->{ $table1->name }{ $table2->name } =
650 0         0 [ 'many2one', $fk{ $table1->name }, $fk{ $table2->name } ];
651             $self->_can_link->{ $table2->name }{ $table1->name } =
652 0         0 [ 'one2many', $fk{ $table2->name }, $fk{ $table1->name } ];
653              
654             # non-trivial traversal. one way to link table1,
655             # many ways to link table2
656             }
657 1         48 elsif ( scalar( @{ $fk{ $table1->name } } == 1 )
658 0         0 and scalar( @{ $fk{ $table2->name } } > 1 ) )
659             {
660             $self->_can_link->{ $table1->name }{ $table2->name } =
661 0         0 [ 'one2many', $fk{ $table1->name }, $fk{ $table2->name } ];
662             $self->_can_link->{ $table2->name }{ $table1->name } =
663 0         0 [ 'many2one', $fk{ $table2->name }, $fk{ $table1->name } ];
664              
665             # non-trivial traversal. many ways to link table1 and table2
666             }
667 1         60 elsif ( scalar( @{ $fk{ $table1->name } } > 1 )
668 1         41 and scalar( @{ $fk{ $table2->name } } > 1 ) )
669             {
670             $self->_can_link->{ $table1->name }{ $table2->name } =
671 1         47 [ 'many2many', $fk{ $table1->name }, $fk{ $table2->name } ];
672             $self->_can_link->{ $table2->name }{ $table1->name } =
673 1         39 [ 'many2many', $fk{ $table2->name }, $fk{ $table1->name } ];
674              
675             # one of the tables didn't export a key
676             # to this table, no linking possible
677             }
678             else {
679 0         0 $self->_can_link->{ $table1->name }{ $table2->name } = [0];
680 0         0 $self->_can_link->{ $table2->name }{ $table1->name } = [0];
681             }
682              
683 2         97 return $self->_can_link->{ $table1->name }{ $table2->name };
684             }
685              
686             =head2 name
687              
688             Get or set the table's name.
689              
690             Errors ("No table name") if you try to set a blank name.
691              
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").
695              
696             my $table_name = $table->name('foo');
697              
698             =cut
699              
700             has name => (
701             is => 'rw',
702             isa => sub { throw("No table name") unless $_[0] },
703             );
704              
705             around name => sub {
706             my $orig = shift;
707             my $self = shift;
708              
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 );
713             }
714             }
715              
716             return ex2err($orig, $self, @_);
717             };
718              
719             =head2 schema
720              
721             Get or set the table's schema object.
722              
723             my $schema = $table->schema;
724              
725             =cut
726              
727             has schema => ( is => 'rw', isa => schema_obj('Schema'), weak_ref => 1 );
728              
729             around schema => \&ex2err;
730              
731             sub primary_key {
732              
733             =pod
734              
735             =head2 primary_key
736              
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 object representing
742             the primary key.
743              
744             These are equivalent:
745              
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 ]);
752              
753             my $pk = $table->primary_key;
754              
755             =cut
756              
757 1472     1472 1 6040 my $self = shift;
758 1472         4353 my $fields = parse_list_arg( @_ );
759              
760 1472         2566 my $constraint;
761 1472 100       3737 if ( @$fields ) {
762 206         556 for my $f ( @$fields ) {
763 215 100       848 return $self->error(qq[Invalid field "$f"]) unless
764             $self->get_field($f);
765             }
766              
767 200         4175 my $has_pk;
768 200         854 for my $c ( $self->get_constraints ) {
769 97 100       2515 if ( $c->type eq PRIMARY_KEY ) {
770 87         1808 $has_pk = 1;
771 87         216 $c->fields( @{ $c->fields }, @$fields );
  87         361  
772 87         302 $constraint = $c;
773             }
774             }
775              
776 200 100       855 unless ( $has_pk ) {
777 113 50       501 $constraint = $self->add_constraint(
778             type => PRIMARY_KEY,
779             fields => $fields,
780             ) or return;
781             }
782             }
783              
784 1466 100       3322 if ( $constraint ) {
785 200         743 return $constraint;
786             }
787             else {
788 1266         3332 for my $c ( $self->get_constraints ) {
789 1037 100       28701 return $c if $c->type eq PRIMARY_KEY;
790             }
791             }
792              
793 438         2767 return;
794             }
795              
796             =head2 options
797              
798             Get or append to the table's options (e.g., table types for MySQL).
799             Returns an array or array reference.
800              
801             my @options = $table->options;
802              
803             =cut
804              
805             with ListAttr options => ( append => 1 );
806              
807             =head2 order
808              
809             Get or set the table's order.
810              
811             my $order = $table->order(3);
812              
813             =cut
814              
815             has order => ( is => 'rw', default => quote_sub(q{ 0 }) );
816              
817             around order => sub {
818             my ( $orig, $self, $arg ) = @_;
819              
820             if ( defined $arg && $arg =~ /^\d+$/ ) {
821             return $self->$orig($arg);
822             }
823              
824             return $self->$orig;
825             };
826              
827             =head2 field_names
828              
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.
832              
833             my @names = $constraint->field_names;
834              
835             =cut
836              
837             sub field_names {
838 3     3 1 779 my $self = shift;
839             my @fields =
840 3         14 map { $_->name }
  13         436  
841             $self->get_fields;
842              
843 3 50       70 if ( @fields ) {
844 3 50       39 return wantarray ? @fields : \@fields;
845             }
846             else {
847 0         0 $self->error('No fields');
848 0         0 return;
849             }
850             }
851              
852             sub equals {
853              
854             =pod
855              
856             =head2 equals
857              
858             Determines if this table is the same as another
859              
860             my $isIdentical = $table1->equals( $table2 );
861              
862             =cut
863              
864 0     0 1 0 my $self = shift;
865 0         0 my $other = shift;
866 0         0 my $case_insensitive = shift;
867              
868 0 0       0 return 0 unless $self->SUPER::equals($other);
869 0 0       0 return 0 unless $case_insensitive ? uc($self->name) eq uc($other->name) : $self->name eq $other->name;
    0          
870 0 0       0 return 0 unless $self->_compare_objects(scalar $self->options, scalar $other->options);
871 0 0       0 return 0 unless $self->_compare_objects(scalar $self->extra, scalar $other->extra);
872              
873             # Fields
874             # Go through our fields
875 0         0 my %checkedFields;
876 0         0 foreach my $field ( $self->get_fields ) {
877 0         0 my $otherField = $other->get_field($field->name, $case_insensitive);
878 0 0       0 return 0 unless $field->equals($otherField, $case_insensitive);
879 0         0 $checkedFields{$field->name} = 1;
880             }
881             # Go through the other table's fields
882 0         0 foreach my $otherField ( $other->get_fields ) {
883 0 0       0 next if $checkedFields{$otherField->name};
884 0         0 return 0;
885             }
886              
887             # Constraints
888             # Go through our constraints
889 0         0 my %checkedConstraints;
890             CONSTRAINT:
891 0         0 foreach my $constraint ( $self->get_constraints ) {
892 0         0 foreach my $otherConstraint ( $other->get_constraints ) {
893 0 0       0 if ( $constraint->equals($otherConstraint, $case_insensitive) ) {
894 0         0 $checkedConstraints{$otherConstraint} = 1;
895 0         0 next CONSTRAINT;
896             }
897             }
898 0         0 return 0;
899             }
900             # Go through the other table's constraints
901             CONSTRAINT2:
902 0         0 foreach my $otherConstraint ( $other->get_constraints ) {
903 0 0       0 next if $checkedFields{$otherConstraint};
904 0         0 foreach my $constraint ( $self->get_constraints ) {
905 0 0       0 if ( $otherConstraint->equals($constraint, $case_insensitive) ) {
906 0         0 next CONSTRAINT2;
907             }
908             }
909 0         0 return 0;
910             }
911              
912             # Indices
913             # Go through our indices
914 0         0 my %checkedIndices;
915             INDEX:
916 0         0 foreach my $index ( $self->get_indices ) {
917 0         0 foreach my $otherIndex ( $other->get_indices ) {
918 0 0       0 if ( $index->equals($otherIndex, $case_insensitive) ) {
919 0         0 $checkedIndices{$otherIndex} = 1;
920 0         0 next INDEX;
921             }
922             }
923 0         0 return 0;
924             }
925             # Go through the other table's indices
926             INDEX2:
927 0         0 foreach my $otherIndex ( $other->get_indices ) {
928 0 0       0 next if $checkedIndices{$otherIndex};
929 0         0 foreach my $index ( $self->get_indices ) {
930 0 0       0 if ( $otherIndex->equals($index, $case_insensitive) ) {
931 0         0 next INDEX2;
932             }
933             }
934 0         0 return 0;
935             }
936              
937 0         0 return 1;
938             }
939              
940             =head1 LOOKUP METHODS
941              
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
944             Constraint objects.
945              
946             =over 4
947              
948             =item pkey_fields
949              
950             The primary key fields.
951              
952             =item fkey_fields
953              
954             All foreign key fields.
955              
956             =item nonpkey_fields
957              
958             All the fields except the primary key.
959              
960             =item data_fields
961              
962             All non key fields.
963              
964             =item unique_fields
965              
966             All fields with unique constraints.
967              
968             =item unique_constraints
969              
970             All this tables unique constraints.
971              
972             =item fkey_constraints
973              
974             All this tables foreign key constraints. (See primary_key method to get the
975             primary key constraint)
976              
977             =back
978              
979             =cut
980              
981             sub pkey_fields {
982 3     3 1 1346 my $me = shift;
983 3         14 my @fields = grep { $_->is_primary_key } $me->get_fields;
  14         646  
984 3 50       184 return wantarray ? @fields : \@fields;
985             }
986              
987             sub fkey_fields {
988 1     1 1 1261 my $me = shift;
989 1         3 my @fields;
990 1         5 push @fields, $_->fields foreach $me->fkey_constraints;
991 1 50       6 return wantarray ? @fields : \@fields;
992             }
993              
994             sub nonpkey_fields {
995 1     1 1 1098 my $me = shift;
996 1         5 my @fields = grep { !$_->is_primary_key } $me->get_fields;
  4         77  
997 1 50       13 return wantarray ? @fields : \@fields;
998             }
999              
1000             sub data_fields {
1001 3     3 1 1599 my $me = shift;
1002             my @fields =
1003 3   100     12 grep { !$_->is_foreign_key and !$_->is_primary_key } $me->get_fields;
  14         606  
1004 3 50       134 return wantarray ? @fields : \@fields;
1005             }
1006              
1007             sub unique_fields {
1008 1     1 1 1198 my $me = shift;
1009 1         2 my @fields;
1010 1         4 push @fields, $_->fields foreach $me->unique_constraints;
1011 1 50       11 return wantarray ? @fields : \@fields;
1012             }
1013              
1014             sub unique_constraints {
1015 2     2 1 1063 my $me = shift;
1016 2         6 my @cons = grep { $_->type eq UNIQUE } $me->get_constraints;
  6         206  
1017 2 50       59 return wantarray ? @cons : \@cons;
1018             }
1019              
1020             sub fkey_constraints {
1021 2     2 1 7 my $me = shift;
1022 2         6 my @cons = grep { $_->type eq FOREIGN_KEY } $me->get_constraints;
  6         238  
1023 2 50       49 return wantarray ? @cons : \@cons;
1024             }
1025              
1026             # Must come after all 'has' declarations
1027             around new => \&ex2err;
1028              
1029             1;
1030              
1031             =pod
1032              
1033             =head1 AUTHORS
1034              
1035             Ken Youens-Clark Ekclark@cpan.orgE,
1036             Allen Day Eallenday@ucla.eduE.
1037              
1038             =cut