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::Producer::Table> table we are producing, which you
52 can then use to walk the schema via the methods documented in that
53 module. You also get L<schema> as a shortcut to the
54 L<SQL::Translator::Producer::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 initiallize 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 Its also particulary 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 origional 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 bewteen 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.
156 # -------------------------------------------------------------------
160 use vars qw[ $DEBUG $VERSION @EXPORT_OK ];
162 $DEBUG = 0 unless defined $DEBUG;
168 use base qw(Exporter);
169 @EXPORT_OK = qw(produce);
171 use SQL::Translator::Utils 'debug';
177 local $DEBUG = $Translator->debug;
178 my $scma = $Translator->schema;
179 my $pargs = $Translator->producer_args;
180 my $file = $pargs->{'tt_table'} or die "No template file given!";
181 $pargs->{on_exists} ||= "die";
183 debug "Processing template $file\n";
185 my $tt = Template->new(
187 ABSOLUTE => 1, # Set so we can use from the command line sensibly
188 RELATIVE => 1, # Maybe the cmd line code should set it! Security!
189 %$pargs, # Allow any TT opts to be passed in the producer_args
190 ) || die "Failed to initialize Template object: ".Template->error;
192 for my $tbl ( sort {$a->order <=> $b->order} $scma->get_tables ) {
194 $tt->process( $file, {
195 translator => $Translator,
199 or die "Error processing template '$file' for table '".$tbl->name
203 # Write out the file...
204 write_file( table_file($tbl), $outtmp ) if $pargs->{mk_files};
210 # Work out the filename for a given table.
213 my $pargs = $Translator->producer_args;
214 my $root = $pargs->{mk_files_base};
215 my $ext = $pargs->{mk_file_ext};
216 return "$root/$tbl.$ext";
219 # Write the src given to the file given, handling the on_exists arg.
221 my ($file, $src) = @_;
222 my $pargs = $Translator->producer_args;
223 my $root = $pargs->{mk_files_base};
226 if ( $pargs->{on_exists} eq "skip" ) {
227 warn "Skipping existing $file\n";
230 elsif ( $pargs->{on_exists} eq "die" ) {
231 die "File $file already exists.\n";
233 elsif ( $pargs->{on_exists} eq "replace" ) {
234 warn "Replacing $file.\n";
236 elsif ( $pargs->{on_exists} eq "insert" ) {
237 warn "Inserting into $file.\n";
238 $src = insert_code($file, $src);
241 die "Unknown on_exists action: $pargs->{on_exists}\n";
245 if ( my $interactive = -t STDIN && -t STDOUT ) {
246 warn "Creating $file.\n";
250 my ($dir) = $file =~ m!^(.*)/!; # Want greedy, eveything before the last /
251 if ( $dir and not -d $dir and $pargs->{mk_file_dir} ) { mkpath($dir); }
253 debug "Writing to $file\n";
254 open( FILE, ">$file") or die "Error opening file $file : $!\n";
259 # Reads file and inserts code between the insert comments and returns the new
262 my ($file, $src) = @_;
263 my $pargs = $Translator->producer_args;
264 my $cstart = $pargs->{insert_comment_start} || "SQLF_INSERT_START";
265 my $cend = $pargs->{insert_comment_end} || "SQLF_INSERT_END";
267 # Slurp in the origional file
268 open ( FILE, "<", "$file") or die "Error opening file $file : $!\n";
273 # Insert the new code between the insert comments
275 $orig =~ s/^\s*?$cstart\s*?\n.*?^\s*?$cend\s*?\n/\n$cstart\n$src\n$cend\n/ms
277 warn "No insert done\n";
285 # -------------------------------------------------------------------
291 Mark Addison E<lt>grommit@users.sourceforge.netE<gt>.
295 - Some tests for the various on exists options (they have been tested
296 implicitley through use in a project but need some proper tests).
298 - More docs on code generation strategies.
300 - Better hooks for filename generation.
302 - Integrate with L<TT::Base> and L<TTSchema>.