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
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);
--- /dev/null
+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<ttfile> that is the file name of the
+template to use. This template has one var added to it called C<schema>, 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<t/data/template/basic.tt> 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<More template vars?> e.g. [% tables %] as a shortcut for
+[% schema.get_tables %].
+
+=cut
--- /dev/null
+#!/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, <DATA> ,"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
+
--- /dev/null
+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 %]