From: Mark Addison Date: Thu, 7 Aug 2003 14:19:33 +0000 (+0000) Subject: Added TTSchema producer. X-Git-Tag: v0.04~353 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=2b2601b506861fa81674c960752231365bdbf436;p=dbsrgits%2FSQL-Translator.git Added TTSchema producer. --- diff --git a/MANIFEST b/MANIFEST index 5963dfd..591ffbb 100644 --- a/MANIFEST +++ b/MANIFEST @@ -29,6 +29,7 @@ lib/SQL/Translator/Producer/PostgreSQL.pm lib/SQL/Translator/Producer/SQLite.pm lib/SQL/Translator/Producer/Sybase.pm lib/SQL/Translator/Producer/SqlfXML.pm +lib/SQL/Translator/Producer/TTSchema.pm lib/SQL/Translator/Schema.pm lib/SQL/Translator/Schema/Constants.pm lib/SQL/Translator/Schema/Constraint.pm diff --git a/Makefile.PL b/Makefile.PL index 5ae5a21..549808b 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -23,8 +23,10 @@ check_version('IO::Scalar' => 0 => 0); check_version('Parse::RecDescent' => 1.94 => 0); check_version('Pod::Usage' => 0 => 0); check_version('Spreadsheet::ParseExcel' => 0 => 1); +check_version('Template' => 2.10 => 1); check_version('Test::More' => 0 => 0); check_version('Test::Exception' => 0 => 0); +check_version('Test::Differences' => 0 => 1); check_version('Text::ParseWords' => 0 => 0); check_version('Text::RecordParser' => 0.02 => 0); check_version('XML::Writer' => 0 => 1); diff --git a/lib/SQL/Translator/Producer/TTSchema.pm b/lib/SQL/Translator/Producer/TTSchema.pm new file mode 100644 index 0000000..dc9b64e --- /dev/null +++ b/lib/SQL/Translator/Producer/TTSchema.pm @@ -0,0 +1,113 @@ +package SQL::Translator::Producer::TTSchema; + +=pod + +=head1 NAME + +SQL::Translator::Producer::TTSchema - Produces output using the template toolkit +from a SQL schema. + +=cut + + +use strict; +use warnings; + +use vars qw[ $DEBUG $VERSION @EXPORT_OK ]; +#$VERSION = sprintf "%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/; +$VERSION = 0.1; +$DEBUG = 0 unless defined $DEBUG; + +use Data::Dumper; +use Exporter; +use base qw(Exporter); +@EXPORT_OK = qw(produce); + +use base qw/SQL::Translator::Producer/; # Doesn't do anything at the mo! +use Template; + +sub debug { + warn @_,"\n" if $DEBUG; +} + +sub produce { + my $translator = shift; + local $DEBUG = $translator->debug; + my $scma = $translator->schema; + my $args = $translator->producer_args; + my $file = delete $args->{ttfile} or die "No template file!"; + + debug "Processing template $file\n"; + my $out; + my $tt = Template->new( + DEBUG => $DEBUG, + ABSOLUTE => 1, # Set so we can use from the command line sensible. + RELATIVE => 1, # Maybe the cmd line code should set it! Security! + %$args, # Allow any TT opts to be passed in the producer_args + + ) || die "Failed to initialize Template object: ".Template->error; + $tt->process($file,{ schema => $scma },\$out) + or die "Error processing template '$file': ".$tt->error; + + return $out; +}; + +1; + +__END__ + +=pod + +=head1 SYNOPSIS + + use SQL::Translator; + $translator = SQL::Translator->new( + from => "MySQL", + filename => "foo_schema.sql", + to => "TT", + producer_args => { + ttfile => "foo_template.tt", + }, + ); + print $translator->translate; + +=head1 DESCRIPTION + +Produces schema output using a given Template Tookit template. + +It needs one additional producer_arg of C that is the file name of the +template to use. This template has one var added to it called C, which +is the SQL::Translator::Producer::Schema object so you can then template via +its methods. + + database: [% schema.database %] + tables: + [% FOREACH table = schema.get_tables %] + [% table.name %] + ================ + [% FOREACH field = table.get_fields %] + [% field.name %] [% field.datatype %]([% field.size %]) + [% END -%] + [% END %] + +See F for a more complete example. + +You can also set any of the options used to initiallize the Template object by +adding them to your producer_args. See Template Toolkit docs for details of +the options. + + $translator = SQL::Translator->new( + to => "TT", + producer_args => { + ttfile => "foo_template.tt", + INCLUDE_PATH => "/foo/templates/tt", + INTERPOLATE => 1, + }, + ); + +=head1 TODO + +B e.g. [% tables %] as a shortcut for +[% schema.get_tables %]. + +=cut diff --git a/t/18ttschema-producer.t b/t/18ttschema-producer.t new file mode 100644 index 0000000..a398f66 --- /dev/null +++ b/t/18ttschema-producer.t @@ -0,0 +1,192 @@ +#!/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 Test::More; +use Test::Exception; + +use Data::Dumper; +BEGIN { our %opt; map { $opt{$_}=1 if s/^-// } @ARGV; } +use constant DEBUG => (exists $opt{d} ? 1 : 0); +local $SIG{__WARN__} = sub { diag "[warn] ", @_; }; + +use FindBin qw/$Bin/; + +# Testing 1,2,3,4... +#============================================================================= + +eval { require Template; }; +if ($@ && $@ =~ m!locate Template.pm in!) { + plan skip_all => "You need Template Toolkit to run this test."; +} +eval { require Test::Differences; }; +if ($@ && $@ =~ m!locate Test/Differences.pm in!) { + plan skip_all => "You need Test::Differences for this test."; +} +use Test::Differences; +plan tests => 3; + +use SQL::Translator; +use SQL::Translator::Producer::TTSchema; + +# Parse the test XML schema +our $obj; +$obj = SQL::Translator->new( + debug => DEBUG, #$opt{d}, + show_warnings => 1, + add_drop_table => 1, + from => "SqlfXML", + filename => "$Bin/data/xml/schema-basic.xml", + to => "TTSchema", + producer_args => { + ttfile => "$Bin/data/template/basic.tt", + }, +); +my $out; +lives_ok { $out = $obj->translate; } "Produced template"; +ok $out ne "" ,"Output has some content"; +local $/ = undef; # slurp +eq_or_diff $out, ,"Output looks right"; +# I'm sure if this diff is the best test, it is probaly too sensitive. But it +# at least it will blow up if anything changes! + +print $out if DEBUG; +#print "Debug:", Dumper($obj) if DEBUG; + +__DATA__ +Schema: +Database: + +Table: Basic +========================================================================== + +Fields + id + data_type: int + size: 10 + is_nullable: 0 + default_value: + is_primary_key: 1 + is_unique: 0 + is_auto_increment: 1 + is_foreign_key: 0 + foreign_key_reference: + is_valid: 1 + order: 1 + extra: + table: Basic + + title + data_type: varchar + size: 100 + is_nullable: 0 + default_value: hello + is_primary_key: 0 + is_unique: 0 + is_auto_increment: 0 + is_foreign_key: 0 + foreign_key_reference: + is_valid: 1 + order: 2 + extra: + table: Basic + + description + data_type: text + size: 0 + is_nullable: 1 + default_value: + is_primary_key: 0 + is_unique: 0 + is_auto_increment: 0 + is_foreign_key: 0 + foreign_key_reference: + is_valid: 1 + order: 3 + extra: + table: Basic + + email + data_type: varchar + size: 255 + is_nullable: 1 + default_value: + is_primary_key: 0 + is_unique: 1 + is_auto_increment: 0 + is_foreign_key: 0 + foreign_key_reference: + is_valid: 1 + order: 4 + extra: + table: Basic + + explicitnulldef + data_type: varchar + size: 0 + is_nullable: 1 + default_value: + is_primary_key: 0 + is_unique: 0 + is_auto_increment: 0 + is_foreign_key: 0 + foreign_key_reference: + is_valid: 1 + order: 5 + extra: + table: Basic + + explicitemptystring + data_type: varchar + size: 0 + is_nullable: 1 + default_value: + is_primary_key: 0 + is_unique: 0 + is_auto_increment: 0 + is_foreign_key: 0 + foreign_key_reference: + is_valid: 1 + order: 6 + extra: + table: Basic + + +Indices + titleindex + table: Basic + fields: title + type: NORMAL + options: + is_valid: 1 + + +Constraints + ? + type: PRIMARY KEY + fields: id + expression: + match_type: + reference_fields: + reference_table: + deferrable: 1 + on_delete: + on_update: + options: + is_valid: 1 + + emailuniqueindex + type: UNIQUE + fields: email + expression: + match_type: + reference_fields: + reference_table: + deferrable: 1 + on_delete: + on_update: + options: + is_valid: 1 + diff --git a/t/data/template/basic.tt b/t/data/template/basic.tt new file mode 100644 index 0000000..aaf1285 --- /dev/null +++ b/t/data/template/basic.tt @@ -0,0 +1,51 @@ +Schema: [% schema.name %] +Database: [% schema.database %] + +[%- FOREACH table = schema.get_tables %] +Table: [% table.name %] +========================================================================== + +Fields + [%- FOREACH field = table.get_fields %] + [% field.name %] + data_type: [% field.data_type %] + size: [% field.size %] + is_nullable: [% field.is_nullable %] + default_value: [% field.default_value %] + is_primary_key: [% field.is_primary_key %] + is_unique: [% field.is_unique %] + is_auto_increment: [% field.is_auto_increment %] + is_foreign_key: [% field.is_foreign_key %] + foreign_key_reference: [% field.foreign_key_reference %] + is_valid: [% field.is_valid %] + order: [% field.order %] + extra: [% field.extra %] + table: [% field.table.name %] + [% END %] + +Indices + [%- FOREACH index = table.get_indices %] + [% index.name %] + table: [% index.table.name %] + fields: [% index.fields.join(', ') %] + type: [% index.type %] + options: [% index.options %] + is_valid: [% index.is_valid %] + [% END %] + +Constraints + [%- FOREACH constraint = table.get_constraints %] + [% constraint.name OR "?" %] + type: [% constraint.type %] + fields: [% constraint.fields.join(', ') %] + expression: [% constraint.expression %] + match_type: [% constraint.match_type %] + reference_fields: [% constraint.reference_fields.join(', ') %] + reference_table: [% constraint.reference_table.join(', ') %] + deferrable: [% constraint.deferrable %] + on_delete: [% constraint.on_delete %] + on_update: [% constraint.on_update %] + options: [% constraint.options %] + is_valid: [% constraint.is_valid %] + [% END -%] +[% END %]