Yay, versioning!
[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/;
4386b954 8use File::Spec;
a02675cd 9
41a6f8c0 10use base qw/DBIx::Class/;
a02675cd 11
0dc79249 12__PACKAGE__->mk_classdata('class_mappings' => {});
13__PACKAGE__->mk_classdata('source_registrations' => {});
1e10a11d 14__PACKAGE__->mk_classdata('storage_type' => '::DBI');
d7156e50 15__PACKAGE__->mk_classdata('storage');
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}";
267 eval "use $comp_class"; # If it fails, assume the user fixed it
268 if ($@) {
75d07914 269 $comp_class =~ s/::/\//g;
3b24f6ea 270 die $@ unless $@ =~ /Can't locate.+$comp_class\.pm\sin\s\@INC/;
75d07914 271 warn $@ if $@;
e6efde04 272 }
bab77431 273
274 $comp_class->source_name($comp) unless $comp_class->source_name;
275
276 push(@to_register, [ $comp_class->source_name, $comp_class ]);
bfb2bd4f 277 }
5ce32fc1 278 }
a02675cd 279 }
e6efde04 280 Class::C3->reinitialize;
281
282 foreach my $to (@to_register) {
283 $class->register_class(@$to);
284 # if $class->can('result_source_instance');
285 }
a02675cd 286}
287
87c4e602 288=head2 compose_connection
289
27f01d1f 290=over 4
291
ebc77b53 292=item Arguments: $target_namespace, @db_info
429bd4f1 293
d601dc88 294=item Return Value: $new_schema
27f01d1f 295
296=back
076652e8 297
2053ab2a 298Calls L<DBIx::Class::Schema/"compose_namespace"> to the target namespace,
299calls L<DBIx::Class::Schema/connection> with @db_info on the new schema,
300then injects the L<DBix::Class::ResultSetProxy> component and a
301resultset_instance classdata entry on all the new classes, in order to support
82b01c38 302$target_namespaces::$class->search(...) method calls.
303
304This is primarily useful when you have a specific need for class method access
305to a connection. In normal usage it is preferred to call
306L<DBIx::Class::Schema/connect> and use the resulting schema object to operate
307on L<DBIx::Class::ResultSet> objects with L<DBIx::Class::Schema/resultset> for
308more information.
54540863 309
076652e8 310=cut
311
a02675cd 312sub compose_connection {
ea20d0fd 313 my ($self, $target, @info) = @_;
80c90f5d 314 my $base = 'DBIx::Class::ResultSetProxy';
8ef144ff 315 eval "require ${base};";
bc0c9800 316 $self->throw_exception
317 ("No arguments to load_classes and couldn't load ${base} ($@)")
318 if $@;
be381829 319
320 if ($self eq $target) {
321 # Pathological case, largely caused by the docs on early C::M::DBIC::Plain
322 foreach my $moniker ($self->sources) {
323 my $source = $self->source($moniker);
324 my $class = $source->result_class;
325 $self->inject_base($class, $base);
326 $class->mk_classdata(resultset_instance => $source->resultset);
327 $class->mk_classdata(class_resolver => $self);
328 }
50041f3c 329 $self->connection(@info);
be381829 330 return $self;
331 }
332
66d9ef6b 333 my $schema = $self->compose_namespace($target, $base);
ecceadff 334 {
335 no strict 'refs';
336 *{"${target}::schema"} = sub { $schema };
337 }
338
66d9ef6b 339 $schema->connection(@info);
0dc79249 340 foreach my $moniker ($schema->sources) {
341 my $source = $schema->source($moniker);
342 my $class = $source->result_class;
343 #warn "$moniker $class $source ".$source->storage;
8c49f629 344 $class->mk_classdata(result_source_instance => $source);
ea20d0fd 345 $class->mk_classdata(resultset_instance => $source->resultset);
66d9ef6b 346 $class->mk_classdata(class_resolver => $schema);
bfb2bd4f 347 }
348 return $schema;
e678398e 349}
350
77254782 351=head2 compose_namespace
352
27f01d1f 353=over 4
354
355=item Arguments: $target_namespace, $additional_base_class?
82b01c38 356
d601dc88 357=item Return Value: $new_schema
27f01d1f 358
359=back
13765dad 360
82b01c38 361For each L<DBIx::Class::ResultSource> in the schema, this method creates a
362class in the target namespace (e.g. $target_namespace::CD,
363$target_namespace::Artist) that inherits from the corresponding classes
364attached to the current schema.
77254782 365
82b01c38 366It also attaches a corresponding L<DBIx::Class::ResultSource> object to the
367new $schema object. If C<$additional_base_class> is given, the new composed
368classes will inherit from first the corresponding classe from the current
369schema then the base class.
370
2053ab2a 371For example, for a schema with My::Schema::CD and My::Schema::Artist classes,
82b01c38 372
373 $schema->compose_namespace('My::DB', 'Base::Class');
374 print join (', ', @My::DB::CD::ISA) . "\n";
375 print join (', ', @My::DB::Artist::ISA) ."\n";
376
2053ab2a 377will produce the output
82b01c38 378
379 My::Schema::CD, Base::Class
380 My::Schema::Artist, Base::Class
77254782 381
382=cut
383
e678398e 384sub compose_namespace {
66d9ef6b 385 my ($self, $target, $base) = @_;
386 my %reg = %{ $self->source_registrations };
11b78bd6 387 my %target;
388 my %map;
66d9ef6b 389 my $schema = $self->clone;
e9100ff7 390 {
391 no warnings qw/redefine/;
392 local *Class::C3::reinitialize = sub { };
393 foreach my $moniker ($schema->sources) {
394 my $source = $schema->source($moniker);
395 my $target_class = "${target}::${moniker}";
396 $self->inject_base(
397 $target_class => $source->result_class, ($base ? $base : ())
398 );
399 $source->result_class($target_class);
400 }
b7951443 401 }
e9100ff7 402 Class::C3->reinitialize();
11b78bd6 403 {
404 no strict 'refs';
1edaf6fe 405 foreach my $meth (qw/class source resultset/) {
406 *{"${target}::${meth}"} =
407 sub { shift->schema->$meth(@_) };
408 }
11b78bd6 409 }
bfb2bd4f 410 return $schema;
b7951443 411}
412
87c4e602 413=head2 setup_connection_class
414
27f01d1f 415=over 4
416
ebc77b53 417=item Arguments: $target, @info
27f01d1f 418
419=back
076652e8 420
82b01c38 421Sets up a database connection class to inject between the schema and the
422subclasses that the schema creates.
429bd4f1 423
076652e8 424=cut
425
b7951443 426sub setup_connection_class {
427 my ($class, $target, @info) = @_;
63e9583a 428 $class->inject_base($target => 'DBIx::Class::DB');
429 #$target->load_components('DB');
b7951443 430 $target->connection(@info);
431}
432
87c4e602 433=head2 connection
434
27f01d1f 435=over 4
436
ebc77b53 437=item Arguments: @args
66d9ef6b 438
d601dc88 439=item Return Value: $new_schema
27f01d1f 440
441=back
82b01c38 442
443Instantiates a new Storage object of type
444L<DBIx::Class::Schema/"storage_type"> and passes the arguments to
445$storage->connect_info. Sets the connection in-place on the schema. See
446L<DBIx::Class::Storage::DBI/"connect_info"> for more information.
66d9ef6b 447
448=cut
449
450sub connection {
451 my ($self, @info) = @_;
e59d3e5b 452 return $self if !@info && $self->storage;
1e10a11d 453 my $storage_class = $self->storage_type;
454 $storage_class = 'DBIx::Class::Storage'.$storage_class
455 if $storage_class =~ m/^::/;
8ef144ff 456 eval "require ${storage_class};";
bc0c9800 457 $self->throw_exception(
458 "No arguments to load_classes and couldn't load ${storage_class} ($@)"
459 ) if $@;
66d9ef6b 460 my $storage = $storage_class->new;
461 $storage->connect_info(\@info);
462 $self->storage($storage);
4386b954 463 $self->on_connect() if($self->can('on_connect'));
66d9ef6b 464 return $self;
465}
466
87c4e602 467=head2 connect
468
27f01d1f 469=over 4
470
ebc77b53 471=item Arguments: @info
66d9ef6b 472
d601dc88 473=item Return Value: $new_schema
27f01d1f 474
475=back
82b01c38 476
477This is a convenience method. It is equivalent to calling
478$schema->clone->connection(@info). See L</connection> and L</clone> for more
479information.
66d9ef6b 480
481=cut
482
08b515f1 483sub connect { shift->clone->connection(@_) }
484
485=head2 txn_begin
486
82b01c38 487Begins a transaction (does nothing if AutoCommit is off). Equivalent to
488calling $schema->storage->txn_begin. See
489L<DBIx::Class::Storage::DBI/"txn_begin"> for more information.
08b515f1 490
491=cut
492
493sub txn_begin { shift->storage->txn_begin }
494
495=head2 txn_commit
496
82b01c38 497Commits the current transaction. Equivalent to calling
498$schema->storage->txn_commit. See L<DBIx::Class::Storage::DBI/"txn_commit">
499for more information.
08b515f1 500
501=cut
502
503sub txn_commit { shift->storage->txn_commit }
504
505=head2 txn_rollback
506
82b01c38 507Rolls back the current transaction. Equivalent to calling
508$schema->storage->txn_rollback. See
509L<DBIx::Class::Storage::DBI/"txn_rollback"> for more information.
08b515f1 510
511=cut
512
513sub txn_rollback { shift->storage->txn_rollback }
66d9ef6b 514
a62cf8d4 515=head2 txn_do
516
27f01d1f 517=over 4
518
ebc77b53 519=item Arguments: C<$coderef>, @coderef_args?
82b01c38 520
d601dc88 521=item Return Value: The return value of $coderef
27f01d1f 522
523=back
a62cf8d4 524
82b01c38 525Executes C<$coderef> with (optional) arguments C<@coderef_args> atomically,
526returning its result (if any). If an exception is caught, a rollback is issued
527and the exception is rethrown. If the rollback fails, (i.e. throws an
528exception) an exception is thrown that includes a "Rollback failed" message.
a62cf8d4 529
530For example,
531
24d67825 532 my $author_rs = $schema->resultset('Author')->find(1);
a62cf8d4 533
534 my $coderef = sub {
24d67825 535 my ($author, @titles) = @_;
a62cf8d4 536
537 # If any one of these fails, the entire transaction fails
24d67825 538 $author->create_related('books', {
539 title => $_
540 }) foreach (@titles);
a62cf8d4 541
24d67825 542 return $author->books;
a62cf8d4 543 };
544
545 my $rs;
546 eval {
24d67825 547 $rs = $schema->txn_do($coderef, $author_rs, qw/Night Day It/);
a62cf8d4 548 };
549
550 if ($@) {
551 my $error = $@;
552 if ($error =~ /Rollback failed/) {
553 die "something terrible has happened!";
554 } else {
555 deal_with_failed_transaction();
a62cf8d4 556 }
557 }
558
82b01c38 559In a nested transaction (calling txn_do() from within a txn_do() coderef) only
560the outermost transaction will issue a L<DBIx::Class::Schema/"txn_commit"> on
561the Schema's storage, and txn_do() can be called in void, scalar and list
562context and it will behave as expected.
a62cf8d4 563
564=cut
565
566sub txn_do {
567 my ($self, $coderef, @args) = @_;
568
171dadd7 569 ref $self or $self->throw_exception
570 ('Cannot execute txn_do as a class method');
571 ref $coderef eq 'CODE' or $self->throw_exception
572 ('$coderef must be a CODE reference');
a62cf8d4 573
574 my (@return_values, $return_value);
575
576 $self->txn_begin; # If this throws an exception, no rollback is needed
577
e7f2b7d5 578 my $wantarray = wantarray; # Need to save this since the context
75d07914 579 # inside the eval{} block is independent
580 # of the context that called txn_do()
a62cf8d4 581 eval {
82b01c38 582
24d67825 583 # Need to differentiate between scalar/list context to allow for
584 # returning a list in scalar context to get the size of the list
a62cf8d4 585 if ($wantarray) {
eeb34228 586 # list context
a62cf8d4 587 @return_values = $coderef->(@args);
eeb34228 588 } elsif (defined $wantarray) {
589 # scalar context
a62cf8d4 590 $return_value = $coderef->(@args);
eeb34228 591 } else {
592 # void context
593 $coderef->(@args);
a62cf8d4 594 }
595 $self->txn_commit;
596 };
597
598 if ($@) {
599 my $error = $@;
600
601 eval {
602 $self->txn_rollback;
603 };
604
605 if ($@) {
606 my $rollback_error = $@;
607 my $exception_class = "DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION";
608 $self->throw_exception($error) # propagate nested rollback
75d07914 609 if $rollback_error =~ /$exception_class/;
a62cf8d4 610
bc0c9800 611 $self->throw_exception(
612 "Transaction aborted: $error. Rollback failed: ${rollback_error}"
613 );
a62cf8d4 614 } else {
615 $self->throw_exception($error); # txn failed but rollback succeeded
616 }
617 }
618
619 return $wantarray ? @return_values : $return_value;
620}
621
66d9ef6b 622=head2 clone
623
27f01d1f 624=over 4
625
d601dc88 626=item Return Value: $new_schema
27f01d1f 627
628=back
82b01c38 629
66d9ef6b 630Clones the schema and its associated result_source objects and returns the
631copy.
632
633=cut
634
635sub clone {
636 my ($self) = @_;
637 my $clone = bless({ (ref $self ? %$self : ()) }, ref $self || $self);
638 foreach my $moniker ($self->sources) {
639 my $source = $self->source($moniker);
640 my $new = $source->new($source);
641 $clone->register_source($moniker => $new);
642 }
643 return $clone;
644}
645
87c4e602 646=head2 populate
647
27f01d1f 648=over 4
649
ebc77b53 650=item Arguments: $moniker, \@data;
27f01d1f 651
652=back
a37a4697 653
654Populates the source registered with the given moniker with the supplied data.
82b01c38 655@data should be a list of listrefs -- the first containing column names, the
656second matching values.
657
658i.e.,
a37a4697 659
24d67825 660 $schema->populate('Artist', [
661 [ qw/artistid name/ ],
662 [ 1, 'Popular Band' ],
663 [ 2, 'Indie Band' ],
a62cf8d4 664 ...
665 ]);
a37a4697 666
667=cut
668
669sub populate {
670 my ($self, $name, $data) = @_;
671 my $rs = $self->resultset($name);
672 my @names = @{shift(@$data)};
84e3c114 673 my @created;
a37a4697 674 foreach my $item (@$data) {
675 my %create;
676 @create{@names} = @$item;
84e3c114 677 push(@created, $rs->create(\%create));
a37a4697 678 }
84e3c114 679 return @created;
a37a4697 680}
681
5160b401 682=head2 throw_exception
701da8c4 683
75d07914 684=over 4
82b01c38 685
ebc77b53 686=item Arguments: $message
82b01c38 687
688=back
689
690Throws an exception. Defaults to using L<Carp::Clan> to report errors from
691user's perspective.
701da8c4 692
693=cut
694
695sub throw_exception {
696 my ($self) = shift;
697 croak @_;
698}
699
ec6704d4 700=head2 deploy (EXPERIMENTAL)
1c339d71 701
82b01c38 702=over 4
703
ebc77b53 704=item Arguments: $sqlt_args
82b01c38 705
706=back
707
708Attempts to deploy the schema to the current storage using L<SQL::Translator>.
ec6704d4 709
710Note that this feature is currently EXPERIMENTAL and may not work correctly
711across all databases, or fully handle complex relationships.
1c339d71 712
713=cut
714
715sub deploy {
cb561d1a 716 my ($self, $sqltargs) = @_;
1c339d71 717 $self->throw_exception("Can't deploy without storage") unless $self->storage;
cb561d1a 718 $self->storage->deploy($self, undef, $sqltargs);
1c339d71 719}
720
c0f61310 721=head2 create_ddl_dir (EXPERIMENTAL)
722
723=over 4
724
4386b954 725=item Arguments: \@databases, $version, $directory, $preversion, $sqlt_args
c0f61310 726
727=back
728
729Creates an SQL file based on the Schema, for each of the specified
4386b954 730database types, in the given directory. Given a previous version number,
731this will also create a file containing the ALTER TABLE statements to
732transform the previous schema into the current one. Note that these
733statements may contain DROP TABLE or DROP COLUMN statements that can
734potentially destroy data.
c0f61310 735
4386b954 736The file names are created using the C<ddl_filename> method below, please
737override thus method in your schema if you would like a different file
738name format. For the ALTER file, the same format is used, replacing
739$version in the name with "$preversion-$version".
740
741If no arguments are passed, then the following default values are used:
742
743=over 4
744
745=item databases - ['MySQL', 'SQLite', 'PostgreSQL']
746
747=item version - $schema->VERSION
748
749=item directory - './'
750
751=item preversion - <none>
752
753=back
c0f61310 754Note that this feature is currently EXPERIMENTAL and may not work correctly
755across all databases, or fully handle complex relationships.
756
4386b954 757WARNING: Please check all SQL files created, before applying them.
758
c0f61310 759=cut
760
e673f011 761sub create_ddl_dir
762{
763 my $self = shift;
764
765 $self->throw_exception("Can't create_ddl_dir without storage") unless $self->storage;
766 $self->storage->create_ddl_dir($self, @_);
767}
768
4386b954 769=head2 ddl_filename
770
771=over 4
772
773=item Arguments: $directory, $database-type, $version
774
775=back
776
777This method is called by C<create_ddl_dir> to compose a file name out of
778the supplied directory, database type and version number. The default file
779name format is: "$filename-$version-$type.sql".
780
781You may override this method in your schema if you wish to use a different
782format.
783
784=cut
785
e673f011 786sub ddl_filename
787{
4386b954 788 my ($self, $dir, $type, $version) = @_;
e673f011 789
790 my $filename = ref($self);
791 $filename =~ s/^.*:://;
4386b954 792 $filename = File::Spec->catpath($dir, "$filename-$version-$type.sql");
e673f011 793
794 return $filename;
795}
796
a02675cd 7971;
c2da098a 798
c2da098a 799=head1 AUTHORS
800
daec44b8 801Matt S. Trout <mst@shadowcatsystems.co.uk>
c2da098a 802
803=head1 LICENSE
804
805You may distribute this code under the same terms as Perl itself.
806
807=cut
808