Strip evil svn:keywords
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator / Producer / TT / Table.pm
CommitLineData
0be5b227 1package SQL::Translator::Producer::TT::Table;
2
3# -------------------------------------------------------------------
d4f84dd1 4# $Id: Table.pm 1440 2009-01-17 16:31:57Z jawnsy $
0be5b227 5# -------------------------------------------------------------------
478f608d 6# Copyright (C) 2002-2009 SQLFairy Authors
0be5b227 7#
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.
11#
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.
16#
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
20# 02111-1307 USA
21# -------------------------------------------------------------------
22
23=pod
24
25=head1 NAME
26
27SQL::Translator::Producer::TT::Table -
28 Produces output using the Template Toolkit from a SQL schema, per table.
29
30=head1 SYNOPSIS
31
32 # Normal STDOUT version
33 #
34 my $translator = SQL::Translator->new(
35 from => 'MySQL',
36 filename => 'foo_schema.sql',
37 to => 'TT::Table',
38 producer_args => {
39 tt_table => 'foo_table.tt',
40 },
41 );
42 print $translator->translate;
43
44 # To generate a file per table
45 #
46 my $translator = SQL::Translator->new(
47 from => 'MySQL',
48 filename => 'foo_schema.sql',
49 to => 'TT::Table',
50 producer_args => {
51 tt_table => 'foo_table.tt.html',
52 mk_files => 1,
53 mk_files_base => "./doc/tables",
54 mk_file_ext => ".html",
55 on_exists => "replace",
56 },
57 );
58 #
59 # ./doc/tables/ now contains the templated tables as $tablename.html
60 #
61
62=head1 DESCRIPTION
63
f65806ce 64Produces schema output using a given Template Tookit template,
65processing that template for each table in the schema. Optionally
66allows you to write the result for each table to a separate file.
0be5b227 67
68It needs one additional producer_arg of C<tt_table> which is the file
f65806ce 69name of the template to use. This template will be passed a template
70var of C<table>, which is the current
1672901e 71L<SQL::Translator::Producer::Table> table we are producing, which you
f65806ce 72can then use to walk the schema via the methods documented in that
1672901e 73module. You also get L<schema> as a shortcut to the
74L<SQL::Translator::Producer::Schema> for the table and C<translator>,
75the L<SQL::Translator> object for this parse in case you want to get
f65806ce 76access to any of the options etc set here.
0be5b227 77
78Here's a brief example of what the template could look like:
79
80 [% table.name %]
81 ================
82 [% FOREACH field = table.get_fields %]
83 [% field.name %] [% field.data_type %]([% field.size %])
84 [% END -%]
85
86See F<t/data/template/table.tt> for a more complete example.
87
f65806ce 88You can also set any of the options used to initiallize the Template
89object by adding them to your producer_args. See Template Toolkit docs
90for details of the options.
0be5b227 91
92 $translator = SQL::Translator->new(
93 to => 'TT',
94 producer_args => {
95 ttfile => 'foo_template.tt',
96 INCLUDE_PATH => '/foo/templates/tt',
97 INTERPOLATE => 1,
98 },
99 );
100
f65806ce 101If you set C<mk_files> and its additional options the producer will
102write a separate file for each table in the schema. This is useful for
103producing things like HTML documentation where every table gets its
104own page (you could also use TTSchema producer to add an index page).
105Its also particulary good for code generation where you want to
106produce a class file per table.
0be5b227 107
108=head1 OPTIONS
109
110=over 4
111
112=item tt_table
113
114File name of the template to run for each table.
115
116=item mk_files
117
f65806ce 118Set to true to output a file for each table in the schema (as well as
119returning the whole lot back to the Translalor and hence STDOUT). The
120file will be named after the table, with the optional C<mk_files_ext>
121added and placed in the directory C<mk_files_base>.
0be5b227 122
123=item mk_files_ext
124
125Extension (without the dot) to add to the filename when using mk_files.
126
127=item mk_files_base = DIR
128
f65806ce 129Dir to build the table files into when using mk_files. Defaults to the
130current directory.
0be5b227 131
132=item mk_file_dir
133
f65806ce 134Set true and if the file needs to written to a directory that doesn't
135exist, it will be created first.
0be5b227 136
137=item on_exists [Default:replace]
138
f65806ce 139What to do if we are running with mk_files and a file already exists
140where we want to write our output. One of "skip", "die", "replace",
141"insert". The default is die.
0be5b227 142
f65806ce 143B<replace> - Over-write the existing file with the new one, clobbering
144anything already there.
0be5b227 145
f65806ce 146B<skip> - Leave the origional file as it was and don't write the new
147version anywhere.
0be5b227 148
149B<die> - Die with an existing file error.
150
f65806ce 151B<insert> - Insert the generated output into the file bewteen a set of
152special comments (defined by the following options.) Any code between
153the comments will be overwritten (ie the results from a previous
154produce) but the rest of the file is left alone (your custom code).
155This is particularly useful for code generation as it allows you to
1672901e 156generate schema derived code and then add your own custom code
157to the file. Then when the schema changes you just re-produce to
f65806ce 158insert the new code.
0be5b227 159
160=item insert_comment_start
161
1672901e 162The comment to look for in the file when on_exists is C<insert>. Default
f65806ce 163is C<SQLF INSERT START>. Must appear on it own line, with only
164whitespace either side, to be recognised.
0be5b227 165
166=item insert_comment_end
167
1672901e 168The end comment to look for in the file when on_exists is C<insert>.
f65806ce 169Default is C<SQLF INSERT END>. Must appear on it own line, with only
170whitespace either side, to be recognised.
0be5b227 171
172=back
173
174=cut
175
176# -------------------------------------------------------------------
177
178use strict;
179
478f608d 180use vars qw[ $DEBUG @EXPORT_OK ];
0be5b227 181$DEBUG = 0 unless defined $DEBUG;
182
183use File::Path;
184use Template;
185use Data::Dumper;
186use Exporter;
187use base qw(Exporter);
188@EXPORT_OK = qw(produce);
189
190use SQL::Translator::Utils 'debug';
191
192my $Translator;
193
194sub produce {
195 $Translator = shift;
196 local $DEBUG = $Translator->debug;
197 my $scma = $Translator->schema;
198 my $pargs = $Translator->producer_args;
199 my $file = $pargs->{'tt_table'} or die "No template file given!";
200 $pargs->{on_exists} ||= "die";
201
202 debug "Processing template $file\n";
203 my $out;
204 my $tt = Template->new(
205 DEBUG => $DEBUG,
206 ABSOLUTE => 1, # Set so we can use from the command line sensibly
207 RELATIVE => 1, # Maybe the cmd line code should set it! Security!
208 %$pargs, # Allow any TT opts to be passed in the producer_args
209 ) || die "Failed to initialize Template object: ".Template->error;
210
211 for my $tbl ( sort {$a->order <=> $b->order} $scma->get_tables ) {
212 my $outtmp;
213 $tt->process( $file, {
214 translator => $Translator,
215 schema => $scma,
216 table => $tbl,
217 }, \$outtmp )
218 or die "Error processing template '$file' for table '".$tbl->name
219 ."': ".$tt->error;
220 $out .= $outtmp;
221
222 # Write out the file...
223 write_file( table_file($tbl), $outtmp ) if $pargs->{mk_files};
224 }
225
226 return $out;
227};
228
229# Work out the filename for a given table.
230sub table_file {
231 my ($tbl) = shift;
232 my $pargs = $Translator->producer_args;
233 my $root = $pargs->{mk_files_base};
234 my $ext = $pargs->{mk_file_ext};
235 return "$root/$tbl.$ext";
236}
237
238# Write the src given to the file given, handling the on_exists arg.
239sub write_file {
240 my ($file, $src) = @_;
241 my $pargs = $Translator->producer_args;
242 my $root = $pargs->{mk_files_base};
243
244 if ( -e $file ) {
245 if ( $pargs->{on_exists} eq "skip" ) {
246 warn "Skipping existing $file\n";
247 return 1;
248 }
249 elsif ( $pargs->{on_exists} eq "die" ) {
250 die "File $file already exists.\n";
251 }
252 elsif ( $pargs->{on_exists} eq "replace" ) {
253 warn "Replacing $file.\n";
254 }
255 elsif ( $pargs->{on_exists} eq "insert" ) {
256 warn "Inserting into $file.\n";
257 $src = insert_code($file, $src);
258 }
259 else {
260 die "Unknown on_exists action: $pargs->{on_exists}\n";
261 }
262 }
263 else {
264 warn "Creating $file.\n";
265 }
266
267 my ($dir) = $file =~ m!^(.*)/!; # Want greedy, eveything before the last /
268 if ( $dir and not -d $dir and $pargs->{mk_file_dir} ) { mkpath($dir); }
269
270 debug "Writing to $file\n";
271 open( FILE, ">$file") or die "Error opening file $file : $!\n";
272 print FILE $src;
273 close(FILE);
274}
275
276# Reads file and inserts code between the insert comments and returns the new
277# source.
278sub insert_code {
279 my ($file, $src) = @_;
280 my $pargs = $Translator->producer_args;
281 my $cstart = $pargs->{insert_comment_start} || "SQLF_INSERT_START";
282 my $cend = $pargs->{insert_comment_end} || "SQLF_INSERT_END";
283
284 # Slurp in the origional file
285 open ( FILE, "<", "$file") or die "Error opening file $file : $!\n";
286 local $/ = undef;
287 my $orig = <FILE>;
288 close(FILE);
289
290 # Insert the new code between the insert comments
291 unless (
292 $orig =~ s/^\s*?$cstart\s*?\n.*?^\s*?$cend\s*?\n/\n$cstart\n$src\n$cend\n/ms
293 ) {
294 warn "No insert done\n";
295 }
296
297 return $orig;
298}
299
3001;
301
302# -------------------------------------------------------------------
303
304=pod
305
306=head1 AUTHOR
307
308Mark Addison E<lt>grommit@users.sourceforge.netE<gt>.
309
310=head1 TODO
311
1672901e 312- Some tests for the various on exists options (they have been tested
0be5b227 313implicitley through use in a project but need some proper tests).
314
1672901e 315- More docs on code generation strategies.
0be5b227 316
1672901e 317- Better hooks for filename generation.
0be5b227 318
1672901e 319- Integrate with L<TT::Base> and L<TTSchema>.
0be5b227 320
321=head1 SEE ALSO
322
323SQL::Translator.
324
325=cut