1 package SQL::Translator::Producer::TT::Table;
3 # -------------------------------------------------------------------
4 # $Id: Table.pm,v 1.3 2004-08-19 20:58:05 grommit Exp $
5 # -------------------------------------------------------------------
6 # Copyright (C) 2002-4 SQLFairy Authors
8 # This program is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU General Public License as
10 # published by the Free Software Foundation; version 2.
12 # This program is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 # -------------------------------------------------------------------
27 SQL::Translator::Producer::TT::Table -
28 Produces output using the Template Toolkit from a SQL schema, per table.
32 # Normal STDOUT version
34 my $translator = SQL::Translator->new(
36 filename => 'foo_schema.sql',
39 tt_table => 'foo_table.tt',
42 print $translator->translate;
44 # To generate a file per table
46 my $translator = SQL::Translator->new(
48 filename => 'foo_schema.sql',
51 tt_table => 'foo_table.tt.html',
53 mk_files_base => "./doc/tables",
54 mk_file_ext => ".html",
55 on_exists => "replace",
59 # ./doc/tables/ now contains the templated tables as $tablename.html
64 Produces schema output using a given Template Tookit template,
65 processing that template for each table in the schema. Optionally
66 allows you to write the result for each table to a separate file.
68 It needs one additional producer_arg of C<tt_table> which is the file
69 name of the template to use. This template will be passed a template
70 var of C<table>, which is the current
71 L<SQL::Translator::Producer::Table> table we are producing, which you
72 can then use to walk the schema via the methods documented in that
73 module. You also get L<schema> as a shortcut to the
74 L<SQL::Translator::Producer::Schema> for the table and C<translator>,
75 the L<SQL::Translator> object for this parse in case you want to get
76 access to any of the options etc set here.
78 Here's a brief example of what the template could look like:
82 [% FOREACH field = table.get_fields %]
83 [% field.name %] [% field.data_type %]([% field.size %])
86 See F<t/data/template/table.tt> for a more complete example.
88 You can also set any of the options used to initiallize the Template
89 object by adding them to your producer_args. See Template Toolkit docs
90 for details of the options.
92 $translator = SQL::Translator->new(
95 ttfile => 'foo_template.tt',
96 INCLUDE_PATH => '/foo/templates/tt',
101 If you set C<mk_files> and its additional options the producer will
102 write a separate file for each table in the schema. This is useful for
103 producing things like HTML documentation where every table gets its
104 own page (you could also use TTSchema producer to add an index page).
105 Its also particulary good for code generation where you want to
106 produce a class file per table.
114 File name of the template to run for each table.
118 Set to true to output a file for each table in the schema (as well as
119 returning the whole lot back to the Translalor and hence STDOUT). The
120 file will be named after the table, with the optional C<mk_files_ext>
121 added and placed in the directory C<mk_files_base>.
125 Extension (without the dot) to add to the filename when using mk_files.
127 =item mk_files_base = DIR
129 Dir to build the table files into when using mk_files. Defaults to the
134 Set true and if the file needs to written to a directory that doesn't
135 exist, it will be created first.
137 =item on_exists [Default:replace]
139 What to do if we are running with mk_files and a file already exists
140 where we want to write our output. One of "skip", "die", "replace",
141 "insert". The default is die.
143 B<replace> - Over-write the existing file with the new one, clobbering
144 anything already there.
146 B<skip> - Leave the origional file as it was and don't write the new
149 B<die> - Die with an existing file error.
151 B<insert> - Insert the generated output into the file bewteen a set of
152 special comments (defined by the following options.) Any code between
153 the comments will be overwritten (ie the results from a previous
154 produce) but the rest of the file is left alone (your custom code).
155 This is particularly useful for code generation as it allows you to
156 generate schema derived code and then add your own custom code
157 to the file. Then when the schema changes you just re-produce to
160 =item insert_comment_start
162 The comment to look for in the file when on_exists is C<insert>. Default
163 is C<SQLF INSERT START>. Must appear on it own line, with only
164 whitespace either side, to be recognised.
166 =item insert_comment_end
168 The end comment to look for in the file when on_exists is C<insert>.
169 Default is C<SQLF INSERT END>. Must appear on it own line, with only
170 whitespace either side, to be recognised.
176 # -------------------------------------------------------------------
180 use vars qw[ $DEBUG $VERSION @EXPORT_OK ];
181 $VERSION = sprintf "%d.%02d", q$Revision: 1.3 $ =~ /(\d+)\.(\d+)/;
182 $DEBUG = 0 unless defined $DEBUG;
188 use base qw(Exporter);
189 @EXPORT_OK = qw(produce);
191 use SQL::Translator::Utils 'debug';
197 local $DEBUG = $Translator->debug;
198 my $scma = $Translator->schema;
199 my $pargs = $Translator->producer_args;
200 my $file = $pargs->{'tt_table'} or die "No template file given!";
201 $pargs->{on_exists} ||= "die";
203 debug "Processing template $file\n";
205 my $tt = Template->new(
207 ABSOLUTE => 1, # Set so we can use from the command line sensibly
208 RELATIVE => 1, # Maybe the cmd line code should set it! Security!
209 %$pargs, # Allow any TT opts to be passed in the producer_args
210 ) || die "Failed to initialize Template object: ".Template->error;
212 for my $tbl ( sort {$a->order <=> $b->order} $scma->get_tables ) {
214 $tt->process( $file, {
215 translator => $Translator,
219 or die "Error processing template '$file' for table '".$tbl->name
223 # Write out the file...
224 write_file( table_file($tbl), $outtmp ) if $pargs->{mk_files};
230 # Work out the filename for a given table.
233 my $pargs = $Translator->producer_args;
234 my $root = $pargs->{mk_files_base};
235 my $ext = $pargs->{mk_file_ext};
236 return "$root/$tbl.$ext";
239 # Write the src given to the file given, handling the on_exists arg.
241 my ($file, $src) = @_;
242 my $pargs = $Translator->producer_args;
243 my $root = $pargs->{mk_files_base};
246 if ( $pargs->{on_exists} eq "skip" ) {
247 warn "Skipping existing $file\n";
250 elsif ( $pargs->{on_exists} eq "die" ) {
251 die "File $file already exists.\n";
253 elsif ( $pargs->{on_exists} eq "replace" ) {
254 warn "Replacing $file.\n";
256 elsif ( $pargs->{on_exists} eq "insert" ) {
257 warn "Inserting into $file.\n";
258 $src = insert_code($file, $src);
261 die "Unknown on_exists action: $pargs->{on_exists}\n";
265 warn "Creating $file.\n";
268 my ($dir) = $file =~ m!^(.*)/!; # Want greedy, eveything before the last /
269 if ( $dir and not -d $dir and $pargs->{mk_file_dir} ) { mkpath($dir); }
271 debug "Writing to $file\n";
272 open( FILE, ">$file") or die "Error opening file $file : $!\n";
277 # Reads file and inserts code between the insert comments and returns the new
280 my ($file, $src) = @_;
281 my $pargs = $Translator->producer_args;
282 my $cstart = $pargs->{insert_comment_start} || "SQLF_INSERT_START";
283 my $cend = $pargs->{insert_comment_end} || "SQLF_INSERT_END";
285 # Slurp in the origional file
286 open ( FILE, "<", "$file") or die "Error opening file $file : $!\n";
291 # Insert the new code between the insert comments
293 $orig =~ s/^\s*?$cstart\s*?\n.*?^\s*?$cend\s*?\n/\n$cstart\n$src\n$cend\n/ms
295 warn "No insert done\n";
303 # -------------------------------------------------------------------
309 Mark Addison E<lt>grommit@users.sourceforge.netE<gt>.
313 - Some tests for the various on exists options (they have been tested
314 implicitley through use in a project but need some proper tests).
316 - More docs on code generation strategies.
318 - Better hooks for filename generation.
320 - Integrate with L<TT::Base> and L<TTSchema>.