1 package SQL::Translator::Schema::Field;
7 SQL::Translator::Schema::Field - SQL::Translator field object
11 use SQL::Translator::Schema::Field;
12 my $field = SQL::Translator::Schema::Field->new(
19 C<SQL::Translator::Schema::Field> is the field object.
26 use SQL::Translator::Schema::Constants;
27 use SQL::Translator::Types qw(schema_obj);
28 use SQL::Translator::Utils qw(parse_list_arg ex2err throw);
31 SQL::Translator::Schema::Role::Extra
32 SQL::Translator::Schema::Role::Error
33 SQL::Translator::Schema::Role::Compare
36 our ( $TABLE_COUNT, $VIEW_COUNT );
38 our $VERSION = '1.59';
40 # Stringify to our name, being careful not to pass any args through so we don't
41 # accidentally set it to undef. We also have to tweak bool so the object is
42 # still true when it doesn't have a name (which shouldn't happen!).
44 '""' => sub { shift->name },
45 'bool' => sub { $_[0]->name || $_[0] },
49 use DBI qw(:sql_types);
51 # Mapping from string to sql contstant
53 integer => SQL_INTEGER,
56 smallint => SQL_SMALLINT,
57 bigint => 9999, # DBI doesn't export a constatn for this. Le suck
61 decimal => SQL_DECIMAL,
62 numeric => SQL_NUMERIC,
68 datetime => SQL_DATETIME,
69 timestamp => SQL_TIMESTAMP,
73 varchar => SQL_VARCHAR,
75 varbinary => SQL_VARBINARY,
78 text => SQL_LONGVARCHAR
86 my $field = SQL::Translator::Schema::Field->new(
93 around BUILDARGS => sub {
96 my $args = $self->$orig(@_);
98 foreach my $arg (keys %{$args}) {
99 delete $args->{$arg} unless defined($args->{$arg});
106 Get or set the comments on a field. May be called several times to
107 set and it will accumulate the comments. Called in an array context,
108 returns each comment individually; called in a scalar context, returns
109 all the comments joined on newlines.
111 $field->comments('foo');
112 $field->comments('bar');
113 print join( ', ', $field->comments ); # prints "foo, bar"
119 coerce => sub { ref($_[0]) eq 'ARRAY' ? $_[0] : [$_[0]] },
120 default => sub { [] },
123 around comments => sub {
128 $arg = $arg->[0] if ref $arg;
129 push @{ $self->$orig }, $arg if $arg;
134 : join( "\n", @{ $self->$orig } );
140 Get or set the field's data type.
142 my $data_type = $field->data_type('integer');
146 has data_type => ( is => 'rw', default => sub { '' } );
150 Constant from DBI package representing this data type. See L<DBI/DBI Constants>
155 has sql_data_type => ( is => 'rw', lazy => 1, builder => 1 );
157 sub _build_sql_data_type {
158 $type_mapping{lc $_[0]->data_type} || SQL_UNKNOWN_TYPE;
163 Get or set the field's default value. Will return undef if not defined
164 and could return the empty string (it's a valid default value), so don't
165 assume an error like other methods.
167 my $default = $field->default_value('foo');
171 has default_value => ( is => 'rw' );
175 Get or set the field's "extra" attibutes (e.g., "ZEROFILL" for MySQL).
176 Accepts a hash(ref) of name/value pairs to store; returns a hash.
178 $field->extra( qualifier => 'ZEROFILL' );
179 my %extra = $field->extra;
183 =head2 foreign_key_reference
185 Get or set the field's foreign key reference;
187 my $constraint = $field->foreign_key_reference( $constraint );
191 has foreign_key_reference => (
193 predicate => '_has_foreign_key_reference',
194 isa => schema_obj('Constraint'),
197 around foreign_key_reference => sub {
201 if ( my $arg = shift ) {
203 'Foreign key reference for ', $self->name, 'already defined'
204 ) if $self->_has_foreign_key_reference;
206 return ex2err($orig, $self, $arg);
211 =head2 is_auto_increment
213 Get or set the field's C<is_auto_increment> attribute.
215 my $is_auto = $field->is_auto_increment(1);
219 has is_auto_increment => (
221 coerce => sub { $_[0] ? 1 : 0 },
226 sub _build_is_auto_increment {
229 if ( my $table = $self->table ) {
230 if ( my $schema = $table->schema ) {
232 $schema->database eq 'PostgreSQL' &&
233 $self->data_type eq 'serial'
242 =head2 is_foreign_key
244 Returns whether or not the field is a foreign key.
246 my $is_fk = $field->is_foreign_key;
250 has is_foreign_key => (
252 coerce => sub { $_[0] ? 1 : 0 },
257 sub _build_is_foreign_key {
260 if ( my $table = $self->table ) {
261 for my $c ( $table->get_constraints ) {
262 if ( $c->type eq FOREIGN_KEY ) {
263 my %fields = map { $_, 1 } $c->fields;
264 if ( $fields{ $self->name } ) {
265 $self->foreign_key_reference( $c );
276 Get or set whether the field can be null. If not defined, then
277 returns "1" (assumes the field can be null). The argument is evaluated
278 by Perl for True or False, so the following are eqivalent:
280 $is_nullable = $field->is_nullable(0);
281 $is_nullable = $field->is_nullable('');
282 $is_nullable = $field->is_nullable('0');
284 While this is technically a field constraint, it's probably easier to
285 represent this as an attribute of the field. In order keep things
286 consistent, any other constraint on the field (unique, primary, and
287 foreign keys; checks) are represented as table constraints.
293 coerce => sub { $_[0] ? 1 : 0 },
294 default => sub { 1 },
297 around is_nullable => sub {
298 my ($orig, $self, $arg) = @_;
300 $self->$orig($self->is_primary_key ? 0 : defined $arg ? $arg : ());
303 =head2 is_primary_key
305 Get or set the field's C<is_primary_key> attribute. Does not create
306 a table constraint (should it?).
308 my $is_pk = $field->is_primary_key(1);
312 has is_primary_key => (
314 coerce => sub { $_[0] ? 1 : 0 },
319 sub _build_is_primary_key {
322 if ( my $table = $self->table ) {
323 if ( my $pk = $table->primary_key ) {
324 my %fields = map { $_, 1 } $pk->fields;
325 return $fields{ $self->name } || 0;
333 Determine whether the field has a UNIQUE constraint or not.
335 my $is_unique = $field->is_unique;
339 has is_unique => ( is => 'lazy', init_arg => undef );
341 sub _build_is_unique {
344 if ( my $table = $self->table ) {
345 for my $c ( $table->get_constraints ) {
346 if ( $c->type eq UNIQUE ) {
347 my %fields = map { $_, 1 } $c->fields;
348 if ( $fields{ $self->name } ) {
363 Determine whether the field is valid or not.
365 my $ok = $field->is_valid;
370 return $self->error('No name') unless $self->name;
371 return $self->error('No data type') unless $self->data_type;
372 return $self->error('No table object') unless $self->table;
378 Get or set the field's name.
380 my $name = $field->name('foo');
382 The field object will also stringify to its name.
384 my $setter_name = "set_$field";
386 Errors ("No field name") if you try to set a blank name.
390 has name => ( is => 'rw', isa => sub { throw( "No field name" ) unless $_[0] } );
396 if ( my ($arg) = @_ ) {
397 if ( my $schema = $self->table ) {
398 return $self->error( qq[Can't use field name "$arg": field exists] )
399 if $schema->get_field( $arg );
403 return ex2err($orig, $self, @_);
410 Read only method to return the fields name with its table name pre-pended.
416 return $self->table.".".$self->name;
421 Get or set the field's order.
423 my $order = $field->order(3);
427 has order => ( is => 'rw', default => sub { 0 } );
429 around order => sub {
430 my ( $orig, $self, $arg ) = @_;
432 if ( defined $arg && $arg =~ /^\d+$/ ) {
433 return $self->$orig($arg);
443 Shortcut to get the fields schema ($field->table->schema) or undef if it
446 my $schema = $field->schema;
451 if ( my $table = $self->table ) { return $table->schema || undef; }
457 Get or set the field's size. Accepts a string, array or arrayref of
458 numbers and returns a string.
461 $field->size( [ 255 ] );
462 $size = $field->size( 10, 2 );
463 print $size; # prints "10,2"
465 $size = $field->size( '10, 2' );
466 print $size; # prints "10,2"
472 default => sub { [0] },
474 my @sizes = grep { defined && m/^\d+(?:\.\d+)?$/ } @{parse_list_arg($_[0])};
475 @sizes ? \@sizes : [0];
482 my $numbers = parse_list_arg( @_ );
486 for my $num ( @$numbers ) {
487 if ( defined $num && $num =~ m/^\d+(?:\.\d+)?$/ ) {
491 $self->$orig(\@new) if @new; # only set if all OK
495 ? @{ $self->$orig || [0] }
496 : join( ',', @{ $self->$orig || [0] } )
502 Get or set the field's table object. As the table object stringifies this can
503 also be used to get the table name.
505 my $table = $field->table;
506 print "Table name: $table";
510 has table => ( is => 'rw', isa => schema_obj('Table') );
512 around table => \&ex2err;
516 Returns the field exactly as the parser found it
520 has parsed_field => ( is => 'rw' );
522 around parsed_field => sub {
526 return $self->$orig(@_) || $self;
531 Determines if this field is the same as another
533 my $isIdentical = $field1->equals( $field2 );
537 around equals => sub {
541 my $case_insensitive = shift;
543 return 0 unless $self->$orig($other);
544 return 0 unless $case_insensitive ? uc($self->name) eq uc($other->name) : $self->name eq $other->name;
546 # Comparing types: use sql_data_type if both are not 0. Else use string data_type
547 if ($self->sql_data_type && $other->sql_data_type) {
548 return 0 unless $self->sql_data_type == $other->sql_data_type
550 return 0 unless lc($self->data_type) eq lc($other->data_type)
553 return 0 unless $self->size eq $other->size;
556 my $lhs = $self->default_value;
557 $lhs = \'NULL' unless defined $lhs;
558 my $lhs_is_ref = ! ! ref $lhs;
560 my $rhs = $other->default_value;
561 $rhs = \'NULL' unless defined $rhs;
562 my $rhs_is_ref = ! ! ref $rhs;
564 # If only one is a ref, fail. -- rjbs, 2008-12-02
565 return 0 if $lhs_is_ref xor $rhs_is_ref;
567 my $effective_lhs = $lhs_is_ref ? $$lhs : $lhs;
568 my $effective_rhs = $rhs_is_ref ? $$rhs : $rhs;
570 return 0 if $effective_lhs ne $effective_rhs;
573 return 0 unless $self->is_nullable eq $other->is_nullable;
574 # return 0 unless $self->is_unique eq $other->is_unique;
575 return 0 unless $self->is_primary_key eq $other->is_primary_key;
576 # return 0 unless $self->is_foreign_key eq $other->is_foreign_key;
577 return 0 unless $self->is_auto_increment eq $other->is_auto_increment;
578 # return 0 unless $self->comments eq $other->comments;
579 return 0 unless $self->_compare_objects(scalar $self->extra, scalar $other->extra);
585 # Destroy cyclical references.
588 undef $self->{'table'};
589 undef $self->{'foreign_key_reference'};
592 # Must come after all 'has' declarations
593 around new => \&ex2err;
601 Ken Youens-Clark E<lt>kclark@cpan.orgE<gt>.