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