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