Reduce $Id to its normal form
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator / Schema / Field.pm
CommitLineData
3c5de62a 1package SQL::Translator::Schema::Field;
2
3# ----------------------------------------------------------------------
782b5a43 4# $Id$
3c5de62a 5# ----------------------------------------------------------------------
478f608d 6# Copyright (C) 2002-2009 SQLFairy Authors
3c5de62a 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
27SQL::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(
b9dc0b40 33 name => 'foo',
34 table => $table,
3c5de62a 35 );
36
37=head1 DESCRIPTION
38
39C<SQL::Translator::Schema::Field> is the field object.
40
41=head1 METHODS
42
43=cut
44
45use strict;
43b9dc7a 46use SQL::Translator::Schema::Constants;
ec2ab48d 47use SQL::Translator::Utils 'parse_list_arg';
3c5de62a 48
b6a880d1 49use base 'SQL::Translator::Schema::Object';
50
da06ac74 51use vars qw($VERSION $TABLE_COUNT $VIEW_COUNT);
52
53$VERSION = '1.99';
65dd38c0 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!).
58use overload
59 '""' => sub { shift->name },
60 'bool' => sub { $_[0]->name || $_[0] },
61 fallback => 1,
62;
3c5de62a 63
9ab59f87 64use DBI qw(:sql_types);
65
66# Mapping from string to sql contstant
67our %type_mapping = (
68 integer => SQL_INTEGER,
69 int => SQL_INTEGER,
70
71 smallint => SQL_SMALLINT,
72 bigint => 9999, # DBI doesn't export a constatn for this. Le suck
73
74 double => SQL_DOUBLE,
75
76 decimal => SQL_DECIMAL,
77 numeric => SQL_NUMERIC,
78 dec => SQL_DECIMAL,
79
80 bit => SQL_BIT,
81
82 date => SQL_DATE,
83 datetime => SQL_DATETIME,
84 timestamp => SQL_TIMESTAMP,
85 time => SQL_TIME,
86
87 char => SQL_CHAR,
88 varchar => SQL_VARCHAR,
89 binary => SQL_BINARY,
90 varbinary => SQL_VARBINARY,
91 tinyblob => SQL_BLOB,
92 blob => SQL_BLOB,
93 text => SQL_LONGVARCHAR
94
95);
3c5de62a 96# ----------------------------------------------------------------------
9371be50 97
98__PACKAGE__->_attributes( qw/
99 table name data_type size is_primary_key is_nullable
b1789409 100 is_auto_increment default_value comments is_foreign_key
6b2dbb1a 101 is_unique order sql_data_type
9371be50 102/);
3c5de62a 103
104=pod
105
106=head2 new
107
108Object constructor.
109
0bf88ce5 110 my $field = SQL::Translator::Schema::Field->new(
111 name => 'foo',
112 table => $table,
b9dc0b40 113 );
3c5de62a 114
115=cut
116
3c5de62a 117# ----------------------------------------------------------------------
5ac417ad 118sub comments {
119
120=pod
121
122=head2 comments
123
124Get or set the comments on a field. May be called several times to
125set and it will accumulate the comments. Called in an array context,
126returns each comment individually; called in a scalar context, returns
127all the comments joined on newlines.
128
129 $field->comments('foo');
130 $field->comments('bar');
131 print join( ', ', $field->comments ); # prints "foo, bar"
132
133=cut
134
135 my $self = shift;
aadf4042 136
137 for my $arg ( @_ ) {
138 $arg = $arg->[0] if ref $arg;
c33df5c4 139 push @{ $self->{'comments'} }, $arg if $arg;
aadf4042 140 }
5ac417ad 141
c33df5c4 142 if ( @{ $self->{'comments'} || [] } ) {
143 return wantarray
144 ? @{ $self->{'comments'} || [] }
145 : join( "\n", @{ $self->{'comments'} || [] } );
146 }
147 else {
148 return wantarray ? () : '';
149 }
5ac417ad 150}
151
152
153# ----------------------------------------------------------------------
3c5de62a 154sub data_type {
155
156=pod
157
158=head2 data_type
159
43b9dc7a 160Get or set the field's data type.
3c5de62a 161
162 my $data_type = $field->data_type('integer');
163
164=cut
165
166 my $self = shift;
9ab59f87 167 if (@_) {
168 $self->{'data_type'} = $_[0];
169 $self->{'sql_data_type'} = $type_mapping{lc $_[0]} || SQL_UNKNOWN_TYPE unless exists $self->{sql_data_type};
170 }
3c5de62a 171 return $self->{'data_type'} || '';
172}
173
6b2dbb1a 174sub sql_data_type {
175
176=head2 sql_data_type
177
178Constant from DBI package representing this data type. See L<DBI/DBI Constants>
179for more details.
180
181=cut
182
183 my $self = shift;
184 $self->{sql_data_type} = shift if @_;
185 return $self->{sql_data_type} || 0;
186
187}
188
3c5de62a 189# ----------------------------------------------------------------------
43b9dc7a 190sub default_value {
191
192=pod
193
194=head2 default_value
195
196Get or set the field's default value. Will return undef if not defined
197and could return the empty string (it's a valid default value), so don't
198assume an error like other methods.
199
200 my $default = $field->default_value('foo');
201
202=cut
203
204 my ( $self, $arg ) = @_;
205 $self->{'default_value'} = $arg if defined $arg;
206 return $self->{'default_value'};
207}
208
209# ----------------------------------------------------------------------
9966eebc 210=pod
211
212=head2 extra
213
214Get or set the field's "extra" attibutes (e.g., "ZEROFILL" for MySQL).
215Accepts a hash(ref) of name/value pairs to store; returns a hash.
216
217 $field->extra( qualifier => 'ZEROFILL' );
218 my %extra = $field->extra;
219
220=cut
221
9966eebc 222
223# ----------------------------------------------------------------------
224sub foreign_key_reference {
225
226=pod
227
228=head2 foreign_key_reference
229
230Get or set the field's foreign key reference;
231
232 my $constraint = $field->foreign_key_reference( $constraint );
233
234=cut
235
236 my $self = shift;
237
238 if ( my $arg = shift ) {
239 my $class = 'SQL::Translator::Schema::Constraint';
240 if ( UNIVERSAL::isa( $arg, $class ) ) {
241 return $self->error(
242 'Foreign key reference for ', $self->name, 'already defined'
243 ) if $self->{'foreign_key_reference'};
244
245 $self->{'foreign_key_reference'} = $arg;
246 }
247 else {
248 return $self->error(
249 "Argument to foreign_key_reference is not an $class object"
250 );
251 }
252 }
253
254 return $self->{'foreign_key_reference'};
255}
256
257# ----------------------------------------------------------------------
43b9dc7a 258sub is_auto_increment {
259
260=pod
261
262=head2 is_auto_increment
263
264Get or set the field's C<is_auto_increment> attribute.
265
b9dc0b40 266 my $is_auto = $field->is_auto_increment(1);
43b9dc7a 267
268=cut
269
270 my ( $self, $arg ) = @_;
271
272 if ( defined $arg ) {
273 $self->{'is_auto_increment'} = $arg ? 1 : 0;
274 }
275
276 unless ( defined $self->{'is_auto_increment'} ) {
277 if ( my $table = $self->table ) {
278 if ( my $schema = $table->schema ) {
279 if (
280 $schema->database eq 'PostgreSQL' &&
281 $self->data_type eq 'serial'
282 ) {
283 $self->{'is_auto_increment'} = 1;
284 }
285 }
286 }
287 }
288
289 return $self->{'is_auto_increment'} || 0;
290}
291
292# ----------------------------------------------------------------------
9966eebc 293sub is_foreign_key {
294
295=pod
296
297=head2 is_foreign_key
298
299Returns whether or not the field is a foreign key.
300
301 my $is_fk = $field->is_foreign_key;
302
303=cut
304
305 my ( $self, $arg ) = @_;
306
307 unless ( defined $self->{'is_foreign_key'} ) {
308 if ( my $table = $self->table ) {
309 for my $c ( $table->get_constraints ) {
310 if ( $c->type eq FOREIGN_KEY ) {
311 my %fields = map { $_, 1 } $c->fields;
312 if ( $fields{ $self->name } ) {
313 $self->{'is_foreign_key'} = 1;
314 $self->foreign_key_reference( $c );
315 last;
316 }
317 }
318 }
319 }
320 }
321
322 return $self->{'is_foreign_key'} || 0;
323}
324
9966eebc 325# ----------------------------------------------------------------------
ec2ab48d 326sub is_nullable {
327
328=pod
329
330=head2 is_nullable
331
b9dc0b40 332Get or set whether the field can be null. If not defined, then
ec2ab48d 333returns "1" (assumes the field can be null). The argument is evaluated
334by Perl for True or False, so the following are eqivalent:
335
336 $is_nullable = $field->is_nullable(0);
337 $is_nullable = $field->is_nullable('');
338 $is_nullable = $field->is_nullable('0');
339
340While this is technically a field constraint, it's probably easier to
341represent this as an attribute of the field. In order keep things
342consistent, any other constraint on the field (unique, primary, and
343foreign keys; checks) are represented as table constraints.
344
345=cut
346
347 my ( $self, $arg ) = @_;
348
349 if ( defined $arg ) {
350 $self->{'is_nullable'} = $arg ? 1 : 0;
351 }
352
42c8fad4 353 if (
354 defined $self->{'is_nullable'} &&
355 $self->{'is_nullable'} == 1 &&
356 $self->is_primary_key
357 ) {
358 $self->{'is_nullable'} = 0;
359 }
360
ec2ab48d 361 return defined $self->{'is_nullable'} ? $self->{'is_nullable'} : 1;
362}
363
364# ----------------------------------------------------------------------
3c5de62a 365sub is_primary_key {
366
367=pod
368
369=head2 is_primary_key
370
ec2ab48d 371Get or set the field's C<is_primary_key> attribute. Does not create
372a table constraint (should it?).
3c5de62a 373
374 my $is_pk = $field->is_primary_key(1);
375
376=cut
377
378 my ( $self, $arg ) = @_;
379
380 if ( defined $arg ) {
381 $self->{'is_primary_key'} = $arg ? 1 : 0;
382 }
383
43b9dc7a 384 unless ( defined $self->{'is_primary_key'} ) {
385 if ( my $table = $self->table ) {
386 if ( my $pk = $table->primary_key ) {
387 my %fields = map { $_, 1 } $pk->fields;
388 $self->{'is_primary_key'} = $fields{ $self->name } || 0;
389 }
390 else {
391 $self->{'is_primary_key'} = 0;
392 }
393 }
394 }
395
3c5de62a 396 return $self->{'is_primary_key'} || 0;
397}
398
399# ----------------------------------------------------------------------
ee2766f4 400sub is_unique {
401
402=pod
403
404=head2 is_unique
405
406Determine whether the field has a UNIQUE constraint or not.
407
408 my $is_unique = $field->is_unique;
409
410=cut
411
412 my $self = shift;
413
414 unless ( defined $self->{'is_unique'} ) {
415 if ( my $table = $self->table ) {
416 for my $c ( $table->get_constraints ) {
417 if ( $c->type eq UNIQUE ) {
418 my %fields = map { $_, 1 } $c->fields;
419 if ( $fields{ $self->name } ) {
420 $self->{'is_unique'} = 1;
421 last;
422 }
423 }
424 }
425 }
426 }
427
428 return $self->{'is_unique'} || 0;
429}
430
431# ----------------------------------------------------------------------
ec2ab48d 432sub is_valid {
433
434=pod
435
436=head2 is_valid
437
438Determine whether the field is valid or not.
439
440 my $ok = $field->is_valid;
441
442=cut
443
444 my $self = shift;
445 return $self->error('No name') unless $self->name;
446 return $self->error('No data type') unless $self->data_type;
447 return $self->error('No table object') unless $self->table;
448 return 1;
449}
450
451# ----------------------------------------------------------------------
3c5de62a 452sub name {
453
454=pod
455
456=head2 name
457
458Get or set the field's name.
459
65dd38c0 460 my $name = $field->name('foo');
461
462The field object will also stringify to its name.
463
464 my $setter_name = "set_$field";
465
466Errors ("No field name") if you try to set a blank name.
3c5de62a 467
468=cut
469
470 my $self = shift;
43b9dc7a 471
65dd38c0 472 if ( @_ ) {
473 my $arg = shift || return $self->error( "No field name" );
43b9dc7a 474 if ( my $table = $self->table ) {
65dd38c0 475 return $self->error( qq[Can't use field name "$arg": field exists] )
43b9dc7a 476 if $table->get_field( $arg );
477 }
478
479 $self->{'name'} = $arg;
480 }
481
3c5de62a 482 return $self->{'name'} || '';
483}
484
4809213f 485sub full_name {
486
487=head2 full_name
488
489Read only method to return the fields name with its table name pre-pended.
490e.g. "person.foo".
491
492=cut
493
494 my $self = shift;
495 return $self->table.".".$self->name;
496}
497
3c5de62a 498# ----------------------------------------------------------------------
ec2ab48d 499sub order {
3c5de62a 500
501=pod
502
ec2ab48d 503=head2 order
3c5de62a 504
ec2ab48d 505Get or set the field's order.
3c5de62a 506
ec2ab48d 507 my $order = $field->order(3);
3c5de62a 508
509=cut
510
511 my ( $self, $arg ) = @_;
512
ec2ab48d 513 if ( defined $arg && $arg =~ /^\d+$/ ) {
514 $self->{'order'} = $arg;
3c5de62a 515 }
516
ec2ab48d 517 return $self->{'order'} || 0;
43b9dc7a 518}
519
520# ----------------------------------------------------------------------
c1e3c768 521sub schema {
522
523=head2 schema
524
525Shortcut to get the fields schema ($field->table->schema) or undef if it
526doesn't have one.
527
528 my $schema = $field->schema;
529
530=cut
531
532 my $self = shift;
533 if ( my $table = $self->table ) { return $table->schema || undef; }
534 return undef;
535}
536
537# ----------------------------------------------------------------------
43b9dc7a 538sub size {
539
540=pod
541
542=head2 size
543
544Get or set the field's size. Accepts a string, array or arrayref of
545numbers and returns a string.
546
547 $field->size( 30 );
548 $field->size( [ 255 ] );
549 $size = $field->size( 10, 2 );
550 print $size; # prints "10,2"
551
552 $size = $field->size( '10, 2' );
553 print $size; # prints "10,2"
554
555=cut
556
557 my $self = shift;
ec2ab48d 558 my $numbers = parse_list_arg( @_ );
43b9dc7a 559
560 if ( @$numbers ) {
561 my @new;
562 for my $num ( @$numbers ) {
563 if ( defined $num && $num =~ m/^\d+(?:\.\d+)?$/ ) {
564 push @new, $num;
565 }
566 }
567 $self->{'size'} = \@new if @new; # only set if all OK
568 }
569
ec2ab48d 570 return wantarray
aadf4042 571 ? @{ $self->{'size'} || [0] }
ec2ab48d 572 : join( ',', @{ $self->{'size'} || [0] } )
573 ;
43b9dc7a 574}
575
576# ----------------------------------------------------------------------
577sub table {
578
579=pod
580
581=head2 table
582
b9dc0b40 583Get or set the field's table object. As the table object stringifies this can
584also be used to get the table name.
43b9dc7a 585
586 my $table = $field->table;
b9dc0b40 587 print "Table name: $table";
43b9dc7a 588
589=cut
590
591 my $self = shift;
592 if ( my $arg = shift ) {
593 return $self->error('Not a table object') unless
594 UNIVERSAL::isa( $arg, 'SQL::Translator::Schema::Table' );
595 $self->{'table'} = $arg;
596 }
597
598 return $self->{'table'};
3c5de62a 599}
600
07d6e5f7 601sub parsed_field {
602
603=head2
604
605Returns the field exactly as the parser found it
606
607=cut
608
609 my $self = shift;
610
611 if (@_) {
612 my $value = shift;
613 $self->{parsed_field} = $value;
614 return $value || $self;
615 }
616 return $self->{parsed_field} || $self;
617}
618
ec2ab48d 619# ----------------------------------------------------------------------
abf315bb 620sub equals {
621
622=pod
623
624=head2 equals
625
626Determines if this field is the same as another
627
628 my $isIdentical = $field1->equals( $field2 );
629
630=cut
631
632 my $self = shift;
633 my $other = shift;
634 my $case_insensitive = shift;
635
636 return 0 unless $self->SUPER::equals($other);
637 return 0 unless $case_insensitive ? uc($self->name) eq uc($other->name) : $self->name eq $other->name;
6b2dbb1a 638
639 # Comparing types: use sql_data_type if both are not 0. Else use string data_type
640 if ($self->sql_data_type && $other->sql_data_type) {
641 return 0 unless $self->sql_data_type == $other->sql_data_type
642 } else {
643 return 0 unless lc($self->data_type) eq lc($other->data_type)
644 }
645
abf315bb 646 return 0 unless $self->size eq $other->size;
f5fd433f 647
648 {
649 my $lhs = $self->default_value;
650 $lhs = \'NULL' unless defined $lhs;
651 my $lhs_is_ref = ! ! ref $lhs;
652
653 my $rhs = $other->default_value;
654 $rhs = \'NULL' unless defined $rhs;
655 my $rhs_is_ref = ! ! ref $rhs;
656
657 # If only one is a ref, fail. -- rjbs, 2008-12-02
658 return 0 if $lhs_is_ref xor $rhs_is_ref;
659
660 my $effective_lhs = $lhs_is_ref ? $$lhs : $lhs;
661 my $effective_rhs = $rhs_is_ref ? $$rhs : $rhs;
662
663 return 0 if $effective_lhs ne $effective_rhs;
664 }
665
abf315bb 666 return 0 unless $self->is_nullable eq $other->is_nullable;
afb07483 667# return 0 unless $self->is_unique eq $other->is_unique;
abf315bb 668 return 0 unless $self->is_primary_key eq $other->is_primary_key;
65e7a069 669# return 0 unless $self->is_foreign_key eq $other->is_foreign_key;
abf315bb 670 return 0 unless $self->is_auto_increment eq $other->is_auto_increment;
671# return 0 unless $self->comments eq $other->comments;
4598b71c 672 return 0 unless $self->_compare_objects(scalar $self->extra, scalar $other->extra);
abf315bb 673 return 1;
674}
675
676# ----------------------------------------------------------------------
ec2ab48d 677sub DESTROY {
9966eebc 678#
679# Destroy cyclical references.
680#
ec2ab48d 681 my $self = shift;
9966eebc 682 undef $self->{'table'};
683 undef $self->{'foreign_key_reference'};
ec2ab48d 684}
685
3c5de62a 6861;
687
688# ----------------------------------------------------------------------
689
690=pod
691
692=head1 AUTHOR
693
6606c4c6 694Ken Y. Clark E<lt>kclark@cpan.orgE<gt>.
3c5de62a 695
696=cut