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   2432 use Moo;
  73         18747  
  73         421  
23 73     73   24038 use SQL::Translator::Utils qw(parse_list_arg ex2err throw carp_ro);
  73         182  
  73         4719  
24 73     73   1071 use SQL::Translator::Types qw(schema_obj);
  73         158  
  73         2995  
25 73     73   1394 use SQL::Translator::Role::ListAttr;
  73         162  
  73         521  
26 73     73   3615 use SQL::Translator::Schema::Constants;
  73         185  
  73         4864  
27 73     73   28643 use SQL::Translator::Schema::Constraint;
  73         224  
  73         2465  
28 73     73   33707 use SQL::Translator::Schema::Field;
  73         234  
  73         3742  
29 73     73   38574 use SQL::Translator::Schema::Index;
  73         1613  
  73         2669  
30              
31 73     73   31934 use Carp::Clan '^SQL::Translator';
  73         105006  
  73         482  
32 73     73   7631 use List::Util 'max';
  73         166  
  73         5678  
33 73     73   531 use Sub::Quote qw(quote_sub);
  73         167  
  73         7939  
34              
35             extends 'SQL::Translator::Schema::Object';
36              
37             our $VERSION = '1.6_3';
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   50229 '""' => sub { shift->name },
44 6307 50   6307   199040 'bool' => sub { $_[0]->name || $_[0] },
45 73         848 fallback => 1,
46 73     73   459 ;
  73         197  
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 560     560 1 4997 my $self = shift;
85 560         1008 my $constraint_class = 'SQL::Translator::Schema::Constraint';
86 560         764 my $constraint;
87              
88 560 100       3124 if ( UNIVERSAL::isa( $_[0], $constraint_class ) ) {
89 3         5 $constraint = shift;
90 3         61 $constraint->table( $self );
91             }
92             else {
93 557         3628 my %args = @_;
94 557         1284 $args{'table'} = $self;
95 557 50       11231 $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 560         12889 my $ok = 1;
104 560         1932 my $pk = $self->primary_key;
105 560 100 100     14783 if ( $pk && $constraint->type eq PRIMARY_KEY ) {
    100          
106 78         1541 $self->primary_key( $constraint->fields );
107 78 50       1526 $pk->name($constraint->name) if $constraint->name;
108 78         1586 my %extra = $constraint->extra;
109 78 100       612 $pk->extra(%extra) if keys %extra;
110 78         625 $constraint = $pk;
111 78         197 $ok = 0;
112             }
113             elsif ( $constraint->type eq PRIMARY_KEY ) {
114 210         4407 for my $fname ( $constraint->fields ) {
115 234 50       1122 if ( my $f = $self->get_field( $fname ) ) {
116 234         7188 $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 560 100       9932 if ( $ok ) {
143 482         761 push @{ $self->_constraints }, $constraint;
  482         7274  
144             }
145              
146 560         6284 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 7 my $self = shift;
161 3         6 my $constraint_class = 'SQL::Translator::Schema::Constraint';
162 3         5 my $constraint_name;
163              
164 3 100       14 if ( UNIVERSAL::isa( $_[0], $constraint_class ) ) {
165 1         15 $constraint_name = shift->name;
166             }
167             else {
168 2         4 $constraint_name = shift;
169             }
170              
171 3 100 66     11 if ( ! ($self->_has_constraints && grep { $_->name eq $constraint_name } @ { $self->_constraints }) ) {
  8         138  
  3         40  
172 1         19 return $self->error(qq[Can't drop constraint: "$constraint_name" doesn't exist]);
173             }
174              
175 2         4 my @cs = @{ $self->_constraints };
  2         26  
176 2         17 my ($constraint_id) = grep { $cs[$_]->name eq $constraint_name } (0..$#cs);
  6         82  
177 2         4 my $constraint = splice(@{$self->_constraints}, $constraint_id, 1);
  2         26  
178              
179 2         15 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 128     128 1 4328 my $self = shift;
208 128         287 my $index_class = 'SQL::Translator::Schema::Index';
209 128         217 my $index;
210              
211 128 100       1013 if ( UNIVERSAL::isa( $_[0], $index_class ) ) {
212 3         5 $index = shift;
213 3         59 $index->table( $self );
214             }
215             else {
216 125         586 my %args = @_;
217 125         290 $args{'table'} = $self;
218 125 50       2681 $index = $index_class->new( \%args ) or return
219             $self->error( $index_class->error );
220             }
221 128         3220 foreach my $ex_index ($self->get_indices) {
222 63 50       1506 return if ($ex_index->equals($index));
223             }
224 128         611 push @{ $self->_indices }, $index;
  128         1968  
225 128         1869 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 2957 my $self = shift;
240 3         4 my $index_class = 'SQL::Translator::Schema::Index';
241 3         4 my $index_name;
242              
243 3 100       14 if ( UNIVERSAL::isa( $_[0], $index_class ) ) {
244 1         14 $index_name = shift->name;
245             }
246             else {
247 2         3 $index_name = shift;
248             }
249              
250 3 100 66     14 if ( ! ($self->_has_indices && grep { $_->name eq $index_name } @{ $self->_indices }) ) {
  5         83  
  3         39  
251 1         25 return $self->error(qq[Can't drop index: "$index_name" doesn't exist]);
252             }
253              
254 2         15 my @is = @{ $self->_indices };
  2         136  
255 2         18 my ($index_id) = grep { $is[$_]->name eq $index_name } (0..$#is);
  4         166  
256 2         11 my $index = splice(@{$self->_indices}, $index_id, 1);
  2         26  
257              
258 2         16 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 1383     1383 1 8123 my $self = shift;
292 1383         2170 my $field_class = 'SQL::Translator::Schema::Field';
293 1383         1976 my $field;
294              
295 1383 100       6762 if ( UNIVERSAL::isa( $_[0], $field_class ) ) {
296 7         16 $field = shift;
297 7         135 $field->table( $self );
298             }
299             else {
300 1376         8295 my %args = @_;
301 1376         3489 $args{'table'} = $self;
302 1376 100       27687 $field = $field_class->new( \%args ) or return
303             $self->error( $field_class->error );
304             }
305              
306 1382         26313 my $existing_order = { map { $_->order => $_->name } $self->get_fields };
  4909         128772  
307              
308             # supplied order, possible unordered assembly
309 1382 100       41420 if ( $field->order ) {
310 181 100       2649 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         16 $existing_order->{$field->order},
316             ;
317             }
318             }
319             else {
320 1201   100     8789 my $last_field_no = max(keys %$existing_order) || 0;
321 1201 100       4080 if ( $last_field_no != scalar keys %$existing_order ) {
322 1         18 croak sprintf
323             "Table '%s' field order incomplete - unable to auto-determine order for newly added field",
324             $self->name,
325             ;
326             }
327              
328 1200         18947 $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 1380         21043 my $field_name = $field->name;
333              
334 1380 100       23075 if ( $self->get_field($field_name) ) {
335 2         66 return $self->error(qq[Can't use field name "$field_name": field exists]);
336             }
337             else {
338 1378         18595 $self->_fields->{ $field_name } = $field;
339             }
340              
341 1378         15439 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 40 my $self = shift;
356 3         7 my $field_class = 'SQL::Translator::Schema::Field';
357 3         4 my $field_name;
358              
359 3 100       16 if ( UNIVERSAL::isa( $_[0], $field_class ) ) {
360 1         17 $field_name = shift->name;
361             }
362             else {
363 2         3 $field_name = shift;
364             }
365 3         20 my %args = @_;
366 3         7 my $cascade = $args{'cascade'};
367              
368 3 100 66     50 if ( ! ($self->_has_fields && exists $self->_fields->{ $field_name } ) ) {
369 1         24 return $self->error(qq[Can't drop field: "$field_name" doesn't exists]);
370             }
371              
372 2         38 my $field = delete $self->_fields->{ $field_name };
373              
374 2 50       14 if ( $cascade ) {
375             # Remove this field from all indices using it
376 2         6 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         55 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         5 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 2535     2535 1 16172 my $self = shift;
438              
439 2535 100       7497 if ( $self->_has_constraints ) {
440             return wantarray
441 1897 100       3864 ? @{ $self->_constraints } : $self->_constraints;
  1895         29716  
442             }
443             else {
444 638         11437 $self->error('No constraints');
445 638         1713 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 563     563 1 10791 my $self = shift;
459              
460 563 100       2124 if ( $self->_has_indices ) {
461             return wantarray
462 192 100       515 ? @{ $self->_indices }
  191         3160  
463             : $self->_indices;
464             }
465             else {
466 371         7336 $self->error('No indices');
467 371         1319 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 4901     4901 1 7556 my $self = shift;
481 4901 50       11925 my $field_name = shift or return $self->error('No field name');
482 4901         20846 my $case_insensitive = shift;
483 4901 100       18803 return $self->error(qq[Field "$field_name" does not exist])
484             unless $self->_has_fields;
485 4560 100       8977 if ( $case_insensitive ) {
486 1         4 $field_name = uc($field_name);
487 1         1 foreach my $field ( keys %{$self->_fields} ) {
  1         21  
488 2 100       26 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 4559 100       64958 exists $self->_fields->{ $field_name };
494 3432         73049 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 2261     2261 1 20599 my $self = shift;
507             my @fields =
508 8374         12419 map { $_->[1] }
509 14763         20791 sort { $a->[0] <=> $b->[0] }
510 8374         133408 map { [ $_->order, $_ ] }
511 2261 100       3486 values %{ $self->_has_fields ? $self->_fields : {} };
  2261         34999  
512              
513 2261 100       6828 if ( @fields ) {
514 1937 100       6974 return wantarray ? @fields : \@fields;
515             }
516             else {
517 324         6422 $self->error('No fields');
518 324         1005 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 1496 my $self = shift;
532 59 50       1007 return $self->error('No name') unless $self->name;
533 59 100       1280 return $self->error('No fields') unless $self->get_fields;
534              
535 57         247 for my $object (
536             $self->get_fields, $self->get_indices, $self->get_constraints
537             ) {
538 327 100       1013 return $object->error unless $object->is_valid;
539             }
540              
541 54         277 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   29 my $self = shift;
556 3 100       44 return 0 if $self->is_data;
557              
558 2         14 my %fk = ();
559              
560 2         8 foreach my $field ( $self->get_fields ) {
561 5 100       120 next unless $field->is_foreign_key;
562 4         78 $fk{$field->foreign_key_reference->reference_table}++;
563             }
564              
565 2         37 foreach my $referenced (keys %fk){
566 3 100       8 if($fk{$referenced} > 1){
567 1         8 return 0;
568             }
569             }
570              
571 1         7 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   36 my $self = shift;
586              
587 4         13 foreach my $field ( $self->get_fields ) {
588 9 100 100     235 if ( !$field->is_primary_key and !$field->is_foreign_key ) {
589 2         39 return 1;
590             }
591             }
592              
593 2         69 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 851 my ( $self, $table1, $table2 ) = @_;
608              
609             return $self->_can_link->{ $table1->name }{ $table2->name }
610 3 50       69 if defined $self->_can_link->{ $table1->name }{ $table2->name };
611              
612 3 50       93 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         26 my %fk = ();
619              
620 3         9 foreach my $field ( $self->get_fields ) {
621 7 100       110 if ( $field->is_foreign_key ) {
622 6         31 push @{ $fk{ $field->foreign_key_reference->reference_table } },
  6         83  
623             $field->foreign_key_reference;
624             }
625             }
626              
627 3 100 66     57 if ( !defined( $fk{ $table1->name } ) or !defined( $fk{ $table2->name } ) )
628             {
629 1         33 $self->_can_link->{ $table1->name }{ $table2->name } = [0];
630 1         33 $self->_can_link->{ $table2->name }{ $table1->name } = [0];
631 1         31 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     37 if ( scalar( @{ $fk{ $table1->name } } == 1 )
  2 50 50     31  
    50 50        
    50 50        
636 1         46 and scalar( @{ $fk{ $table2->name } } == 1 ) )
637             {
638             $self->_can_link->{ $table1->name }{ $table2->name } =
639 1         33 [ 'one2one', $fk{ $table1->name }, $fk{ $table2->name } ];
640             $self->_can_link->{ $table1->name }{ $table2->name } =
641 1         31 [ '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         32 elsif ( scalar( @{ $fk{ $table1->name } } > 1 )
647 1         33 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         30 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         33 elsif ( scalar( @{ $fk{ $table1->name } } > 1 )
668 1         32 and scalar( @{ $fk{ $table2->name } } > 1 ) )
669             {
670             $self->_can_link->{ $table1->name }{ $table2->name } =
671 1         32 [ 'many2many', $fk{ $table1->name }, $fk{ $table2->name } ];
672             $self->_can_link->{ $table2->name }{ $table1->name } =
673 1         30 [ '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         60 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 1493     1493 1 5233 my $self = shift;
758 1493         3672 my $fields = parse_list_arg( @_ );
759              
760 1493         2284 my $constraint;
761 1493 100       3448 if ( @$fields ) {
762 206         499 for my $f ( @$fields ) {
763 215 100       667 return $self->error(qq[Invalid field "$f"]) unless
764             $self->get_field($f);
765             }
766              
767 200         3504 my $has_pk;
768 200         863 for my $c ( $self->get_constraints ) {
769 97 100       2062 if ( $c->type eq PRIMARY_KEY ) {
770 87         1465 $has_pk = 1;
771 87         164 $c->fields( @{ $c->fields }, @$fields );
  87         312  
772 87         268 $constraint = $c;
773             }
774             }
775              
776 200 100       734 unless ( $has_pk ) {
777 113 50       440 $constraint = $self->add_constraint(
778             type => PRIMARY_KEY,
779             fields => $fields,
780             ) or return;
781             }
782             }
783              
784 1487 100       3094 if ( $constraint ) {
785 200         672 return $constraint;
786             }
787             else {
788 1287         3268 for my $c ( $self->get_constraints ) {
789 1079 100       25941 return $c if $c->type eq PRIMARY_KEY;
790             }
791             }
792              
793 447         2334 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 725 my $self = shift;
839             my @fields =
840 3         11 map { $_->name }
  13         353  
841             $self->get_fields;
842              
843 3 50       54 if ( @fields ) {
844 3 50       30 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 1697 my $me = shift;
983 3         15 my @fields = grep { $_->is_primary_key } $me->get_fields;
  14         487  
984 3 50       151 return wantarray ? @fields : \@fields;
985             }
986              
987             sub fkey_fields {
988 1     1 1 1875 my $me = shift;
989 1         3 my @fields;
990 1         4 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 1498 my $me = shift;
996 1         5 my @fields = grep { !$_->is_primary_key } $me->get_fields;
  4         69  
997 1 50       11 return wantarray ? @fields : \@fields;
998             }
999              
1000             sub data_fields {
1001 3     3 1 1715 my $me = shift;
1002             my @fields =
1003 3   100     12 grep { !$_->is_foreign_key and !$_->is_primary_key } $me->get_fields;
  14         524  
1004 3 50       110 return wantarray ? @fields : \@fields;
1005             }
1006              
1007             sub unique_fields {
1008 1     1 1 1758 my $me = shift;
1009 1         3 my @fields;
1010 1         6 push @fields, $_->fields foreach $me->unique_constraints;
1011 1 50       6 return wantarray ? @fields : \@fields;
1012             }
1013              
1014             sub unique_constraints {
1015 2     2 1 1470 my $me = shift;
1016 2         10 my @cons = grep { $_->type eq UNIQUE } $me->get_constraints;
  6         181  
1017 2 50       42 return wantarray ? @cons : \@cons;
1018             }
1019              
1020             sub fkey_constraints {
1021 2     2 1 8 my $me = shift;
1022 2         9 my @cons = grep { $_->type eq FOREIGN_KEY } $me->get_constraints;
  6         182  
1023 2 50       44 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