1 package SQL::Translator::Schema;
7 SQL::Translator::Schema - SQL::Translator schema object
11 use SQL::Translator::Schema;
12 my $schema = SQL::Translator::Schema->new(
16 my $table = $schema->add_table( name => 'foo' );
17 my $view = $schema->add_view( name => 'bar', sql => '...' );
22 C<SQL::Translator::Schema> is the object that accepts, validates, and
23 returns the database structure.
30 use SQL::Translator::Schema::Constants;
31 use SQL::Translator::Schema::Procedure;
32 use SQL::Translator::Schema::Table;
33 use SQL::Translator::Schema::Trigger;
34 use SQL::Translator::Schema::View;
36 use SQL::Translator::Utils 'parse_list_arg';
40 SQL::Translator::Role::Error
41 SQL::Translator::Role::BuildArgs
42 SQL::Translator::Schema::Role::Extra
43 SQL::Translator::Schema::Role::Compare
46 our $VERSION = '1.59';
49 has _order => (is => 'ro', default => sub { +{ map { $_ => 0 } qw/
57 # FIXME - to be removed, together with the SQL::Translator::Schema::Graph* stuff
58 # looks like a remnant of the Turnkey project integration back in 2003-4
59 # Appears to be quite dead
62 eval { require Class::MakeMethods }
63 or croak 'You need to install the CPAN dependency Class::MakeMethods to use as_graph()';
65 require SQL::Translator::Schema::Graph;
69 return SQL::Translator::Schema::Graph->new(
70 translator => $self->translator );
79 Returns a Graph::Directed object with the table names for nodes.
83 require Graph::Directed;
86 my $g = Graph::Directed->new;
88 for my $table ( $self->get_tables ) {
89 my $tname = $table->name;
90 $g->add_vertex( $tname );
92 for my $field ( $table->get_fields ) {
93 if ( $field->is_foreign_key ) {
94 my $fktable = $field->foreign_key_reference->reference_table;
96 $g->add_edge( $fktable, $tname );
104 has _tables => ( is => 'ro', init_arg => undef, default => sub { +{} } );
112 Add a table object. Returns the new SQL::Translator::Schema::Table object.
113 The "name" parameter is required. If you try to create a table with the
114 same name as an existing table, you will get an error and the table will
117 my $t1 = $schema->add_table( name => 'foo' ) or die $schema->error;
118 my $t2 = SQL::Translator::Schema::Table->new( name => 'bar' );
119 $t2 = $schema->add_table( $table_bar ) or die $schema->error;
124 my $table_class = 'SQL::Translator::Schema::Table';
127 if ( UNIVERSAL::isa( $_[0], $table_class ) ) {
129 $table->schema($self);
132 my %args = ref $_[0] eq 'HASH' ? %{ $_[0] } : @_;
133 $args{'schema'} = $self;
134 $table = $table_class->new( \%args )
135 or return $self->error( $table_class->error );
138 $table->order( ++$self->_order->{table} );
140 # We know we have a name as the Table->new above errors if none given.
141 my $table_name = $table->name;
143 if ( defined $self->_tables->{$table_name} ) {
144 return $self->error(qq[Can't use table name "$table_name": table exists]);
147 $self->_tables->{$table_name} = $table;
159 Remove a table from the schema. Returns the table object if the table was found
160 and removed, an error otherwise. The single parameter can be either a table
161 name or an C<SQL::Translator::Schema::Table> object. The "cascade" parameter
162 can be set to 1 to also drop all triggers on the table, default is 0.
164 $schema->drop_table('mytable');
165 $schema->drop_table('mytable', cascade => 1);
170 my $table_class = 'SQL::Translator::Schema::Table';
173 if ( UNIVERSAL::isa( $_[0], $table_class ) ) {
174 $table_name = shift->name;
180 my $cascade = $args{'cascade'};
182 if ( !exists $self->_tables->{$table_name} ) {
183 return $self->error(qq[Can't drop table: $table_name" doesn't exist]);
186 my $table = delete $self->_tables->{$table_name};
190 # Drop all triggers on this table
191 $self->drop_trigger()
192 for ( grep { $_->on_table eq $table_name } values %{ $self->_triggers } );
197 has _procedures => ( is => 'ro', init_arg => undef, default => sub { +{} } );
205 Add a procedure object. Returns the new SQL::Translator::Schema::Procedure
206 object. The "name" parameter is required. If you try to create a procedure
207 with the same name as an existing procedure, you will get an error and the
208 procedure will not be created.
210 my $p1 = $schema->add_procedure( name => 'foo' );
211 my $p2 = SQL::Translator::Schema::Procedure->new( name => 'bar' );
212 $p2 = $schema->add_procedure( $procedure_bar ) or die $schema->error;
217 my $procedure_class = 'SQL::Translator::Schema::Procedure';
220 if ( UNIVERSAL::isa( $_[0], $procedure_class ) ) {
222 $procedure->schema($self);
225 my %args = ref $_[0] eq 'HASH' ? %{ $_[0] } : @_;
226 $args{'schema'} = $self;
227 return $self->error('No procedure name') unless $args{'name'};
228 $procedure = $procedure_class->new( \%args )
229 or return $self->error( $procedure_class->error );
232 $procedure->order( ++$self->_order->{proc} );
233 my $procedure_name = $procedure->name
234 or return $self->error('No procedure name');
236 if ( defined $self->_procedures->{$procedure_name} ) {
238 qq[Can't create procedure: "$procedure_name" exists] );
241 $self->_procedures->{$procedure_name} = $procedure;
251 =head2 drop_procedure
253 Remove a procedure from the schema. Returns the procedure object if the
254 procedure was found and removed, an error otherwise. The single parameter
255 can be either a procedure name or an C<SQL::Translator::Schema::Procedure>
258 $schema->drop_procedure('myprocedure');
263 my $proc_class = 'SQL::Translator::Schema::Procedure';
266 if ( UNIVERSAL::isa( $_[0], $proc_class ) ) {
267 $proc_name = shift->name;
273 if ( !exists $self->_procedures->{$proc_name} ) {
275 qq[Can't drop procedure: $proc_name" doesn't exist]);
278 my $proc = delete $self->_procedures->{$proc_name};
283 has _triggers => ( is => 'ro', init_arg => undef, default => sub { +{} } );
291 Add a trigger object. Returns the new SQL::Translator::Schema::Trigger object.
292 The "name" parameter is required. If you try to create a trigger with the
293 same name as an existing trigger, you will get an error and the trigger will
296 my $t1 = $schema->add_trigger( name => 'foo' );
297 my $t2 = SQL::Translator::Schema::Trigger->new( name => 'bar' );
298 $t2 = $schema->add_trigger( $trigger_bar ) or die $schema->error;
303 my $trigger_class = 'SQL::Translator::Schema::Trigger';
306 if ( UNIVERSAL::isa( $_[0], $trigger_class ) ) {
308 $trigger->schema($self);
311 my %args = ref $_[0] eq 'HASH' ? %{ $_[0] } : @_;
312 $args{'schema'} = $self;
313 return $self->error('No trigger name') unless $args{'name'};
314 $trigger = $trigger_class->new( \%args )
315 or return $self->error( $trigger_class->error );
318 $trigger->order( ++$self->_order->{trigger} );
320 my $trigger_name = $trigger->name or return $self->error('No trigger name');
321 if ( defined $self->_triggers->{$trigger_name} ) {
322 return $self->error(qq[Can't create trigger: "$trigger_name" exists]);
325 $self->_triggers->{$trigger_name} = $trigger;
337 Remove a trigger from the schema. Returns the trigger object if the trigger was
338 found and removed, an error otherwise. The single parameter can be either a
339 trigger name or an C<SQL::Translator::Schema::Trigger> object.
341 $schema->drop_trigger('mytrigger');
346 my $trigger_class = 'SQL::Translator::Schema::Trigger';
349 if ( UNIVERSAL::isa( $_[0], $trigger_class ) ) {
350 $trigger_name = shift->name;
353 $trigger_name = shift;
356 if ( !exists $self->_triggers->{$trigger_name} ) {
358 qq[Can't drop trigger: $trigger_name" doesn't exist]);
361 my $trigger = delete $self->_triggers->{$trigger_name};
366 has _views => ( is => 'ro', init_arg => undef, default => sub { +{} } );
374 Add a view object. Returns the new SQL::Translator::Schema::View object.
375 The "name" parameter is required. If you try to create a view with the
376 same name as an existing view, you will get an error and the view will
379 my $v1 = $schema->add_view( name => 'foo' );
380 my $v2 = SQL::Translator::Schema::View->new( name => 'bar' );
381 $v2 = $schema->add_view( $view_bar ) or die $schema->error;
386 my $view_class = 'SQL::Translator::Schema::View';
389 if ( UNIVERSAL::isa( $_[0], $view_class ) ) {
391 $view->schema($self);
394 my %args = ref $_[0] eq 'HASH' ? %{ $_[0] } : @_;
395 $args{'schema'} = $self;
396 return $self->error('No view name') unless $args{'name'};
397 $view = $view_class->new( \%args ) or return $view_class->error;
400 $view->order( ++$self->_order->{view} );
401 my $view_name = $view->name or return $self->error('No view name');
403 if ( defined $self->_views->{$view_name} ) {
404 return $self->error(qq[Can't create view: "$view_name" exists]);
407 $self->_views->{$view_name} = $view;
419 Remove a view from the schema. Returns the view object if the view was found
420 and removed, an error otherwise. The single parameter can be either a view
421 name or an C<SQL::Translator::Schema::View> object.
423 $schema->drop_view('myview');
428 my $view_class = 'SQL::Translator::Schema::View';
431 if ( UNIVERSAL::isa( $_[0], $view_class ) ) {
432 $view_name = shift->name;
438 if ( !exists $self->_views->{$view_name} ) {
439 return $self->error(qq[Can't drop view: $view_name" doesn't exist]);
442 my $view = delete $self->_views->{$view_name};
449 Get or set the schema's database. (optional)
451 my $database = $schema->database('PostgreSQL');
455 has database => ( is => 'rw', default => sub { '' } );
463 Returns true if all the tables and views are valid.
465 my $ok = $schema->is_valid or die $schema->error;
471 return $self->error('No tables') unless $self->get_tables;
473 for my $object ( $self->get_tables, $self->get_views ) {
474 return $object->error unless $object->is_valid;
486 Returns a procedure by the name provided.
488 my $procedure = $schema->get_procedure('foo');
493 my $procedure_name = shift or return $self->error('No procedure name');
494 return $self->error(qq[Table "$procedure_name" does not exist])
495 unless exists $self->_procedures->{$procedure_name};
496 return $self->_procedures->{$procedure_name};
503 =head2 get_procedures
505 Returns all the procedures as an array or array reference.
507 my @procedures = $schema->get_procedures;
514 sort { $a->[0] <=> $b->[0] }
515 map { [ $_->order, $_ ] } values %{ $self->_procedures };
518 return wantarray ? @procedures : \@procedures;
521 $self->error('No procedures');
522 return wantarray ? () : undef;
532 Returns a table by the name provided.
534 my $table = $schema->get_table('foo');
539 my $table_name = shift or return $self->error('No table name');
540 my $case_insensitive = shift;
541 if ( $case_insensitive ) {
542 $table_name = uc($table_name);
543 foreach my $table ( keys %{$self->_tables} ) {
544 return $self->_tables->{$table} if $table_name eq uc($table);
546 return $self->error(qq[Table "$table_name" does not exist]);
548 return $self->error(qq[Table "$table_name" does not exist])
549 unless exists $self->_tables->{$table_name};
550 return $self->_tables->{$table_name};
559 Returns all the tables as an array or array reference.
561 my @tables = $schema->get_tables;
568 sort { $a->[0] <=> $b->[0] }
569 map { [ $_->order, $_ ] } values %{ $self->_tables };
572 return wantarray ? @tables : \@tables;
575 $self->error('No tables');
576 return wantarray ? () : undef;
586 Returns a trigger by the name provided.
588 my $trigger = $schema->get_trigger('foo');
593 my $trigger_name = shift or return $self->error('No trigger name');
594 return $self->error(qq[Table "$trigger_name" does not exist])
595 unless exists $self->_triggers->{$trigger_name};
596 return $self->_triggers->{$trigger_name};
605 Returns all the triggers as an array or array reference.
607 my @triggers = $schema->get_triggers;
614 sort { $a->[0] <=> $b->[0] }
615 map { [ $_->order, $_ ] } values %{ $self->_triggers };
618 return wantarray ? @triggers : \@triggers;
621 $self->error('No triggers');
622 return wantarray ? () : undef;
632 Returns a view by the name provided.
634 my $view = $schema->get_view('foo');
639 my $view_name = shift or return $self->error('No view name');
640 return $self->error('View "$view_name" does not exist')
641 unless exists $self->_views->{$view_name};
642 return $self->_views->{$view_name};
651 Returns all the views as an array or array reference.
653 my @views = $schema->get_views;
660 sort { $a->[0] <=> $b->[0] }
661 map { [ $_->order, $_ ] } values %{ $self->_views };
664 return wantarray ? @views : \@views;
667 $self->error('No views');
668 return wantarray ? () : undef;
672 sub make_natural_joins {
676 =head2 make_natural_joins
678 Creates foriegn key relationships among like-named fields in different
679 tables. Accepts the following arguments:
685 A True or False argument which determins whether or not to perform
686 the joins from primary keys to fields of the same name in other tables
690 A list of fields to skip in the joins
694 $schema->make_natural_joins(
696 skip_fields => 'name,department_id',
703 my $join_pk_only = $args{'join_pk_only'} || 0;
705 map { s/^\s+|\s+$//g; $_, 1 } @{ parse_list_arg( $args{'skip_fields'} ) };
707 my ( %common_keys, %pk );
708 for my $table ( $self->get_tables ) {
709 for my $field ( $table->get_fields ) {
710 my $field_name = $field->name or next;
711 next if $skip_fields{$field_name};
712 $pk{$field_name} = 1 if $field->is_primary_key;
713 push @{ $common_keys{$field_name} }, $table->name;
717 for my $field ( keys %common_keys ) {
718 next if $join_pk_only and !defined $pk{$field};
720 my @table_names = @{ $common_keys{$field} };
721 next unless scalar @table_names > 1;
723 for my $i ( 0 .. $#table_names ) {
724 my $table1 = $self->get_table( $table_names[$i] ) or next;
726 for my $j ( 1 .. $#table_names ) {
727 my $table2 = $self->get_table( $table_names[$j] ) or next;
728 next if $table1->name eq $table2->name;
730 $table1->add_constraint(
733 reference_table => $table2->name,
734 reference_fields => $field,
745 Get or set the schema's name. (optional)
747 my $schema_name = $schema->name('Foo Database');
751 has name => ( is => 'rw', default => sub { '' } );
757 Get the SQL::Translator instance that instantiated the parser.
761 has translator => ( is => 'rw', weak_ref => 1 );
769 Ken Youens-Clark E<lt>kclark@cpan.orgE<gt>.