0773a44c19caffd6267bc30ef597f451b6a8614c
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator / Schema / Field.pm
1 package SQL::Translator::Schema::Field;
2
3 # ----------------------------------------------------------------------
4 # $Id: Field.pm,v 1.15 2004-03-23 21:26:55 grommit Exp $
5 # ----------------------------------------------------------------------
6 # Copyright (C) 2002-4 SQLFairy Authors
7 #
8 # This program is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU General Public License as
10 # published by the Free Software Foundation; version 2.
11 #
12 # This program is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 # General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 # 02111-1307  USA
21 # -------------------------------------------------------------------
22
23 =pod
24
25 =head1 NAME
26
27 SQL::Translator::Schema::Field - SQL::Translator field object
28
29 =head1 SYNOPSIS
30
31   use SQL::Translator::Schema::Field;
32   my $field = SQL::Translator::Schema::Field->new(
33       name => 'foo',
34       sql  => 'select * from foo',
35   );
36
37 =head1 DESCRIPTION
38
39 C<SQL::Translator::Schema::Field> is the field object.
40
41 =head1 METHODS
42
43 =cut
44
45 use strict;
46 use Class::Base;
47 use SQL::Translator::Schema::Constants;
48 use SQL::Translator::Utils 'parse_list_arg';
49
50 use base 'Class::Base';
51 use vars qw($VERSION $TABLE_COUNT $VIEW_COUNT);
52
53 $VERSION = sprintf "%d.%02d", q$Revision: 1.15 $ =~ /(\d+)\.(\d+)/;
54
55 # Stringify to our name, being careful not to pass any args through so we don't
56 # accidentally set it to undef. We also have to tweak bool so the object is
57 # still true when it doesn't have a name (which shouldn't happen!).
58 use overload
59     '""'     => sub { shift->name },
60     'bool'   => sub { $_[0]->name || $_[0] },
61     fallback => 1,
62 ;
63
64 # ----------------------------------------------------------------------
65 sub init {
66
67 =pod
68
69 =head2 new
70
71 Object constructor.
72
73   my $schema = SQL::Translator::Schema::Field->new;
74
75 =cut
76
77     my ( $self, $config ) = @_;
78
79     for my $arg ( 
80         qw[ 
81             table name data_type size is_primary_key is_nullable
82             is_auto_increment default_value comments
83         ] 
84     ) {
85         next unless defined $config->{ $arg };
86         defined $self->$arg( $config->{ $arg } ) or return;
87     }
88
89     return $self;
90 }
91
92 # ----------------------------------------------------------------------
93 sub comments {
94
95 =pod
96
97 =head2 comments
98
99 Get or set the comments on a field.  May be called several times to 
100 set and it will accumulate the comments.  Called in an array context,
101 returns each comment individually; called in a scalar context, returns
102 all the comments joined on newlines.
103
104   $field->comments('foo');
105   $field->comments('bar');
106   print join( ', ', $field->comments ); # prints "foo, bar"
107
108 =cut
109
110     my $self = shift;
111
112     for my $arg ( @_ ) {
113         $arg = $arg->[0] if ref $arg;
114         push @{ $self->{'comments'} }, $arg if $arg;
115     }
116
117     if ( @{ $self->{'comments'} || [] } ) {
118         return wantarray 
119             ? @{ $self->{'comments'} || [] }
120             : join( "\n", @{ $self->{'comments'} || [] } );
121     }
122     else {
123         return wantarray ? () : '';
124     }
125 }
126
127
128 # ----------------------------------------------------------------------
129 sub data_type {
130
131 =pod
132
133 =head2 data_type
134
135 Get or set the field's data type.
136
137   my $data_type = $field->data_type('integer');
138
139 =cut
140
141     my $self = shift;
142     $self->{'data_type'} = shift if @_;
143     return $self->{'data_type'} || '';
144 }
145
146 # ----------------------------------------------------------------------
147 sub default_value {
148
149 =pod
150
151 =head2 default_value
152
153 Get or set the field's default value.  Will return undef if not defined
154 and could return the empty string (it's a valid default value), so don't 
155 assume an error like other methods.
156
157   my $default = $field->default_value('foo');
158
159 =cut
160
161     my ( $self, $arg ) = @_;
162     $self->{'default_value'} = $arg if defined $arg;
163     return $self->{'default_value'};
164 }
165
166 # ----------------------------------------------------------------------
167 sub extra {
168
169 =pod
170
171 =head2 extra
172
173 Get or set the field's "extra" attibutes (e.g., "ZEROFILL" for MySQL).
174 Accepts a hash(ref) of name/value pairs to store;  returns a hash.
175
176   $field->extra( qualifier => 'ZEROFILL' );
177   my %extra = $field->extra;
178
179 =cut
180
181     my $self = shift;
182     my $args = ref $_[0] eq 'HASH' ? shift : { @_ };
183
184     while ( my ( $key, $value ) = each %$args ) {
185         $self->{'extra'}{ $key } = $value;
186     }
187
188     return %{ $self->{'extra'} || {} };
189 }
190
191 # ----------------------------------------------------------------------
192 sub foreign_key_reference {
193
194 =pod
195
196 =head2 foreign_key_reference
197
198 Get or set the field's foreign key reference;
199
200   my $constraint = $field->foreign_key_reference( $constraint );
201
202 =cut
203
204     my $self = shift;
205
206     if ( my $arg = shift ) {
207         my $class = 'SQL::Translator::Schema::Constraint';
208         if ( UNIVERSAL::isa( $arg, $class ) ) {
209             return $self->error(
210                 'Foreign key reference for ', $self->name, 'already defined'
211             ) if $self->{'foreign_key_reference'};
212
213             $self->{'foreign_key_reference'} = $arg;
214         }
215         else {
216             return $self->error(
217                 "Argument to foreign_key_reference is not an $class object"
218             );
219         }
220     }
221
222     return $self->{'foreign_key_reference'};
223 }
224
225 # ----------------------------------------------------------------------
226 sub is_auto_increment {
227
228 =pod
229
230 =head2 is_auto_increment
231
232 Get or set the field's C<is_auto_increment> attribute.
233
234   my $is_pk = $field->is_auto_increment(1);
235
236 =cut
237
238     my ( $self, $arg ) = @_;
239
240     if ( defined $arg ) {
241         $self->{'is_auto_increment'} = $arg ? 1 : 0;
242     }
243
244     unless ( defined $self->{'is_auto_increment'} ) {
245         if ( my $table = $self->table ) {
246             if ( my $schema = $table->schema ) {
247                 if ( 
248                     $schema->database eq 'PostgreSQL' &&
249                     $self->data_type eq 'serial'
250                 ) {
251                     $self->{'is_auto_increment'} = 1;
252                 }
253             }
254         }
255     }
256
257     return $self->{'is_auto_increment'} || 0;
258 }
259
260 # ----------------------------------------------------------------------
261 sub is_foreign_key {
262
263 =pod
264
265 =head2 is_foreign_key
266
267 Returns whether or not the field is a foreign key.
268
269   my $is_fk = $field->is_foreign_key;
270
271 =cut
272
273     my ( $self, $arg ) = @_;
274
275     unless ( defined $self->{'is_foreign_key'} ) {
276         if ( my $table = $self->table ) {
277             for my $c ( $table->get_constraints ) {
278                 if ( $c->type eq FOREIGN_KEY ) {
279                     my %fields = map { $_, 1 } $c->fields;
280                     if ( $fields{ $self->name } ) {
281                         $self->{'is_foreign_key'} = 1;
282                         $self->foreign_key_reference( $c );
283                         last;
284                     }
285                 }
286             }
287         }
288     }
289
290     return $self->{'is_foreign_key'} || 0;
291 }
292
293 # ----------------------------------------------------------------------
294 sub is_nullable {
295
296 =pod
297
298 =head2 is_nullable
299
300 Get or set the whether the field can be null.  If not defined, then 
301 returns "1" (assumes the field can be null).  The argument is evaluated
302 by Perl for True or False, so the following are eqivalent:
303
304   $is_nullable = $field->is_nullable(0);
305   $is_nullable = $field->is_nullable('');
306   $is_nullable = $field->is_nullable('0');
307
308 While this is technically a field constraint, it's probably easier to
309 represent this as an attribute of the field.  In order keep things
310 consistent, any other constraint on the field (unique, primary, and
311 foreign keys; checks) are represented as table constraints.
312
313 =cut
314
315     my ( $self, $arg ) = @_;
316
317     if ( defined $arg ) {
318         $self->{'is_nullable'} = $arg ? 1 : 0;
319     }
320
321     if ( 
322         defined $self->{'is_nullable'} && 
323         $self->{'is_nullable'} == 1    &&
324         $self->is_primary_key
325     ) {
326         $self->{'is_nullable'} = 0;
327     }
328
329     return defined $self->{'is_nullable'} ? $self->{'is_nullable'} : 1;
330 }
331
332 # ----------------------------------------------------------------------
333 sub is_primary_key {
334
335 =pod
336
337 =head2 is_primary_key
338
339 Get or set the field's C<is_primary_key> attribute.  Does not create
340 a table constraint (should it?).
341
342   my $is_pk = $field->is_primary_key(1);
343
344 =cut
345
346     my ( $self, $arg ) = @_;
347
348     if ( defined $arg ) {
349         $self->{'is_primary_key'} = $arg ? 1 : 0;
350     }
351
352     unless ( defined $self->{'is_primary_key'} ) {
353         if ( my $table = $self->table ) {
354             if ( my $pk = $table->primary_key ) {
355                 my %fields = map { $_, 1 } $pk->fields;
356                 $self->{'is_primary_key'} = $fields{ $self->name } || 0;
357             }
358             else {
359                 $self->{'is_primary_key'} = 0;
360             }
361         }
362     }
363
364     return $self->{'is_primary_key'} || 0;
365 }
366
367 # ----------------------------------------------------------------------
368 sub is_unique {
369
370 =pod
371
372 =head2 is_unique
373
374 Determine whether the field has a UNIQUE constraint or not.
375
376   my $is_unique = $field->is_unique;
377
378 =cut
379
380     my $self = shift;
381     
382     unless ( defined $self->{'is_unique'} ) {
383         if ( my $table = $self->table ) {
384             for my $c ( $table->get_constraints ) {
385                 if ( $c->type eq UNIQUE ) {
386                     my %fields = map { $_, 1 } $c->fields;
387                     if ( $fields{ $self->name } ) {
388                         $self->{'is_unique'} = 1;
389                         last;
390                     }
391                 }
392             }
393         }
394     }
395
396     return $self->{'is_unique'} || 0;
397 }
398
399 # ----------------------------------------------------------------------
400 sub is_valid {
401
402 =pod
403
404 =head2 is_valid
405
406 Determine whether the field is valid or not.
407
408   my $ok = $field->is_valid;
409
410 =cut
411
412     my $self = shift;
413     return $self->error('No name')         unless $self->name;
414     return $self->error('No data type')    unless $self->data_type;
415     return $self->error('No table object') unless $self->table;
416     return 1;
417 }
418
419 # ----------------------------------------------------------------------
420 sub name {
421
422 =pod
423
424 =head2 name
425
426 Get or set the field's name.
427
428  my $name = $field->name('foo');
429
430 The field object will also stringify to its name.
431
432  my $setter_name = "set_$field";
433
434 Errors ("No field name") if you try to set a blank name.
435
436 =cut
437
438     my $self = shift;
439
440     if ( @_ ) {
441         my $arg = shift || return $self->error( "No field name" );
442         if ( my $table = $self->table ) {
443             return $self->error( qq[Can't use field name "$arg": field exists] )
444                 if $table->get_field( $arg );
445         }
446
447         $self->{'name'} = $arg;
448     }
449
450     return $self->{'name'} || '';
451 }
452
453 sub full_name {
454
455 =head2 full_name
456
457 Read only method to return the fields name with its table name pre-pended.
458 e.g. "person.foo".
459
460 =cut
461
462     my $self = shift;
463     return $self->table.".".$self->name;
464 }
465
466 # ----------------------------------------------------------------------
467 sub order {
468
469 =pod
470
471 =head2 order
472
473 Get or set the field's order.
474
475   my $order = $field->order(3);
476
477 =cut
478
479     my ( $self, $arg ) = @_;
480
481     if ( defined $arg && $arg =~ /^\d+$/ ) {
482         $self->{'order'} = $arg;
483     }
484
485     return $self->{'order'} || 0;
486 }
487
488 # ----------------------------------------------------------------------
489 sub size {
490
491 =pod
492
493 =head2 size
494
495 Get or set the field's size.  Accepts a string, array or arrayref of
496 numbers and returns a string.
497
498   $field->size( 30 );
499   $field->size( [ 255 ] );
500   $size = $field->size( 10, 2 );
501   print $size; # prints "10,2"
502
503   $size = $field->size( '10, 2' );
504   print $size; # prints "10,2"
505
506 =cut
507
508     my $self    = shift;
509     my $numbers = parse_list_arg( @_ );
510
511     if ( @$numbers ) {
512         my @new;
513         for my $num ( @$numbers ) {
514             if ( defined $num && $num =~ m/^\d+(?:\.\d+)?$/ ) {
515                 push @new, $num;
516             }
517         }
518         $self->{'size'} = \@new if @new; # only set if all OK
519     }
520
521     return wantarray 
522         ? @{ $self->{'size'} || [0] }
523         : join( ',', @{ $self->{'size'} || [0] } )
524     ;
525 }
526
527 # ----------------------------------------------------------------------
528 sub table {
529
530 =pod
531
532 =head2 table
533
534 Get or set the field's table object.
535
536   my $table = $field->table;
537
538 =cut
539
540     my $self = shift;
541     if ( my $arg = shift ) {
542         return $self->error('Not a table object') unless
543             UNIVERSAL::isa( $arg, 'SQL::Translator::Schema::Table' );
544         $self->{'table'} = $arg;
545     }
546
547     return $self->{'table'};
548 }
549
550 # ----------------------------------------------------------------------
551 sub DESTROY {
552 #
553 # Destroy cyclical references.
554 #
555     my $self = shift;
556     undef $self->{'table'};
557     undef $self->{'foreign_key_reference'};
558 }
559
560 1;
561
562 # ----------------------------------------------------------------------
563
564 =pod
565
566 =head1 AUTHOR
567
568 Ken Y. Clark E<lt>kclark@cpan.orgE<gt>.
569
570 =cut