Added Globals filter.
Mark Addison [Mon, 6 Mar 2006 17:46:57 +0000 (17:46 +0000)]
Changes
lib/SQL/Translator/Filter/Globals.pm [new file with mode: 0644]
t/39-filter-globals.t [new file with mode: 0644]

diff --git a/Changes b/Changes
index b58efd1..ac76a7f 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,6 +1,6 @@
 
 * Added mysql_character_set for 4.1+ -mda
-* Two experimental filters (DefaultExtra, Names). -mda
+* New filters, Names and Globals. -mda
 * Added the initial work on a template based Dia UML producer. -mda
 
 # -----------------------------------------------------------
diff --git a/lib/SQL/Translator/Filter/Globals.pm b/lib/SQL/Translator/Filter/Globals.pm
new file mode 100644 (file)
index 0000000..9262590
--- /dev/null
@@ -0,0 +1,162 @@
+package SQL::Translator::Filter::Globals;
+
+# -------------------------------------------------------------------
+# $Id: Globals.pm,v 1.1 2006-03-06 17:46:57 grommit Exp $
+# -------------------------------------------------------------------
+# Copyright (C) 2002-4 SQLFairy Authors
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307  USA
+# -------------------------------------------------------------------
+
+=head1 NAME
+
+SQL::Translator::Filter::Globals - Add global fields and indices to all tables.
+
+=head1 SYNOPSIS
+
+  # e.g. Add timestamp field to all tables.
+  use SQL::Translator;
+
+  my $sqlt = SQL::Translator->new(
+      from => 'MySQL',
+      to   => 'MySQL',
+      filters => [
+        Globals => {
+            fields => [
+                {
+                    name => 'modified'
+                    data_type => 'TIMESTAMP'
+                }
+            ],
+            indices => [
+                { 
+                    fields => 'modifed',
+                },
+            ]
+        },
+      ],
+  ) || die "SQLFairy error : ".SQL::Translator->error;
+  my $sql = $sqlt->translate || die "SQLFairy error : ".$sqlt->error;
+
+=cut
+
+use strict;
+use vars qw/$VERSION/;
+$VERSION=0.1;
+
+sub filter {
+    my $schema = shift;
+    my %args = @_;
+    my $global_table = $args{global_table} ||= '_GLOBAL_';
+
+    my (@global_fields, @global_indices);
+    push @global_fields, @{ $args{fields} }   if $args{fields};
+    push @global_indices, @{ $args{indices} } if $args{indices};
+
+    # Pull fields and indices off global table and then remove it.
+    if ( my $gtbl = $schema->get_table( $global_table ) ) {
+
+        foreach ( $gtbl->get_fields ) {
+            # We don't copy the order attrib so the added fields should get
+            # pushed on the end of each table.
+            push @global_fields, {
+                name                  => $_->name,
+                comments              => "".$_->comments,
+                data_type             => $_->data_type,
+                default_value         => $_->default_value,
+                size                  => [$_->size],
+                extra                 => scalar($_->extra),
+                foreign_key_reference => $_->foreign_key_reference,
+                is_auto_increment     => $_->is_auto_increment,
+                is_foreign_key        => $_->is_foreign_key,
+                is_nullable           => $_->is_nullable,
+                is_primary_key        => $_->is_primary_key,
+                is_unique             => $_->is_unique,
+                is_valid              => $_->is_valid,
+            };
+        }
+
+        foreach ( $gtbl->get_indices ) {
+            push @global_indices, {
+                name    => $_->name,
+                type    => $_->type,
+                fields  => [$_->fields],
+                options => [$_->options],
+            };
+        }
+
+        $schema->drop_table($gtbl);
+    }
+
+    # Add globalis to tables
+    foreach my $tbl ( $schema->get_tables ) {
+
+        foreach my $new_fld ( @global_fields ) {
+            # Don't add if field already there
+            next if $tbl->get_field( $new_fld->{name} );
+            $tbl->add_field( %$new_fld );
+        }
+
+        foreach my $new_index ( @global_indices ) {
+            # Don't add if already there
+            #next if $tbl->get_index( $new_index->{name} );
+            $tbl->add_index( %$new_index );
+        }
+    }
+}
+
+1;
+
+__END__
+
+=head1 DESCRIPTION
+
+Adds global fields and indices to all tables in the schema.
+The globals to add can either be defined in the filter args or using a _GLOBAL_
+table (see below).
+
+If a table already contains a field with the same name as a global then it is
+skipped for that table.
+
+=head2 The _GLOBAL_ Table
+
+An alternative to using the args is to add a table called C<_GLOBAL_> to the
+schema and then just use the filter. Any fields and indices defined on this table
+will be added to all the tables in the schema and the _GLOBAL_ table removed.
+
+The name of the global can be changed using a C<global_table> arg to the
+filter.
+
+=head1 SEE ALSO
+
+L<perl(1)>, L<SQL::Translator>
+
+=head1 BUGS
+
+Will generate duplicate indices if an index already exists on a table the same
+as one added globally.
+
+=head1 TODO
+
+Global addition of constraints.
+
+Some extra data values that can be used to control the global addition. e.g.
+'skip_global'.
+
+=head1 AUTHOR
+
+Mark Addison <grommit@users.sourceforge.net>
+
+=cut
diff --git a/t/39-filter-globals.t b/t/39-filter-globals.t
new file mode 100644 (file)
index 0000000..4bc19c1
--- /dev/null
@@ -0,0 +1,149 @@
+#!/usr/bin/perl -w
+# vim:filetype=perl
+
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl test.pl'
+
+use strict;
+use Test::More;
+use Test::Exception;
+use Test::SQL::Translator qw(maybe_plan);
+
+use Data::Dumper;
+
+BEGIN {
+    maybe_plan(4, 'YAML', 'Test::Differences')
+}
+use Test::Differences;
+use SQL::Translator;
+
+# The _GLOBAL_ table should be removed and its fields copied onto all other
+# tables.
+my $in_yaml = qq{---
+schema:
+  tables:
+    _GLOBAL_:
+      name: _GLOBAL_
+      fields:
+        modified:
+          name: modified
+          data_type: timestamp
+      indices:
+        - fields:
+            - modified
+    Person:
+      name: Person
+      fields:
+        first_name:
+          data_type: foovar
+          name: first_name
+};
+
+my $ans_yaml = qq{---
+schema:
+  procedures: {}
+  tables:
+    Person:
+      comments: ''
+      constraints: []
+      fields:
+        created:
+          comments: ''
+          data_type: timestamp
+          default_value: ~
+          extra: {}
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: created
+          order: 3
+          size:
+            - 0
+        first_name:
+          comments: ''
+          data_type: foovar
+          default_value: ~
+          extra: {}
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: first_name
+          order: 2
+          size:
+            - 0
+        modified:
+          comments: ''
+          data_type: timestamp
+          default_value: ~
+          extra: {}
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: modified
+          order: 4
+          size:
+            - 0
+      indices:
+        - fields:
+            - created
+          name: ''
+          options: []
+          type: NORMAL
+        - fields:
+            - modified
+          name: ''
+          options: []
+          type: NORMAL
+      name: Person
+      options: []
+      order: 2
+  triggers: {}
+  views: {}
+translator:
+  add_drop_table: 0
+  filename: ~
+  no_comments: 0
+  parser_args: {}
+  parser_type: SQL::Translator::Parser::YAML
+  producer_args: {}
+  producer_type: SQL::Translator::Producer::YAML
+  show_warnings: 1
+  trace: 0
+  version: 0.07
+};
+
+# Parse the test XML schema
+my $obj;
+$obj = SQL::Translator->new(
+    debug         => 0,
+    show_warnings => 1,
+    from          => "YAML",
+    to            => "YAML",
+    data          => $in_yaml,
+    filters => [
+        # Filter from SQL::Translator::Filter::*
+        [ 'Globals',
+            # A global field to add given in the args
+            fields => [
+                {
+                    name => 'created',
+                    data_type => 'timestamp',
+                    is_nullable => 0,
+                }
+            ],
+            indices => [
+                {
+                    fields => 'created',
+                }
+            ],
+        ],
+    ],
+
+) or die "Failed to create translator object: ".SQL::Translator->error;
+
+my $out;
+lives_ok { $out = $obj->translate; }  "Translate ran";
+is $obj->error, ''                   ,"No errors";
+ok $out ne ""                        ,"Produced something!";
+eq_or_diff $out, $ans_yaml           ,"Output looks right";
+#print "$out\n";