reshuffling the division of labor between Storage and Storage::DBI (not complete)
[dbsrgits/DBIx-Class-Historic.git] / lib / DBIx / Class / Schema.pm
CommitLineData
a02675cd 1package DBIx::Class::Schema;
2
3use strict;
4use warnings;
aa562407 5
701da8c4 6use Carp::Clan qw/^DBIx::Class/;
a917fb06 7use Scalar::Util qw/weaken/;
a02675cd 8
41a6f8c0 9use base qw/DBIx::Class/;
a02675cd 10
0dc79249 11__PACKAGE__->mk_classdata('class_mappings' => {});
12__PACKAGE__->mk_classdata('source_registrations' => {});
1e10a11d 13__PACKAGE__->mk_classdata('storage_type' => '::DBI');
d7156e50 14__PACKAGE__->mk_classdata('storage');
82cc0386 15__PACKAGE__->mk_classdata('exception_action');
a02675cd 16
c2da098a 17=head1 NAME
18
19DBIx::Class::Schema - composable schemas
20
21=head1 SYNOPSIS
22
24d67825 23 package Library::Schema;
c2da098a 24 use base qw/DBIx::Class::Schema/;
bab77431 25
24d67825 26 # load Library::Schema::CD, Library::Schema::Book, Library::Schema::DVD
27 __PACKAGE__->load_classes(qw/CD Book DVD/);
c2da098a 28
24d67825 29 package Library::Schema::CD;
03312470 30 use base qw/DBIx::Class/;
77254782 31 __PACKAGE__->load_components(qw/PK::Auto Core/); # for example
24d67825 32 __PACKAGE__->table('cd');
c2da098a 33
5d9076f2 34 # Elsewhere in your code:
24d67825 35 my $schema1 = Library::Schema->connect(
a3d93194 36 $dsn,
37 $user,
38 $password,
24d67825 39 { AutoCommit => 0 },
a3d93194 40 );
bab77431 41
24d67825 42 my $schema2 = Library::Schema->connect($coderef_returning_dbh);
c2da098a 43
24d67825 44 # fetch objects using Library::Schema::DVD
45 my $resultset = $schema1->resultset('DVD')->search( ... );
46 my @dvd_objects = $schema2->resultset('DVD')->search( ... );
c2da098a 47
48=head1 DESCRIPTION
49
a3d93194 50Creates database classes based on a schema. This is the recommended way to
51use L<DBIx::Class> and allows you to use more than one concurrent connection
52with your classes.
429bd4f1 53
03312470 54NB: If you're used to L<Class::DBI> it's worth reading the L</SYNOPSIS>
2053ab2a 55carefully, as DBIx::Class does things a little differently. Note in
03312470 56particular which module inherits off which.
57
c2da098a 58=head1 METHODS
59
87c4e602 60=head2 register_class
61
27f01d1f 62=over 4
63
ebc77b53 64=item Arguments: $moniker, $component_class
27f01d1f 65
66=back
076652e8 67
71f9df37 68Registers a class which isa DBIx::Class::ResultSourceProxy. Equivalent to
2053ab2a 69calling:
66d9ef6b 70
181a28f4 71 $schema->register_source($moniker, $component_class->result_source_instance);
076652e8 72
c2da098a 73=cut
74
a02675cd 75sub register_class {
0dc79249 76 my ($self, $moniker, $to_register) = @_;
77 $self->register_source($moniker => $to_register->result_source_instance);
74b92d9a 78}
79
87c4e602 80=head2 register_source
81
27f01d1f 82=over 4
83
ebc77b53 84=item Arguments: $moniker, $result_source
27f01d1f 85
86=back
076652e8 87
82b01c38 88Registers the L<DBIx::Class::ResultSource> in the schema with the given
89moniker.
076652e8 90
91=cut
92
0dc79249 93sub register_source {
94 my ($self, $moniker, $source) = @_;
95 my %reg = %{$self->source_registrations};
96 $reg{$moniker} = $source;
97 $self->source_registrations(\%reg);
98 $source->schema($self);
a917fb06 99 weaken($source->{schema}) if ref($self);
0dc79249 100 if ($source->result_class) {
101 my %map = %{$self->class_mappings};
102 $map{$source->result_class} = $moniker;
103 $self->class_mappings(\%map);
104 }
75d07914 105}
a02675cd 106
bfb2bd4f 107=head2 class
108
27f01d1f 109=over 4
82b01c38 110
ebc77b53 111=item Arguments: $moniker
27f01d1f 112
d601dc88 113=item Return Value: $classname
27f01d1f 114
115=back
82b01c38 116
2053ab2a 117Retrieves the result class name for the given moniker. For example:
82b01c38 118
119 my $class = $schema->class('CD');
bfb2bd4f 120
121=cut
122
123sub class {
0dc79249 124 my ($self, $moniker) = @_;
125 return $self->source($moniker)->result_class;
bfb2bd4f 126}
127
ea20d0fd 128=head2 source
129
27f01d1f 130=over 4
131
ebc77b53 132=item Arguments: $moniker
27f01d1f 133
d601dc88 134=item Return Value: $result_source
82b01c38 135
27f01d1f 136=back
82b01c38 137
24d67825 138 my $source = $schema->source('Book');
ea20d0fd 139
82b01c38 140Returns the L<DBIx::Class::ResultSource> object for the registered moniker.
ea20d0fd 141
142=cut
143
144sub source {
0dc79249 145 my ($self, $moniker) = @_;
146 my $sreg = $self->source_registrations;
147 return $sreg->{$moniker} if exists $sreg->{$moniker};
148
149 # if we got here, they probably passed a full class name
150 my $mapped = $self->class_mappings->{$moniker};
701da8c4 151 $self->throw_exception("Can't find source for ${moniker}")
0dc79249 152 unless $mapped && exists $sreg->{$mapped};
153 return $sreg->{$mapped};
ea20d0fd 154}
155
0dc79249 156=head2 sources
157
27f01d1f 158=over 4
159
d601dc88 160=item Return Value: @source_monikers
27f01d1f 161
162=back
82b01c38 163
164Returns the source monikers of all source registrations on this schema.
2053ab2a 165For example:
82b01c38 166
167 my @source_monikers = $schema->sources;
0dc79249 168
169=cut
170
171sub sources { return keys %{shift->source_registrations}; }
172
ea20d0fd 173=head2 resultset
174
27f01d1f 175=over 4
176
ebc77b53 177=item Arguments: $moniker
27f01d1f 178
d601dc88 179=item Return Value: $result_set
82b01c38 180
27f01d1f 181=back
82b01c38 182
24d67825 183 my $rs = $schema->resultset('DVD');
ea20d0fd 184
82b01c38 185Returns the L<DBIx::Class::ResultSet> object for the registered moniker.
ea20d0fd 186
187=cut
188
189sub resultset {
0dc79249 190 my ($self, $moniker) = @_;
191 return $self->source($moniker)->resultset;
ea20d0fd 192}
193
87c4e602 194=head2 load_classes
195
27f01d1f 196=over 4
197
198=item Arguments: @classes?, { $namespace => [ @classes ] }+
199
200=back
076652e8 201
82b01c38 202With no arguments, this method uses L<Module::Find> to find all classes under
203the schema's namespace. Otherwise, this method loads the classes you specify
204(using L<use>), and registers them (using L</"register_class">).
076652e8 205
2053ab2a 206It is possible to comment out classes with a leading C<#>, but note that perl
207will think it's a mistake (trying to use a comment in a qw list), so you'll
208need to add C<no warnings 'qw';> before your load_classes call.
5ce32fc1 209
2053ab2a 210Example:
82b01c38 211
212 My::Schema->load_classes(); # loads My::Schema::CD, My::Schema::Artist,
75d07914 213 # etc. (anything under the My::Schema namespace)
82b01c38 214
215 # loads My::Schema::CD, My::Schema::Artist, Other::Namespace::Producer but
216 # not Other::Namespace::LinerNotes nor My::Schema::Track
217 My::Schema->load_classes(qw/ CD Artist #Track /, {
218 Other::Namespace => [qw/ Producer #LinerNotes /],
219 });
220
076652e8 221=cut
222
a02675cd 223sub load_classes {
5ce32fc1 224 my ($class, @params) = @_;
bab77431 225
5ce32fc1 226 my %comps_for;
bab77431 227
5ce32fc1 228 if (@params) {
229 foreach my $param (@params) {
230 if (ref $param eq 'ARRAY') {
231 # filter out commented entries
232 my @modules = grep { $_ !~ /^#/ } @$param;
bab77431 233
5ce32fc1 234 push (@{$comps_for{$class}}, @modules);
235 }
236 elsif (ref $param eq 'HASH') {
237 # more than one namespace possible
238 for my $comp ( keys %$param ) {
239 # filter out commented entries
240 my @modules = grep { $_ !~ /^#/ } @{$param->{$comp}};
241
242 push (@{$comps_for{$comp}}, @modules);
243 }
244 }
245 else {
246 # filter out commented entries
247 push (@{$comps_for{$class}}, $param) if $param !~ /^#/;
248 }
249 }
250 } else {
41a6f8c0 251 eval "require Module::Find;";
bc0c9800 252 $class->throw_exception(
253 "No arguments to load_classes and couldn't load Module::Find ($@)"
254 ) if $@;
255 my @comp = map { substr $_, length "${class}::" }
256 Module::Find::findallmod($class);
5ce32fc1 257 $comps_for{$class} = \@comp;
41a6f8c0 258 }
5ce32fc1 259
e6efde04 260 my @to_register;
261 {
262 no warnings qw/redefine/;
263 local *Class::C3::reinitialize = sub { };
264 foreach my $prefix (keys %comps_for) {
265 foreach my $comp (@{$comps_for{$prefix}||[]}) {
266 my $comp_class = "${prefix}::${comp}";
c037c03a 267 $class->ensure_class_loaded($comp_class);
bab77431 268 $comp_class->source_name($comp) unless $comp_class->source_name;
269
270 push(@to_register, [ $comp_class->source_name, $comp_class ]);
bfb2bd4f 271 }
5ce32fc1 272 }
a02675cd 273 }
e6efde04 274 Class::C3->reinitialize;
275
276 foreach my $to (@to_register) {
277 $class->register_class(@$to);
278 # if $class->can('result_source_instance');
279 }
a02675cd 280}
281
87c4e602 282=head2 compose_connection
283
27f01d1f 284=over 4
285
ebc77b53 286=item Arguments: $target_namespace, @db_info
429bd4f1 287
d601dc88 288=item Return Value: $new_schema
27f01d1f 289
290=back
076652e8 291
2053ab2a 292Calls L<DBIx::Class::Schema/"compose_namespace"> to the target namespace,
293calls L<DBIx::Class::Schema/connection> with @db_info on the new schema,
294then injects the L<DBix::Class::ResultSetProxy> component and a
295resultset_instance classdata entry on all the new classes, in order to support
82b01c38 296$target_namespaces::$class->search(...) method calls.
297
298This is primarily useful when you have a specific need for class method access
299to a connection. In normal usage it is preferred to call
300L<DBIx::Class::Schema/connect> and use the resulting schema object to operate
301on L<DBIx::Class::ResultSet> objects with L<DBIx::Class::Schema/resultset> for
302more information.
54540863 303
076652e8 304=cut
305
a02675cd 306sub compose_connection {
ea20d0fd 307 my ($self, $target, @info) = @_;
80c90f5d 308 my $base = 'DBIx::Class::ResultSetProxy';
8ef144ff 309 eval "require ${base};";
bc0c9800 310 $self->throw_exception
311 ("No arguments to load_classes and couldn't load ${base} ($@)")
312 if $@;
be381829 313
314 if ($self eq $target) {
315 # Pathological case, largely caused by the docs on early C::M::DBIC::Plain
316 foreach my $moniker ($self->sources) {
317 my $source = $self->source($moniker);
318 my $class = $source->result_class;
319 $self->inject_base($class, $base);
320 $class->mk_classdata(resultset_instance => $source->resultset);
321 $class->mk_classdata(class_resolver => $self);
322 }
50041f3c 323 $self->connection(@info);
be381829 324 return $self;
325 }
326
66d9ef6b 327 my $schema = $self->compose_namespace($target, $base);
ecceadff 328 {
329 no strict 'refs';
330 *{"${target}::schema"} = sub { $schema };
331 }
332
66d9ef6b 333 $schema->connection(@info);
0dc79249 334 foreach my $moniker ($schema->sources) {
335 my $source = $schema->source($moniker);
336 my $class = $source->result_class;
337 #warn "$moniker $class $source ".$source->storage;
8c49f629 338 $class->mk_classdata(result_source_instance => $source);
ea20d0fd 339 $class->mk_classdata(resultset_instance => $source->resultset);
66d9ef6b 340 $class->mk_classdata(class_resolver => $schema);
bfb2bd4f 341 }
342 return $schema;
e678398e 343}
344
77254782 345=head2 compose_namespace
346
27f01d1f 347=over 4
348
349=item Arguments: $target_namespace, $additional_base_class?
82b01c38 350
d601dc88 351=item Return Value: $new_schema
27f01d1f 352
353=back
13765dad 354
82b01c38 355For each L<DBIx::Class::ResultSource> in the schema, this method creates a
356class in the target namespace (e.g. $target_namespace::CD,
357$target_namespace::Artist) that inherits from the corresponding classes
358attached to the current schema.
77254782 359
82b01c38 360It also attaches a corresponding L<DBIx::Class::ResultSource> object to the
361new $schema object. If C<$additional_base_class> is given, the new composed
362classes will inherit from first the corresponding classe from the current
363schema then the base class.
364
2053ab2a 365For example, for a schema with My::Schema::CD and My::Schema::Artist classes,
82b01c38 366
367 $schema->compose_namespace('My::DB', 'Base::Class');
368 print join (', ', @My::DB::CD::ISA) . "\n";
369 print join (', ', @My::DB::Artist::ISA) ."\n";
370
2053ab2a 371will produce the output
82b01c38 372
373 My::Schema::CD, Base::Class
374 My::Schema::Artist, Base::Class
77254782 375
376=cut
377
e678398e 378sub compose_namespace {
66d9ef6b 379 my ($self, $target, $base) = @_;
380 my %reg = %{ $self->source_registrations };
11b78bd6 381 my %target;
382 my %map;
66d9ef6b 383 my $schema = $self->clone;
e9100ff7 384 {
385 no warnings qw/redefine/;
386 local *Class::C3::reinitialize = sub { };
387 foreach my $moniker ($schema->sources) {
388 my $source = $schema->source($moniker);
389 my $target_class = "${target}::${moniker}";
390 $self->inject_base(
391 $target_class => $source->result_class, ($base ? $base : ())
392 );
393 $source->result_class($target_class);
9d3d5af3 394 $target_class->result_source_instance($source)
395 if $target_class->can('result_source_instance');
e9100ff7 396 }
b7951443 397 }
e9100ff7 398 Class::C3->reinitialize();
11b78bd6 399 {
400 no strict 'refs';
1edaf6fe 401 foreach my $meth (qw/class source resultset/) {
402 *{"${target}::${meth}"} =
403 sub { shift->schema->$meth(@_) };
404 }
11b78bd6 405 }
bfb2bd4f 406 return $schema;
b7951443 407}
408
87c4e602 409=head2 setup_connection_class
410
27f01d1f 411=over 4
412
ebc77b53 413=item Arguments: $target, @info
27f01d1f 414
415=back
076652e8 416
82b01c38 417Sets up a database connection class to inject between the schema and the
418subclasses that the schema creates.
429bd4f1 419
076652e8 420=cut
421
b7951443 422sub setup_connection_class {
423 my ($class, $target, @info) = @_;
63e9583a 424 $class->inject_base($target => 'DBIx::Class::DB');
425 #$target->load_components('DB');
b7951443 426 $target->connection(@info);
427}
428
87c4e602 429=head2 connection
430
27f01d1f 431=over 4
432
ebc77b53 433=item Arguments: @args
66d9ef6b 434
d601dc88 435=item Return Value: $new_schema
27f01d1f 436
437=back
82b01c38 438
439Instantiates a new Storage object of type
440L<DBIx::Class::Schema/"storage_type"> and passes the arguments to
441$storage->connect_info. Sets the connection in-place on the schema. See
442L<DBIx::Class::Storage::DBI/"connect_info"> for more information.
66d9ef6b 443
444=cut
445
446sub connection {
447 my ($self, @info) = @_;
e59d3e5b 448 return $self if !@info && $self->storage;
1e10a11d 449 my $storage_class = $self->storage_type;
450 $storage_class = 'DBIx::Class::Storage'.$storage_class
451 if $storage_class =~ m/^::/;
8ef144ff 452 eval "require ${storage_class};";
bc0c9800 453 $self->throw_exception(
454 "No arguments to load_classes and couldn't load ${storage_class} ($@)"
455 ) if $@;
82cc0386 456 my $storage = $storage_class->new($self);
66d9ef6b 457 $storage->connect_info(\@info);
458 $self->storage($storage);
459 return $self;
460}
461
87c4e602 462=head2 connect
463
27f01d1f 464=over 4
465
ebc77b53 466=item Arguments: @info
66d9ef6b 467
d601dc88 468=item Return Value: $new_schema
27f01d1f 469
470=back
82b01c38 471
472This is a convenience method. It is equivalent to calling
473$schema->clone->connection(@info). See L</connection> and L</clone> for more
474information.
66d9ef6b 475
476=cut
477
08b515f1 478sub connect { shift->clone->connection(@_) }
479
4012acd8 480=head2 txn_do
08b515f1 481
4012acd8 482=over 4
08b515f1 483
4012acd8 484=item Arguments: C<$coderef>, @coderef_args?
08b515f1 485
4012acd8 486=item Return Value: The return value of $coderef
08b515f1 487
4012acd8 488=back
08b515f1 489
4012acd8 490Executes C<$coderef> with (optional) arguments C<@coderef_args> atomically,
491returning its result (if any). Equivalent to calling $schema->storage->txn_do.
492See L<DBIx::Class::Storage/"txn_do"> for more information.
08b515f1 493
4012acd8 494This interface is preferred over using the individual methods L</txn_begin>,
495L</txn_commit>, and L</txn_rollback> below.
08b515f1 496
4012acd8 497=cut
08b515f1 498
4012acd8 499sub txn_do {
500 my $self = shift;
08b515f1 501
4012acd8 502 $self->storage or $self->throw_exception
503 ('txn_do called on $schema without storage');
08b515f1 504
4012acd8 505 $self->storage->txn_do(@_);
506}
08b515f1 507
4012acd8 508=head2 txn_begin
a62cf8d4 509
4012acd8 510Begins a transaction (does nothing if AutoCommit is off). Equivalent to
511calling $schema->storage->txn_begin. See
512L<DBIx::Class::Storage::DBI/"txn_begin"> for more information.
27f01d1f 513
4012acd8 514=cut
82b01c38 515
4012acd8 516sub txn_begin {
517 my $self = shift;
27f01d1f 518
4012acd8 519 $self->storage or $self->throw_exception
520 ('txn_begin called on $schema without storage');
a62cf8d4 521
4012acd8 522 $self->storage->txn_begin;
523}
a62cf8d4 524
4012acd8 525=head2 txn_commit
a62cf8d4 526
4012acd8 527Commits the current transaction. Equivalent to calling
528$schema->storage->txn_commit. See L<DBIx::Class::Storage::DBI/"txn_commit">
529for more information.
a62cf8d4 530
4012acd8 531=cut
a62cf8d4 532
4012acd8 533sub txn_commit {
534 my $self = shift;
a62cf8d4 535
4012acd8 536 $self->storage or $self->throw_exception
537 ('txn_commit called on $schema without storage');
a62cf8d4 538
4012acd8 539 $self->storage->txn_commit;
540}
70634260 541
4012acd8 542=head2 txn_rollback
a62cf8d4 543
4012acd8 544Rolls back the current transaction. Equivalent to calling
545$schema->storage->txn_rollback. See
546L<DBIx::Class::Storage::DBI/"txn_rollback"> for more information.
a62cf8d4 547
548=cut
549
4012acd8 550sub txn_rollback {
551 my $self = shift;
a62cf8d4 552
19630353 553 $self->storage or $self->throw_exception
4012acd8 554 ('txn_rollback called on $schema without storage');
a62cf8d4 555
4012acd8 556 $self->storage->txn_rollback;
a62cf8d4 557}
558
66d9ef6b 559=head2 clone
560
27f01d1f 561=over 4
562
d601dc88 563=item Return Value: $new_schema
27f01d1f 564
565=back
82b01c38 566
66d9ef6b 567Clones the schema and its associated result_source objects and returns the
568copy.
569
570=cut
571
572sub clone {
573 my ($self) = @_;
04786a4c 574 my $clone = { (ref $self ? %$self : ()) };
575 bless $clone, (ref $self || $self);
576
66d9ef6b 577 foreach my $moniker ($self->sources) {
578 my $source = $self->source($moniker);
579 my $new = $source->new($source);
580 $clone->register_source($moniker => $new);
581 }
82cc0386 582 $clone->storage->set_schema($clone) if $clone->storage;
66d9ef6b 583 return $clone;
584}
585
87c4e602 586=head2 populate
587
27f01d1f 588=over 4
589
ebc77b53 590=item Arguments: $moniker, \@data;
27f01d1f 591
592=back
a37a4697 593
594Populates the source registered with the given moniker with the supplied data.
82b01c38 595@data should be a list of listrefs -- the first containing column names, the
596second matching values.
597
598i.e.,
a37a4697 599
24d67825 600 $schema->populate('Artist', [
601 [ qw/artistid name/ ],
602 [ 1, 'Popular Band' ],
603 [ 2, 'Indie Band' ],
a62cf8d4 604 ...
605 ]);
a37a4697 606
607=cut
608
609sub populate {
610 my ($self, $name, $data) = @_;
611 my $rs = $self->resultset($name);
612 my @names = @{shift(@$data)};
84e3c114 613 my @created;
a37a4697 614 foreach my $item (@$data) {
615 my %create;
616 @create{@names} = @$item;
84e3c114 617 push(@created, $rs->create(\%create));
a37a4697 618 }
84e3c114 619 return @created;
a37a4697 620}
621
82cc0386 622=head2 exception_action
623
624=over 4
625
626=item Arguments: $code_reference
627
628=back
629
db5dc233 630If C<exception_action> is set for this class/object, L</throw_exception>
631will prefer to call this code reference with the exception as an argument,
632rather than its normal <croak> action.
633
634Your subroutine should probably just wrap the error in the exception
635object/class of your choosing and rethrow. If, against all sage advice,
636you'd like your C<exception_action> to suppress a particular exception
637completely, simply have it return true.
82cc0386 638
639Example:
640
641 package My::Schema;
642 use base qw/DBIx::Class::Schema/;
643 use My::ExceptionClass;
644 __PACKAGE__->exception_action(sub { My::ExceptionClass->throw(@_) });
645 __PACKAGE__->load_classes;
646
db5dc233 647 # or:
82cc0386 648 my $schema_obj = My::Schema->connect( .... );
649 $schema_obj->exception_action(sub { My::ExceptionClass->throw(@_) });
650
db5dc233 651 # suppress all exceptions, like a moron:
652 $schema_obj->exception_action(sub { 1 });
653
5160b401 654=head2 throw_exception
701da8c4 655
75d07914 656=over 4
82b01c38 657
ebc77b53 658=item Arguments: $message
82b01c38 659
660=back
661
662Throws an exception. Defaults to using L<Carp::Clan> to report errors from
db5dc233 663user's perspective. See L</exception_action> for details on overriding
664this method's behavior.
701da8c4 665
666=cut
667
668sub throw_exception {
82cc0386 669 my $self = shift;
db5dc233 670 croak @_ if !$self->exception_action || !$self->exception_action->(@_);
701da8c4 671}
672
ec6704d4 673=head2 deploy (EXPERIMENTAL)
1c339d71 674
82b01c38 675=over 4
676
ebc77b53 677=item Arguments: $sqlt_args
82b01c38 678
679=back
680
681Attempts to deploy the schema to the current storage using L<SQL::Translator>.
ec6704d4 682
683Note that this feature is currently EXPERIMENTAL and may not work correctly
684across all databases, or fully handle complex relationships.
1c339d71 685
51bace1c 686See L<SQL::Translator/METHODS> for a list of values for C<$sqlt_args>. The most
687common value for this would be C<< { add_drop_table => 1, } >> to have the SQL
688produced include a DROP TABLE statement for each table created.
689
1c339d71 690=cut
691
692sub deploy {
cb561d1a 693 my ($self, $sqltargs) = @_;
1c339d71 694 $self->throw_exception("Can't deploy without storage") unless $self->storage;
cb561d1a 695 $self->storage->deploy($self, undef, $sqltargs);
1c339d71 696}
697
c0f61310 698=head2 create_ddl_dir (EXPERIMENTAL)
699
700=over 4
701
702=item Arguments: \@databases, $version, $directory, $sqlt_args
703
704=back
705
706Creates an SQL file based on the Schema, for each of the specified
707database types, in the given directory.
708
709Note that this feature is currently EXPERIMENTAL and may not work correctly
710across all databases, or fully handle complex relationships.
711
712=cut
713
e673f011 714sub create_ddl_dir
715{
716 my $self = shift;
717
718 $self->throw_exception("Can't create_ddl_dir without storage") unless $self->storage;
719 $self->storage->create_ddl_dir($self, @_);
720}
721
9b83fccd 722=head2 ddl_filename (EXPERIMENTAL)
723
724 my $filename = $table->ddl_filename($type, $dir, $version)
725
726Creates a filename for a SQL file based on the table class name. Not
727intended for direct end user use.
728
729=cut
730
e673f011 731sub ddl_filename
732{
733 my ($self, $type, $dir, $version) = @_;
734
735 my $filename = ref($self);
9e7b9292 736 $filename =~ s/::/-/;
e673f011 737 $filename = "$dir$filename-$version-$type.sql";
738
739 return $filename;
740}
741
a02675cd 7421;
c2da098a 743
c2da098a 744=head1 AUTHORS
745
daec44b8 746Matt S. Trout <mst@shadowcatsystems.co.uk>
c2da098a 747
748=head1 LICENSE
749
750You may distribute this code under the same terms as Perl itself.
751
752=cut
753