1 package SQL::Translator::Producer::TT::Table;
7 SQL::Translator::Producer::TT::Table -
8 Produces output using the Template Toolkit from a SQL schema, per table.
12 # Normal STDOUT version
14 my $translator = SQL::Translator->new(
16 filename => 'foo_schema.sql',
19 tt_table => 'foo_table.tt',
22 print $translator->translate;
24 # To generate a file per table
26 my $translator = SQL::Translator->new(
28 filename => 'foo_schema.sql',
31 tt_table => 'foo_table.tt.html',
33 mk_files_base => "./doc/tables",
34 mk_file_ext => ".html",
35 on_exists => "replace",
39 # ./doc/tables/ now contains the templated tables as $tablename.html
44 Produces schema output using a given Template Tookit template,
45 processing that template for each table in the schema. Optionally
46 allows you to write the result for each table to a separate file.
48 It needs one additional producer_arg of C<tt_table> which is the file
49 name of the template to use. This template will be passed a template
50 var of C<table>, which is the current
51 L<SQL::Translator::Schema::Table> table we are producing,
52 which you can then use to walk the schema via the methods documented
53 in that module. You also get C<schema> as a shortcut to the
54 L<SQL::Translator::Schema> for the table and C<translator>,
55 the L<SQL::Translator> object for this parse in case you want to get
56 access to any of the options etc set here.
58 Here's a brief example of what the template could look like:
62 [% FOREACH field = table.get_fields %]
63 [% field.name %] [% field.data_type %]([% field.size %])
66 See F<t/data/template/table.tt> for a more complete example.
68 You can also set any of the options used to initialize the Template
69 object by adding them to your producer_args. See Template Toolkit docs
70 for details of the options.
72 $translator = SQL::Translator->new(
75 ttfile => 'foo_template.tt',
76 INCLUDE_PATH => '/foo/templates/tt',
81 If you set C<mk_files> and its additional options the producer will
82 write a separate file for each table in the schema. This is useful for
83 producing things like HTML documentation where every table gets its
84 own page (you could also use TTSchema producer to add an index page).
85 It's also particularly good for code generation where you want to
86 produce a class file per table.
94 File name of the template to run for each table.
98 Set to true to output a file for each table in the schema (as well as
99 returning the whole lot back to the Translalor and hence STDOUT). The
100 file will be named after the table, with the optional C<mk_files_ext>
101 added and placed in the directory C<mk_files_base>.
105 Extension (without the dot) to add to the filename when using mk_files.
107 =item mk_files_base = DIR
109 Dir to build the table files into when using mk_files. Defaults to the
114 Set true and if the file needs to written to a directory that doesn't
115 exist, it will be created first.
117 =item on_exists [Default:replace]
119 What to do if we are running with mk_files and a file already exists
120 where we want to write our output. One of "skip", "die", "replace",
121 "insert". The default is die.
123 B<replace> - Over-write the existing file with the new one, clobbering
124 anything already there.
126 B<skip> - Leave the original file as it was and don't write the new
129 B<die> - Die with an existing file error.
131 B<insert> - Insert the generated output into the file between a set of
132 special comments (defined by the following options.) Any code between
133 the comments will be overwritten (ie the results from a previous
134 produce) but the rest of the file is left alone (your custom code).
135 This is particularly useful for code generation as it allows you to
136 generate schema derived code and then add your own custom code
137 to the file. Then when the schema changes you just re-produce to
140 =item insert_comment_start
142 The comment to look for in the file when on_exists is C<insert>. Default
143 is C<SQLF INSERT START>. Must appear on it own line, with only
144 whitespace either side, to be recognised.
146 =item insert_comment_end
148 The end comment to look for in the file when on_exists is C<insert>.
149 Default is C<SQLF INSERT END>. Must appear on it own line, with only
150 whitespace either side, to be recognised.
159 our ( $DEBUG, @EXPORT_OK );
160 our $VERSION = '1.59';
161 $DEBUG = 0 unless defined $DEBUG;
167 use base qw(Exporter);
168 @EXPORT_OK = qw(produce);
170 use SQL::Translator::Utils 'debug';
176 local $DEBUG = $Translator->debug;
177 my $scma = $Translator->schema;
178 my $pargs = $Translator->producer_args;
179 my $file = $pargs->{'tt_table'} or die "No template file given!";
180 $pargs->{on_exists} ||= "die";
182 debug "Processing template $file\n";
184 my $tt = Template->new(
186 ABSOLUTE => 1, # Set so we can use from the command line sensibly
187 RELATIVE => 1, # Maybe the cmd line code should set it! Security!
188 %$pargs, # Allow any TT opts to be passed in the producer_args
189 ) || die "Failed to initialize Template object: ".Template->error;
191 for my $tbl ( sort {$a->order <=> $b->order} $scma->get_tables ) {
193 $tt->process( $file, {
194 translator => $Translator,
198 or die "Error processing template '$file' for table '".$tbl->name
202 # Write out the file...
203 write_file( table_file($tbl), $outtmp ) if $pargs->{mk_files};
209 # Work out the filename for a given table.
212 my $pargs = $Translator->producer_args;
213 my $root = $pargs->{mk_files_base};
214 my $ext = $pargs->{mk_file_ext};
215 return "$root/$tbl.$ext";
218 # Write the src given to the file given, handling the on_exists arg.
220 my ($file, $src) = @_;
221 my $pargs = $Translator->producer_args;
222 my $root = $pargs->{mk_files_base};
225 if ( $pargs->{on_exists} eq "skip" ) {
226 warn "Skipping existing $file\n";
229 elsif ( $pargs->{on_exists} eq "die" ) {
230 die "File $file already exists.\n";
232 elsif ( $pargs->{on_exists} eq "replace" ) {
233 warn "Replacing $file.\n";
235 elsif ( $pargs->{on_exists} eq "insert" ) {
236 warn "Inserting into $file.\n";
237 $src = insert_code($file, $src);
240 die "Unknown on_exists action: $pargs->{on_exists}\n";
244 if ( my $interactive = -t STDIN && -t STDOUT ) {
245 warn "Creating $file.\n";
249 my ($dir) = $file =~ m!^(.*)/!; # Want greedy, everything before the last /
250 if ( $dir and not -d $dir and $pargs->{mk_file_dir} ) { mkpath($dir); }
252 debug "Writing to $file\n";
253 open( FILE, ">$file") or die "Error opening file $file : $!\n";
258 # Reads file and inserts code between the insert comments and returns the new
261 my ($file, $src) = @_;
262 my $pargs = $Translator->producer_args;
263 my $cstart = $pargs->{insert_comment_start} || "SQLF_INSERT_START";
264 my $cend = $pargs->{insert_comment_end} || "SQLF_INSERT_END";
266 # Slurp in the original file
267 open ( FILE, "<", "$file") or die "Error opening file $file : $!\n";
272 # Insert the new code between the insert comments
274 $orig =~ s/^\s*?$cstart\s*?\n.*?^\s*?$cend\s*?\n/\n$cstart\n$src\n$cend\n/ms
276 warn "No insert done\n";
288 Mark Addison E<lt>grommit@users.sourceforge.netE<gt>.
292 - Some tests for the various on exists options (they have been tested
293 implicitly through use in a project but need some proper tests).
295 - More docs on code generation strategies.
297 - Better hooks for filename generation.
299 - Integrate with L<TT::Base|SQL::Translator::Producer::TT::Base> and
300 L<TTSchema|SQL::Translator::Producer::TTSchema>.